Files
adam-acs/inertia/pages/firmware_catalog/FirmwareCatalogCreate.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

97 lines
4.3 KiB
Vue

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { router } from '@inertiajs/vue3'
import { useI18n } from 'vue-i18n'
import TitleBar from '~/components/TitleBar.vue'
import { fetchWithCsrf } from '~/helpers/fetch_with_csrf'
const { t } = useI18n()
const form = ref({
identifier: '',
productClass: '',
version: '',
downloadUrl: '',
checksum: '',
checksumType: 'sha256' as 'sha256' | 'md5',
fileSize: null as number | null,
})
const errorMsg = ref('')
const productClasses = ref<string[]>([])
onMounted(async () => {
try {
const res = await fetch('/internal/devices/criteria-values')
if (res.ok) productClasses.value = (await res.json()).productClasses || []
} catch { /* optional */ }
})
async function submitForm() {
try {
const res = await fetchWithCsrf('/internal/firmware-catalog/entries', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(form.value),
})
if (res.ok) { router.get('/firmware-catalog') }
else { errorMsg.value = (await res.json()).message || 'Creation failed.' }
} catch { errorMsg.value = 'Network error.' }
}
</script>
<template>
<TitleBar section="firmware" :subtitle="t('labels.newFirmwareEntry')" />
<div class="container-xxl py-4">
<div v-if="errorMsg" class="alert alert-danger">{{ errorMsg }}</div>
<form @submit.prevent="submitForm">
<div class="card border-0 shadow-sm mb-4">
<div class="card-header"><h2 class="h6 mb-0">{{ t('labels.firmwareDetails') }}</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 font-monospace" placeholder="bm632w-1.0.0" required />
<div class="form-text">{{ t('placeholder.modelPath') }}</div>
</div>
<div class="col-md-6">
<label class="form-label">{{ t('labels.productClass') }} <span class="text-danger">*</span></label>
<input v-model="form.productClass" list="datalist-productClass" type="text" class="form-control" placeholder="BM632w" autocomplete="off" required />
<datalist id="datalist-productClass">
<option v-for="pc in productClasses" :key="pc" :value="pc" />
</datalist>
</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.fileSize') }}</label>
<input v-model.number="form.fileSize" type="number" class="form-control" min="0" placeholder="10485760" />
</div>
<div class="col-md-3">
<label class="form-label">{{ t('labels.checksumType') }}</label>
<select v-model="form.checksumType" class="form-select">
<option value="sha256">SHA-256</option>
<option value="md5">MD5</option>
</select>
</div>
<div class="col-12">
<label class="form-label">{{ t('labels.firmwareUrl') }} <span class="text-danger">*</span></label>
<input v-model="form.downloadUrl" type="url" class="form-control font-monospace" placeholder="http://firmware-server.local/firmware.bin" required />
</div>
<div class="col-12">
<label class="form-label">{{ t('labels.checksum') }} <span class="text-danger">*</span></label>
<input v-model="form.checksum" type="text" class="form-control font-monospace" placeholder="a1b2c3d4e5f6…" required />
</div>
</div>
</div>
</div>
<div class="d-flex gap-2 justify-content-end">
<button type="button" class="btn btn-outline-secondary" @click="router.get('/firmware-catalog')">{{ t('button.cancel') }}</button>
<button type="submit" class="btn btn-primary">{{ t('button.create') }}</button>
</div>
</form>
</div>
</template>