Archived chats: a page to find them again, Restore chat, delete
ci / ui (push) Waiting to run
ci / check (push) Failing after 3s
ci / start (push) Failing after 3s

Archive was one-way in the app. Archived (sidebar, under Files) reads
GET /api/v2/chats?archived=true, newest first and paged; a row opens the
chat, Restore chat PATCHes archived:false and reads the sidebar again, and
the row's menu deletes. An open archived chat says so in its header, with
Restore chat there and in its menu. The words are the web's own ("Archived",
"Restore chat"). Tests: D2 at 1280 and 390 px.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
HomerandClaude Opus 5.5 committed 2026-11-10 12:19:35 +00:00
1 parent cf13d49ed6
commit 94e903ef70
10 files changed
+323 -3

No files matched your search

+34
View File
@@ -1629,6 +1629,40 @@ details[open] > summary .step__chev .icon { transform: rotate(90deg); }
.findings__item { min-width: 0; overflow-wrap: anywhere; }
.ask__subagent { color: var(--ink); }
/* --- Archived chats: icon · title over its folder and date · Unarchive · more, on known tracks. */
.arch { list-style: none; margin: 0; padding: 0; display: grid; }
.arow {
display: grid;
grid-template-columns: 16px minmax(0, 1fr) auto var(--control-h-sm);
gap: var(--sp-3);
align-items: center;
min-height: var(--control-h);
padding: var(--sp-1) 0;
border-bottom: var(--border-w) solid var(--border);
}
.arow__icon { display: grid; place-items: center; color: var(--ink-faint); }
.arow__icon.is-agent { color: var(--leaf); }
.arow__icon .icon { width: 14px; height: 14px; }
.arow__open {
display: grid;
min-width: 0;
min-height: var(--control-h);
padding: var(--sp-1) 0;
text-align: left;
color: var(--ink);
background: transparent;
border: 0;
cursor: pointer;
}
.arow__open:hover .arow__title { text-decoration: underline; }
.arow__title, .arow__sub { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.arow__title { font: var(--text-sm) / var(--leading-tight) var(--font-body); }
.arow__sub { font: var(--text-xs) var(--font-ui); color: var(--ink-faint); }
.arch__more { margin-top: var(--sp-3); }
.arch__page { display: grid; gap: var(--sp-3); }
.head__unarchive { white-space: nowrap; }
/* --- Narrower windows ---------------------------------------------------------------------- */
/* 64rem (--bp-wide): a panel goes over the chat instead of beside it. */
+24
View File
@@ -55,6 +55,7 @@ const LEMBAS_I18N = {
"Answer": "Odpovědět",
"Approve this code in the page that opened in your browser:": "Potvrďte tento kód na stránce, která se otevřela ve vašem prohlížeči:",
"Archive chat": "Archivovat konverzaci",
"Archived": "Archivované",
"Attach files": "Přikládat soubory",
"Auto — asks nothing": "Auto — na nic se neptá",
"Automatic compaction is off.": "Automatické shrnutí je vypnuté.",
@@ -168,6 +169,7 @@ const LEMBAS_I18N = {
"New chat": "Nová konverzace",
"New scheduled task": "Nová naplánovaná úloha",
"Next run": "Další spuštění",
"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 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.",
@@ -226,6 +228,7 @@ const LEMBAS_I18N = {
"Rename chat": "Přejmenovat konverzaci",
"Rename…": "Přejmenovat…",
"Restore": "Obnovit",
"Restore chat": "Obnovit konverzaci",
"Result": "Výsledek",
"Resume": "Pokračovat",
"Resume %(title)s": "Obnovit %(title)s",
@@ -452,6 +455,7 @@ const LEMBAS_I18N = {
"Answer": "Antworten",
"Approve this code in the page that opened in your browser:": "Bestätigen Sie diesen Code auf der Seite, die sich in Ihrem Browser geöffnet hat:",
"Archive chat": "Chat archivieren",
"Archived": "Archiviert",
"Attach files": "Dateien anhängen",
"Auto — asks nothing": "Auto — fragt nichts",
"Automatic compaction is off.": "Die automatische Zusammenfassung ist aus.",
@@ -565,6 +569,7 @@ const LEMBAS_I18N = {
"New chat": "Neuer Chat",
"New scheduled task": "Neue geplante Aufgabe",
"Next run": "Nächster Lauf",
"No archived chats.": "Keine archivierten Chats.",
"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 files written in this chat yet.": "In diesem Chat wurde noch keine Datei geschrieben.",
@@ -623,6 +628,7 @@ const LEMBAS_I18N = {
"Rename chat": "Chat umbenennen",
"Rename…": "Umbenennen…",
"Restore": "Wiederherstellen",
"Restore chat": "Chat wiederherstellen",
"Result": "Ergebnis",
"Resume": "Fortsetzen",
"Resume %(title)s": "%(title)s fortsetzen",
@@ -849,6 +855,7 @@ const LEMBAS_I18N = {
"Answer": "Responder",
"Approve this code in the page that opened in your browser:": "Apruebe este código en la página que se abrió en su navegador:",
"Archive chat": "Archivar chat",
"Archived": "Archivados",
"Attach files": "Adjuntar archivos",
"Auto — asks nothing": "Auto — no pregunta nada",
"Automatic compaction is off.": "La compactación automática está desactivada.",
@@ -962,6 +969,7 @@ const LEMBAS_I18N = {
"New chat": "Nuevo chat",
"New scheduled task": "Nueva tarea programada",
"Next run": "Próxima ejecución",
"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 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.",
@@ -1020,6 +1028,7 @@ const LEMBAS_I18N = {
"Rename chat": "Renombrar chat",
"Rename…": "Renombrar…",
"Restore": "Restaurar",
"Restore chat": "Restaurar chat",
"Result": "Resultado",
"Resume": "Reanudar",
"Resume %(title)s": "Reanudar %(title)s",
@@ -1246,6 +1255,7 @@ const LEMBAS_I18N = {
"Answer": "Répondre",
"Approve this code in the page that opened in your browser:": "Approuvez ce code sur la page qui s'est ouverte dans votre navigateur :",
"Archive chat": "Archiver la conversation",
"Archived": "Archivées",
"Attach files": "Joindre des fichiers",
"Auto — asks nothing": "Auto — ne demande rien",
"Automatic compaction is off.": "Le compactage automatique est désactivé.",
@@ -1359,6 +1369,7 @@ const LEMBAS_I18N = {
"New chat": "Nouvelle conversation",
"New scheduled task": "Nouvelle tâche planifiée",
"Next run": "Prochaine exécution",
"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 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.",
@@ -1417,6 +1428,7 @@ const LEMBAS_I18N = {
"Rename chat": "Renommer la conversation",
"Rename…": "Renommer…",
"Restore": "Restaurer",
"Restore chat": "Restaurer la conversation",
"Result": "Résultat",
"Resume": "Reprendre",
"Resume %(title)s": "Reprendre %(title)s",
@@ -1643,6 +1655,7 @@ const LEMBAS_I18N = {
"Answer": "Válasz",
"Approve this code in the page that opened in your browser:": "Hagyja jóvá ezt a kódot a böngészőjében megnyílt oldalon:",
"Archive chat": "Csevegés archiválása",
"Archived": "Archivált",
"Attach files": "Fájlok csatolása",
"Auto — asks nothing": "Auto — semmit nem kérdez",
"Automatic compaction is off.": "Az automatikus tömörítés ki van kapcsolva.",
@@ -1756,6 +1769,7 @@ const LEMBAS_I18N = {
"New chat": "Új csevegés",
"New scheduled task": "Új ütemezett feladat",
"Next run": "Következő futá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 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.",
@@ -1814,6 +1828,7 @@ const LEMBAS_I18N = {
"Rename chat": "Csevegés átnevezése",
"Rename…": "Átnevezés…",
"Restore": "Visszaállítás",
"Restore chat": "Csevegés visszaállítása",
"Result": "Eredmény",
"Resume": "Folytatás",
"Resume %(title)s": "%(title)s folytatása",
@@ -2040,6 +2055,7 @@ const LEMBAS_I18N = {
"Answer": "Rispondi",
"Approve this code in the page that opened in your browser:": "Approvi questo codice nella pagina che si è aperta nel suo browser:",
"Archive chat": "Archivia chat",
"Archived": "Archiviate",
"Attach files": "Allegare file",
"Auto — asks nothing": "Auto — non chiede nulla",
"Automatic compaction is off.": "La compattazione automatica è disattivata.",
@@ -2153,6 +2169,7 @@ const LEMBAS_I18N = {
"New chat": "Nuova chat",
"New scheduled task": "Nuova attività pianificata",
"Next run": "Prossima esecuzione",
"No archived chats.": "Nessuna chat archiviata.",
"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 files written in this chat yet.": "In questa chat non è ancora stato scritto alcun file.",
@@ -2211,6 +2228,7 @@ const LEMBAS_I18N = {
"Rename chat": "Rinomina chat",
"Rename…": "Rinomina…",
"Restore": "Ripristina",
"Restore chat": "Ripristina chat",
"Result": "Risultato",
"Resume": "Riprendi",
"Resume %(title)s": "Riprendi %(title)s",
@@ -2437,6 +2455,7 @@ const LEMBAS_I18N = {
"Answer": "Odpowiedź",
"Approve this code in the page that opened in your browser:": "Zatwierdź ten kod na stronie, która otworzyła się w przeglądarce:",
"Archive chat": "Archiwizuj czat",
"Archived": "Zarchiwizowane",
"Attach files": "Załączaj pliki",
"Auto — asks nothing": "Auto — o nic nie pyta",
"Automatic compaction is off.": "Automatyczne streszczanie jest wyłączone.",
@@ -2550,6 +2569,7 @@ const LEMBAS_I18N = {
"New chat": "Nowy czat",
"New scheduled task": "Nowe zaplanowane zadanie",
"Next run": "Następne uruchomienie",
"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 day ticked: every day.": "Żaden dzień niezaznaczony: codziennie.",
"No files written in this chat yet.": "W tym czacie nie zapisano jeszcze żadnego pliku.",
@@ -2608,6 +2628,7 @@ const LEMBAS_I18N = {
"Rename chat": "Zmień nazwę czatu",
"Rename…": "Zmień nazwę…",
"Restore": "Przywróć",
"Restore chat": "Przywróć czat",
"Result": "Wynik",
"Resume": "Wznów",
"Resume %(title)s": "Wznów %(title)s",
@@ -2834,6 +2855,7 @@ const LEMBAS_I18N = {
"Answer": "Odpovedať",
"Approve this code in the page that opened in your browser:": "Potvrďte tento kód na stránke, ktorá sa otvorila vo vašom prehliadači:",
"Archive chat": "Archivovať konverzáciu",
"Archived": "Archivované",
"Attach files": "Prikladať súbory",
"Auto — asks nothing": "Auto — na nič sa nepýta",
"Automatic compaction is off.": "Automatické zhrnutie je vypnuté.",
@@ -2947,6 +2969,7 @@ const LEMBAS_I18N = {
"New chat": "Nová konverzácia",
"New scheduled task": "Nová naplánovaná úloha",
"Next run": "Ďalšie spustenie",
"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 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.",
@@ -3005,6 +3028,7 @@ const LEMBAS_I18N = {
"Rename chat": "Premenovať konverzáciu",
"Rename…": "Premenovať…",
"Restore": "Obnoviť",
"Restore chat": "Obnoviť konverzáciu",
"Result": "Výsledok",
"Resume": "Pokračovať",
"Resume %(title)s": "Obnoviť %(title)s",
+10
View File
@@ -53,6 +53,7 @@
<div class="side__nav">
<button type="button" class="navrow" id="nav-scheduled" data-view="scheduled"><span class="navrow__icon"></span><span data-i18n>Scheduled</span></button>
<button type="button" class="navrow" id="nav-files" data-view="files"><span class="navrow__icon"></span><span data-i18n>Files</span></button>
<button type="button" class="navrow" id="nav-archived" data-view="archived"><span class="navrow__icon"></span><span data-i18n>Archived</span></button>
</div>
<ul class="list" id="chat-list" aria-label="Chats" data-i18n-aria-label></ul>
<div class="side__foot">
@@ -123,6 +124,15 @@
<div class="page__body" id="scheduled-body"></div>
</section>
<section class="page" id="page-archived" hidden aria-labelledby="archived-title">
<header class="head">
<h1 class="head__title" id="archived-title" data-i18n>Archived</h1>
<div class="head__place"></div>
<div class="head__tools"><button type="button" class="tool" id="archived-refresh" aria-label="Read again" title="Read again" data-i18n-aria-label data-i18n-title></button></div>
</header>
<div class="page__body" id="archived-body"></div>
</section>
<section class="page settings" id="settings" hidden aria-labelledby="settings-title">
<header class="head">
<h1 class="head__title" id="settings-title" data-i18n>Settings</h1>
+135
View File
@@ -0,0 +1,135 @@
// Archived chats: the ones put away from the sidebar with Archive chat, newest first. Each can be
// opened (read, and written to, as any chat), taken back into the sidebar (Restore chat), or deleted.
//
// GET /chats?archived=true&limit=&before= { chats: [chat], more }
// PATCH /chats/{id} { archived: false } { chat }
// DELETE /chats/{id} 204
//
// A chat's title is the person's or a model's words, set as text.
import { $, h, clear, icon, ICONS, when } from "./dom.js"
import { get, patch, del, why } from "./bridge.js"
import { ask, menu } from "./popup.js"
import { folderName } from "./list.js"
let ctx = null // { open(id), changed(), me() }
let rows = []
let more = false
let error = ""
let loading = false
/** The page, read again from the server. */
export async function showArchived() {
loading = true
error = ""
render()
try {
const r = await get("/chats?archived=true&limit=50")
rows = r.chats || []
more = !!r.more
} catch (err) {
rows = []
more = false
error = why(err)
}
loading = false
render()
}
async function loadMore(button) {
const last = rows[rows.length - 1]
if (!last) return
button.disabled = true
try {
const r = await get(`/chats?archived=true&limit=50&before=${encodeURIComponent(last.id)}`)
rows = rows.concat(r.chats || [])
more = !!r.more
} catch (err) {
error = why(err)
}
render()
}
/** Back into the sidebar. */
export async function unarchive(chat) {
try {
const r = await patch(`/chats/${encodeURIComponent(chat.id)}`, { archived: false })
rows = rows.filter((x) => x.id !== chat.id)
error = ""
render()
ctx?.changed(r?.chat || chat)
return true
} catch (err) {
error = why(err)
render()
return false
}
}
async function remove(chat) {
const yes = await ask({
title: t("Delete this chat?"),
text: t("“%(title)s” is deleted on the server, with its messages and files. This cannot be undone.", { title: chat.title || t("New chat") }),
ok: t("Delete"),
cancel: t("Cancel"),
danger: true,
})
if (!yes) return
try {
await del(`/chats/${encodeURIComponent(chat.id)}`)
rows = rows.filter((x) => x.id !== chat.id)
error = ""
} catch (err) {
error = why(err)
}
render()
}
function row(c) {
const agent = c.kind === "agent"
const title = c.title || t("New chat")
const mayDelete = ctx.me()?.permissions?.["chat.delete"] !== false
const sub = [agent && c.device?.directory ? folderName(c.device.directory) : "", when(c.updated_at)].filter(Boolean).join(" · ")
return h(
"li",
{ class: "arow", dataset: { id: c.id } },
h("span", { class: `arow__icon${agent ? " is-agent" : ""}` }, icon(agent ? ICONS.terminal : ICONS.chat)),
h(
"button",
{ type: "button", class: "arow__open", title, onclick: () => ctx.open(c.id) },
h("span", { class: "arow__title" }, h("bdi", { text: title })),
h("span", { class: "arow__sub", text: sub }),
),
h("button", { type: "button", class: "btn btn--sm arow__unarchive", text: t("Restore chat"), onclick: () => unarchive(c) }),
mayDelete
? h(
"button",
{
type: "button",
class: "tool arow__more",
"aria-label": t("More"),
title: t("More"),
onclick: (e) => menu(e.currentTarget, [{ label: t("Delete chat"), danger: true, run: () => remove(c) }]),
},
icon(ICONS.more),
)
: h("span", { class: "arow__more" }),
)
}
function render() {
const box = clear($("archived-body"))
const parts = []
if (error) parts.push(h("p", { class: "status is-error", text: error }))
if (loading && !rows.length) parts.push(h("p", { class: "muted page__loading", text: t("Loading…") }))
else if (!rows.length && !error) parts.push(h("p", { class: "muted arch__empty", text: t("No archived chats.") }))
if (rows.length) {
parts.push(h("ul", { class: "arch", "aria-label": t("Archived") }, rows.map(row)))
if (more) parts.push(h("button", { type: "button", class: "btn btn--sm arch__more", text: t("More"), onclick: (e) => loadMore(e.currentTarget) }))
}
box.append(h("div", { class: "arch__page" }, parts))
}
export function initArchived(context) {
ctx = context
}
+13 -1
View File
@@ -18,6 +18,7 @@ import { readyIds, sending, sent, discard } from "./attach.js"
import { watchActivity, activityChanged, planList, activityButton, treeChanged } from "./activity.js"
import { agentBlock, agentReady, agentState, onAgentChange } from "./agent.js"
import { folderName } from "./list.js"
import { unarchive } from "./archived.js"
import { isProgress, progressLine, progressTicks } from "./progress.js"
import { aimTerminal, terminalButton, terminalOpen, toggleTerminal } from "./terminal.js"
@@ -691,6 +692,8 @@ function renderHead(chat) {
// "Continue in a terminal" stays in the chat's menu.
if (deviceOf(chat.device.token_id)?.terminal) tools.append(terminalButton())
}
// An archived chat says so where it is read, with the way back into the sidebar.
if (chat.archived) tools.append(h("button", { type: "button", class: "btn btn--sm head__unarchive", text: t("Restore chat"), title: t("Archived"), onclick: () => unarchiveChat(open?.chat || chat) }))
tools.append(activityButton())
tools.append(h("button", { type: "button", class: "tool", "aria-label": t("More"), title: t("More"), onclick: (e) => chatMenu(e.currentTarget, open?.chat || chat) }, icon(ICONS.more)))
}
@@ -947,7 +950,7 @@ export function chatMenu(anchor, chat) {
const items = [{ label: t("Rename…"), run: () => renameChat(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)}`) })
items.push(null, { 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) })
if (mayDelete) items.push({ label: t("Delete chat"), danger: true, run: () => deleteChat(chat) })
menu(anchor, items)
}
@@ -1004,6 +1007,15 @@ async function archiveChat(chat) {
}
}
/** An archived chat, open or in its page's menu, back into the sidebar. */
async function unarchiveChat(chat) {
if (!(await unarchive(chat))) return
if (open?.chat?.id === chat.id) {
open.chat = { ...open.chat, archived: false }
renderHead(open.chat)
}
}
async function deleteChat(chat) {
const yes = await ask({
title: t("Delete this chat?"),
+1
View File
@@ -99,6 +99,7 @@ export const ICONS = {
user: ["M8 2a3 3 0 110 6 3 3 0 010-6zm0 1.5a1.5 1.5 0 100 3 1.5 1.5 0 000-3z", "M2.5 14c0-2.9 2.4-4.75 5.5-4.75S13.5 11.1 13.5 14H12c0-2-1.65-3.25-4-3.25S4 12 4 14z"],
check: "M6.5 10.4l6-6 1.06 1.06L6.5 12.53 2.94 8.97 4 7.9z",
bell: ["M8 1.5a4.5 4.5 0 014.5 4.5v3l1.5 2.5H2L3.5 9V6A4.5 4.5 0 018 1.5zM8 3a3 3 0 00-3 3v3.42l-.35.58h6.7L11 9.42V6a3 3 0 00-3-3z", "M6.25 12.5h3.5a1.75 1.75 0 01-3.5 0z"],
archive: ["M1.5 2.5h13v3.5h-13zM3 4v.5h10V4z", "M2.5 6.5H4V12h8V6.5h1.5v7h-11z", "M6 7.5h4V9H6z"],
info: ["M8 1.5a6.5 6.5 0 110 13 6.5 6.5 0 010-13zM8 3a5 5 0 100 10A5 5 0 008 3z", "M7.25 7h1.5v4.5h-1.5zM7.25 4.5h1.5V6h-1.5z"],
}
+20 -2
View File
@@ -19,12 +19,13 @@ import { initPalette, openPalette } from "./palette.js"
import { initActivity, showPanel, togglePanel, panelOpen } from "./activity.js"
import { initAgent, link } from "./agent.js"
import { initScheduled, showScheduled, scheduledCommands } from "./scheduled.js"
import { initArchived, showArchived } from "./archived.js"
import { closePopover } from "./popup.js"
import { noteSubagentsCap } from "./models.js"
let status = null
let view = "" // "setup" | "app"
let page = "chat" // "chat" | "files" | "scheduled" | "settings"
let page = "chat" // "chat" | "files" | "scheduled" | "archived" | "settings"
let me = null
let models = []
let devices = [] // this account's linked devices
@@ -154,7 +155,7 @@ function accountButton() {
// --- The pages ----------------------------------------------------------------------------------
/** Show one page in the main area: the chat, the files, the scheduled tasks, or the settings. */
/** Show one page in the main area: the chat, the files, the scheduled tasks, the archived chats, or the settings. */
function showPage(name) {
page = name
closePopover()
@@ -162,6 +163,7 @@ function showPage(name) {
$("main").hidden = name !== "chat"
$("page-files").hidden = name !== "files"
$("page-scheduled").hidden = name !== "scheduled"
$("page-archived").hidden = name !== "archived"
$("settings").hidden = name !== "settings"
for (const b of document.querySelectorAll(".navrow[data-view]")) b.setAttribute("aria-current", String(b.dataset.view === name))
if (name !== "chat") {
@@ -209,6 +211,11 @@ function showSettings(on, section) {
if (section) scrollToSection(section)
}
function showArchivedPage() {
showPage("archived")
showArchived()
}
function showFiles(which) {
showPage("files")
if (which) showFilesTab(which)
@@ -223,6 +230,7 @@ function commands() {
{ label: t("Scheduled"), run: () => (showPage("scheduled"), showScheduled()) },
...scheduledCommands(),
{ label: t("Files"), run: () => showFiles() },
{ label: t("Archived"), run: showArchivedPage },
{ label: t("Settings"), run: () => showSettings(true) },
]
if (openChatId()) out.push({ label: panelOpen() ? t("Close the activity panel") : t("Open the activity panel"), run: togglePanel })
@@ -291,6 +299,12 @@ async function boot() {
},
})
initAttach({ chat: () => openChatId() || "", allowed: () => me?.permissions?.["files.upload"] !== false })
initArchived({
me: () => me,
open: (id) => showChat(id),
// Back in the sidebar: the list again.
changed: () => refreshList(),
})
initPalette({ commands, open: (c) => showChat(c.id) })
initScheduled({ status: () => status, models: () => models, me: () => me, openChat: (id) => showChat(id), show: () => showPage("scheduled") })
onViewer((on) => {
@@ -326,6 +340,10 @@ async function boot() {
})
$("nav-files").querySelector(".navrow__icon").replaceChildren(icon(ICONS.folder))
$("nav-files").addEventListener("click", () => showFiles())
$("nav-archived").querySelector(".navrow__icon").replaceChildren(icon(ICONS.archive))
$("nav-archived").addEventListener("click", showArchivedPage)
$("archived-refresh").replaceChildren(icon(ICONS.refresh))
$("archived-refresh").addEventListener("click", () => showArchived())
accountButton()
$("settings-btn").addEventListener("click", () => showSettings(page !== "settings"))
$("settings-close").replaceChildren(icon(ICONS.close))