i18n: Add ~50 new translation keys (device, trace, sequence, inspector, configDetail, common sections), remove 15 unused keys. Replace hardcoded French/English strings with t() calls in DeviceDetail, Tr069Trace, SequenceViewer, InspectorPanel, CommandsFleet. Build + 765 tests pass.
This commit is contained in:
1 parent
850a3a17b2
commit
198f15ec9b
7 files changed
+189
-68
No files matched your search
@@ -1,11 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import type { CwmpExchange } from '../composables/useExchangeStream'
|
||||
|
||||
const props = defineProps<{
|
||||
selectedMessage: CwmpExchange | null
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const panelWidth = ref(400)
|
||||
const isResizing = ref(false)
|
||||
const copyConfirmation = ref(false)
|
||||
@@ -227,7 +229,7 @@ watch(
|
||||
<div v-if="!selectedMessage" class="inspector-placeholder d-flex align-items-center justify-content-center h-100 text-muted">
|
||||
<div class="text-center p-4">
|
||||
<i class="bi bi-file-earmark-code fs-1 d-block mb-3 opacity-50"></i>
|
||||
<p class="mb-0">Sélectionnez un message pour inspecter son contenu XML</p>
|
||||
<p class="mb-0">{{ t('inspector.selectMessage') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, nextTick, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { formatTimestamp, truncateMethod, needsTruncation, formatTraceStartTime } from '../helpers/sequence_viewer_helpers'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
export interface CwmpExchange {
|
||||
sequenceNumber: number
|
||||
timestamp: string
|
||||
@@ -338,11 +341,11 @@ const connectionBadgeClass = computed(() => {
|
||||
const connectionLabel = computed(() => {
|
||||
switch (connectionState.value) {
|
||||
case 'connected':
|
||||
return 'Connecté'
|
||||
return t('sequence.connected')
|
||||
case 'paused':
|
||||
return 'Pause'
|
||||
return t('sequence.paused')
|
||||
case 'disconnected':
|
||||
return 'Déconnecté'
|
||||
return t('sequence.disconnected')
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
@@ -418,7 +421,7 @@ watch(
|
||||
@click="requestClear"
|
||||
:disabled="isClearing"
|
||||
>
|
||||
Effacer les échanges
|
||||
{{ t('sequence.clearExchanges') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -451,7 +454,7 @@ watch(
|
||||
</svg>
|
||||
</div>
|
||||
<p class="text-muted mb-0">
|
||||
Aucun échange enregistré. Les messages SOAP apparaîtront ici lors de la prochaine connexion du CPE.
|
||||
{{ t('sequence.noExchanges') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -465,7 +468,7 @@ watch(
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="me-1" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1"/>
|
||||
</svg>
|
||||
Reprendre le défilement automatique
|
||||
{{ t('sequence.resumeScroll') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -491,9 +494,9 @@ watch(
|
||||
|
||||
<!-- Lifeline headers -->
|
||||
<div class="d-flex align-items-center border-bottom px-3 py-2 bg-light">
|
||||
<div class="text-center fw-bold small text-nowrap" style="width: 36px">CPE</div>
|
||||
<div class="text-center fw-bold small text-nowrap" style="width: 36px">{{ t('sequence.cpe') }}</div>
|
||||
<div class="flex-grow-1"></div>
|
||||
<div class="text-center fw-bold small text-nowrap" style="width: 36px">ACS</div>
|
||||
<div class="text-center fw-bold small text-nowrap" style="width: 36px">{{ t('sequence.acs') }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Messages container with scroll -->
|
||||
@@ -509,10 +512,10 @@ watch(
|
||||
<div class="spinner-border spinner-border-sm text-muted" role="status">
|
||||
<span class="visually-hidden">Chargement des messages plus anciens…</span>
|
||||
</div>
|
||||
<span class="text-muted small ms-2">Chargement…</span>
|
||||
<span class="text-muted small ms-2">{{ t('sequence.loading') }}</span>
|
||||
</div>
|
||||
<div v-else-if="!hasMoreOlderMessages && messages.length > BATCH_SIZE" class="text-center py-2">
|
||||
<span class="text-muted small">Tous les messages sont chargés</span>
|
||||
<span class="text-muted small">{{ t('sequence.allLoaded') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -555,7 +558,7 @@ watch(
|
||||
v-if="message.cwmpMethod === 'Empty'"
|
||||
class="small text-muted fst-italic mb-1"
|
||||
>
|
||||
POST vide
|
||||
{{ t('sequence.emptyPost') }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
@@ -604,7 +607,7 @@ watch(
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 id="clearConfirmLabel" class="modal-title">Effacer les échanges</h5>
|
||||
<h5 id="clearConfirmLabel" class="modal-title">{{ t('sequence.clearExchanges') }}</h5>
|
||||
<button type="button" class="btn-close" aria-label="Fermer" @click="cancelClear"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
+75
-18
@@ -38,21 +38,14 @@
|
||||
"name": "Name",
|
||||
"value": "Value",
|
||||
"type": "Type",
|
||||
"writable": "Writable",
|
||||
"discovery": "Discovery",
|
||||
"provisioning": "Provisioning",
|
||||
"criteria": "Criteria",
|
||||
"modelPaths": "Model Paths",
|
||||
"actions": "Actions",
|
||||
"actionType": "Action Type",
|
||||
"modelPath": "Model Path",
|
||||
"deviceIdentifier": "Device Identifier",
|
||||
"version": "Version",
|
||||
"policy": "Policy",
|
||||
"enabled": "Enabled",
|
||||
"disabled": "Disabled",
|
||||
"tags": "Tags",
|
||||
"compliance": "Compliance",
|
||||
"updatedAt": "Updated",
|
||||
"search": "Search",
|
||||
"general": "General",
|
||||
@@ -80,7 +73,8 @@
|
||||
"checksum": "Checksum",
|
||||
"filterByProductClass": "Filter by product class…",
|
||||
"saveChanges": "Save changes",
|
||||
"hardwareVersion": "Hardware version"
|
||||
"hardwareVersion": "Hardware version",
|
||||
"devices": "Devices"
|
||||
},
|
||||
"button": {
|
||||
"refresh": "Refresh",
|
||||
@@ -92,9 +86,7 @@
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm",
|
||||
"fleetManagement": "Fleet Management ({count})",
|
||||
"addCriteria": "Add Criteria",
|
||||
"addModelPath": "Add Path",
|
||||
"addAction": "Add Action",
|
||||
"addParameter": "Add Parameter",
|
||||
"previous": "Previous",
|
||||
"next": "Next"
|
||||
@@ -105,8 +97,7 @@
|
||||
},
|
||||
"placeholder": {
|
||||
"search": "Search...",
|
||||
"modelPath": "e.g. InternetGatewayDevice.DeviceInfo.",
|
||||
"value": "Value"
|
||||
"modelPath": "e.g. InternetGatewayDevice.DeviceInfo."
|
||||
},
|
||||
"options": {
|
||||
"NI": "Non-Immediate (NI)",
|
||||
@@ -172,7 +163,6 @@
|
||||
"tabInventory": "Inventory",
|
||||
"tabParameters": "Parameters",
|
||||
"tabCompliance": "Compliance",
|
||||
"tabDryRun": "Dry Run",
|
||||
"tabHistory": "History",
|
||||
"totalDevices": "Matching devices",
|
||||
"compliant": "Compliant",
|
||||
@@ -180,10 +170,6 @@
|
||||
"noMatchingDevices": "No devices match this configuration criteria.",
|
||||
"loadCompliance": "Load compliance report",
|
||||
"complianceError": "Error loading compliance report.",
|
||||
"diffs": "Diffs",
|
||||
"dryRunDesc": "Simulate applying this configuration to a device without making any real changes.",
|
||||
"dryRunPlaceholder": "e.g. AABBCC-Device-123",
|
||||
"runDryRun": "Run",
|
||||
"dryRunError": "Error during dry run.",
|
||||
"firmwareSkipped": "firmware outside schedule window",
|
||||
"paramDiffs": "Parameter differences",
|
||||
@@ -191,6 +177,77 @@
|
||||
"targetValue": "Target value",
|
||||
"notSet": "(not set)",
|
||||
"noParamDiffs": "No parameter differences.",
|
||||
"firmwarePath": "Firmware migration path"
|
||||
"firmwarePath": "Firmware migration path",
|
||||
"parameter": "Parameter",
|
||||
"expectedValue": "Expected value",
|
||||
"noCriteria": "No criteria defined.",
|
||||
"parameterConditions": "Parameter conditions",
|
||||
"noInventoryPaths": "No inventory paths defined.",
|
||||
"noParameters": "No parameters defined.",
|
||||
"noHistory": "No history available.",
|
||||
"date": "Date",
|
||||
"close": "Close"
|
||||
},
|
||||
"device": {
|
||||
"identity": "Identity",
|
||||
"identifier": "Identifier",
|
||||
"versions": "Versions",
|
||||
"system": "System",
|
||||
"nextConnection": "Next connection",
|
||||
"clientReferences": "Client references",
|
||||
"deleteDevice": "Delete device",
|
||||
"confirmDeleteMessage": "Confirm deletion of",
|
||||
"exchanges": "TR-069 Exchanges",
|
||||
"enableTracing": "Enable tracing",
|
||||
"tracingActive": "Tracing active"
|
||||
},
|
||||
"trace": {
|
||||
"tracedDevices": "Traced devices",
|
||||
"description": "Enable tracing on a device then click \"View\" to see live exchanges.",
|
||||
"deviceId": "Device ID",
|
||||
"started": "Started",
|
||||
"remove": "Remove",
|
||||
"enableTracing": "Enable tracing",
|
||||
"editJson": "Edit JSON",
|
||||
"editConfig": "Tracing configuration",
|
||||
"formatJson": "Format",
|
||||
"saveApply": "Save",
|
||||
"expectedFormat": "Expected format:",
|
||||
"notTraced": "This device is not traced yet.",
|
||||
"noTracedDevices": "No traced devices."
|
||||
},
|
||||
"sequence": {
|
||||
"cpe": "CPE",
|
||||
"acs": "ACS",
|
||||
"emptyPost": "Empty POST",
|
||||
"session": "Session",
|
||||
"goTo": "Go to…",
|
||||
"clear": "Clear",
|
||||
"clearExchanges": "Clear exchanges",
|
||||
"connected": "Connected",
|
||||
"paused": "Paused",
|
||||
"disconnected": "Disconnected",
|
||||
"resumeScroll": "Resume auto-scroll",
|
||||
"allLoaded": "All messages loaded",
|
||||
"loading": "Loading…",
|
||||
"noExchanges": "No exchanges recorded. SOAP messages will appear here on the next CPE connection.",
|
||||
"confirmClear": "Are you sure you want to delete all recorded exchanges for this device? This action is irreversible.",
|
||||
"confirmClearTitle": "Clear exchanges"
|
||||
},
|
||||
"inspector": {
|
||||
"title": "Inspector",
|
||||
"selectMessage": "Select a message to see its content.",
|
||||
"direction": "Direction",
|
||||
"method": "Method",
|
||||
"session": "Session",
|
||||
"timestamp": "Timestamp",
|
||||
"rawXml": "Raw XML"
|
||||
},
|
||||
"common": {
|
||||
"confirm": "Confirm",
|
||||
"cancel": "Cancel",
|
||||
"close": "Close",
|
||||
"actions": "Actions",
|
||||
"selected": "selected"
|
||||
}
|
||||
}
|
||||
+75
-18
@@ -38,21 +38,14 @@
|
||||
"name": "Nom",
|
||||
"value": "Valeur",
|
||||
"type": "Type",
|
||||
"writable": "Modifiable",
|
||||
"discovery": "Découverte",
|
||||
"provisioning": "Provisionnement",
|
||||
"criteria": "Critères",
|
||||
"modelPaths": "Chemins du modèle",
|
||||
"actions": "Actions",
|
||||
"actionType": "Type d'action",
|
||||
"modelPath": "Chemin du modèle",
|
||||
"deviceIdentifier": "Identifiant équipement",
|
||||
"version": "Version",
|
||||
"policy": "Politique",
|
||||
"enabled": "Activé",
|
||||
"disabled": "Désactivé",
|
||||
"tags": "Tags",
|
||||
"compliance": "Conformité",
|
||||
"updatedAt": "Modifié",
|
||||
"search": "Rechercher",
|
||||
"general": "Général",
|
||||
@@ -80,7 +73,8 @@
|
||||
"checksum": "Checksum",
|
||||
"filterByProductClass": "Filtrer par classe produit…",
|
||||
"saveChanges": "Enregistrer",
|
||||
"hardwareVersion": "Version matérielle"
|
||||
"hardwareVersion": "Version matérielle",
|
||||
"devices": "Équipements"
|
||||
},
|
||||
"button": {
|
||||
"refresh": "Rafraîchir",
|
||||
@@ -92,9 +86,7 @@
|
||||
"cancel": "Annuler",
|
||||
"confirm": "Confirmer",
|
||||
"fleetManagement": "Gestion de flotte ({count})",
|
||||
"addCriteria": "Ajouter un critère",
|
||||
"addModelPath": "Ajouter un chemin",
|
||||
"addAction": "Ajouter une action",
|
||||
"addParameter": "Ajouter un paramètre",
|
||||
"previous": "Précédent",
|
||||
"next": "Suivant"
|
||||
@@ -105,8 +97,7 @@
|
||||
},
|
||||
"placeholder": {
|
||||
"search": "Rechercher...",
|
||||
"modelPath": "Ex: InternetGatewayDevice.DeviceInfo.",
|
||||
"value": "Valeur"
|
||||
"modelPath": "Ex: InternetGatewayDevice.DeviceInfo."
|
||||
},
|
||||
"options": {
|
||||
"NI": "Non-immédiat (NI)",
|
||||
@@ -172,7 +163,6 @@
|
||||
"tabInventory": "Inventaire",
|
||||
"tabParameters": "Paramètres",
|
||||
"tabCompliance": "Conformité",
|
||||
"tabDryRun": "Dry Run",
|
||||
"tabHistory": "Historique",
|
||||
"totalDevices": "Équipements correspondants",
|
||||
"compliant": "Conforme",
|
||||
@@ -180,10 +170,6 @@
|
||||
"noMatchingDevices": "Aucun équipement ne correspond aux critères.",
|
||||
"loadCompliance": "Charger le rapport de conformité",
|
||||
"complianceError": "Erreur lors du chargement de la conformité.",
|
||||
"diffs": "Différences",
|
||||
"dryRunDesc": "Simulez l'application de cette configuration sur un équipement sans effectuer de modification réelle.",
|
||||
"dryRunPlaceholder": "ex: AABBCC-Device-123",
|
||||
"runDryRun": "Lancer",
|
||||
"dryRunError": "Erreur lors du dry run.",
|
||||
"firmwareSkipped": "firmware hors plage horaire",
|
||||
"paramDiffs": "Différences de paramètres",
|
||||
@@ -191,6 +177,77 @@
|
||||
"targetValue": "Valeur cible",
|
||||
"notSet": "(non défini)",
|
||||
"noParamDiffs": "Aucune différence de paramètres.",
|
||||
"firmwarePath": "Chemin de migration firmware"
|
||||
"firmwarePath": "Chemin de migration firmware",
|
||||
"parameter": "Paramètre",
|
||||
"expectedValue": "Valeur attendue",
|
||||
"noCriteria": "Aucun critère défini.",
|
||||
"parameterConditions": "Conditions sur les paramètres",
|
||||
"noInventoryPaths": "Aucun chemin d'inventaire défini.",
|
||||
"noParameters": "Aucun paramètre défini.",
|
||||
"noHistory": "Aucun historique disponible.",
|
||||
"date": "Date",
|
||||
"close": "Fermer"
|
||||
},
|
||||
"device": {
|
||||
"identity": "Identité",
|
||||
"identifier": "Identifiant",
|
||||
"versions": "Versions",
|
||||
"system": "Système",
|
||||
"nextConnection": "Prochaine connexion",
|
||||
"clientReferences": "Références client",
|
||||
"deleteDevice": "Supprimer l'équipement",
|
||||
"confirmDeleteMessage": "Confirmer la suppression de",
|
||||
"exchanges": "Échanges TR-069",
|
||||
"enableTracing": "Activer le tracing",
|
||||
"tracingActive": "Tracing actif"
|
||||
},
|
||||
"trace": {
|
||||
"tracedDevices": "Équipements tracés",
|
||||
"description": "Activez le tracing sur un équipement puis cliquez sur « Voir » pour visualiser les échanges en direct.",
|
||||
"deviceId": "Device ID",
|
||||
"started": "Démarré",
|
||||
"remove": "Supprimer",
|
||||
"enableTracing": "Activer le tracing",
|
||||
"editJson": "Éditer JSON",
|
||||
"editConfig": "Configuration du tracing",
|
||||
"formatJson": "Formater",
|
||||
"saveApply": "Sauvegarder",
|
||||
"expectedFormat": "Format attendu :",
|
||||
"notTraced": "L'équipement n'est pas encore tracé.",
|
||||
"noTracedDevices": "Aucun équipement tracé."
|
||||
},
|
||||
"sequence": {
|
||||
"cpe": "CPE",
|
||||
"acs": "ACS",
|
||||
"emptyPost": "POST vide",
|
||||
"session": "Session",
|
||||
"goTo": "Aller à…",
|
||||
"clear": "Effacer",
|
||||
"clearExchanges": "Effacer les échanges",
|
||||
"connected": "Connecté",
|
||||
"paused": "Pause",
|
||||
"disconnected": "Déconnecté",
|
||||
"resumeScroll": "Reprendre le défilement automatique",
|
||||
"allLoaded": "Tous les messages sont chargés",
|
||||
"loading": "Chargement…",
|
||||
"noExchanges": "Aucun échange enregistré. Les messages SOAP apparaîtront ici lors de la prochaine connexion du CPE.",
|
||||
"confirmClear": "Êtes-vous sûr de vouloir supprimer tous les échanges enregistrés pour cet équipement ? Cette action est irréversible.",
|
||||
"confirmClearTitle": "Effacer les échanges"
|
||||
},
|
||||
"inspector": {
|
||||
"title": "Inspecteur",
|
||||
"selectMessage": "Sélectionnez un message pour voir son contenu.",
|
||||
"direction": "Direction",
|
||||
"method": "Méthode",
|
||||
"session": "Session",
|
||||
"timestamp": "Horodatage",
|
||||
"rawXml": "XML brut"
|
||||
},
|
||||
"common": {
|
||||
"confirm": "Confirmer",
|
||||
"cancel": "Annuler",
|
||||
"close": "Fermer",
|
||||
"actions": "Actions",
|
||||
"selected": "sélectionné(s)"
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ function sendFleetCommand() {
|
||||
<path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm.93-9.412-1 4.705c-.07.34.029.533.304.533.194 0 .487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703 0-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381 2.29-.287zM8 5.5a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/>
|
||||
</svg>
|
||||
<span>
|
||||
<strong>{{ devices?.length || 0 }}</strong> {{ t('labels.devices').toLowerCase() }} sélectionné(s)
|
||||
<strong>{{ devices?.length || 0 }}</strong> {{ t('labels.devices').toLowerCase() }} {{ t('common.selected') }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -218,14 +218,14 @@ async function resolveAllProviders() {
|
||||
|
||||
<!-- En-tête de la carte -->
|
||||
<div class="px-3 pt-3 pb-2">
|
||||
<span class="text-uppercase fw-bold" style="font-size:0.65rem;letter-spacing:.1em;color:#888">Identité</span>
|
||||
<span class="text-uppercase fw-bold" style="font-size:0.65rem;letter-spacing:.1em;color:#888">{{ t('device.identity') }}</span>
|
||||
</div>
|
||||
|
||||
<div class="px-3 pb-3 d-flex flex-column gap-2">
|
||||
|
||||
<!-- Zone 1 : Identifiant -->
|
||||
<div class="rounded-3 px-3 py-3" style="background:#f6f7f9">
|
||||
<div class="text-muted fw-bold text-uppercase mb-3" style="font-size:0.62rem;letter-spacing:.08em">Identifiant</div>
|
||||
<div class="text-muted fw-bold text-uppercase mb-3" style="font-size:0.62rem;letter-spacing:.08em">{{ t('device.identifier') }}</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div class="text-muted fw-bold text-uppercase mb-1" style="font-size:0.62rem;letter-spacing:.06em">{{ t('labels.manufacturer') }}</div>
|
||||
@@ -256,7 +256,7 @@ async function resolveAllProviders() {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" viewBox="0 0 1000 1000" class="text-muted flex-shrink-0">
|
||||
<path d="M500 75.5c-234.72 0-425 190.28-425 425s190.28 425 425 425 425-190.28 425-425-190.28-425-425-425m0 100a75 75 0 1 1-75 75 75 75 0 0 1 75-75m125 600H400v-25.737l5.287-.167c15.555-.5 27.115-4.919 34.368-13.136 2.576-2.972 6.956-13.1 6.956-47.153v-227.2c0-32.392-4.523-44.6-8.311-49.141-5.359-6.391-16.516-10.147-33.17-11.156l-5.13-.31v-26h175v313.807c0 32.415 8.457 44.618 12.24 49.142 5.34 6.389 15.68 10.142 32.625 11.152l5.135.3v25.6Z" style="fill-rule:evenodd"/>
|
||||
</svg>
|
||||
<span class="text-muted fw-bold text-uppercase" style="font-size:0.62rem;letter-spacing:.08em">Versions</span>
|
||||
<span class="text-muted fw-bold text-uppercase" style="font-size:0.62rem;letter-spacing:.08em">{{ t('device.versions') }}</span>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-6">
|
||||
@@ -278,7 +278,7 @@ async function resolveAllProviders() {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" viewBox="0 0 1000 1000" class="text-muted flex-shrink-0">
|
||||
<path d="M827.568 500.5c0-110.61 120.715-26.921 64.516-162.6-56.231-135.681-82.391 8.823-160.606-69.384s66.333-104.365-69.36-160.562c-135.718-56.2-52.024 64.481-162.61 64.481-110.619 0-26.921-120.68-162.612-64.481s8.827 82.349-69.391 160.562-104.372-66.3-160.575 69.384c-56.23 135.679 64.486 51.99 64.486 162.6S50.7 527.419 106.93 663.1c56.2 135.681 82.359-8.823 160.575 69.352 78.218 78.214-66.3 104.4 69.391 160.6s51.993-64.483 162.612-64.483c110.586 0 26.892 120.678 162.61 64.483 135.693-56.2-8.854-82.384 69.36-160.6 78.215-78.175 104.375 66.329 160.606-69.352 56.199-135.681-64.516-51.99-64.516-162.6M500 301.015c110.457 0 200 89.537 200 199.985s-89.543 199.985-200 199.985S300 611.448 300 501s89.543-199.985 200-199.985" style="fill-rule:evenodd"/>
|
||||
</svg>
|
||||
<span class="text-muted fw-bold text-uppercase" style="font-size:0.62rem;letter-spacing:.08em">Système</span>
|
||||
<span class="text-muted fw-bold text-uppercase" style="font-size:0.62rem;letter-spacing:.08em">{{ t('device.system') }}</span>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
@@ -341,7 +341,7 @@ async function resolveAllProviders() {
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-muted fw-bold text-uppercase mb-1" style="font-size:0.62rem;letter-spacing:.06em">Prochaine connexion</div>
|
||||
<div class="text-muted fw-bold text-uppercase mb-1" style="font-size:0.62rem;letter-spacing:.06em">{{ t('device.nextConnection') }}</div>
|
||||
<div class="font-monospace small fw-medium">{{ estimatedNextConnection || '—' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -355,7 +355,7 @@ async function resolveAllProviders() {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" viewBox="0 0 16 16" class="text-muted flex-shrink-0">
|
||||
<path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6m2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0m4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 4m-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10s-3.516.68-4.168 1.332c-.678.678-.83 1.418-.832 1.664z"/>
|
||||
</svg>
|
||||
<span class="text-muted fw-bold text-uppercase" style="font-size:0.62rem;letter-spacing:.08em">Références client</span>
|
||||
<span class="text-muted fw-bold text-uppercase" style="font-size:0.62rem;letter-spacing:.08em">{{ t('device.clientReferences') }}</span>
|
||||
<button class="btn btn-link btn-sm p-0 ms-auto" @click="resolveAllProviders" :disabled="resolvingProvider !== null">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2z"/>
|
||||
@@ -478,7 +478,7 @@ async function resolveAllProviders() {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="me-1" viewBox="0 0 16 16">
|
||||
<path d="M13.5 1a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3M11 2.5a2.5 2.5 0 1 1 .603 1.628l-6.718 3.12a2.499 2.499 0 0 1 0 1.504l6.718 3.12a2.5 2.5 0 1 1-.488.876l-6.718-3.12a2.5 2.5 0 1 1 0-3.256l6.718-3.12A2.5 2.5 0 0 1 11 2.5"/>
|
||||
</svg>
|
||||
{{ tracingAction ? '…' : isTraced ? 'Tracing actif' : 'Activer le tracing' }}
|
||||
{{ tracingAction ? '…' : isTraced ? t('device.tracingActive') : t('device.enableTracing') }}
|
||||
</button>
|
||||
<Link
|
||||
:href="`/tr069-trace?device=${encodeURIComponent(device.identifier)}`"
|
||||
@@ -488,17 +488,17 @@ async function resolveAllProviders() {
|
||||
<path d="M10.5 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0"/>
|
||||
<path d="M0 8s3-5.5 8-5.5S16 8 16 8s-3 5.5-8 5.5S0 8 0 8m8 3.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7"/>
|
||||
</svg>
|
||||
Échanges TR-069
|
||||
{{ t('device.exchanges') }}
|
||||
</Link>
|
||||
|
||||
<button class="btn btn-outline-danger btn-sm ms-auto" @click="showDeleteConfirm = true">
|
||||
Supprimer l'équipement
|
||||
{{ t('device.deleteDevice') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Confirmation suppression -->
|
||||
<div v-if="showDeleteConfirm" class="alert alert-danger d-flex align-items-center gap-3 mt-3 mb-0">
|
||||
<span>Confirmer la suppression de <strong>{{ device.identifier }}</strong> ?</span>
|
||||
<span>{{ t('device.confirmDeleteMessage') }} <strong>{{ device.identifier }}</strong> ?</span>
|
||||
<button class="btn btn-danger btn-sm" @click="deleteDevice">Confirmer</button>
|
||||
<button class="btn btn-outline-secondary btn-sm" @click="showDeleteConfirm = false">Annuler</button>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import TitleBar from '~/components/TitleBar.vue'
|
||||
import SequenceViewer from '~/components/SequenceViewer.vue'
|
||||
import InspectorPanel from '~/components/InspectorPanel.vue'
|
||||
@@ -15,6 +16,7 @@ type TraceEntry = {
|
||||
}
|
||||
|
||||
const tracedDevices = ref<TraceEntry[]>([])
|
||||
const { t } = useI18n()
|
||||
const loadingEntries = ref(false)
|
||||
const removingDeviceId = ref<string | null>(null)
|
||||
const entriesError = ref('')
|
||||
@@ -204,8 +206,8 @@ function formatJson() {
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div>
|
||||
<h2 class="h4 mb-1">Traced devices</h2>
|
||||
<p class="text-muted small mb-0">Activez le tracing sur un équipement puis cliquez sur "Voir" pour visualiser les échanges en direct.</p>
|
||||
<h2 class="h4 mb-1">{{ t('trace.tracedDevices') }}</h2>
|
||||
<p class="text-muted small mb-0">{{ t('trace.description') }}</p>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="badge bg-dark">{{ tracedDevices.length }}</span>
|
||||
@@ -221,12 +223,12 @@ function formatJson() {
|
||||
<div v-if="entriesError" class="alert alert-danger" role="alert">{{ entriesError }}</div>
|
||||
<div v-if="actionError" class="alert alert-warning" role="alert">{{ actionError }}</div>
|
||||
<div v-if="pendingDeviceId && !tracedDeviceIds.has(pendingDeviceId)" class="alert alert-info d-flex align-items-center gap-3 mb-3">
|
||||
<span>L'équipement <strong class="font-monospace">{{ pendingDeviceId }}</strong> n'est pas encore tracé.</span>
|
||||
<span>L'équipement <strong class="font-monospace">{{ pendingDeviceId }}</strong> {{ t('trace.notTraced') }}</span>
|
||||
<button
|
||||
class="btn btn-sm btn-primary ms-auto"
|
||||
@click="enableTrace(pendingDeviceId)"
|
||||
>
|
||||
Activer le tracing
|
||||
{{ t('trace.enableTracing') }}
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary" @click="pendingDeviceId = null">✕</button>
|
||||
</div>
|
||||
@@ -237,12 +239,12 @@ function formatJson() {
|
||||
<table class="table table-sm table-hover align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Device ID</th>
|
||||
<th>{{ t('trace.deviceId') }}</th>
|
||||
<th>Manufacturer</th>
|
||||
<th>Product Class</th>
|
||||
<th>Serial Number</th>
|
||||
<th>OUI</th>
|
||||
<th>Started</th>
|
||||
<th>{{ t('trace.started') }}</th>
|
||||
<th class="text-end">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -272,7 +274,7 @@ function formatJson() {
|
||||
</tr>
|
||||
<tr v-if="tracedDevices.length === 0">
|
||||
<td colspan="7" class="text-center text-muted py-4">
|
||||
Aucun équipement tracé. Utilisez "Edit JSON" pour en ajouter ou activez le tracing depuis la fiche d'équipement.
|
||||
{{ t('trace.noTracedDevices') }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -341,7 +343,7 @@ function formatJson() {
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 id="jsonEditorModalLabel" class="modal-title">Edit Trace Configuration</h5>
|
||||
<h5 id="jsonEditorModalLabel" class="modal-title">{{ t('trace.editConfig') }}</h5>
|
||||
<button type="button" class="btn-close" aria-label="Close" @click="closeJsonEditor"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
Reference in new issue
Block a user