From 07f2fe849d44f7ac4a70d3d27c0477a1b45ebb36 Mon Sep 17 00:00:00 2001 From: ashvin Date: Sat, 14 Mar 2026 22:59:22 +0100 Subject: [PATCH] fix: rename Sonar to NetScan-AI in all UI text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Title bar: SONAR → NetScan-AI - Quit dialog: "Quitter Sonar ?" → "Quitter NetScan-AI ?" - Error dialog: binary path sonar → netscan-ai - Alt attributes on logo images Co-Authored-By: Claude Sonnet 4.6 --- src/components/ErrorDialog.vue | 2 +- src/components/NavBar/TopBar.vue | 198 +++++++++++++++++++++++++--- src/components/QuitDialog.vue | 2 +- src/components/homeVue/Capture.vue | 2 +- src/components/homeVue/FromPcap.vue | 2 +- 5 files changed, 181 insertions(+), 25 deletions(-) diff --git a/src/components/ErrorDialog.vue b/src/components/ErrorDialog.vue index 469d7f36b..380d62157 100644 --- a/src/components/ErrorDialog.vue +++ b/src/components/ErrorDialog.vue @@ -56,7 +56,7 @@

Sur NixOS : remplacez nom_du_binaire par - target/debug/sonar ou le chemin du binaire compilé. + target/debug/netscan-ai ou le chemin du binaire compilé.

