rename: Minuteur Dragodinde → Obsidienne
- Renommage complet dans package.json, main.ts, UI, tray, notifications - GUID NSIS fixe pour mise à jour propre (pas de doublon d'installation) - Migration automatique des données depuis %APPDATA%\Minuteur Dragodinde\ - Rétrocompatibilité import : backups 'minuteur-dragodinde' toujours acceptés - Mise à jour README changelog, CLAUDE.md, docs, maquettes, page ntfy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8af626dd66
commit
0c3b5e27a7
@ -14,7 +14,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
Minuteur Dragodinde is a Windows desktop app (Electron + Vite + TypeScript) for managing Dragodinde breeding timers in Dofus 3. French-language UI.
|
Obsidienne (anciennement "Minuteur Dragodinde") is a Windows desktop app (Electron + Vite + TypeScript) for managing Dragodinde breeding timers in Dofus 3. French-language UI.
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ Checks Gitea Releases API on startup (after 3s) and hourly. Downloads NSIS Setup
|
|||||||
|
|
||||||
### Dev vs packaged mode
|
### Dev vs packaged mode
|
||||||
|
|
||||||
When `!app.isPackaged`, userData is stored in `MinuteurDragodinde-DEV` (isolated from installed app) and a DEV badge is injected into the UI.
|
When `!app.isPackaged`, userData is stored in `Obsidienne-DEV` (isolated from installed app) and a DEV badge is injected into the UI. On first packaged launch, data is auto-migrated from the old `Minuteur Dragodinde` folder.
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
|
|||||||
16
README.md
16
README.md
@ -1,4 +1,4 @@
|
|||||||
# ⚔ Obsidienne — Minuteur Dragodinde (Dofus 3)
|
# ⚔ Obsidienne — Élevage Dragodinde (Dofus 3)
|
||||||
|
|
||||||
Application desktop Windows de gestion d'élevage de Dragodindes pour Dofus 3.
|
Application desktop Windows de gestion d'élevage de Dragodindes pour Dofus 3.
|
||||||
Construite avec **Electron + Vite + TypeScript** en architecture **DDD hexagonale**.
|
Construite avec **Electron + Vite + TypeScript** en architecture **DDD hexagonale**.
|
||||||
@ -39,7 +39,7 @@ Construite avec **Electron + Vite + TypeScript** en architecture **DDD hexagonal
|
|||||||
|
|
||||||
## Installation (utilisateurs)
|
## Installation (utilisateurs)
|
||||||
|
|
||||||
1. Télécharger `Minuteur Dragodinde Setup x.x.x.exe` depuis la section [Releases](https://gitea.mickael-pol.fr/mickael/dd-timer/releases)
|
1. Télécharger `Obsidienne Setup x.x.x.exe` depuis la section [Releases](https://gitea.mickael-pol.fr/mickael/dd-timer/releases)
|
||||||
2. **Clic droit → Propriétés → cocher "Débloquer" → OK** (important, une seule fois)
|
2. **Clic droit → Propriétés → cocher "Débloquer" → OK** (important, une seule fois)
|
||||||
3. Double-cliquer pour lancer l'installation
|
3. Double-cliquer pour lancer l'installation
|
||||||
4. L'app apparaît dans le menu Démarrer et sur le Bureau
|
4. L'app apparaît dans le menu Démarrer et sur le Bureau
|
||||||
@ -122,7 +122,7 @@ L'application utilise **electron-updater** avec un fichier `latest.yml` pour la
|
|||||||
# 2. Build l'application
|
# 2. Build l'application
|
||||||
npm run build
|
npm run build
|
||||||
# → Génère dans dist/ :
|
# → Génère dans dist/ :
|
||||||
# - Minuteur Dragodinde Setup 1.x.x.exe
|
# - Obsidienne Setup 1.x.x.exe
|
||||||
# - latest.yml (version + sha512, requis par electron-updater)
|
# - latest.yml (version + sha512, requis par electron-updater)
|
||||||
|
|
||||||
# 3. Committer et tagger
|
# 3. Committer et tagger
|
||||||
@ -133,7 +133,7 @@ git push && git push --tags
|
|||||||
|
|
||||||
# 4. Sur Gitea : Releases → Nouvelle release → tag v1.x.x
|
# 4. Sur Gitea : Releases → Nouvelle release → tag v1.x.x
|
||||||
# Attacher les 2 fichiers :
|
# Attacher les 2 fichiers :
|
||||||
# - Minuteur Dragodinde Setup 1.x.x.exe
|
# - Obsidienne Setup 1.x.x.exe
|
||||||
# - latest.yml
|
# - latest.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -236,6 +236,12 @@ src/
|
|||||||
- 🛡 **Nettoyage Ctrl+Z listener** — `removeEventListener` dans `destroy()` pour éviter les memory leaks
|
- 🛡 **Nettoyage Ctrl+Z listener** — `removeEventListener` dans `destroy()` pour éviter les memory leaks
|
||||||
- 🛡 **Toast stale container** — protection `isConnected` contre les conteneurs DOM détachés
|
- 🛡 **Toast stale container** — protection `isConnected` contre les conteneurs DOM détachés
|
||||||
|
|
||||||
|
#### Renommage
|
||||||
|
- 🏷 **Renommage "Minuteur Dragodinde" → "Obsidienne"** — nouveau nom d'application, raccourcis, titre, tray, notifications
|
||||||
|
- 🔄 **Migration automatique des données** — copie transparente du fichier de sauvegarde depuis l'ancien dossier `%APPDATA%\Minuteur Dragodinde\` au premier lancement
|
||||||
|
- 🔄 **GUID NSIS fixe** — l'installeur reconnaît l'ancienne version et la remplace proprement (pas de doublon)
|
||||||
|
- 🔄 **Rétrocompatibilité import** — les backups exportés avec `app: 'minuteur-dragodinde'` restent importables
|
||||||
|
|
||||||
#### Technique
|
#### Technique
|
||||||
- ⬆ **Migration electron-updater** — vérification sha512 via `latest.yml`, installation NSIS native, restart auto
|
- ⬆ **Migration electron-updater** — vérification sha512 via `latest.yml`, installation NSIS native, restart auto
|
||||||
- 🎨 **Icône Windows native** — migration `icon.png` → `icon.ico`
|
- 🎨 **Icône Windows native** — migration `icon.png` → `icon.ico`
|
||||||
@ -303,7 +309,7 @@ src/
|
|||||||
- 📝 **Sous-onglets par enclos** (Elevage / Historique bebes)
|
- 📝 **Sous-onglets par enclos** (Elevage / Historique bebes)
|
||||||
- 🔧 **Mode DEV** — Donnees isolees et badge DEV visible quand lance avec `npm start`
|
- 🔧 **Mode DEV** — Donnees isolees et badge DEV visible quand lance avec `npm start`
|
||||||
- ⬆ **Mise a jour automatique** via Gitea Releases avec banniere de progression dans l'interface
|
- ⬆ **Mise a jour automatique** via Gitea Releases avec banniere de progression dans l'interface
|
||||||
- 🔧 Correction de l'identifiant applicatif (`fr.mickael-pol.minuteur-dragodinde`)
|
- 🔧 Correction de l'identifiant applicatif (`fr.mickael-pol.obsidienne`)
|
||||||
- 🔧 Masquage des spinners natifs sur les champs numeriques
|
- 🔧 Masquage des spinners natifs sur les champs numeriques
|
||||||
|
|
||||||
### v1.0.0
|
### v1.0.0
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# Algorithmes de calcul — Minuteur Dragodinde
|
# Algorithmes de calcul — Obsidienne
|
||||||
|
|
||||||
Ce document décrit tous les algorithmes utilisés dans l'application, expliqués simplement.
|
Ce document décrit tous les algorithmes utilisés dans l'application, expliqués simplement.
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# Fonctionnalités par écran — Minuteur Dragodinde
|
# Fonctionnalités par écran — Obsidienne
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>Minuteur Dragodinde - Notifications</title>
|
<title>Obsidienne - Notifications</title>
|
||||||
<style>
|
<style>
|
||||||
*{box-sizing:border-box;margin:0;padding:0}
|
*{box-sizing:border-box;margin:0;padding:0}
|
||||||
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#0b0b14;color:#dddaf8;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:20px}
|
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#0b0b14;color:#dddaf8;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:20px}
|
||||||
@ -23,7 +23,7 @@ h1{font-size:1.3rem;margin-bottom:8px}
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h1>Minuteur Dragodinde</h1>
|
<h1>Obsidienne</h1>
|
||||||
<p class="sub">Notifications mobiles</p>
|
<p class="sub">Notifications mobiles</p>
|
||||||
|
|
||||||
<div id="loading">
|
<div id="loading">
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "minuteur-dragodinde",
|
"name": "obsidienne",
|
||||||
"version": "1.1.6",
|
"version": "1.1.6",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "minuteur-dragodinde",
|
"name": "obsidienne",
|
||||||
"version": "1.1.6",
|
"version": "1.1.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"electron-updater": "^6.8.3"
|
"electron-updater": "^6.8.3"
|
||||||
|
|||||||
13
package.json
13
package.json
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "minuteur-dragodinde",
|
"name": "obsidienne",
|
||||||
"version": "1.1.6",
|
"version": "1.1.6",
|
||||||
"description": "Minuteur elevage Dragodinde Dofus 3",
|
"description": "Obsidienne — Minuteur d'élevage Dragodinde pour Dofus 3",
|
||||||
"main": "dist-electron/main.js",
|
"main": "dist-electron/main.js",
|
||||||
"author": "Mickael",
|
"author": "Mickael",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -14,12 +14,12 @@
|
|||||||
"test:e2e": "npx playwright test"
|
"test:e2e": "npx playwright test"
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"appId": "fr.mickael-pol.minuteur-dragodinde",
|
"appId": "fr.mickael-pol.obsidienne",
|
||||||
"publish": {
|
"publish": {
|
||||||
"provider": "generic",
|
"provider": "generic",
|
||||||
"url": "https://gitea.mickael-pol.fr/mickael/dd-timer/releases/download/latest"
|
"url": "https://gitea.mickael-pol.fr/mickael/dd-timer/releases/download/latest"
|
||||||
},
|
},
|
||||||
"productName": "Minuteur Dragodinde",
|
"productName": "Obsidienne",
|
||||||
"directories": {
|
"directories": {
|
||||||
"output": "dist"
|
"output": "dist"
|
||||||
},
|
},
|
||||||
@ -48,7 +48,8 @@
|
|||||||
"allowToChangeInstallationDirectory": true,
|
"allowToChangeInstallationDirectory": true,
|
||||||
"createDesktopShortcut": true,
|
"createDesktopShortcut": true,
|
||||||
"createStartMenuShortcut": true,
|
"createStartMenuShortcut": true,
|
||||||
"shortcutName": "Minuteur Dragodinde",
|
"shortcutName": "Obsidienne",
|
||||||
|
"guid": "3b4a21ac-02a8-4525-a48b-988079fc75d4",
|
||||||
"deleteAppDataOnUninstall": false,
|
"deleteAppDataOnUninstall": false,
|
||||||
"runAfterFinish": true
|
"runAfterFinish": true
|
||||||
}
|
}
|
||||||
@ -71,7 +72,7 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://gitea.mickael-pol.fr/mickael/dd-timer.git"
|
"url": "https://gitea.mickael-pol.fr/mickael/dd-timer.git"
|
||||||
},
|
},
|
||||||
"productName": "Minuteur Dragodinde",
|
"productName": "Obsidienne",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"electron-updater": "^6.8.3"
|
"electron-updater": "^6.8.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<html class="dark" lang="fr"><head>
|
<html class="dark" lang="fr"><head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
<title>Minuteur Dragodinde - L'Archive d'Obsidienne</title>
|
<title>Obsidienne - Dashboard</title>
|
||||||
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,container-queries"></script>
|
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,container-queries"></script>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Cinzel:wght@400;700&display=swap" rel="stylesheet"/>
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Cinzel:wght@400;700&display=swap" rel="stylesheet"/>
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons+Round" rel="stylesheet"/>
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons+Round" rel="stylesheet"/>
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<html class="dark" lang="fr"><head>
|
<html class="dark" lang="fr"><head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
<title>Minuteur Dragodinde - Enclos 1</title>
|
<title>Obsidienne - Enclos 1</title>
|
||||||
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,container-queries"></script>
|
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,container-queries"></script>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Outfit:wght@400;600;700&family=Material+Icons+Round&display=swap" rel="stylesheet"/>
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Outfit:wght@400;600;700&family=Material+Icons+Round&display=swap" rel="stylesheet"/>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@ -14,10 +14,10 @@ import fs from 'fs';
|
|||||||
import { autoUpdater } from 'electron-updater';
|
import { autoUpdater } from 'electron-updater';
|
||||||
|
|
||||||
// ─── NOM DE L'APPLICATION ─────────────────────────────────────────────────────
|
// ─── NOM DE L'APPLICATION ─────────────────────────────────────────────────────
|
||||||
app.setName('Minuteur Dragodinde');
|
app.setName('Obsidienne');
|
||||||
// Windows utilise l'AppUserModelId pour le nom affiché dans les notifications
|
// Windows utilise l'AppUserModelId pour le nom affiché dans les notifications
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
app.setAppUserModelId('Minuteur Dragodinde');
|
app.setAppUserModelId('Obsidienne');
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── MODE DEV / E2E ────────────────────────────<E29480><E29480>─────────────────────────────
|
// ─── MODE DEV / E2E ────────────────────────────<E29480><E29480>─────────────────────────────
|
||||||
@ -26,7 +26,23 @@ if (process.env.ELECTRON_USER_DATA_DIR) {
|
|||||||
app.setPath('userData', process.env.ELECTRON_USER_DATA_DIR);
|
app.setPath('userData', process.env.ELECTRON_USER_DATA_DIR);
|
||||||
} else if (!app.isPackaged) {
|
} else if (!app.isPackaged) {
|
||||||
// En dev (npm start), les données sont isolées de l'app installée
|
// En dev (npm start), les données sont isolées de l'app installée
|
||||||
app.setPath('userData', path.join(app.getPath('appData'), 'MinuteurDragodinde-DEV'));
|
app.setPath('userData', path.join(app.getPath('appData'), 'Obsidienne-DEV'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── MIGRATION DONNÉES (ancien nom → Obsidienne) ────────────────────────────
|
||||||
|
// Les utilisateurs de "Minuteur Dragodinde" conservent leurs données après le renommage
|
||||||
|
if (app.isPackaged) {
|
||||||
|
const oldDataFile = path.join(app.getPath('appData'), 'Minuteur Dragodinde', 'dd-timer-data.json');
|
||||||
|
const newDataFile = path.join(app.getPath('userData'), 'dd-timer-data.json');
|
||||||
|
if (!fs.existsSync(newDataFile) && fs.existsSync(oldDataFile)) {
|
||||||
|
try {
|
||||||
|
fs.mkdirSync(path.dirname(newDataFile), { recursive: true });
|
||||||
|
fs.copyFileSync(oldDataFile, newDataFile);
|
||||||
|
console.log('Migration données: Minuteur Dragodinde → Obsidienne OK');
|
||||||
|
} catch (e: unknown) {
|
||||||
|
console.error('Migration données échouée:', (e as Error).message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── CONFIG GITEA ─────────────────────────────────────────────────────────────
|
// ─── CONFIG GITEA ─────────────────────────────────────────────────────────────
|
||||||
@ -59,7 +75,7 @@ function getAppIcon(): Electron.NativeImage {
|
|||||||
function createWindow(): void {
|
function createWindow(): void {
|
||||||
mainWindow = new BrowserWindow({
|
mainWindow = new BrowserWindow({
|
||||||
width: 1280, height: 900, minWidth: 960, minHeight: 650,
|
width: 1280, height: 900, minWidth: 960, minHeight: 650,
|
||||||
title: 'Minuteur Dragodinde - Dofus 3',
|
title: 'Obsidienne - Dofus 3',
|
||||||
icon: getAppIcon(),
|
icon: getAppIcon(),
|
||||||
backgroundColor: '#0b0b14',
|
backgroundColor: '#0b0b14',
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
@ -85,7 +101,7 @@ function createWindow(): void {
|
|||||||
buttons: ['Minimiser', 'Quitter'],
|
buttons: ['Minimiser', 'Quitter'],
|
||||||
defaultId: 0,
|
defaultId: 0,
|
||||||
cancelId: 0,
|
cancelId: 0,
|
||||||
title: 'Minuteur Dragodinde',
|
title: 'Obsidienne',
|
||||||
message: 'Que souhaites-tu faire ?',
|
message: 'Que souhaites-tu faire ?',
|
||||||
detail: 'Minimiser garde l\'app en arriere-plan.\nLes alarmes continueront de sonner.',
|
detail: 'Minimiser garde l\'app en arriere-plan.\nLes alarmes continueront de sonner.',
|
||||||
});
|
});
|
||||||
@ -127,7 +143,7 @@ function createWindow(): void {
|
|||||||
// ─── TRAY ─────────────────────────────────────────────────────────────────────
|
// ─── TRAY ─────────────────────────────────────────────────────────────────────
|
||||||
function createTray(): void {
|
function createTray(): void {
|
||||||
tray = new Tray(getAppIcon());
|
tray = new Tray(getAppIcon());
|
||||||
tray.setToolTip(`Minuteur Dragodinde v${CURRENT_VERSION}`);
|
tray.setToolTip(`Obsidienne v${CURRENT_VERSION}`);
|
||||||
rebuildTrayMenu();
|
rebuildTrayMenu();
|
||||||
tray.on('double-click', () => { mainWindow!.show(); mainWindow!.focus(); });
|
tray.on('double-click', () => { mainWindow!.show(); mainWindow!.focus(); });
|
||||||
}
|
}
|
||||||
@ -135,7 +151,7 @@ function createTray(): void {
|
|||||||
function rebuildTrayMenu(): void {
|
function rebuildTrayMenu(): void {
|
||||||
if (!tray) return;
|
if (!tray) return;
|
||||||
const items: Electron.MenuItemConstructorOptions[] = [
|
const items: Electron.MenuItemConstructorOptions[] = [
|
||||||
{ label: `Minuteur Dragodinde v${CURRENT_VERSION}`, enabled: false },
|
{ label: `Obsidienne v${CURRENT_VERSION}`, enabled: false },
|
||||||
{ type: 'separator' },
|
{ type: 'separator' },
|
||||||
{ label: 'Ouvrir', click: () => { mainWindow!.show(); mainWindow!.focus(); } },
|
{ label: 'Ouvrir', click: () => { mainWindow!.show(); mainWindow!.focus(); } },
|
||||||
];
|
];
|
||||||
@ -361,7 +377,7 @@ function checkForUpdates(silent = false): void {
|
|||||||
path: `/api/v1/repos/${GITEA_USER}/${GITEA_REPO}/releases?limit=1`,
|
path: `/api/v1/repos/${GITEA_USER}/${GITEA_REPO}/releases?limit=1`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': `MinuteurDragodinde/${CURRENT_VERSION}`,
|
'User-Agent': `Obsidienne/${CURRENT_VERSION}`,
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -56,7 +56,7 @@ export class App {
|
|||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<button class="app-hamburger" id="hamburger-btn">☰</button>
|
<button class="app-hamburger" id="hamburger-btn">☰</button>
|
||||||
<div class="app-header-text">
|
<div class="app-header-text">
|
||||||
<h1 class="app-title"><span class="app-title-icon">⚔</span> Minuteur Dragodinde</h1>
|
<h1 class="app-title"><span class="app-title-icon">⚔</span> Obsidienne</h1>
|
||||||
<p class="app-subtitle">Dofus 3 · Gestion multi-enclos en temps réel</p>
|
<p class="app-subtitle">Dofus 3 · Gestion multi-enclos en temps réel</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-hamburger" style="visibility:hidden;pointer-events:none;" aria-hidden="true"></div>
|
<div class="app-hamburger" style="visibility:hidden;pointer-events:none;" aria-hidden="true"></div>
|
||||||
|
|||||||
@ -301,7 +301,7 @@ export class ParametresView {
|
|||||||
const { ntfyTopic } = this.getSettings();
|
const { ntfyTopic } = this.getSettings();
|
||||||
if (!ntfyTopic) return;
|
if (!ntfyTopic) return;
|
||||||
const url = `${NTFY_BASE}/${ntfyTopic}`;
|
const url = `${NTFY_BASE}/${ntfyTopic}`;
|
||||||
(window as any).electronAPI?.sendNtfy?.(url, 'Test alarme', 'Ceci est un test de la notification mobile Minuteur Dragodinde !');
|
(window as any).electronAPI?.sendNtfy?.(url, 'Test alarme', 'Ceci est un test de la notification mobile Obsidienne !');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ══ Backup / Restore ══ */
|
/* ══ Backup / Restore ══ */
|
||||||
@ -319,7 +319,7 @@ export class ParametresView {
|
|||||||
|
|
||||||
const version = await api.getVersion?.() ?? 'unknown';
|
const version = await api.getVersion?.() ?? 'unknown';
|
||||||
const backup = {
|
const backup = {
|
||||||
app: 'minuteur-dragodinde',
|
app: 'obsidienne',
|
||||||
version,
|
version,
|
||||||
exportedAt: new Date().toISOString(),
|
exportedAt: new Date().toISOString(),
|
||||||
data: JSON.parse(raw),
|
data: JSON.parse(raw),
|
||||||
@ -366,7 +366,7 @@ export class ParametresView {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Validation du format backup
|
// Validation du format backup
|
||||||
if (parsed.app === 'minuteur-dragodinde' && parsed.data && typeof parsed.data === 'object' && parsed.data !== null) {
|
if ((parsed.app === 'obsidienne' || parsed.app === 'minuteur-dragodinde') && parsed.data && typeof parsed.data === 'object' && parsed.data !== null) {
|
||||||
if (!validateEnclosData(parsed.data)) {
|
if (!validateEnclosData(parsed.data)) {
|
||||||
Toast.show('error', 'Le backup contient des données corrompues ou incomplètes.');
|
Toast.show('error', 'Le backup contient des données corrompues ou incomplètes.');
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -57,19 +57,19 @@ describe('Sécurité — Hardening', () => {
|
|||||||
describe('Validation backup — format métadonnées', () => {
|
describe('Validation backup — format métadonnées', () => {
|
||||||
it('backup valide contient app, version, exportedAt, data', () => {
|
it('backup valide contient app, version, exportedAt, data', () => {
|
||||||
const backup = {
|
const backup = {
|
||||||
app: 'minuteur-dragodinde',
|
app: 'obsidienne',
|
||||||
version: '1.1.6',
|
version: '1.1.6',
|
||||||
exportedAt: new Date().toISOString(),
|
exportedAt: new Date().toISOString(),
|
||||||
data: { enclos: [] },
|
data: { enclos: [] },
|
||||||
};
|
};
|
||||||
expect(backup.app).toBe('minuteur-dragodinde');
|
expect(backup.app).toBe('obsidienne');
|
||||||
expect(typeof backup.version).toBe('string');
|
expect(typeof backup.version).toBe('string');
|
||||||
expect(typeof backup.exportedAt).toBe('string');
|
expect(typeof backup.exportedAt).toBe('string');
|
||||||
expect(backup.data).toBeDefined();
|
expect(backup.data).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('data: null est détecté comme invalide', () => {
|
it('data: null est détecté comme invalide', () => {
|
||||||
const backup = { app: 'minuteur-dragodinde', data: null };
|
const backup = { app: 'obsidienne', data: null };
|
||||||
// typeof null === 'object' mais data === null doit être rejeté
|
// typeof null === 'object' mais data === null doit être rejeté
|
||||||
expect(backup.data === null).toBe(true);
|
expect(backup.data === null).toBe(true);
|
||||||
expect(!!(backup.data && typeof backup.data === 'object' && backup.data !== null)).toBe(false);
|
expect(!!(backup.data && typeof backup.data === 'object' && backup.data !== null)).toBe(false);
|
||||||
|
|||||||
@ -112,6 +112,6 @@ describe('Validation import — validateEnclosData', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('rejette un objet backup avec data: null', () => {
|
it('rejette un objet backup avec data: null', () => {
|
||||||
expect(validateEnclosData({ app: 'minuteur-dragodinde', data: null })).toBe(false);
|
expect(validateEnclosData({ app: 'obsidienne', data: null })).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user