feat: onglets Réglages & Aide + icône Gitea

Réglages : préférences (langue, notifications push + test), gestion complète des tokens d'accès (liste/création/révocation, garde anti lock-out sur le dernier token), URL Gitea configurable, infos serveur en lecture seule (port/bind/origines/VAPID + flags CLI). Aide : documentation bilingue EN/FR de toutes les fonctionnalités, avec recherche. Icône Gitea (lien externe) dans la nav (sidebar + MoreSheet mobile).

Backend : routes /api/v1/auth/tokens (GET/POST/DELETE) + tokenId dans /me ; routes/settings.ts (GET/PATCH, allow-list stricte gitea_url, aucun secret exposé, URL validée http/https anti-XSS) ; AuthService.listTokens/revokeToken (transaction). Front : NavItem gère les liens externes, nav primaire/secondaire, store settings, vues SettingsView/HelpView.

236 tests verts (+15 nouveaux : auth-tokens, settings-routes).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Johan LEROY
2026-06-18 14:16:53 +02:00
parent 0fd1d1f55c
commit 8cce1dc1e4
23 changed files with 1469 additions and 24 deletions

View File

@@ -0,0 +1,34 @@
import { defineStore } from 'pinia';
import { ref } from 'vue';
import type { ServerInfo, SettingsResponse, UpdateSettingsRequest } from '@arboretum/shared';
import { api } from '../lib/api';
// Réglages serveur + intégrations. `giteaUrl` alimente l'item de nav Gitea (affiché si défini).
// Les préférences purement client (langue) restent gérées par l'i18n/localStorage.
export const useSettingsStore = defineStore('settings', () => {
const server = ref<ServerInfo | null>(null);
const giteaUrl = ref<string | null>(null);
const loaded = ref(false);
const saving = ref(false);
function apply(res: SettingsResponse): void {
server.value = res.server;
giteaUrl.value = res.settings.giteaUrl;
loaded.value = true;
}
async function fetch(): Promise<void> {
apply(await api.get<SettingsResponse>('/api/v1/settings'));
}
async function save(patch: UpdateSettingsRequest): Promise<void> {
saving.value = true;
try {
apply(await api.patch<SettingsResponse>('/api/v1/settings', patch));
} finally {
saving.value = false;
}
}
return { server, giteaUrl, loaded, saving, fetch, save };
});