diff --git a/src/components/NavBar/TopBar.vue b/src/components/NavBar/TopBar.vue index cc7e10268..cf8988b14 100644 --- a/src/components/NavBar/TopBar.vue +++ b/src/components/NavBar/TopBar.vue @@ -7,6 +7,7 @@ @@ -32,14 +33,23 @@ - - + +
+ + +
+ + + +
+
+
+ +
+ + +
+ + + +
+
+
+
@@ -90,7 +118,7 @@
-
SONAR
+
NetScan-AI
@@ -125,6 +153,7 @@ import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'; import { exit } from '@tauri-apps/plugin-process'; import { info, error } from '@tauri-apps/plugin-log'; import { save } from '@tauri-apps/plugin-dialog'; +import { downloadDir } from '@tauri-apps/api/path'; import { register, unregister } from '@tauri-apps/plugin-global-shortcut'; // when using `"withGlobalTauri": true`, you may use // const { register } = window.__TAURI__.globalShortcut; @@ -163,10 +192,17 @@ export default { showMatrice: true, shortcuts: [] as string[], isMaximized: false, + isRecording: false, + showSaveMenu: false, + showExportMenu: false, + _closeMenu: null as null | (() => void), }; }, async mounted() { appWindow = getCurrentWebviewWindow(); + const closeMenu = () => { this.showExportMenu = false; this.showSaveMenu = false; }; + document.addEventListener('click', closeMenu, true); + this._closeMenu = closeMenu; this.isMaximized = await appWindow.isMaximized(); await appWindow.onResized(async () => { this.isMaximized = await appWindow!.isMaximized(); @@ -204,8 +240,8 @@ export default { }, async beforeUnmount() { - // recommandé en dev/hot reload await this.unbindAllShortcuts(); + if (this._closeMenu) document.removeEventListener('click', this._closeMenu, true); }, methods: { bindShortcut(shortcut: string, handler: () => void) { @@ -289,9 +325,16 @@ export default { } }, async triggerSave() { - info("trigger save") + this.showSaveMenu = false; this.SaveAsCsv(); - + }, + triggerSavePng() { + this.showSaveMenu = false; + document.dispatchEvent(new CustomEvent('export-png')); + }, + triggerSaveSvg() { + this.showSaveMenu = false; + document.dispatchEvent(new CustomEvent('export-svg')); }, async reset() { info("reset") @@ -316,13 +359,52 @@ export default { info("[TopBar] Bouton IA cliqué"); this.$emit('toggle-ai'); }, + + async startPcapRecord() { + this.showSaveMenu = false; + const path = await save({ + filters: [{ name: 'PCAP', extensions: ['pcap'] }], + title: 'Enregistrer en PCAP', + defaultPath: getCurrentDate() + '_capture.pcap', + }); + if (!path) return; + await invoke('start_pcap_record', { path }).catch((e: any) => error('start_pcap_record:', e)); + this.isRecording = true; + }, + + async stopPcapRecord() { + this.showSaveMenu = false; + const path = await invoke('stop_pcap_record').catch((e: any) => { error('stop_pcap_record:', e); return null }); + this.isRecording = false; + if (path) info('PCAP enregistré : ' + path); + }, + + async exportRules(type: 'snort' | 'suricata' | 'iptables') { + this.showExportMenu = false; + const ext = type === 'iptables' ? 'sh' : 'rules'; + const path = await save({ + filters: [{ name: type, extensions: [ext] }], + title: `Exporter règles ${type}`, + defaultPath: `${getCurrentDate()}_${type}.${ext}`, + }); + if (!path) return; + const cmd = type === 'snort' ? 'export_snort_rules' + : type === 'suricata' ? 'export_suricata_rules' + : 'export_iptables'; + await invoke(cmd, { path }).catch((e: any) => error(`${cmd}:`, e)); + info(`Règles ${type} exportées : ${path}`); + }, async start() { - if (this.captureStore.isRunning) { - return; - } - const onEvent = new Channel(); - this.captureStore.setChannel(onEvent); // 🟢 rendre le Channel accessible + if (this.captureStore.isRunning) return; + + const dir = await downloadDir().catch(() => '.'); + const pcapPath = `${dir}/${getCurrentDate()}_capture.pcap`; + await invoke('start_pcap_record', { path: pcapPath }) + .then(() => { this.isRecording = true; info('Enregistrement PCAP : ' + pcapPath); }) + .catch((e: any) => error('start_pcap_record:', e)); + const onEvent = new Channel(); + this.captureStore.setChannel(onEvent); await invoke('start_capture', { onEvent }) .then((status) => { const typedStatus = status as { is_running: boolean }; @@ -332,17 +414,22 @@ export default { .catch(displayCaptureError); }, async stop() { - if (!this.captureStore.isRunning) { - return; - } + if (!this.captureStore.isRunning) return; + const onEvent = this.captureStore.getChannel(); - await invoke('stop_capture',{ onEvent }) + await invoke('stop_capture', { onEvent }) .then((status) => { const typedStatus = status as { is_running: boolean }; this.captureStore.updateStatus(typedStatus); info('Capture arrêtée : ' + this.captureStore.isRunning); }) .catch(displayCaptureError); + + if (this.isRecording) { + await invoke('stop_pcap_record') + .then((path) => { this.isRecording = false; info('PCAP enregistré : ' + path); }) + .catch((e: any) => error('stop_pcap_record:', e)); + } }, toggleView() { info('Vue basculée'); @@ -494,6 +581,7 @@ export default { .logo-btn { padding: 3px; margin-right: 4px; + position: relative; } .logo-img { @@ -528,4 +616,72 @@ export default { color: #a0a0e8; background-color: #35355a; } + +.rec-dot { + position: absolute; + bottom: 3px; + right: 3px; + width: 5px; + height: 5px; + border-radius: 50%; + background: #e05555; + animation: rec-pulse 1.2s ease-in-out infinite; +} + +@keyframes rec-pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.3; } +} + +/* Export rules dropdown */ +.export-wrap { + position: relative; +} + +.export-menu { + position: absolute; + top: calc(100% + 4px); + left: 0; + background: #2c2c3a; + border: 1px solid #3c3c50; + border-radius: 6px; + padding: 4px 0; + min-width: 120px; + z-index: 10000; + box-shadow: 0 4px 16px rgba(0,0,0,0.4); +} + +.export-menu button { + display: block; + width: 100%; + padding: 6px 14px; + background: transparent; + border: none; + color: #a0a0b8; + font-size: 12px; + text-align: left; + cursor: pointer; + transition: background 0.12s ease, color 0.12s ease; +} + +.export-menu button:hover { + background: #383850; + color: #d4d4d8; +} + +.export-menu button.record-item { + color: #e05555; +} +.export-menu button.record-item:hover { + background: #3a2020; + color: #f07070; +} + +.menu-fade-enter-active, .menu-fade-leave-active { + transition: opacity 0.12s ease, transform 0.12s cubic-bezier(0.22, 1, 0.36, 1); +} +.menu-fade-enter-from, .menu-fade-leave-to { + opacity: 0; + transform: translateY(-4px); +} \ No newline at end of file diff --git a/src/components/QuitDialog.vue b/src/components/QuitDialog.vue index 2d59b368b..22f432fcb 100644 --- a/src/components/QuitDialog.vue +++ b/src/components/QuitDialog.vue @@ -12,7 +12,7 @@
-

Quitter Sonar ?

+

Quitter NetScan-AI ?

Les données non sauvegardées seront perdues.

diff --git a/src/components/homeVue/Capture.vue b/src/components/homeVue/Capture.vue index 2b93830b8..c102f909c 100644 --- a/src/components/homeVue/Capture.vue +++ b/src/components/homeVue/Capture.vue @@ -1,6 +1,6 @@