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).
This commit is contained in:
@@ -1,12 +1,17 @@
|
||||
import { computed, type Component } from 'vue';
|
||||
import { useRoute, type RouteLocationRaw } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { GitBranch, TerminalSquare, Boxes } from '@lucide/vue';
|
||||
import { Boxes, GitBranch, LifeBuoy, Settings, TerminalSquare } from '@lucide/vue';
|
||||
import { useSessionsStore } from '../stores/sessions';
|
||||
import { useSettingsStore } from '../stores/settings';
|
||||
import GiteaIcon from '../components/ui/GiteaIcon.vue';
|
||||
|
||||
export interface NavEntry {
|
||||
key: string;
|
||||
to: RouteLocationRaw;
|
||||
/** route interne (exclusif avec `href`). */
|
||||
to?: RouteLocationRaw;
|
||||
/** lien externe ouvert dans un nouvel onglet (exclusif avec `to`). */
|
||||
href?: string;
|
||||
icon: Component;
|
||||
label: string;
|
||||
match: string[]; // noms de routes considérés actifs pour cet item
|
||||
@@ -18,19 +23,33 @@ export function useNav() {
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const sessions = useSessionsStore();
|
||||
const settings = useSettingsStore();
|
||||
|
||||
// sessions vivantes bloquées sur un dialogue (le cœur de la supervision mobile).
|
||||
const waitingCount = computed(
|
||||
() => sessions.sessions.filter((s) => s.live && s.activity === 'waiting').length,
|
||||
);
|
||||
|
||||
const items = computed<NavEntry[]>(() => [
|
||||
// Onglets principaux : barre du bas mobile + haut de sidebar.
|
||||
const primary = computed<NavEntry[]>(() => [
|
||||
{ key: 'worktrees', to: { name: 'dashboard' }, icon: GitBranch, label: t('nav.worktrees'), match: ['dashboard'], badge: 0 },
|
||||
{ key: 'sessions', to: { name: 'sessions' }, icon: TerminalSquare, label: t('nav.sessions'), match: ['sessions', 'session'], badge: waitingCount.value },
|
||||
{ key: 'groups', to: { name: 'groups' }, icon: Boxes, label: t('nav.groups'), match: ['groups', 'group'], badge: 0 },
|
||||
]);
|
||||
|
||||
// Onglets secondaires : réglages, aide, et lien externe Gitea (uniquement si l'URL est configurée).
|
||||
const secondary = computed<NavEntry[]>(() => {
|
||||
const items: NavEntry[] = [
|
||||
{ key: 'settings', to: { name: 'settings' }, icon: Settings, label: t('nav.settings'), match: ['settings'], badge: 0 },
|
||||
{ key: 'help', to: { name: 'help' }, icon: LifeBuoy, label: t('nav.help'), match: ['help'], badge: 0 },
|
||||
];
|
||||
if (settings.giteaUrl) {
|
||||
items.push({ key: 'gitea', href: settings.giteaUrl, icon: GiteaIcon, label: t('nav.gitea'), match: [], badge: 0 });
|
||||
}
|
||||
return items;
|
||||
});
|
||||
|
||||
const isActive = (match: string[]): boolean => match.includes(String(route.name));
|
||||
|
||||
return { items, isActive, waitingCount };
|
||||
return { primary, secondary, isActive, waitingCount };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user