Files
adam-acs/inertia/pages/configurations/ConfigurationCreate.vue
T
kevin.lhereec 8cddf98093
Build & Deploy / build (push) Successful in 30s
Build & Deploy / docker (push) Successful in 1m6s
Build & Deploy / deploy (push) Failing after 33s
fix: CSRF token sur les requetes mutantes /internal + IPv6 Docker + tests Connection Request
- Ajout de fetchWithCsrf() helper qui lit le cookie XSRF-TOKEN et injecte
  X-XSRF-TOKEN sur toutes les requetes POST/PUT/PATCH/DELETE vers /internal/*
- Remplacement de fetch() par fetchWithCsrf() dans tous les composants Vue
  concernes (Tr069Trace, DeviceDetail, SequenceViewer, Home, configurations,
  firmware_catalog)
- Activation IPv6 sur les reseaux Docker (enable_ipv6: true, subnet fd00:adam::/64)
  dans docker-compose.yml et docker-compose.prod.yml
- Ajout tests unitaires DeviceService.sendWakeOnWlan : IPv4, IPv6, ENETUNREACH,
  credentials fallback chain (11 tests)
2026-07-17 10:16:29 +02:00

184 lines
7.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { ref } from 'vue'
import { router } from '@inertiajs/vue3'
import { useI18n } from 'vue-i18n'
import TitleBar from '~/components/TitleBar.vue'
import TagsInput from '~/components/configuration/TagsInput.vue'
import CriteriaEditor from '~/components/configuration/CriteriaEditor.vue'
import { fetchWithCsrf } from '~/helpers/fetch_with_csrf'
const { t } = useI18n()
const form = ref({
identifier: '',
name: '',
version: '1.0.0',
priority: 1,
policy: 'maintain',
enabled: true,
tags: [] as string[],
criteria: {} as Record<string, string>,
inventory: [] as { path: string }[],
desiredParameters: [] as { name: string; value: string; type: string }[],
})
const errorMsg = ref('')
function addInventoryPath() {
form.value.inventory.push({ path: '' })
}
function removeInventoryPath(index: number) {
form.value.inventory.splice(index, 1)
}
function addParameter() {
form.value.desiredParameters.push({ name: '', value: '', type: 'string' })
}
function removeParameter(index: number) {
form.value.desiredParameters.splice(index, 1)
}
async function submitForm() {
errorMsg.value = ''
try {
const response = await fetchWithCsrf('/internal/configurations', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(form.value),
})
if (response.ok) {
router.get('/configurations')
} else {
const err = await response.json()
errorMsg.value = err.message || 'An error occurred'
}
} catch (e) {
errorMsg.value = 'Failed to create configuration'
}
}
function goBack() {
router.get('/configurations')
}
</script>
<template>
<TitleBar section="configurations" subtitle="New Configuration" />
<div class="container-xxl py-4">
<div class="row">
<div class="col-12">
<div v-if="errorMsg" class="alert alert-danger mb-3">{{ errorMsg }}</div>
<form @submit.prevent="submitForm">
<!-- General Info -->
<div class="card border-0 shadow-sm mb-4">
<div class="card-header"><h2 class="h6 mb-0">{{ t('labels.general') }}</h2></div>
<div class="card-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">{{ t('labels.identifier') }} <span class="text-danger">*</span></label>
<input v-model="form.identifier" type="text" class="form-control" placeholder="my-config-001" required />
<div class="form-text">Kebab-case, e.g. bm632w-standard</div>
</div>
<div class="col-md-6">
<label class="form-label">{{ t('labels.name') }} <span class="text-danger">*</span></label>
<input v-model="form.name" type="text" class="form-control" placeholder="BM632w Standard" required />
</div>
<div class="col-md-3">
<label class="form-label">{{ t('labels.version') }} <span class="text-danger">*</span></label>
<input v-model="form.version" type="text" class="form-control" placeholder="1.0.0" pattern="\d+\.\d+\.\d+" required />
</div>
<div class="col-md-3">
<label class="form-label">{{ t('labels.priority') }} <span class="text-danger">*</span></label>
<input v-model.number="form.priority" type="number" class="form-control" min="1" required />
</div>
<div class="col-md-3">
<label class="form-label">{{ t('labels.policy') }} <span class="text-danger">*</span></label>
<select v-model="form.policy" class="form-select" required>
<option value="maintain">{{ t('labels.maintain') }}</option>
<option value="once">{{ t('labels.once') }}</option>
</select>
</div>
<div class="col-md-3 d-flex align-items-end">
<div class="form-check form-switch mb-2">
<input v-model="form.enabled" type="checkbox" class="form-check-input" id="enabled" role="switch" />
<label class="form-check-label" for="enabled">{{ t('labels.enabled') }}</label>
</div>
</div>
<div class="col-12">
<label class="form-label">{{ t('labels.tags') }}</label>
<TagsInput v-model="form.tags" />
</div>
</div>
</div>
</div>
<!-- Criteria -->
<div class="card border-0 shadow-sm mb-4">
<div class="card-header"><h2 class="h6 mb-0">{{ t('labels.matchingCriteria') }}</h2></div>
<div class="card-body">
<CriteriaEditor v-model="form.criteria" />
</div>
</div>
<!-- Inventory Paths -->
<div class="card border-0 shadow-sm mb-4">
<div class="card-header"><h2 class="h6 mb-0">{{ t('labels.inventoryPaths') }}</h2></div>
<div class="card-body">
<div v-for="(path, i) in form.inventory" :key="i" class="input-group mb-2">
<input v-model="path.path" type="text" class="form-control font-monospace" placeholder="InternetGatewayDevice.DeviceInfo." />
<button type="button" class="btn btn-outline-danger" @click="removeInventoryPath(i)">×</button>
</div>
<button type="button" class="btn btn-outline-secondary btn-sm mt-1" @click="addInventoryPath">
+ {{ t('button.addModelPath') }}
</button>
</div>
</div>
<!-- Desired Parameters -->
<div class="card border-0 shadow-sm mb-4">
<div class="card-header"><h2 class="h6 mb-0">{{ t('labels.desiredParameters') }}</h2></div>
<div class="card-body">
<div v-for="(param, i) in form.desiredParameters" :key="i" class="row g-2 mb-2 align-items-center">
<div class="col-md-5">
<input v-model="param.name" type="text" class="form-control form-control-sm font-monospace" placeholder="Parameter name" />
</div>
<div class="col-md-4">
<input v-model="param.value" type="text" class="form-control form-control-sm" placeholder="Value" />
</div>
<div class="col-md-2">
<select v-model="param.type" class="form-select form-select-sm">
<option value="string">string</option>
<option value="int">int</option>
<option value="unsignedInt">unsignedInt</option>
<option value="boolean">boolean</option>
<option value="dateTime">dateTime</option>
</select>
</div>
<div class="col-md-1 text-end">
<button type="button" class="btn btn-outline-danger btn-sm" @click="removeParameter(i)">×</button>
</div>
</div>
<button type="button" class="btn btn-outline-secondary btn-sm mt-1" @click="addParameter">
+ {{ t('button.addParameter') }}
</button>
</div>
</div>
<!-- Actions -->
<div class="d-flex gap-2 justify-content-end">
<button type="button" class="btn btn-outline-secondary" @click="goBack">{{ t('button.cancel') }}</button>
<button type="submit" class="btn btn-primary">{{ t('button.create') }}</button>
</div>
</form>
</div>
</div>
</div>
</template>