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).
34 lines
1.4 KiB
Vue
34 lines
1.4 KiB
Vue
<template>
|
|
<!-- Ligne de config serveur en lecture seule : label + valeur (+ flag CLI) + copier. -->
|
|
<div class="flex flex-wrap items-center gap-x-3 gap-y-0.5 py-2">
|
|
<dt class="w-40 shrink-0 text-sm text-zinc-400">{{ label }}</dt>
|
|
<dd class="flex min-w-0 flex-1 items-center gap-2">
|
|
<span :class="['min-w-0 flex-1 break-all text-sm text-zinc-200', mono ? 'font-mono text-xs' : '']">{{ value }}</span>
|
|
<span v-if="flag" class="hidden shrink-0 font-mono text-[11px] text-zinc-600 sm:inline" :title="t('settings.flagHint', { flag })">{{ flag }}</span>
|
|
<BaseButton size="sm" variant="ghost" icon-only :icon="copied ? Check : Copy" :aria-label="t('settings.copy')" @click="copy" />
|
|
</dd>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { Check, Copy } from '@lucide/vue';
|
|
import BaseButton from '../ui/BaseButton.vue';
|
|
|
|
const props = defineProps<{ label: string; value: string; flag?: string; mono?: boolean }>();
|
|
const { t } = useI18n();
|
|
|
|
const copied = ref(false);
|
|
// Auto-contenu : on ne confirme (✓) qu'après la résolution réelle de l'écriture presse-papiers.
|
|
async function copy(): Promise<void> {
|
|
try {
|
|
await navigator.clipboard.writeText(props.value);
|
|
copied.value = true;
|
|
setTimeout(() => (copied.value = false), 1500);
|
|
} catch {
|
|
/* presse-papiers indisponible (http non sécurisé) : silencieux */
|
|
}
|
|
}
|
|
</script>
|