From f46a6b441275fd0036f158e5cdc1fc8bc3eb7c28 Mon Sep 17 00:00:00 2001 From: Anais Saraiva Date: Mon, 21 Sep 2026 16:12:51 +0200 Subject: [PATCH] update --- another_prompt | 7 ++++ frontend/src/components/Login.tsx | 10 ++--- frontend/src/components/dialogs.tsx | 58 ++++++++++++++++------------- frontend/src/lib/i18n.ts | 42 +++++++++++++++------ frontend/tsconfig.json | 4 +- 5 files changed, 77 insertions(+), 44 deletions(-) diff --git a/another_prompt b/another_prompt index 407d921..69bfcde 100644 --- a/another_prompt +++ b/another_prompt @@ -42,3 +42,10 @@ Système de service mails aussi pour les comptes (optionel) pour recovery passwo when disabling attachment sendability: the text "Message" placeholder nto the composer chat are too tigh to the left border, make a fallback padding when no attachment button make in the settigns: an sub category: changing key, admiting TOTP key/passkey for security + +--- bugd II: +sur la page share, l' avatar de l'utilisateur ne s'affiche pas -> fix sa + +--- improvements: +éviter de ask h24 ollama pour ces modèles quand un utilisateur ce connece. c'est le backend qui sert les demande d el'utilisateurs. iL relay pas sur le ollama. Le backend vas cacher avec un TLL les modèles présent en mémire dans un objet qui est dans le backend. refresh avec un TT: toutes les minutes. +L'administrateur lui, qand il demande les modèles dams le ollama, lui, force un refresh . diff --git a/frontend/src/components/Login.tsx b/frontend/src/components/Login.tsx index 17ad31f..9e05c07 100644 --- a/frontend/src/components/Login.tsx +++ b/frontend/src/components/Login.tsx @@ -89,7 +89,7 @@ export function Login({ onLogin }: { onLogin: (user: UserType) => void }) { {totpToken ? (

- Two-factor for @{totpUsername} — enter the 6-digit code from your authenticator app. + {t("login.totpIntro", { user: "@" + totpUsername })}

@@ -156,13 +156,13 @@ export function Login({ onLogin }: { onLogin: (user: UserType) => void }) {

)} )}
- New here? + {t("login.newHere")}
void }) { const [error, setError] = useState(""); const [rotatedKey, setRotatedKey] = useState(null); const [armingRotate, setArmingRotate] = useState(false); - const [armingDelete, setArmingDelete] = useState(false); + const [confirmDelete, setConfirmDelete] = useState(false); useEffect(() => { api.totpStatus().then((r) => setTotpOn(r.enabled)).catch(() => setTotpOn(false)); @@ -776,14 +776,11 @@ function SecuritySection({ onKeyRotated }: { onKeyRotated?: () => void }) { } async function removeAccount() { - if (!armingDelete) { - setArmingDelete(true); - return; - } setBusy(true); setError(""); try { await api.deleteMe(); + setConfirmDelete(false); onKeyRotated?.(); } catch (err) { setError(err instanceof Error ? err.message : "Delete failed"); @@ -796,24 +793,10 @@ function SecuritySection({ onKeyRotated }: { onKeyRotated?: () => void }) {

Access key

- {rotatedKey ? ( -
-

New key — copy it now, it won't be shown again:

-
- {rotatedKey} - -
-

Your old sessions are revoked. Log back in with the new key.

- -
- ) : ( - <> -

Rotate your access key. Old sessions are revoked immediately — you'll log back in with the new key.

- - - )} +

Rotate your access key. Old sessions are revoked immediately — you'll log back in with the new key.

+
@@ -880,12 +863,35 @@ function SecuritySection({ onKeyRotated }: { onKeyRotated?: () => void }) { Danger zone

Permanently delete your account with all chats, shares and sessions. Cannot be undone.

-
{error &&

{error}

} + + {}} title="New access key" icon={KeyRound}> +
+

Copy it now — it won't be shown again. Your old sessions are revoked.

+
+ {rotatedKey} + {rotatedKey && } +
+ +
+
+ + setConfirmDelete(false)} + onConfirm={removeAccount} + title="Delete your account?" + message="This permanently removes your account with all conversations, shares and sessions. This cannot be undone." + confirmLabel="Delete forever" + /> +
+ ); +}
); } diff --git a/frontend/src/lib/i18n.ts b/frontend/src/lib/i18n.ts index 0497c59..6458f6d 100644 --- a/frontend/src/lib/i18n.ts +++ b/frontend/src/lib/i18n.ts @@ -56,8 +56,12 @@ const en = { "login.forgot": "Forgot your access key?", "login.perk1": "Private by design — no cookies, no tracking", "login.perk2": "Your own models, streamed in real time", - "login.adminNote": - "Admin key lives in the server .env; user keys are issued by the admin.", + "login.adminNotePre": "Admin key lives in the server ", + "login.adminNotePost": "; user keys are issued by the admin.", + "login.totpIntro": "Two-factor for @{user} — enter the 6-digit code from your authenticator app.", + "login.totpAria": "Authenticator code", + "login.totpInvalid": "Invalid code", + "login.verify": "Verify", "sidebar.newChat": "New chat", "sidebar.collapse": "Collapse sidebar", @@ -357,8 +361,12 @@ const es: Dict = { "login.forgot": "¿Olvidaste tu clave de acceso?", "login.perk1": "Privado por diseño — sin cookies ni rastreo", "login.perk2": "Tus propios modelos, en tiempo real", - "login.adminNote": - "La clave de admin vive en el .env del servidor; las claves de usuario las emite el admin.", + "login.adminNotePre": "La clave de admin vive en el .env del servidor", + "login.adminNotePost": "; las claves de usuario las emite el admin.", + "login.totpIntro": "Doble factor para @{user} — escribe el código de 6 dígitos de tu app.", + "login.totpAria": "Código de autenticación", + "login.totpInvalid": "Código inválido", + "login.verify": "Verificar", "sidebar.newChat": "Nuevo chat", "sidebar.collapse": "Ocultar barra lateral", @@ -650,8 +658,12 @@ const fr: Dict = { "login.forgot": "Clé d'accès oubliée ?", "login.perk1": "Privé par conception — sans cookies ni suivi", "login.perk2": "Vos propres modèles, en temps réel", - "login.adminNote": - "La clé admin vit dans le .env du serveur ; les clés utilisateur sont émises par l'admin.", + "login.adminNotePre": "La clé admin vit dans le .env du serveur", + "login.adminNotePost": " ; les clés utilisateur sont émises par l'admin.", + "login.totpIntro": "Double facteur pour @{user} — entrez le code à 6 chiffres de votre app.", + "login.totpAria": "Code d'authentification", + "login.totpInvalid": "Code invalide", + "login.verify": "Vérifier", "sidebar.newChat": "Nouveau chat", "sidebar.collapse": "Masquer la barre latérale", @@ -943,8 +955,12 @@ const ru: Dict = { "login.forgot": "Забыли ключ доступа?", "login.perk1": "Приватность по умолчанию — без cookies и трекинга", "login.perk2": "Ваши модели, в реальном времени", - "login.adminNote": - "Ключ админа живёт в .env сервера; ключи пользователей выдаёт админ.", + "login.adminNotePre": "Ключ админа живёт в .env сервера", + "login.adminNotePost": "; ключи пользователей выдаёт админ.", + "login.totpIntro": "Двухфакторка для @{user} — введите 6-значный код из приложения.", + "login.totpAria": "Код аутентификатора", + "login.totpInvalid": "Неверный код", + "login.verify": "Проверить", "sidebar.newChat": "Новый чат", "sidebar.collapse": "Скрыть панель", @@ -1225,8 +1241,12 @@ const it: Dict = { "login.forgot": "Chiave dimenticata?", "login.perk1": "Privato per progettazione — niente cookie né traccianti", "login.perk2": "I tuoi modelli, in tempo reale", - "login.adminNote": - "La chiave admin vive nel .env del server; le chiavi utente le emette l'admin.", + "login.adminNotePre": "La chiave admin vive nel .env del server", + "login.adminNotePost": "; le chiavi utente le emette l'admin.", + "login.totpIntro": "Doppio fattore per @{user} — inserisci il codice a 6 cifre dall'app.", + "login.totpAria": "Codice autenticatore", + "login.totpInvalid": "Codice non valido", + "login.verify": "Verifica", "sidebar.newChat": "Nuova chat", "sidebar.collapse": "Nascondi barra laterale", @@ -1815,7 +1835,7 @@ export function t( let s: string = dicts[current][key] ?? dicts.en[key] ?? key; if (vars) { for (const [k, v] of Object.entries(vars)) - s = s.split(`{${k}}`).join(String(v)); + s = s.replaceAll(`{${k}}`, String(v)); } return s; } diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index a4c834a..0426f7b 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "module": "ESNext", "skipLibCheck": true, "moduleResolution": "bundler",