Pinned chats and chat folders in the sidebar
ci / ui (push) Waiting to run
ci / check (push) Failing after 3s
ci / start (push) Failing after 4s

The server's /api/v2 sets `pinned` on PATCH /chats/{id} and makes, renames and deletes
folders. The sidebar lists the pinned chats first, then the folders (nested, folded as the
server keeps them, each counting its chats), then the rest by day; searching lists every
match flat. A chat's menu pins it and moves it (to no folder, any folder, or a new one);
a folder's menu renames it, makes one inside it, deletes it (its chats stay). Tests F8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
HomerandClaude Opus 5.5 committed 2026-11-10 13:24:34 +00:00
1 parent 04736db057
commit be70e1a628
8 files changed
+480 -10

No files matched your search

+4
View File
@@ -20,6 +20,10 @@ All notable changes to LLeMbas Desktop. The format follows
server says it, unless this computer's or another of the app's nine is chosen (kept in the app; server says it, unless this computer's or another of the app's nine is chosen (kept in the app;
the window opens again in it). The theme is the account's, and choosing one saves it there, so the window opens again in it). The theme is the account's, and choosing one saves it there, so
the web interface and the phone follow; on a server that cannot be told, it is kept in the app. the web interface and the phone follow; on a server that cannot be told, it is kept in the app.
- **Pinned chats and chat folders.** The sidebar lists the pinned chats first, then the account's
folders, nested and folded as the server keeps them, then the rest by day. A chat's menu pins
it and moves it into a folder or a new one; a folder's menu renames it, makes one inside it, or
deletes it (its chats stay, back in the list). The search line still lists every match.
### Fixed ### Fixed
+53
View File
@@ -471,6 +471,19 @@ KEYS = (
"Kept in this app on this computer; the account's theme stays as it is.", "Kept in this app on this computer; the account's theme stays as it is.",
"The account's (%(language)s)", "The account's (%(language)s)",
"Saved to your account: the web interface and the phone follow it too.", "Saved to your account: the web interface and the phone follow it too.",
# list.js, chat.js: pinned chats and chat folders
"Pinned chats",
"Pin chat",
"Unpin chat",
"New folder",
"Rename folder",
"Delete folder",
"Folder name",
"Move to folder…",
"No folder",
"New folder…",
"Create",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.",
) )
# The app's own sentences. The mode names (Manual, Edit, Auto, Plan) stay English, as the # The app's own sentences. The mode names (Manual, Edit, Auto, Plan) stay English, as the
@@ -714,6 +727,11 @@ OWN: dict[str, dict[str, str]] = {
"Kept in this app on this computer; the account's theme stays as it is.": "Uloženo v této aplikaci na tomto počítači; vzhled účtu zůstává, jak je.", "Kept in this app on this computer; the account's theme stays as it is.": "Uloženo v této aplikaci na tomto počítači; vzhled účtu zůstává, jak je.",
"The account's (%(language)s)": "Podle účtu (%(language)s)", "The account's (%(language)s)": "Podle účtu (%(language)s)",
"Saved to your account: the web interface and the phone follow it too.": "Uloženo do vašeho účtu: řídí se jím i webové rozhraní a telefon.", "Saved to your account: the web interface and the phone follow it too.": "Uloženo do vašeho účtu: řídí se jím i webové rozhraní a telefon.",
"Move to folder…": "Přesunout do složky…",
"No folder": "Bez složky",
"New folder…": "Nová složka…",
"Create": "Vytvořit",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "„%(name)s“ a složky v ní se smažou. Jejich konverzace zůstanou, zpět v seznamu.",
}, },
"de": { "de": {
"Sign in again: the server no longer accepts this app's sign-in.": "Melden Sie sich erneut an: Der Server nimmt die Anmeldung dieser App nicht mehr an.", "Sign in again: the server no longer accepts this app's sign-in.": "Melden Sie sich erneut an: Der Server nimmt die Anmeldung dieser App nicht mehr an.",
@@ -952,6 +970,11 @@ OWN: dict[str, dict[str, str]] = {
"Kept in this app on this computer; the account's theme stays as it is.": "In dieser App auf diesem Computer gespeichert; das Design des Kontos bleibt, wie es ist.", "Kept in this app on this computer; the account's theme stays as it is.": "In dieser App auf diesem Computer gespeichert; das Design des Kontos bleibt, wie es ist.",
"The account's (%(language)s)": "Wie das Konto (%(language)s)", "The account's (%(language)s)": "Wie das Konto (%(language)s)",
"Saved to your account: the web interface and the phone follow it too.": "In Ihrem Konto gespeichert: Die Weboberfläche und das Telefon folgen ihm auch.", "Saved to your account: the web interface and the phone follow it too.": "In Ihrem Konto gespeichert: Die Weboberfläche und das Telefon folgen ihm auch.",
"Move to folder…": "In Ordner verschieben…",
"No folder": "Kein Ordner",
"New folder…": "Neuer Ordner…",
"Create": "Erstellen",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "„%(name)s“ und die Ordner darin werden gelöscht. Ihre Chats bleiben, wieder in der Liste.",
}, },
"es": { "es": {
"Sign in again: the server no longer accepts this app's sign-in.": "Vuelva a iniciar sesión: el servidor ya no acepta el inicio de sesión de esta aplicación.", "Sign in again: the server no longer accepts this app's sign-in.": "Vuelva a iniciar sesión: el servidor ya no acepta el inicio de sesión de esta aplicación.",
@@ -1190,6 +1213,11 @@ OWN: dict[str, dict[str, str]] = {
"Kept in this app on this computer; the account's theme stays as it is.": "Se guarda en esta aplicación en este equipo; el tema de la cuenta no cambia.", "Kept in this app on this computer; the account's theme stays as it is.": "Se guarda en esta aplicación en este equipo; el tema de la cuenta no cambia.",
"The account's (%(language)s)": "El de la cuenta (%(language)s)", "The account's (%(language)s)": "El de la cuenta (%(language)s)",
"Saved to your account: the web interface and the phone follow it too.": "Se guarda en su cuenta: la interfaz web y el teléfono también lo siguen.", "Saved to your account: the web interface and the phone follow it too.": "Se guarda en su cuenta: la interfaz web y el teléfono también lo siguen.",
"Move to folder…": "Mover a una carpeta…",
"No folder": "Sin carpeta",
"New folder…": "Nueva carpeta…",
"Create": "Crear",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "Se eliminan «%(name)s» y las carpetas que contiene. Sus chats se quedan, de vuelta en la lista.",
}, },
"fr": { "fr": {
"Sign in again: the server no longer accepts this app's sign-in.": "Reconnectez-vous : le serveur n’accepte plus la connexion de cette application.", "Sign in again: the server no longer accepts this app's sign-in.": "Reconnectez-vous : le serveur n’accepte plus la connexion de cette application.",
@@ -1428,6 +1456,11 @@ OWN: dict[str, dict[str, str]] = {
"Kept in this app on this computer; the account's theme stays as it is.": "Enregistré dans cette application sur cet ordinateur ; le thème du compte reste tel quel.", "Kept in this app on this computer; the account's theme stays as it is.": "Enregistré dans cette application sur cet ordinateur ; le thème du compte reste tel quel.",
"The account's (%(language)s)": "Celle du compte (%(language)s)", "The account's (%(language)s)": "Celle du compte (%(language)s)",
"Saved to your account: the web interface and the phone follow it too.": "Enregistré dans votre compte : l’interface web et le téléphone le suivent aussi.", "Saved to your account: the web interface and the phone follow it too.": "Enregistré dans votre compte : l’interface web et le téléphone le suivent aussi.",
"Move to folder…": "Déplacer dans un dossier…",
"No folder": "Aucun dossier",
"New folder…": "Nouveau dossier…",
"Create": "Créer",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "« %(name)s » et les dossiers qu’il contient sont supprimés. Leurs conversations restent, de retour dans la liste.",
}, },
"hu": { "hu": {
"Sign in again: the server no longer accepts this app's sign-in.": "Jelentkezzen be újra: a szerver már nem fogadja el ennek az alkalmazásnak a bejelentkezését.", "Sign in again: the server no longer accepts this app's sign-in.": "Jelentkezzen be újra: a szerver már nem fogadja el ennek az alkalmazásnak a bejelentkezését.",
@@ -1666,6 +1699,11 @@ OWN: dict[str, dict[str, str]] = {
"Kept in this app on this computer; the account's theme stays as it is.": "Ebben az alkalmazásban, ezen a számítógépen tárolva; a fiók témája változatlan marad.", "Kept in this app on this computer; the account's theme stays as it is.": "Ebben az alkalmazásban, ezen a számítógépen tárolva; a fiók témája változatlan marad.",
"The account's (%(language)s)": "A fióké (%(language)s)", "The account's (%(language)s)": "A fióké (%(language)s)",
"Saved to your account: the web interface and the phone follow it too.": "A fiókjába mentve: a webes felület és a telefon is ezt követi.", "Saved to your account: the web interface and the phone follow it too.": "A fiókjába mentve: a webes felület és a telefon is ezt követi.",
"Move to folder…": "Áthelyezés mappába…",
"No folder": "Nincs mappa",
"New folder…": "Új mappa…",
"Create": "Létrehozás",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "A(z) „%(name)s” és a benne lévő mappák törlődnek. A beszélgetéseik megmaradnak, vissza a listába.",
}, },
"it": { "it": {
"Sign in again: the server no longer accepts this app's sign-in.": "Accedi di nuovo: il server non accetta più l’accesso di questa app.", "Sign in again: the server no longer accepts this app's sign-in.": "Accedi di nuovo: il server non accetta più l’accesso di questa app.",
@@ -1904,6 +1942,11 @@ OWN: dict[str, dict[str, str]] = {
"Kept in this app on this computer; the account's theme stays as it is.": "Salvato in questa app su questo computer; il tema dell’account resta com’è.", "Kept in this app on this computer; the account's theme stays as it is.": "Salvato in questa app su questo computer; il tema dell’account resta com’è.",
"The account's (%(language)s)": "Quella dell’account (%(language)s)", "The account's (%(language)s)": "Quella dell’account (%(language)s)",
"Saved to your account: the web interface and the phone follow it too.": "Salvato nel tuo account: anche l’interfaccia web e il telefono lo seguono.", "Saved to your account: the web interface and the phone follow it too.": "Salvato nel tuo account: anche l’interfaccia web e il telefono lo seguono.",
"Move to folder…": "Sposta in una cartella…",
"No folder": "Nessuna cartella",
"New folder…": "Nuova cartella…",
"Create": "Crea",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "«%(name)s» e le cartelle al suo interno vengono eliminate. Le loro chat restano, di nuovo nell’elenco.",
}, },
"pl": { "pl": {
"Sign in again: the server no longer accepts this app's sign-in.": "Zaloguj się ponownie: serwer nie przyjmuje już logowania tej aplikacji.", "Sign in again: the server no longer accepts this app's sign-in.": "Zaloguj się ponownie: serwer nie przyjmuje już logowania tej aplikacji.",
@@ -2142,6 +2185,11 @@ OWN: dict[str, dict[str, str]] = {
"Kept in this app on this computer; the account's theme stays as it is.": "Zapisane w tej aplikacji na tym komputerze; motyw konta pozostaje bez zmian.", "Kept in this app on this computer; the account's theme stays as it is.": "Zapisane w tej aplikacji na tym komputerze; motyw konta pozostaje bez zmian.",
"The account's (%(language)s)": "Jak na koncie (%(language)s)", "The account's (%(language)s)": "Jak na koncie (%(language)s)",
"Saved to your account: the web interface and the phone follow it too.": "Zapisane na koncie: interfejs WWW i telefon też się do niego stosują.", "Saved to your account: the web interface and the phone follow it too.": "Zapisane na koncie: interfejs WWW i telefon też się do niego stosują.",
"Move to folder…": "Przenieś do folderu…",
"No folder": "Bez folderu",
"New folder…": "Nowy folder…",
"Create": "Utwórz",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "„%(name)s” i foldery w nim zostaną usunięte. Ich czaty zostaną, z powrotem na liście.",
}, },
"sk": { "sk": {
"Sign in again: the server no longer accepts this app's sign-in.": "Prihláste sa znova: server už neprijíma prihlásenie tejto aplikácie.", "Sign in again: the server no longer accepts this app's sign-in.": "Prihláste sa znova: server už neprijíma prihlásenie tejto aplikácie.",
@@ -2380,6 +2428,11 @@ OWN: dict[str, dict[str, str]] = {
"Kept in this app on this computer; the account's theme stays as it is.": "Uložené v tejto aplikácii na tomto počítači; vzhľad účtu zostáva, ako je.", "Kept in this app on this computer; the account's theme stays as it is.": "Uložené v tejto aplikácii na tomto počítači; vzhľad účtu zostáva, ako je.",
"The account's (%(language)s)": "Podľa účtu (%(language)s)", "The account's (%(language)s)": "Podľa účtu (%(language)s)",
"Saved to your account: the web interface and the phone follow it too.": "Uložené do vášho účtu: riadi sa ním aj webové rozhranie a telefón.", "Saved to your account: the web interface and the phone follow it too.": "Uložené do vášho účtu: riadi sa ním aj webové rozhranie a telefón.",
"Move to folder…": "Presunúť do priečinka…",
"No folder": "Bez priečinka",
"New folder…": "Nový priečinok…",
"Create": "Vytvoriť",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "„%(name)s“ a priečinky v ňom sa zmažú. Ich konverzácie zostanú, späť v zozname.",
}, },
} }
+106
View File
@@ -1094,6 +1094,112 @@ test("E5: at 390 px the Appearance group stays inside the window", async () => {
assert.deepEqual(p.errors, []) assert.deepEqual(p.errors, [])
}) })
// F8: pinned chats and chat folders (fixture folders.json: Waybread, and Recipes inside it, folded).
function f8(over = {}) {
return {
status: status(),
routes: baseRoutes({
"GET /folders": fixture("folders"),
"GET /chats": {
chats: [
chatRow({ id: "chat1", title: "Waybread", pinned: true }),
agentChat({ id: "chat2", title: "Tidy the build", folder_id: "fold1" }),
chatRow({ id: "chat3", title: "Seed cake", folder_id: "fold2" }),
chatRow({ id: "chat4", title: "Loose ends" }),
],
more: false,
},
"PATCH /folders/fold2": { folder: { ...fixture("folders").folders[1], collapsed: false } },
"PATCH /chats/chat4": { chat: chatRow({ id: "chat4", title: "Loose ends", pinned: true }) },
"POST /folders": fixture("folder"),
"DELETE /folders/fold1": null,
...over,
}),
streams: {},
}
}
const sideText = (p) => p.$$eval("#chat-list > li", (lis) => lis.map((li) => li.textContent.replace(/\s+/g, " ").trim()))
test("F8: the sidebar: pinned chats first, then the folders, nested and folded as kept, then the rest", async () => {
const p = await page(f8())
await p.waitForSelector("#chat-list .folderrow")
const items = await sideText(p)
assert.equal(items[0], "Pinned chats")
assert.match(items[1], /Waybread/)
assert.match(items[2], /Waybread\s*2/, "the folder counts the chats inside, its folders' too")
assert.match(items[3], /Tidy the build/)
assert.match(items[4], /Recipes/)
assert.ok(!items.some((x) => /Seed cake/.test(x)), "a folded folder's chats are not shown")
assert.ok(items.some((x) => /Loose ends/.test(x)))
assert.equal(await p.getAttribute('.folderrow[data-folder="fold2"]', "aria-expanded"), "false")
await p.click('.folderrow[data-folder="fold2"]')
await p.waitForSelector('.chatrow[data-id="chat3"]')
const [folded] = await p.evaluate(() => window.__mock.api("PATCH", "/folders/fold2"))
assert.deepEqual(folded.args.body, { collapsed: false })
await shot(p, "f8-folders-1280")
// Searching: every match, flat.
await p.fill("#side-search", "seed")
assert.deepEqual((await sideText(p)).slice(1), ["Seed cake"])
assert.deepEqual(p.errors, [])
})
test("F8: a chat's menu pins it and moves it into a folder, or a new one", async () => {
const p = await page(f8())
await p.waitForSelector('.chatrow[data-id="chat4"]')
await p.click('.chatrow[data-id="chat4"]', { button: "right" })
await p.click(".menu .menu__item >> text=Pin chat")
await p.waitForFunction(() => window.__mock.api("PATCH", "/chats/chat4").length === 1)
assert.deepEqual((await p.evaluate(() => window.__mock.api("PATCH", "/chats/chat4")))[0].args.body, { pinned: true })
await p.click('.chatrow[data-id="chat4"]', { button: "right" })
await p.click(".menu .menu__item >> text=Move to folder…")
const labels = await p.$$eval(".menu .menu__item .menu__label", (l) => l.map((x) => x.textContent.trim()))
assert.deepEqual(labels, ["No folder", "Waybread", "Recipes", "New folder…"])
await p.click(".menu .menu__item >> text=Recipes")
await p.waitForFunction(() => window.__mock.api("PATCH", "/chats/chat4").length === 2)
assert.deepEqual((await p.evaluate(() => window.__mock.api("PATCH", "/chats/chat4")))[1].args.body, { folder_id: "fold2" })
// A new one: named, made, and the chat moved into it.
await p.click('.chatrow[data-id="chat4"]', { button: "right" })
await p.click(".menu .menu__item >> text=Move to folder…")
await p.click(".menu .menu__item >> text=New folder…")
await p.fill("dialog[open] .dialog__input", "Lembas")
await p.click("dialog[open] .btn--primary")
await p.waitForFunction(() => window.__mock.api("PATCH", "/chats/chat4").length === 3)
const made = await p.evaluate(() => window.__mock.api("POST", "/folders"))
assert.deepEqual(made[0].args.body, { name: "Lembas" })
assert.deepEqual((await p.evaluate(() => window.__mock.api("PATCH", "/chats/chat4")))[2].args.body, { folder_id: "fold1" })
assert.deepEqual(p.errors, [])
})
test("F8: a folder's menu renames it and deletes it, its chats kept; a refusal is said", async () => {
const p = await page(f8({ "PATCH /folders/fold1": { __error: { status: 403, detail: "You may not manage folders." } } }))
await p.waitForSelector('.folderrow[data-folder="fold1"]')
await p.click('.folderrow[data-folder="fold1"]', { button: "right" })
await p.click(".menu .menu__item >> text=Rename folder")
await p.fill("dialog[open] .dialog__input", "Bread")
await p.click("dialog[open] .btn--primary")
await p.waitForSelector("#thread-note:not([hidden])")
assert.match(await p.textContent("#thread-note"), /may not manage folders/)
await p.click('.list__folder:has([data-folder="fold1"]) .folderrow__more')
await p.click(".menu .menu__item >> text=Delete folder")
assert.match(await p.textContent("dialog[open]"), /Their chats stay/)
await p.click("dialog[open] .btn--danger")
await p.waitForFunction(() => window.__mock.api("DELETE", "/folders/fold1").length === 1)
assert.equal(await p.evaluate(() => window.__mock.api("DELETE", "/chats").length), 0, "no chat deleted")
assert.deepEqual(p.errors, [])
})
test("F8: at 390 px the folders stay inside the sidebar", async () => {
const p = await page(f8(), { width: 390, height: 844 })
await p.evaluate(() => document.getElementById("side-toggle").click())
await p.waitForSelector('.folderrow[data-folder="fold1"]')
await p.waitForTimeout(400) // the sidebar slides in
assert.ok(await noSideways(p, 390), "nothing scrolls sideways")
await shot(p, "f8-folders-390")
assert.deepEqual(p.errors, [])
})
// --- Run ---------------------------------------------------------------------------------------- // --- Run ----------------------------------------------------------------------------------------
const only = process.argv[2] || "" const only = process.argv[2] || ""
+28
View File
@@ -431,6 +431,34 @@ label, .label { font: var(--text-sm) / var(--leading-tight) var(--font-body); co
.chatrow__state { width: var(--dot-size); height: var(--dot-size); border-radius: var(--radius-full); } .chatrow__state { width: var(--dot-size); height: var(--dot-size); border-radius: var(--radius-full); }
.chatrow__state.is-busy { background: var(--accent); animation: pulse 1.4s var(--ease-in-out) infinite; } .chatrow__state.is-busy { background: var(--accent); animation: pulse 1.4s var(--ease-in-out) infinite; }
.chatrow__state.is-new { background: var(--leaf); } .chatrow__state.is-new { background: var(--leaf); }
/* A chat folder's head: chevron · folder · name · count, and its own ⋯ beside it on one track. */
.list__folder { display: grid; grid-template-columns: minmax(0, 1fr) var(--control-h-sm); align-items: center; }
.folderrow {
display: grid;
grid-template-columns: 12px 16px minmax(0, 1fr) auto;
gap: var(--sp-2);
align-items: center;
height: var(--control-h-sm);
padding: 0 var(--sp-2) 0 calc(var(--sp-2) + var(--depth, 0) * var(--sp-4));
text-align: left;
font: 600 var(--text-sm) / var(--leading-tight) var(--font-ui);
color: var(--ink-muted);
background: transparent;
border: 0;
border-radius: var(--radius-lg);
cursor: pointer;
}
.folderrow:hover { color: var(--ink); background: var(--surface-hover); }
.folderrow__chev, .folderrow__icon { display: grid; place-items: center; color: var(--ink-faint); }
.folderrow__chev .icon { width: 12px; height: 12px; }
.folderrow__icon .icon { width: 14px; height: 14px; }
.folderrow__name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.folderrow__count { font: var(--text-xs) var(--font-ui); color: var(--ink-faint); }
.folderrow__more { display: grid; place-items: center; width: var(--control-h-sm); height: var(--control-h-sm); color: var(--ink-faint); background: transparent; border: 0; border-radius: var(--radius-lg); cursor: pointer; opacity: 0; }
.list__folder:hover .folderrow__more, .folderrow__more:focus-visible { opacity: 1; }
.folderrow__more:hover { color: var(--ink); background: var(--surface-hover); }
@media (hover: none) { .folderrow__more { opacity: 1; } }
.chatrow.is-filed { padding-left: calc(var(--sp-2) + var(--depth, 1) * var(--sp-4)); }
@keyframes pulse { 50% { opacity: 0.35; } } @keyframes pulse { 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .chatrow__state.is-busy { animation: none; } } @media (prefers-reduced-motion: reduce) { .chatrow__state.is-busy { animation: none; } }
+96
View File
@@ -103,10 +103,12 @@ const LEMBAS_I18N = {
"Copy": "Kopírovat", "Copy": "Kopírovat",
"Copy the last command and its output": "Zkopírovat poslední příkaz a jeho výstup", "Copy the last command and its output": "Zkopírovat poslední příkaz a jeho výstup",
"Counted by the model at the last reply; the categories are estimated.": "Spočítal model při poslední odpovědi; kategorie jsou odhadnuté.", "Counted by the model at the last reply; the categories are estimated.": "Spočítal model při poslední odpovědi; kategorie jsou odhadnuté.",
"Create": "Vytvořit",
"Cut short here; the whole of it is in the web interface.": "Zde zkráceno; celé je to ve webovém rozhraní.", "Cut short here; the whole of it is in the web interface.": "Zde zkráceno; celé je to ve webovém rozhraní.",
"Days": "Dny", "Days": "Dny",
"Delete": "Smazat", "Delete": "Smazat",
"Delete chat": "Smazat konverzaci", "Delete chat": "Smazat konverzaci",
"Delete folder": "Smazat složku",
"Delete this chat?": "Smazat tuto konverzaci?", "Delete this chat?": "Smazat tuto konverzaci?",
"Delete this scheduled task?": "Odstranit tuto naplánovanou úlohu?", "Delete this scheduled task?": "Odstranit tuto naplánovanou úlohu?",
"Deny": "Zamítnout", "Deny": "Zamítnout",
@@ -135,6 +137,7 @@ const LEMBAS_I18N = {
"Findings": "Zjištění", "Findings": "Zjištění",
"Finished %(n)s": "Dokončeno: %(n)s", "Finished %(n)s": "Dokončeno: %(n)s",
"Folder": "Složka", "Folder": "Složka",
"Folder name": "Název složky",
"Folder on %(device)s": "Složka na zařízení %(device)s", "Folder on %(device)s": "Složka na zařízení %(device)s",
"Free space": "Volné místo", "Free space": "Volné místo",
"Hello": "Dobrý den", "Hello": "Dobrý den",
@@ -176,15 +179,19 @@ const LEMBAS_I18N = {
"Models": "Modely", "Models": "Modely",
"Models for scheduled tasks": "Modely pro naplánované úlohy", "Models for scheduled tasks": "Modely pro naplánované úlohy",
"More": "Více", "More": "Více",
"Move to folder…": "Přesunout do složky…",
"Never": "Nikdy", "Never": "Nikdy",
"New agent chat": "Nová agentní konverzace", "New agent chat": "Nová agentní konverzace",
"New chat": "Nová konverzace", "New chat": "Nová konverzace",
"New folder": "Nová složka",
"New folder…": "Nová složka…",
"New scheduled task": "Nová naplánovaná úloha", "New scheduled task": "Nová naplánovaná úloha",
"Next run": "Další spuštění", "Next run": "Další spuštění",
"No archived chats.": "Žádné archivované konverzace.", "No archived chats.": "Žádné archivované konverzace.",
"No chat yet. Start one with New chat.": "Zatím žádná konverzace. Začněte ji tlačítkem Nová konverzace.", "No chat yet. Start one with New chat.": "Zatím žádná konverzace. Začněte ji tlačítkem Nová konverzace.",
"No day ticked: every day.": "Žádný den nezaškrtnutý: každý den.", "No day ticked: every day.": "Žádný den nezaškrtnutý: každý den.",
"No files written in this chat yet.": "V tomto chatu se zatím nezapsal žádný soubor.", "No files written in this chat yet.": "V tomto chatu se zatím nezapsal žádný soubor.",
"No folder": "Bez složky",
"No folder yet: add one under Settings, Project folders.": "Zatím žádná složka: přidejte ji v Nastavení, Složky projektů.", "No folder yet: add one under Settings, Project folders.": "Zatím žádná složka: přidejte ji v Nastavení, Složky projektů.",
"No folder yet: the agent can open nothing. Add the folder of a project.": "Zatím žádná složka: agent nemůže nic otevřít. Přidejte složku projektu.", "No folder yet: the agent can open nothing. Add the folder of a project.": "Zatím žádná složka: agent nemůže nic otevřít. Přidejte složku projektu.",
"No model is available to this account.": "Tomuto účtu není dostupný žádný model.", "No model is available to this account.": "Tomuto účtu není dostupný žádný model.",
@@ -220,6 +227,8 @@ const LEMBAS_I18N = {
"Pause": "Pozastavit", "Pause": "Pozastavit",
"Pause %(title)s": "Pozastavit %(title)s", "Pause %(title)s": "Pozastavit %(title)s",
"Paused": "Pozastaveno", "Paused": "Pozastaveno",
"Pin chat": "Připnout konverzaci",
"Pinned chats": "Připnuté konverzace",
"Plan": "Plán", "Plan": "Plán",
"Plan — changes nothing": "Plan — nic nemění", "Plan — changes nothing": "Plan — nic nemění",
"Preview": "Náhled", "Preview": "Náhled",
@@ -238,6 +247,7 @@ const LEMBAS_I18N = {
"Remove %(dir)s": "Odebrat %(dir)s", "Remove %(dir)s": "Odebrat %(dir)s",
"Rename": "Přejmenovat", "Rename": "Přejmenovat",
"Rename chat": "Přejmenovat konverzaci", "Rename chat": "Přejmenovat konverzaci",
"Rename folder": "Přejmenovat složku",
"Rename…": "Přejmenovat…", "Rename…": "Přejmenovat…",
"Restore": "Obnovit", "Restore": "Obnovit",
"Restore chat": "Obnovit konverzaci", "Restore chat": "Obnovit konverzaci",
@@ -360,6 +370,7 @@ const LEMBAS_I18N = {
"Try again": "Zkusit znovu", "Try again": "Zkusit znovu",
"Type a command or a chat's title": "Napište příkaz nebo název konverzace", "Type a command or a chat's title": "Napište příkaz nebo název konverzace",
"Type a folder…": "Zadat složku…", "Type a folder…": "Zadat složku…",
"Unpin chat": "Odepnout konverzaci",
"Up to %(n)s at once": "Nejvýše %(n)s současně", "Up to %(n)s at once": "Nejvýše %(n)s současně",
"Wait until the files are sent.": "Počkejte, až se soubory odešlou.", "Wait until the files are sent.": "Počkejte, až se soubory odešlou.",
"Waiting for a free model": "Čeká na volný model", "Waiting for a free model": "Čeká na volný model",
@@ -429,6 +440,7 @@ const LEMBAS_I18N = {
"waiting for a slot": "čeká na volný slot", "waiting for a slot": "čeká na volný slot",
"window unknown": "okno neznámé", "window unknown": "okno neznámé",
"working": "pracuje", "working": "pracuje",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "„%(name)s“ a složky v ní se smažou. Jejich konverzace zůstanou, zpět v seznamu.",
"“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "„%(title)s“ se smaže na serveru i se svými zprávami a soubory. Nelze to vrátit.", "“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "„%(title)s“ se smaže na serveru i se svými zprávami a soubory. Nelze to vrátit.",
"“%(title)s” stops, and its history goes. The chats it wrote stay.": "„%(title)s“ se zastaví a její historie zmizí. Konverzace, které napsala, zůstanou." "“%(title)s” stops, and its history goes. The chats it wrote stay.": "„%(title)s“ se zastaví a její historie zmizí. Konverzace, které napsala, zůstanou."
}, },
@@ -523,10 +535,12 @@ const LEMBAS_I18N = {
"Copy": "Kopieren", "Copy": "Kopieren",
"Copy the last command and its output": "Den letzten Befehl und seine Ausgabe kopieren", "Copy the last command and its output": "Den letzten Befehl und seine Ausgabe kopieren",
"Counted by the model at the last reply; the categories are estimated.": "Vom Modell bei der letzten Antwort gezählt; die Kategorien sind geschätzt.", "Counted by the model at the last reply; the categories are estimated.": "Vom Modell bei der letzten Antwort gezählt; die Kategorien sind geschätzt.",
"Create": "Erstellen",
"Cut short here; the whole of it is in the web interface.": "Hier gekürzt; vollständig steht es in der Weboberfläche.", "Cut short here; the whole of it is in the web interface.": "Hier gekürzt; vollständig steht es in der Weboberfläche.",
"Days": "Tage", "Days": "Tage",
"Delete": "Löschen", "Delete": "Löschen",
"Delete chat": "Chat löschen", "Delete chat": "Chat löschen",
"Delete folder": "Ordner löschen",
"Delete this chat?": "Diesen Chat löschen?", "Delete this chat?": "Diesen Chat löschen?",
"Delete this scheduled task?": "Diese geplante Aufgabe löschen?", "Delete this scheduled task?": "Diese geplante Aufgabe löschen?",
"Deny": "Ablehnen", "Deny": "Ablehnen",
@@ -555,6 +569,7 @@ const LEMBAS_I18N = {
"Findings": "Erkenntnisse", "Findings": "Erkenntnisse",
"Finished %(n)s": "Fertig: %(n)s", "Finished %(n)s": "Fertig: %(n)s",
"Folder": "Ordner", "Folder": "Ordner",
"Folder name": "Ordnername",
"Folder on %(device)s": "Ordner auf %(device)s", "Folder on %(device)s": "Ordner auf %(device)s",
"Free space": "Freier Platz", "Free space": "Freier Platz",
"Hello": "Hallo", "Hello": "Hallo",
@@ -596,15 +611,19 @@ const LEMBAS_I18N = {
"Models": "Modelle", "Models": "Modelle",
"Models for scheduled tasks": "Modelle für geplante Aufgaben", "Models for scheduled tasks": "Modelle für geplante Aufgaben",
"More": "Mehr", "More": "Mehr",
"Move to folder…": "In Ordner verschieben…",
"Never": "Nie", "Never": "Nie",
"New agent chat": "Neuer Agenten-Chat", "New agent chat": "Neuer Agenten-Chat",
"New chat": "Neuer Chat", "New chat": "Neuer Chat",
"New folder": "Neuer Ordner",
"New folder…": "Neuer Ordner…",
"New scheduled task": "Neue geplante Aufgabe", "New scheduled task": "Neue geplante Aufgabe",
"Next run": "Nächster Lauf", "Next run": "Nächster Lauf",
"No archived chats.": "Keine archivierten Chats.", "No archived chats.": "Keine archivierten Chats.",
"No chat yet. Start one with New chat.": "Noch kein Chat. Beginnen Sie einen mit Neuer Chat.", "No chat yet. Start one with New chat.": "Noch kein Chat. Beginnen Sie einen mit Neuer Chat.",
"No day ticked: every day.": "Kein Tag angehakt: jeden Tag.", "No day ticked: every day.": "Kein Tag angehakt: jeden Tag.",
"No files written in this chat yet.": "In diesem Chat wurde noch keine Datei geschrieben.", "No files written in this chat yet.": "In diesem Chat wurde noch keine Datei geschrieben.",
"No folder": "Kein Ordner",
"No folder yet: add one under Settings, Project folders.": "Noch kein Ordner: Fügen Sie einen unter Einstellungen, Projektordner hinzu.", "No folder yet: add one under Settings, Project folders.": "Noch kein Ordner: Fügen Sie einen unter Einstellungen, Projektordner hinzu.",
"No folder yet: the agent can open nothing. Add the folder of a project.": "Noch kein Ordner: Der Agent kann nichts öffnen. Fügen Sie den Ordner eines Projekts hinzu.", "No folder yet: the agent can open nothing. Add the folder of a project.": "Noch kein Ordner: Der Agent kann nichts öffnen. Fügen Sie den Ordner eines Projekts hinzu.",
"No model is available to this account.": "Diesem Konto steht kein Modell zur Verfügung.", "No model is available to this account.": "Diesem Konto steht kein Modell zur Verfügung.",
@@ -640,6 +659,8 @@ const LEMBAS_I18N = {
"Pause": "Pausieren", "Pause": "Pausieren",
"Pause %(title)s": "%(title)s pausieren", "Pause %(title)s": "%(title)s pausieren",
"Paused": "Pausiert", "Paused": "Pausiert",
"Pin chat": "Chat anheften",
"Pinned chats": "Angeheftete Chats",
"Plan": "Tarif", "Plan": "Tarif",
"Plan — changes nothing": "Plan — ändert nichts", "Plan — changes nothing": "Plan — ändert nichts",
"Preview": "Vorschau", "Preview": "Vorschau",
@@ -658,6 +679,7 @@ const LEMBAS_I18N = {
"Remove %(dir)s": "%(dir)s entfernen", "Remove %(dir)s": "%(dir)s entfernen",
"Rename": "Umbenennen", "Rename": "Umbenennen",
"Rename chat": "Chat umbenennen", "Rename chat": "Chat umbenennen",
"Rename folder": "Ordner umbenennen",
"Rename…": "Umbenennen…", "Rename…": "Umbenennen…",
"Restore": "Wiederherstellen", "Restore": "Wiederherstellen",
"Restore chat": "Chat wiederherstellen", "Restore chat": "Chat wiederherstellen",
@@ -780,6 +802,7 @@ const LEMBAS_I18N = {
"Try again": "Erneut versuchen", "Try again": "Erneut versuchen",
"Type a command or a chat's title": "Befehl oder Chat-Titel eingeben", "Type a command or a chat's title": "Befehl oder Chat-Titel eingeben",
"Type a folder…": "Ordner eingeben…", "Type a folder…": "Ordner eingeben…",
"Unpin chat": "Chat loslösen",
"Up to %(n)s at once": "Bis zu %(n)s gleichzeitig", "Up to %(n)s at once": "Bis zu %(n)s gleichzeitig",
"Wait until the files are sent.": "Warten Sie, bis die Dateien gesendet sind.", "Wait until the files are sent.": "Warten Sie, bis die Dateien gesendet sind.",
"Waiting for a free model": "Wartet auf ein freies Modell", "Waiting for a free model": "Wartet auf ein freies Modell",
@@ -849,6 +872,7 @@ const LEMBAS_I18N = {
"waiting for a slot": "wartet auf einen Platz", "waiting for a slot": "wartet auf einen Platz",
"window unknown": "Fenster unbekannt", "window unknown": "Fenster unbekannt",
"working": "arbeitet", "working": "arbeitet",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "„%(name)s“ und die Ordner darin werden gelöscht. Ihre Chats bleiben, wieder in der Liste.",
"“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "„%(title)s“ wird auf dem Server gelöscht, mit seinen Nachrichten und Dateien. Das lässt sich nicht rückgängig machen.", "“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "„%(title)s“ wird auf dem Server gelöscht, mit seinen Nachrichten und Dateien. Das lässt sich nicht rückgängig machen.",
"“%(title)s” stops, and its history goes. The chats it wrote stay.": "„%(title)s“ hört auf, und ihr Verlauf wird gelöscht. Die Chats, die sie geschrieben hat, bleiben." "“%(title)s” stops, and its history goes. The chats it wrote stay.": "„%(title)s“ hört auf, und ihr Verlauf wird gelöscht. Die Chats, die sie geschrieben hat, bleiben."
}, },
@@ -943,10 +967,12 @@ const LEMBAS_I18N = {
"Copy": "Copiar", "Copy": "Copiar",
"Copy the last command and its output": "Copiar el último comando y su salida", "Copy the last command and its output": "Copiar el último comando y su salida",
"Counted by the model at the last reply; the categories are estimated.": "Contado por el modelo en la última respuesta; las categorías son estimaciones.", "Counted by the model at the last reply; the categories are estimated.": "Contado por el modelo en la última respuesta; las categorías son estimaciones.",
"Create": "Crear",
"Cut short here; the whole of it is in the web interface.": "Recortado aquí; completo está en la interfaz web.", "Cut short here; the whole of it is in the web interface.": "Recortado aquí; completo está en la interfaz web.",
"Days": "Días", "Days": "Días",
"Delete": "Eliminar", "Delete": "Eliminar",
"Delete chat": "Eliminar chat", "Delete chat": "Eliminar chat",
"Delete folder": "Eliminar carpeta",
"Delete this chat?": "¿Eliminar este chat?", "Delete this chat?": "¿Eliminar este chat?",
"Delete this scheduled task?": "¿Eliminar esta tarea programada?", "Delete this scheduled task?": "¿Eliminar esta tarea programada?",
"Deny": "Denegar", "Deny": "Denegar",
@@ -975,6 +1001,7 @@ const LEMBAS_I18N = {
"Findings": "Hallazgos", "Findings": "Hallazgos",
"Finished %(n)s": "Terminadas: %(n)s", "Finished %(n)s": "Terminadas: %(n)s",
"Folder": "Carpeta", "Folder": "Carpeta",
"Folder name": "Nombre de la carpeta",
"Folder on %(device)s": "Carpeta en %(device)s", "Folder on %(device)s": "Carpeta en %(device)s",
"Free space": "Espacio libre", "Free space": "Espacio libre",
"Hello": "Hola", "Hello": "Hola",
@@ -1016,15 +1043,19 @@ const LEMBAS_I18N = {
"Models": "Modelos", "Models": "Modelos",
"Models for scheduled tasks": "Modelos para tareas programadas", "Models for scheduled tasks": "Modelos para tareas programadas",
"More": "Más", "More": "Más",
"Move to folder…": "Mover a una carpeta…",
"Never": "Nunca", "Never": "Nunca",
"New agent chat": "Nuevo chat de agente", "New agent chat": "Nuevo chat de agente",
"New chat": "Nuevo chat", "New chat": "Nuevo chat",
"New folder": "Nueva carpeta",
"New folder…": "Nueva carpeta…",
"New scheduled task": "Nueva tarea programada", "New scheduled task": "Nueva tarea programada",
"Next run": "Próxima ejecución", "Next run": "Próxima ejecución",
"No archived chats.": "No hay chats archivados.", "No archived chats.": "No hay chats archivados.",
"No chat yet. Start one with New chat.": "Aún no hay chats. Empiece uno con Nuevo chat.", "No chat yet. Start one with New chat.": "Aún no hay chats. Empiece uno con Nuevo chat.",
"No day ticked: every day.": "Ningún día marcado: todos los días.", "No day ticked: every day.": "Ningún día marcado: todos los días.",
"No files written in this chat yet.": "Todavía no se ha escrito ningún archivo en este chat.", "No files written in this chat yet.": "Todavía no se ha escrito ningún archivo en este chat.",
"No folder": "Sin carpeta",
"No folder yet: add one under Settings, Project folders.": "Aún no hay carpeta: añada una en Ajustes, Carpetas de proyecto.", "No folder yet: add one under Settings, Project folders.": "Aún no hay carpeta: añada una en Ajustes, Carpetas de proyecto.",
"No folder yet: the agent can open nothing. Add the folder of a project.": "Aún no hay ninguna carpeta: el agente no puede abrir nada. Añada la carpeta de un proyecto.", "No folder yet: the agent can open nothing. Add the folder of a project.": "Aún no hay ninguna carpeta: el agente no puede abrir nada. Añada la carpeta de un proyecto.",
"No model is available to this account.": "Ningún modelo está disponible para esta cuenta.", "No model is available to this account.": "Ningún modelo está disponible para esta cuenta.",
@@ -1060,6 +1091,8 @@ const LEMBAS_I18N = {
"Pause": "Pausar", "Pause": "Pausar",
"Pause %(title)s": "Pausar %(title)s", "Pause %(title)s": "Pausar %(title)s",
"Paused": "En pausa", "Paused": "En pausa",
"Pin chat": "Fijar chat",
"Pinned chats": "Chats fijados",
"Plan": "Plan", "Plan": "Plan",
"Plan — changes nothing": "Plan — no cambia nada", "Plan — changes nothing": "Plan — no cambia nada",
"Preview": "Vista previa", "Preview": "Vista previa",
@@ -1078,6 +1111,7 @@ const LEMBAS_I18N = {
"Remove %(dir)s": "Quitar %(dir)s", "Remove %(dir)s": "Quitar %(dir)s",
"Rename": "Renombrar", "Rename": "Renombrar",
"Rename chat": "Renombrar chat", "Rename chat": "Renombrar chat",
"Rename folder": "Renombrar carpeta",
"Rename…": "Renombrar…", "Rename…": "Renombrar…",
"Restore": "Restaurar", "Restore": "Restaurar",
"Restore chat": "Restaurar chat", "Restore chat": "Restaurar chat",
@@ -1200,6 +1234,7 @@ const LEMBAS_I18N = {
"Try again": "Reintentar", "Try again": "Reintentar",
"Type a command or a chat's title": "Escriba un comando o el título de un chat", "Type a command or a chat's title": "Escriba un comando o el título de un chat",
"Type a folder…": "Escribir una carpeta…", "Type a folder…": "Escribir una carpeta…",
"Unpin chat": "Dejar de fijar el chat",
"Up to %(n)s at once": "Hasta %(n)s a la vez", "Up to %(n)s at once": "Hasta %(n)s a la vez",
"Wait until the files are sent.": "Espere a que se envíen los archivos.", "Wait until the files are sent.": "Espere a que se envíen los archivos.",
"Waiting for a free model": "Esperando un modelo libre", "Waiting for a free model": "Esperando un modelo libre",
@@ -1269,6 +1304,7 @@ const LEMBAS_I18N = {
"waiting for a slot": "esperando una plaza", "waiting for a slot": "esperando una plaza",
"window unknown": "ventana desconocida", "window unknown": "ventana desconocida",
"working": "trabajando", "working": "trabajando",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "Se eliminan «%(name)s» y las carpetas que contiene. Sus chats se quedan, de vuelta en la lista.",
"“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "«%(title)s» se elimina del servidor, con sus mensajes y archivos. No se puede deshacer.", "“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "«%(title)s» se elimina del servidor, con sus mensajes y archivos. No se puede deshacer.",
"“%(title)s” stops, and its history goes. The chats it wrote stay.": "«%(title)s» se detiene y su historial se borra. Los chats que escribió se conservan." "“%(title)s” stops, and its history goes. The chats it wrote stay.": "«%(title)s» se detiene y su historial se borra. Los chats que escribió se conservan."
}, },
@@ -1363,10 +1399,12 @@ const LEMBAS_I18N = {
"Copy": "Copier", "Copy": "Copier",
"Copy the last command and its output": "Copier la dernière commande et sa sortie", "Copy the last command and its output": "Copier la dernière commande et sa sortie",
"Counted by the model at the last reply; the categories are estimated.": "Compté par le modèle lors de la dernière réponse ; les catégories sont estimées.", "Counted by the model at the last reply; the categories are estimated.": "Compté par le modèle lors de la dernière réponse ; les catégories sont estimées.",
"Create": "Créer",
"Cut short here; the whole of it is in the web interface.": "Tronqué ici ; le tout est dans l'interface web.", "Cut short here; the whole of it is in the web interface.": "Tronqué ici ; le tout est dans l'interface web.",
"Days": "Jours", "Days": "Jours",
"Delete": "Supprimer", "Delete": "Supprimer",
"Delete chat": "Supprimer la conversation", "Delete chat": "Supprimer la conversation",
"Delete folder": "Supprimer le dossier",
"Delete this chat?": "Supprimer cette conversation ?", "Delete this chat?": "Supprimer cette conversation ?",
"Delete this scheduled task?": "Supprimer cette tâche planifiée ?", "Delete this scheduled task?": "Supprimer cette tâche planifiée ?",
"Deny": "Refuser", "Deny": "Refuser",
@@ -1395,6 +1433,7 @@ const LEMBAS_I18N = {
"Findings": "Constats", "Findings": "Constats",
"Finished %(n)s": "Terminées : %(n)s", "Finished %(n)s": "Terminées : %(n)s",
"Folder": "Dossier", "Folder": "Dossier",
"Folder name": "Nom du dossier",
"Folder on %(device)s": "Dossier sur %(device)s", "Folder on %(device)s": "Dossier sur %(device)s",
"Free space": "Espace libre", "Free space": "Espace libre",
"Hello": "Bonjour", "Hello": "Bonjour",
@@ -1436,15 +1475,19 @@ const LEMBAS_I18N = {
"Models": "Modèles", "Models": "Modèles",
"Models for scheduled tasks": "Modèles pour les tâches planifiées", "Models for scheduled tasks": "Modèles pour les tâches planifiées",
"More": "Plus", "More": "Plus",
"Move to folder…": "Déplacer dans un dossier…",
"Never": "Jamais", "Never": "Jamais",
"New agent chat": "Nouvelle discussion d'agent", "New agent chat": "Nouvelle discussion d'agent",
"New chat": "Nouvelle conversation", "New chat": "Nouvelle conversation",
"New folder": "Nouveau dossier",
"New folder…": "Nouveau dossier…",
"New scheduled task": "Nouvelle tâche planifiée", "New scheduled task": "Nouvelle tâche planifiée",
"Next run": "Prochaine exécution", "Next run": "Prochaine exécution",
"No archived chats.": "Aucune conversation archivée.", "No archived chats.": "Aucune conversation archivée.",
"No chat yet. Start one with New chat.": "Aucune conversation pour l’instant. Commencez-en une avec Nouvelle conversation.", "No chat yet. Start one with New chat.": "Aucune conversation pour l’instant. Commencez-en une avec Nouvelle conversation.",
"No day ticked: every day.": "Aucun jour coché : tous les jours.", "No day ticked: every day.": "Aucun jour coché : tous les jours.",
"No files written in this chat yet.": "Aucun fichier n’a encore été écrit dans cette conversation.", "No files written in this chat yet.": "Aucun fichier n’a encore été écrit dans cette conversation.",
"No folder": "Aucun dossier",
"No folder yet: add one under Settings, Project folders.": "Aucun dossier pour l'instant : ajoutez-en un dans Paramètres, Dossiers de projet.", "No folder yet: add one under Settings, Project folders.": "Aucun dossier pour l'instant : ajoutez-en un dans Paramètres, Dossiers de projet.",
"No folder yet: the agent can open nothing. Add the folder of a project.": "Aucun dossier pour l'instant : l'agent ne peut rien ouvrir. Ajoutez le dossier d'un projet.", "No folder yet: the agent can open nothing. Add the folder of a project.": "Aucun dossier pour l'instant : l'agent ne peut rien ouvrir. Ajoutez le dossier d'un projet.",
"No model is available to this account.": "Aucun modèle n'est disponible pour ce compte.", "No model is available to this account.": "Aucun modèle n'est disponible pour ce compte.",
@@ -1480,6 +1523,8 @@ const LEMBAS_I18N = {
"Pause": "Mettre en pause", "Pause": "Mettre en pause",
"Pause %(title)s": "Mettre %(title)s en pause", "Pause %(title)s": "Mettre %(title)s en pause",
"Paused": "En pause", "Paused": "En pause",
"Pin chat": "Épingler la discussion",
"Pinned chats": "Discussions épinglées",
"Plan": "Forfait", "Plan": "Forfait",
"Plan — changes nothing": "Plan — ne change rien", "Plan — changes nothing": "Plan — ne change rien",
"Preview": "Aperçu", "Preview": "Aperçu",
@@ -1498,6 +1543,7 @@ const LEMBAS_I18N = {
"Remove %(dir)s": "Retirer %(dir)s", "Remove %(dir)s": "Retirer %(dir)s",
"Rename": "Renommer", "Rename": "Renommer",
"Rename chat": "Renommer la conversation", "Rename chat": "Renommer la conversation",
"Rename folder": "Renommer le dossier",
"Rename…": "Renommer…", "Rename…": "Renommer…",
"Restore": "Restaurer", "Restore": "Restaurer",
"Restore chat": "Restaurer la conversation", "Restore chat": "Restaurer la conversation",
@@ -1620,6 +1666,7 @@ const LEMBAS_I18N = {
"Try again": "Réessayer", "Try again": "Réessayer",
"Type a command or a chat's title": "Tapez une commande ou le titre d'une conversation", "Type a command or a chat's title": "Tapez une commande ou le titre d'une conversation",
"Type a folder…": "Saisir un dossier…", "Type a folder…": "Saisir un dossier…",
"Unpin chat": "Désépingler la discussion",
"Up to %(n)s at once": "Jusqu’à %(n)s à la fois", "Up to %(n)s at once": "Jusqu’à %(n)s à la fois",
"Wait until the files are sent.": "Attendez que les fichiers soient envoyés.", "Wait until the files are sent.": "Attendez que les fichiers soient envoyés.",
"Waiting for a free model": "En attente d’un modèle libre", "Waiting for a free model": "En attente d’un modèle libre",
@@ -1689,6 +1736,7 @@ const LEMBAS_I18N = {
"waiting for a slot": "attend une place", "waiting for a slot": "attend une place",
"window unknown": "fenêtre inconnue", "window unknown": "fenêtre inconnue",
"working": "au travail", "working": "au travail",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "« %(name)s » et les dossiers qu’il contient sont supprimés. Leurs conversations restent, de retour dans la liste.",
"“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "« %(title)s » est supprimée du serveur, avec ses messages et ses fichiers. C'est définitif.", "“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "« %(title)s » est supprimée du serveur, avec ses messages et ses fichiers. C'est définitif.",
"“%(title)s” stops, and its history goes. The chats it wrote stay.": "« %(title)s » s’arrête et son historique disparaît. Les conversations qu’elle a écrites restent." "“%(title)s” stops, and its history goes. The chats it wrote stay.": "« %(title)s » s’arrête et son historique disparaît. Les conversations qu’elle a écrites restent."
}, },
@@ -1783,10 +1831,12 @@ const LEMBAS_I18N = {
"Copy": "Másolás", "Copy": "Másolás",
"Copy the last command and its output": "Az utolsó parancs és kimenetének másolása", "Copy the last command and its output": "Az utolsó parancs és kimenetének másolása",
"Counted by the model at the last reply; the categories are estimated.": "A modell számolta az utolsó válasznál; a kategóriák becslések.", "Counted by the model at the last reply; the categories are estimated.": "A modell számolta az utolsó válasznál; a kategóriák becslések.",
"Create": "Létrehozás",
"Cut short here; the whole of it is in the web interface.": "Itt rövidítve; a teljes a webes felületen van.", "Cut short here; the whole of it is in the web interface.": "Itt rövidítve; a teljes a webes felületen van.",
"Days": "Napok", "Days": "Napok",
"Delete": "Törlés", "Delete": "Törlés",
"Delete chat": "Csevegés törlése", "Delete chat": "Csevegés törlése",
"Delete folder": "Mappa törlése",
"Delete this chat?": "Törli ezt a csevegést?", "Delete this chat?": "Törli ezt a csevegést?",
"Delete this scheduled task?": "Törli ezt az ütemezett feladatot?", "Delete this scheduled task?": "Törli ezt az ütemezett feladatot?",
"Deny": "Elutasítás", "Deny": "Elutasítás",
@@ -1815,6 +1865,7 @@ const LEMBAS_I18N = {
"Findings": "Megállapítások", "Findings": "Megállapítások",
"Finished %(n)s": "Kész: %(n)s", "Finished %(n)s": "Kész: %(n)s",
"Folder": "Mappa", "Folder": "Mappa",
"Folder name": "Mappa neve",
"Folder on %(device)s": "Mappa ezen: %(device)s", "Folder on %(device)s": "Mappa ezen: %(device)s",
"Free space": "Szabad hely", "Free space": "Szabad hely",
"Hello": "Üdv", "Hello": "Üdv",
@@ -1856,15 +1907,19 @@ const LEMBAS_I18N = {
"Models": "Modellek", "Models": "Modellek",
"Models for scheduled tasks": "Modellek az ütemezett feladatokhoz", "Models for scheduled tasks": "Modellek az ütemezett feladatokhoz",
"More": "Több", "More": "Több",
"Move to folder…": "Áthelyezés mappába…",
"Never": "Soha", "Never": "Soha",
"New agent chat": "Új ügynökcsevegés", "New agent chat": "Új ügynökcsevegés",
"New chat": "Új csevegés", "New chat": "Új csevegés",
"New folder": "Új mappa",
"New folder…": "Új mappa…",
"New scheduled task": "Új ütemezett feladat", "New scheduled task": "Új ütemezett feladat",
"Next run": "Következő futás", "Next run": "Következő futás",
"No archived chats.": "Nincs archivált beszélgetés.", "No archived chats.": "Nincs archivált beszélgetés.",
"No chat yet. Start one with New chat.": "Még nincs beszélgetés. Indítson egyet az Új beszélgetés gombbal.", "No chat yet. Start one with New chat.": "Még nincs beszélgetés. Indítson egyet az Új beszélgetés gombbal.",
"No day ticked: every day.": "Ha egy nap sincs bejelölve: minden nap.", "No day ticked: every day.": "Ha egy nap sincs bejelölve: minden nap.",
"No files written in this chat yet.": "Ebben a csevegésben még nem íródott fájl.", "No files written in this chat yet.": "Ebben a csevegésben még nem íródott fájl.",
"No folder": "Nincs mappa",
"No folder yet: add one under Settings, Project folders.": "Még nincs mappa: adjon hozzá egyet a Beállítások, Projektmappák alatt.", "No folder yet: add one under Settings, Project folders.": "Még nincs mappa: adjon hozzá egyet a Beállítások, Projektmappák alatt.",
"No folder yet: the agent can open nothing. Add the folder of a project.": "Még nincs mappa: az ügynök semmit nem nyithat meg. Adja hozzá egy projekt mappáját.", "No folder yet: the agent can open nothing. Add the folder of a project.": "Még nincs mappa: az ügynök semmit nem nyithat meg. Adja hozzá egy projekt mappáját.",
"No model is available to this account.": "Ennek a fióknak nem érhető el modell.", "No model is available to this account.": "Ennek a fióknak nem érhető el modell.",
@@ -1900,6 +1955,8 @@ const LEMBAS_I18N = {
"Pause": "Szüneteltetés", "Pause": "Szüneteltetés",
"Pause %(title)s": "%(title)s szüneteltetése", "Pause %(title)s": "%(title)s szüneteltetése",
"Paused": "Szüneteltetve", "Paused": "Szüneteltetve",
"Pin chat": "Beszélgetés kitűzése",
"Pinned chats": "Kitűzött beszélgetések",
"Plan": "Csomag", "Plan": "Csomag",
"Plan — changes nothing": "Plan — semmit nem változtat", "Plan — changes nothing": "Plan — semmit nem változtat",
"Preview": "Előnézet", "Preview": "Előnézet",
@@ -1918,6 +1975,7 @@ const LEMBAS_I18N = {
"Remove %(dir)s": "%(dir)s eltávolítása", "Remove %(dir)s": "%(dir)s eltávolítása",
"Rename": "Átnevezés", "Rename": "Átnevezés",
"Rename chat": "Csevegés átnevezése", "Rename chat": "Csevegés átnevezése",
"Rename folder": "Mappa átnevezése",
"Rename…": "Átnevezés…", "Rename…": "Átnevezés…",
"Restore": "Visszaállítás", "Restore": "Visszaállítás",
"Restore chat": "Csevegés visszaállítása", "Restore chat": "Csevegés visszaállítása",
@@ -2040,6 +2098,7 @@ const LEMBAS_I18N = {
"Try again": "Újrapróbálás", "Try again": "Újrapróbálás",
"Type a command or a chat's title": "Írjon be egy parancsot vagy egy csevegés címét", "Type a command or a chat's title": "Írjon be egy parancsot vagy egy csevegés címét",
"Type a folder…": "Mappa megadása…", "Type a folder…": "Mappa megadása…",
"Unpin chat": "Kitűzés megszüntetése",
"Up to %(n)s at once": "Legfeljebb %(n)s egyszerre", "Up to %(n)s at once": "Legfeljebb %(n)s egyszerre",
"Wait until the files are sent.": "Várjon, amíg a fájlok elküldődnek.", "Wait until the files are sent.": "Várjon, amíg a fájlok elküldődnek.",
"Waiting for a free model": "Szabad modellre vár", "Waiting for a free model": "Szabad modellre vár",
@@ -2109,6 +2168,7 @@ const LEMBAS_I18N = {
"waiting for a slot": "szabad helyre vár", "waiting for a slot": "szabad helyre vár",
"window unknown": "az ablak ismeretlen", "window unknown": "az ablak ismeretlen",
"working": "dolgozik", "working": "dolgozik",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "A(z) „%(name)s” és a benne lévő mappák törlődnek. A beszélgetéseik megmaradnak, vissza a listába.",
"“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "„%(title)s” törlődik a szerverről, az üzeneteivel és fájljaival együtt. Ez nem vonható vissza.", "“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "„%(title)s” törlődik a szerverről, az üzeneteivel és fájljaival együtt. Ez nem vonható vissza.",
"“%(title)s” stops, and its history goes. The chats it wrote stay.": "„%(title)s” leáll, és az előzményei törlődnek. Az általa írt beszélgetések megmaradnak." "“%(title)s” stops, and its history goes. The chats it wrote stay.": "„%(title)s” leáll, és az előzményei törlődnek. Az általa írt beszélgetések megmaradnak."
}, },
@@ -2203,10 +2263,12 @@ const LEMBAS_I18N = {
"Copy": "Copia", "Copy": "Copia",
"Copy the last command and its output": "Copia l'ultimo comando e il suo output", "Copy the last command and its output": "Copia l'ultimo comando e il suo output",
"Counted by the model at the last reply; the categories are estimated.": "Contato dal modello all’ultima risposta; le categorie sono stime.", "Counted by the model at the last reply; the categories are estimated.": "Contato dal modello all’ultima risposta; le categorie sono stime.",
"Create": "Crea",
"Cut short here; the whole of it is in the web interface.": "Troncato qui; il resto è nell'interfaccia web.", "Cut short here; the whole of it is in the web interface.": "Troncato qui; il resto è nell'interfaccia web.",
"Days": "Giorni", "Days": "Giorni",
"Delete": "Elimina", "Delete": "Elimina",
"Delete chat": "Elimina chat", "Delete chat": "Elimina chat",
"Delete folder": "Elimina cartella",
"Delete this chat?": "Eliminare questa chat?", "Delete this chat?": "Eliminare questa chat?",
"Delete this scheduled task?": "Eliminare questa attività pianificata?", "Delete this scheduled task?": "Eliminare questa attività pianificata?",
"Deny": "Nega", "Deny": "Nega",
@@ -2235,6 +2297,7 @@ const LEMBAS_I18N = {
"Findings": "Risultati", "Findings": "Risultati",
"Finished %(n)s": "Terminate: %(n)s", "Finished %(n)s": "Terminate: %(n)s",
"Folder": "Cartella", "Folder": "Cartella",
"Folder name": "Nome della cartella",
"Folder on %(device)s": "Cartella su %(device)s", "Folder on %(device)s": "Cartella su %(device)s",
"Free space": "Spazio libero", "Free space": "Spazio libero",
"Hello": "Ciao", "Hello": "Ciao",
@@ -2276,15 +2339,19 @@ const LEMBAS_I18N = {
"Models": "Modelli", "Models": "Modelli",
"Models for scheduled tasks": "Modelli per le attività pianificate", "Models for scheduled tasks": "Modelli per le attività pianificate",
"More": "Altro", "More": "Altro",
"Move to folder…": "Sposta in una cartella…",
"Never": "Mai", "Never": "Mai",
"New agent chat": "Nuova chat con agente", "New agent chat": "Nuova chat con agente",
"New chat": "Nuova chat", "New chat": "Nuova chat",
"New folder": "Nuova cartella",
"New folder…": "Nuova cartella…",
"New scheduled task": "Nuova attività pianificata", "New scheduled task": "Nuova attività pianificata",
"Next run": "Prossima esecuzione", "Next run": "Prossima esecuzione",
"No archived chats.": "Nessuna chat archiviata.", "No archived chats.": "Nessuna chat archiviata.",
"No chat yet. Start one with New chat.": "Ancora nessuna chat. Iniziane una con Nuova chat.", "No chat yet. Start one with New chat.": "Ancora nessuna chat. Iniziane una con Nuova chat.",
"No day ticked: every day.": "Nessun giorno spuntato: ogni giorno.", "No day ticked: every day.": "Nessun giorno spuntato: ogni giorno.",
"No files written in this chat yet.": "In questa chat non è ancora stato scritto alcun file.", "No files written in this chat yet.": "In questa chat non è ancora stato scritto alcun file.",
"No folder": "Nessuna cartella",
"No folder yet: add one under Settings, Project folders.": "Nessuna cartella ancora: ne aggiunga una in Impostazioni, Cartelle di progetto.", "No folder yet: add one under Settings, Project folders.": "Nessuna cartella ancora: ne aggiunga una in Impostazioni, Cartelle di progetto.",
"No folder yet: the agent can open nothing. Add the folder of a project.": "Ancora nessuna cartella: l'agente non può aprire nulla. Aggiungi la cartella di un progetto.", "No folder yet: the agent can open nothing. Add the folder of a project.": "Ancora nessuna cartella: l'agente non può aprire nulla. Aggiungi la cartella di un progetto.",
"No model is available to this account.": "Nessun modello è disponibile per questo account.", "No model is available to this account.": "Nessun modello è disponibile per questo account.",
@@ -2320,6 +2387,8 @@ const LEMBAS_I18N = {
"Pause": "Metti in pausa", "Pause": "Metti in pausa",
"Pause %(title)s": "Metti in pausa %(title)s", "Pause %(title)s": "Metti in pausa %(title)s",
"Paused": "In pausa", "Paused": "In pausa",
"Pin chat": "Fissa la chat",
"Pinned chats": "Chat fissate",
"Plan": "Piano", "Plan": "Piano",
"Plan — changes nothing": "Plan — non cambia nulla", "Plan — changes nothing": "Plan — non cambia nulla",
"Preview": "Anteprima", "Preview": "Anteprima",
@@ -2338,6 +2407,7 @@ const LEMBAS_I18N = {
"Remove %(dir)s": "Rimuovi %(dir)s", "Remove %(dir)s": "Rimuovi %(dir)s",
"Rename": "Rinomina", "Rename": "Rinomina",
"Rename chat": "Rinomina chat", "Rename chat": "Rinomina chat",
"Rename folder": "Rinomina cartella",
"Rename…": "Rinomina…", "Rename…": "Rinomina…",
"Restore": "Ripristina", "Restore": "Ripristina",
"Restore chat": "Ripristina chat", "Restore chat": "Ripristina chat",
@@ -2460,6 +2530,7 @@ const LEMBAS_I18N = {
"Try again": "Riprova", "Try again": "Riprova",
"Type a command or a chat's title": "Digiti un comando o il titolo di una chat", "Type a command or a chat's title": "Digiti un comando o il titolo di una chat",
"Type a folder…": "Digita una cartella…", "Type a folder…": "Digita una cartella…",
"Unpin chat": "Togli la chat dalle fissate",
"Up to %(n)s at once": "Fino a %(n)s alla volta", "Up to %(n)s at once": "Fino a %(n)s alla volta",
"Wait until the files are sent.": "Attenda che i file siano inviati.", "Wait until the files are sent.": "Attenda che i file siano inviati.",
"Waiting for a free model": "In attesa di un modello libero", "Waiting for a free model": "In attesa di un modello libero",
@@ -2529,6 +2600,7 @@ const LEMBAS_I18N = {
"waiting for a slot": "in attesa di un posto", "waiting for a slot": "in attesa di un posto",
"window unknown": "finestra sconosciuta", "window unknown": "finestra sconosciuta",
"working": "al lavoro", "working": "al lavoro",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "«%(name)s» e le cartelle al suo interno vengono eliminate. Le loro chat restano, di nuovo nell’elenco.",
"“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "«%(title)s» viene eliminata dal server, con i suoi messaggi e file. Non si può annullare.", "“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "«%(title)s» viene eliminata dal server, con i suoi messaggi e file. Non si può annullare.",
"“%(title)s” stops, and its history goes. The chats it wrote stay.": "«%(title)s» si ferma e la sua cronologia viene eliminata. Le chat che ha scritto restano." "“%(title)s” stops, and its history goes. The chats it wrote stay.": "«%(title)s» si ferma e la sua cronologia viene eliminata. Le chat che ha scritto restano."
}, },
@@ -2623,10 +2695,12 @@ const LEMBAS_I18N = {
"Copy": "Kopiuj", "Copy": "Kopiuj",
"Copy the last command and its output": "Kopiuj ostatnie polecenie i jego wynik", "Copy the last command and its output": "Kopiuj ostatnie polecenie i jego wynik",
"Counted by the model at the last reply; the categories are estimated.": "Policzone przez model przy ostatniej odpowiedzi; kategorie są szacunkowe.", "Counted by the model at the last reply; the categories are estimated.": "Policzone przez model przy ostatniej odpowiedzi; kategorie są szacunkowe.",
"Create": "Utwórz",
"Cut short here; the whole of it is in the web interface.": "Tu skrócone; całość jest w interfejsie WWW.", "Cut short here; the whole of it is in the web interface.": "Tu skrócone; całość jest w interfejsie WWW.",
"Days": "Dni", "Days": "Dni",
"Delete": "Usuń", "Delete": "Usuń",
"Delete chat": "Usuń czat", "Delete chat": "Usuń czat",
"Delete folder": "Usuń folder",
"Delete this chat?": "Usunąć ten czat?", "Delete this chat?": "Usunąć ten czat?",
"Delete this scheduled task?": "Usunąć to zaplanowane zadanie?", "Delete this scheduled task?": "Usunąć to zaplanowane zadanie?",
"Deny": "Odrzuć", "Deny": "Odrzuć",
@@ -2655,6 +2729,7 @@ const LEMBAS_I18N = {
"Findings": "Ustalenia", "Findings": "Ustalenia",
"Finished %(n)s": "Zakończone: %(n)s", "Finished %(n)s": "Zakończone: %(n)s",
"Folder": "Folder", "Folder": "Folder",
"Folder name": "Nazwa folderu",
"Folder on %(device)s": "Folder na %(device)s", "Folder on %(device)s": "Folder na %(device)s",
"Free space": "Wolne miejsce", "Free space": "Wolne miejsce",
"Hello": "Cześć", "Hello": "Cześć",
@@ -2696,15 +2771,19 @@ const LEMBAS_I18N = {
"Models": "Modele", "Models": "Modele",
"Models for scheduled tasks": "Modele dla zaplanowanych zadań", "Models for scheduled tasks": "Modele dla zaplanowanych zadań",
"More": "Więcej", "More": "Więcej",
"Move to folder…": "Przenieś do folderu…",
"Never": "Nigdy", "Never": "Nigdy",
"New agent chat": "Nowy czat z agentem", "New agent chat": "Nowy czat z agentem",
"New chat": "Nowy czat", "New chat": "Nowy czat",
"New folder": "Nowy folder",
"New folder…": "Nowy folder…",
"New scheduled task": "Nowe zaplanowane zadanie", "New scheduled task": "Nowe zaplanowane zadanie",
"Next run": "Następne uruchomienie", "Next run": "Następne uruchomienie",
"No archived chats.": "Brak zarchiwizowanych czatów.", "No archived chats.": "Brak zarchiwizowanych czatów.",
"No chat yet. Start one with New chat.": "Jeszcze nie ma czatu. Zacznij go przyciskiem Nowy czat.", "No chat yet. Start one with New chat.": "Jeszcze nie ma czatu. Zacznij go przyciskiem Nowy czat.",
"No day ticked: every day.": "Żaden dzień niezaznaczony: codziennie.", "No day ticked: every day.": "Żaden dzień niezaznaczony: codziennie.",
"No files written in this chat yet.": "W tym czacie nie zapisano jeszcze żadnego pliku.", "No files written in this chat yet.": "W tym czacie nie zapisano jeszcze żadnego pliku.",
"No folder": "Bez folderu",
"No folder yet: add one under Settings, Project folders.": "Jeszcze nie ma folderu: dodaj go w Ustawieniach, Foldery projektów.", "No folder yet: add one under Settings, Project folders.": "Jeszcze nie ma folderu: dodaj go w Ustawieniach, Foldery projektów.",
"No folder yet: the agent can open nothing. Add the folder of a project.": "Nie ma jeszcze folderu: agent nie może nic otworzyć. Dodaj folder projektu.", "No folder yet: the agent can open nothing. Add the folder of a project.": "Nie ma jeszcze folderu: agent nie może nic otworzyć. Dodaj folder projektu.",
"No model is available to this account.": "Dla tego konta nie jest dostępny żaden model.", "No model is available to this account.": "Dla tego konta nie jest dostępny żaden model.",
@@ -2740,6 +2819,8 @@ const LEMBAS_I18N = {
"Pause": "Wstrzymaj", "Pause": "Wstrzymaj",
"Pause %(title)s": "Wstrzymaj %(title)s", "Pause %(title)s": "Wstrzymaj %(title)s",
"Paused": "Wstrzymany", "Paused": "Wstrzymany",
"Pin chat": "Przypnij czat",
"Pinned chats": "Przypięte czaty",
"Plan": "Plan", "Plan": "Plan",
"Plan — changes nothing": "Plan — niczego nie zmienia", "Plan — changes nothing": "Plan — niczego nie zmienia",
"Preview": "Podgląd", "Preview": "Podgląd",
@@ -2758,6 +2839,7 @@ const LEMBAS_I18N = {
"Remove %(dir)s": "Usuń %(dir)s", "Remove %(dir)s": "Usuń %(dir)s",
"Rename": "Zmień nazwę", "Rename": "Zmień nazwę",
"Rename chat": "Zmień nazwę czatu", "Rename chat": "Zmień nazwę czatu",
"Rename folder": "Zmień nazwę folderu",
"Rename…": "Zmień nazwę…", "Rename…": "Zmień nazwę…",
"Restore": "Przywróć", "Restore": "Przywróć",
"Restore chat": "Przywróć czat", "Restore chat": "Przywróć czat",
@@ -2880,6 +2962,7 @@ const LEMBAS_I18N = {
"Try again": "Spróbuj ponownie", "Try again": "Spróbuj ponownie",
"Type a command or a chat's title": "Wpisz polecenie lub tytuł czatu", "Type a command or a chat's title": "Wpisz polecenie lub tytuł czatu",
"Type a folder…": "Wpisz folder…", "Type a folder…": "Wpisz folder…",
"Unpin chat": "Odepnij czat",
"Up to %(n)s at once": "Do %(n)s naraz", "Up to %(n)s at once": "Do %(n)s naraz",
"Wait until the files are sent.": "Poczekaj, aż pliki zostaną wysłane.", "Wait until the files are sent.": "Poczekaj, aż pliki zostaną wysłane.",
"Waiting for a free model": "Czeka na wolny model", "Waiting for a free model": "Czeka na wolny model",
@@ -2949,6 +3032,7 @@ const LEMBAS_I18N = {
"waiting for a slot": "czeka na wolne miejsce", "waiting for a slot": "czeka na wolne miejsce",
"window unknown": "okno nieznane", "window unknown": "okno nieznane",
"working": "pracuje", "working": "pracuje",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "„%(name)s” i foldery w nim zostaną usunięte. Ich czaty zostaną, z powrotem na liście.",
"“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "„%(title)s” zostanie usunięty z serwera wraz z wiadomościami i plikami. Tego nie można cofnąć.", "“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "„%(title)s” zostanie usunięty z serwera wraz z wiadomościami i plikami. Tego nie można cofnąć.",
"“%(title)s” stops, and its history goes. The chats it wrote stay.": "„%(title)s” zatrzyma się, a jego historia zniknie. Czaty, które napisało, zostaną." "“%(title)s” stops, and its history goes. The chats it wrote stay.": "„%(title)s” zatrzyma się, a jego historia zniknie. Czaty, które napisało, zostaną."
}, },
@@ -3043,10 +3127,12 @@ const LEMBAS_I18N = {
"Copy": "Kopírovať", "Copy": "Kopírovať",
"Copy the last command and its output": "Skopírovať posledný príkaz a jeho výstup", "Copy the last command and its output": "Skopírovať posledný príkaz a jeho výstup",
"Counted by the model at the last reply; the categories are estimated.": "Spočítal model pri poslednej odpovedi; kategórie sú odhadnuté.", "Counted by the model at the last reply; the categories are estimated.": "Spočítal model pri poslednej odpovedi; kategórie sú odhadnuté.",
"Create": "Vytvoriť",
"Cut short here; the whole of it is in the web interface.": "Tu skrátené; celé je to vo webovom rozhraní.", "Cut short here; the whole of it is in the web interface.": "Tu skrátené; celé je to vo webovom rozhraní.",
"Days": "Dni", "Days": "Dni",
"Delete": "Zmazať", "Delete": "Zmazať",
"Delete chat": "Zmazať konverzáciu", "Delete chat": "Zmazať konverzáciu",
"Delete folder": "Zmazať zložku",
"Delete this chat?": "Zmazať túto konverzáciu?", "Delete this chat?": "Zmazať túto konverzáciu?",
"Delete this scheduled task?": "Odstrániť túto naplánovanú úlohu?", "Delete this scheduled task?": "Odstrániť túto naplánovanú úlohu?",
"Deny": "Odmietnuť", "Deny": "Odmietnuť",
@@ -3075,6 +3161,7 @@ const LEMBAS_I18N = {
"Findings": "Zistenia", "Findings": "Zistenia",
"Finished %(n)s": "Dokončené: %(n)s", "Finished %(n)s": "Dokončené: %(n)s",
"Folder": "Priečinok", "Folder": "Priečinok",
"Folder name": "Názov zložky",
"Folder on %(device)s": "Priečinok na zariadení %(device)s", "Folder on %(device)s": "Priečinok na zariadení %(device)s",
"Free space": "Voľné miesto", "Free space": "Voľné miesto",
"Hello": "Dobrý deň", "Hello": "Dobrý deň",
@@ -3116,15 +3203,19 @@ const LEMBAS_I18N = {
"Models": "Modely", "Models": "Modely",
"Models for scheduled tasks": "Modely pre naplánované úlohy", "Models for scheduled tasks": "Modely pre naplánované úlohy",
"More": "Viac", "More": "Viac",
"Move to folder…": "Presunúť do priečinka…",
"Never": "Nikdy", "Never": "Nikdy",
"New agent chat": "Nová agentská konverzácia", "New agent chat": "Nová agentská konverzácia",
"New chat": "Nová konverzácia", "New chat": "Nová konverzácia",
"New folder": "Nová zložka",
"New folder…": "Nový priečinok…",
"New scheduled task": "Nová naplánovaná úloha", "New scheduled task": "Nová naplánovaná úloha",
"Next run": "Ďalšie spustenie", "Next run": "Ďalšie spustenie",
"No archived chats.": "Žiadne archivované konverzácie.", "No archived chats.": "Žiadne archivované konverzácie.",
"No chat yet. Start one with New chat.": "Zatiaľ žiadna konverzácia. Začnite ju tlačidlom Nová konverzácia.", "No chat yet. Start one with New chat.": "Zatiaľ žiadna konverzácia. Začnite ju tlačidlom Nová konverzácia.",
"No day ticked: every day.": "Žiadny deň nezaškrtnutý: každý deň.", "No day ticked: every day.": "Žiadny deň nezaškrtnutý: každý deň.",
"No files written in this chat yet.": "V tomto chate sa zatiaľ nezapísal žiadny súbor.", "No files written in this chat yet.": "V tomto chate sa zatiaľ nezapísal žiadny súbor.",
"No folder": "Bez zložky",
"No folder yet: add one under Settings, Project folders.": "Zatiaľ žiadny priečinok: pridajte ho v Nastaveniach, Priečinky projektov.", "No folder yet: add one under Settings, Project folders.": "Zatiaľ žiadny priečinok: pridajte ho v Nastaveniach, Priečinky projektov.",
"No folder yet: the agent can open nothing. Add the folder of a project.": "Zatiaľ žiadny priečinok: agent nemôže nič otvoriť. Pridajte priečinok projektu.", "No folder yet: the agent can open nothing. Add the folder of a project.": "Zatiaľ žiadny priečinok: agent nemôže nič otvoriť. Pridajte priečinok projektu.",
"No model is available to this account.": "Tomuto účtu nie je dostupný žiadny model.", "No model is available to this account.": "Tomuto účtu nie je dostupný žiadny model.",
@@ -3160,6 +3251,8 @@ const LEMBAS_I18N = {
"Pause": "Pozastaviť", "Pause": "Pozastaviť",
"Pause %(title)s": "Pozastaviť %(title)s", "Pause %(title)s": "Pozastaviť %(title)s",
"Paused": "Pozastavené", "Paused": "Pozastavené",
"Pin chat": "Pripnúť konverzáciu",
"Pinned chats": "Pripnuté konverzácie",
"Plan": "Plán", "Plan": "Plán",
"Plan — changes nothing": "Plan — nič nemení", "Plan — changes nothing": "Plan — nič nemení",
"Preview": "Náhľad", "Preview": "Náhľad",
@@ -3178,6 +3271,7 @@ const LEMBAS_I18N = {
"Remove %(dir)s": "Odstrániť %(dir)s", "Remove %(dir)s": "Odstrániť %(dir)s",
"Rename": "Premenovať", "Rename": "Premenovať",
"Rename chat": "Premenovať konverzáciu", "Rename chat": "Premenovať konverzáciu",
"Rename folder": "Premenovať zložku",
"Rename…": "Premenovať…", "Rename…": "Premenovať…",
"Restore": "Obnoviť", "Restore": "Obnoviť",
"Restore chat": "Obnoviť konverzáciu", "Restore chat": "Obnoviť konverzáciu",
@@ -3300,6 +3394,7 @@ const LEMBAS_I18N = {
"Try again": "Skúsiť znova", "Try again": "Skúsiť znova",
"Type a command or a chat's title": "Napíšte príkaz alebo názov konverzácie", "Type a command or a chat's title": "Napíšte príkaz alebo názov konverzácie",
"Type a folder…": "Zadať priečinok…", "Type a folder…": "Zadať priečinok…",
"Unpin chat": "Odopnúť konverzáciu",
"Up to %(n)s at once": "Najviac %(n)s naraz", "Up to %(n)s at once": "Najviac %(n)s naraz",
"Wait until the files are sent.": "Počkajte, kým sa súbory odošlú.", "Wait until the files are sent.": "Počkajte, kým sa súbory odošlú.",
"Waiting for a free model": "Čaká na voľný model", "Waiting for a free model": "Čaká na voľný model",
@@ -3369,6 +3464,7 @@ const LEMBAS_I18N = {
"waiting for a slot": "čaká na voľný slot", "waiting for a slot": "čaká na voľný slot",
"window unknown": "okno neznáme", "window unknown": "okno neznáme",
"working": "pracuje", "working": "pracuje",
"“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.": "„%(name)s“ a priečinky v ňom sa zmažú. Ich konverzácie zostanú, späť v zozname.",
"“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "„%(title)s“ sa zmaže na serveri aj so svojimi správami a súbormi. Nedá sa to vrátiť.", "“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.": "„%(title)s“ sa zmaže na serveri aj so svojimi správami a súbormi. Nedá sa to vrátiť.",
"“%(title)s” stops, and its history goes. The chats it wrote stay.": "„%(title)s“ sa zastaví a jej história zmizne. Konverzácie, ktoré napísala, zostanú." "“%(title)s” stops, and its history goes. The chats it wrote stay.": "„%(title)s“ sa zastaví a jej história zmizne. Konverzácie, ktoré napísala, zostanú."
} }
+33 -1
View File
@@ -17,7 +17,7 @@ import { avatar, agentsControl, teamPossible, namedOnly, subagentsCap, noteSubag
import { readyIds, sending, sent, discard } from "./attach.js" import { readyIds, sending, sent, discard } from "./attach.js"
import { watchActivity, activityChanged, planList, activityButton, treeChanged } from "./activity.js" import { watchActivity, activityChanged, planList, activityButton, treeChanged } from "./activity.js"
import { agentBlock, agentReady, agentState, onAgentChange } from "./agent.js" import { agentBlock, agentReady, agentState, onAgentChange } from "./agent.js"
import { folderName, listed } from "./list.js" import { folderName, listed, folderTree, newFolder } from "./list.js"
import { unarchive } from "./archived.js" import { unarchive } from "./archived.js"
import { isProgress, progressLine, progressTicks } from "./progress.js" import { isProgress, progressLine, progressTicks } from "./progress.js"
import { aimTerminal, terminalButton, terminalOpen, toggleTerminal } from "./terminal.js" import { aimTerminal, terminalButton, terminalOpen, toggleTerminal } from "./terminal.js"
@@ -1033,6 +1033,10 @@ export function chatMenu(anchor, chat) {
const base = ctx.status()?.server const base = ctx.status()?.server
const mayDelete = ctx.me()?.permissions?.["chat.delete"] !== false const mayDelete = ctx.me()?.permissions?.["chat.delete"] !== false
const items = [{ label: t("Rename…"), run: () => renameChat(chat) }] const items = [{ label: t("Rename…"), run: () => renameChat(chat) }]
if (!chat.archived) {
items.push({ label: chat.pinned ? t("Unpin chat") : t("Pin chat"), run: () => setChat(chat, { pinned: !chat.pinned }) })
items.push({ label: t("Move to folder…"), run: () => moveMenu(anchor, chat) })
}
if (chat.kind === "agent" && chat.device_session_id) items.push({ label: t("Continue in a terminal…"), run: () => continueInTerminal(chat) }) if (chat.kind === "agent" && chat.device_session_id) items.push({ label: t("Continue in a terminal…"), run: () => continueInTerminal(chat) })
if (base) items.push({ label: t("Open in the web interface"), run: () => openLink(`${base}/chat/${encodeURIComponent(chat.id)}`) }) if (base) items.push({ label: t("Open in the web interface"), run: () => openLink(`${base}/chat/${encodeURIComponent(chat.id)}`) })
items.push(null, chat.archived ? { label: t("Restore chat"), run: () => unarchiveChat(chat) } : { label: t("Archive chat"), run: () => archiveChat(chat) }) items.push(null, chat.archived ? { label: t("Restore chat"), run: () => unarchiveChat(chat) } : { label: t("Archive chat"), run: () => archiveChat(chat) })
@@ -1068,6 +1072,34 @@ export async function continueInTerminal(chat) {
}) })
} }
/** Where a chat can go: no folder, any of the account's, or a new one. */
function moveMenu(anchor, chat) {
const here = chat.folder_id || ""
menu(anchor, [
{ label: t("No folder"), checked: !here, run: () => here && setChat(chat, { folder_id: null }) },
...folderTree().map(({ folder, depth }) => ({ label: `${"\u2003".repeat(depth)}${folder.name}`, checked: folder.id === here, run: () => folder.id !== here && setChat(chat, { folder_id: folder.id }) })),
null,
{
label: t("New folder…"),
run: async () => {
const id = await newFolder()
if (id) setChat(chat, { folder_id: id })
},
},
])
}
/** A change to a chat from its menu (pinned, its folder): the list drawn again from the server. */
async function setChat(chat, body) {
try {
const r = await patch(`/chats/${encodeURIComponent(chat.id)}`, body)
if (open?.chat?.id === chat.id && r?.chat) open.chat = r.chat
ctx.changed(r?.chat)
} catch (err) {
alertIn(why(err))
}
}
async function renameChat(chat) { async function renameChat(chat) {
const title = await ask({ title: t("Rename chat"), value: chat.title || "", ok: t("Rename"), cancel: t("Cancel") }) const title = await ask({ title: t("Rename chat"), value: chat.title || "", ok: t("Rename"), cancel: t("Cancel") })
if (!title || title === chat.title) return if (!title || title === chat.title) return
+156 -9
View File
@@ -1,15 +1,23 @@
// The sidebar's chats: agent chats and chats on the server in one list, newest first, under // The sidebar's chats: agent chats and chats on the server in one list, newest first. The
// Today and Earlier. An agent chat carries the agent's mark and its folder's name; one that works // pinned ones first, then the account's chat folders (`GET /folders`, nested, each folding as the
// on another device of the account says so in its title. The search line above narrows the list // server keeps it), then the rest under Today and Earlier. An agent chat carries the agent's mark
// by title (and an agent chat by its folder) as it is typed; Ctrl+K searches everything. // and its project folder's name; one that works on another device of the account says so in its
// title. The search line above narrows the list by title (and an agent chat by its folder) as it
// is typed, flat; Ctrl+K searches everything.
//
// Folders are made, renamed and deleted here (`POST/PATCH/DELETE /folders`); a chat is pinned and
// moved from its own menu (`PATCH /chats/{id}` `pinned`, `folder_id`). Deleting a folder never
// deletes a chat: its chats go back to the list.
import { $, h, clear, append, icon, ICONS } from "./dom.js" import { $, h, clear, append, icon, ICONS } from "./dom.js"
import { get, why } from "./bridge.js" import { get, post, patch, del, why } from "./bridge.js"
import { menu, ask } from "./popup.js"
let ctx = null // { thisDevices(), open(id, kind), current(), menu(anchor, chat) } let ctx = null // { thisDevices(), open(id, kind), current(), menu(anchor, chat), note(text) }
let rows = [] let rows = []
let more = false let more = false
let query = "" let query = ""
let folders = [] // { id, name, parent_id, collapsed, position }
/** Lower case, without diacritics: "Príliš" is found by "prilis". */ /** Lower case, without diacritics: "Príliš" is found by "prilis". */
function fold(text) { function fold(text) {
@@ -22,9 +30,10 @@ function fold(text) {
/** The list again, from the server. */ /** The list again, from the server. */
export async function refreshList() { export async function refreshList() {
try { try {
const r = await get("/chats?limit=50") const [r, f] = await Promise.all([get("/chats?limit=50"), get("/folders").catch(() => ({ folders: [] }))])
rows = r.chats || [] rows = r.chats || []
more = !!r.more more = !!r.more
folders = f.folders || []
render() render()
} catch (err) { } catch (err) {
clear($("chat-list")).append(h("li", { class: "list__note is-error", text: why(err) })) clear($("chat-list")).append(h("li", { class: "list__note is-error", text: why(err) }))
@@ -77,6 +86,108 @@ function row(c) {
return h("li", null, b) return h("li", null, b)
} }
/** A folder's head: it folds and unfolds; its menu renames it, makes one inside, deletes it. */
function folderHead(f, depth, count) {
const open = !f.collapsed
const head = h(
"button",
{
type: "button",
class: "folderrow",
dataset: { folder: f.id },
style: depth ? `--depth: ${depth}` : null,
"aria-expanded": String(open),
title: f.name,
onclick: () => foldFolder(f, !f.collapsed),
},
h("span", { class: "folderrow__chev" }, icon(open ? ICONS.chevronDown : ICONS.chevron)),
h("span", { class: "folderrow__icon" }, icon(ICONS.folder)),
h("span", { class: "folderrow__name", text: f.name }),
h("span", { class: "folderrow__count", text: count ? String(count) : "" }),
)
head.addEventListener("contextmenu", (e) => {
e.preventDefault()
folderMenu(e.clientX || e.clientY ? { x: e.clientX, y: e.clientY } : head, f)
})
const more = h("button", { type: "button", class: "folderrow__more", "aria-label": t("More"), title: t("More"), onclick: (e) => folderMenu(e.currentTarget, f) }, icon(ICONS.more))
return h("li", { class: "list__folder" }, head, more)
}
async function foldFolder(f, collapsed) {
f.collapsed = collapsed
render()
try {
await patch(`/folders/${encodeURIComponent(f.id)}`, { collapsed })
} catch {
// Folding is the sidebar's own business: drawn as asked even where the server did not keep it.
}
}
function folderMenu(anchor, f) {
menu(anchor, [
{ label: t("Rename folder"), run: () => renameFolder(f) },
{ label: t("New folder"), run: () => newFolder(f.id) },
null,
{ label: t("Delete folder"), danger: true, run: () => deleteFolder(f) },
])
}
/** A new folder, at the top level or inside `parent`: its id once made, else "". */
export async function newFolder(parent = "") {
const name = await ask({ title: t("New folder"), text: t("Folder name"), value: "", ok: t("Create"), cancel: t("Cancel") })
if (!name) return ""
try {
const r = await post("/folders", parent ? { name, parent_id: parent } : { name })
await refreshList()
return r.folder?.id || ""
} catch (err) {
ctx.note?.(why(err))
return ""
}
}
async function renameFolder(f) {
const name = await ask({ title: t("Rename folder"), text: t("Folder name"), value: f.name, ok: t("Rename"), cancel: t("Cancel") })
if (!name || name === f.name) return
try {
await patch(`/folders/${encodeURIComponent(f.id)}`, { name })
await refreshList()
} catch (err) {
ctx.note?.(why(err))
}
}
async function deleteFolder(f) {
const ok = await ask({ title: t("Delete folder"), text: t("“%(name)s” and the folders inside it are deleted. Their chats stay, back in the list.", { name: f.name }), ok: t("Delete"), cancel: t("Cancel"), danger: true })
if (!ok) return
try {
await del(`/folders/${encodeURIComponent(f.id)}`)
await refreshList()
} catch (err) {
ctx.note?.(why(err))
}
}
/** The account's chat folders, as the list last read them. */
export function listedFolders() {
return folders
}
/** The folders as a tree, depth first, each with its depth: what a menu of them lists. */
export function folderTree() {
const out = []
const known = new Set(folders.map((f) => f.id))
const walk = (parent, depth) => {
const kids = folders.filter((f) => (f.parent_id && known.has(f.parent_id) ? f.parent_id : null) === parent).sort((a, b) => (a.position ?? 0) - (b.position ?? 0) || a.name.localeCompare(b.name))
for (const f of kids) {
out.push({ folder: f, depth })
walk(f.id, depth + 1)
}
}
walk(null, 0)
return out
}
function isToday(stamp) { function isToday(stamp) {
const d = new Date(stamp) const d = new Date(stamp)
if (Number.isNaN(d.getTime())) return false if (Number.isNaN(d.getTime())) return false
@@ -98,8 +209,44 @@ function render() {
list.append(h("li", { class: "list__note", text: words.length ? t("Nothing matches.") : t("No chat yet. Start one with New chat.") })) list.append(h("li", { class: "list__note", text: words.length ? t("Nothing matches.") : t("No chat yet. Start one with New chat.") }))
return return
} }
const today = visible.filter((r) => isToday(r.updated_at)) // Searching: every match, flat. Otherwise the pinned first, then the folders, then the rest.
const earlier = visible.filter((r) => !isToday(r.updated_at)) let rest = visible
if (!words.length) {
const pinned = visible.filter((r) => r.pinned)
if (pinned.length) append(list, [h("li", { class: "list__head", text: t("Pinned chats") }), pinned.map(row)])
const known = new Set(folders.map((f) => f.id))
const filed = (r) => !r.pinned && r.folder_id && known.has(r.folder_id)
const tree = folderTree()
if (tree.length) {
const inside = (id) => {
// A folder's count: its own chats and those of the folders inside it.
const ids = new Set([id])
for (const { folder } of tree) if (folder.parent_id && ids.has(folder.parent_id)) ids.add(folder.id)
return visible.filter((r) => filed(r) && ids.has(r.folder_id)).length
}
const hidden = new Set() // folders under a folded one
for (const { folder, depth } of tree) {
if (folder.parent_id && hidden.has(folder.parent_id)) {
hidden.add(folder.id)
continue
}
list.append(folderHead(folder, depth, inside(folder.id)))
if (folder.collapsed) {
hidden.add(folder.id)
continue
}
for (const r of visible.filter((x) => filed(x) && x.folder_id === folder.id)) {
const li = row(r)
li.firstChild.style.setProperty("--depth", String(depth + 1))
li.firstChild.classList.add("is-filed")
list.append(li)
}
}
}
rest = visible.filter((r) => !r.pinned && !filed(r))
}
const today = rest.filter((r) => isToday(r.updated_at))
const earlier = rest.filter((r) => !isToday(r.updated_at))
if (today.length) append(list, [h("li", { class: "list__head", text: t("Today") }), today.map(row)]) if (today.length) append(list, [h("li", { class: "list__head", text: t("Today") }), today.map(row)])
if (earlier.length) append(list, [h("li", { class: "list__head", text: t("Earlier") }), earlier.map(row)]) if (earlier.length) append(list, [h("li", { class: "list__head", text: t("Earlier") }), earlier.map(row)])
if (more && !words.length) list.append(h("li", null, h("button", { type: "button", class: "btn btn--sm list__more", text: t("More"), onclick: loadMore }))) if (more && !words.length) list.append(h("li", null, h("button", { type: "button", class: "btn btn--sm list__more", text: t("More"), onclick: loadMore })))
+4
View File
@@ -267,6 +267,10 @@ async function boot() {
showChat(id) showChat(id)
}, },
menu: (anchor, c) => chatMenu(anchor, c), menu: (anchor, c) => chatMenu(anchor, c),
note: (text) => {
$("thread-note").textContent = text
$("thread-note").hidden = !text
},
}) })
initChat({ initChat({
status: () => status, status: () => status,