diff --git a/packages/app/src/components/settings-v2/general.tsx b/packages/app/src/components/settings-v2/general.tsx index b41da107ed6e..002279b61de9 100644 --- a/packages/app/src/components/settings-v2/general.tsx +++ b/packages/app/src/components/settings-v2/general.tsx @@ -8,7 +8,7 @@ import { useDialog } from "@opencode-ai/ui/context/dialog" import { useLanguage } from "@/context/language" import { usePlatform } from "@/context/platform" import { useUpdaterAction } from "../updater-action" -import { useSettings } from "@/context/settings" +import { useSettings, type NavigationMode } from "@/context/settings" import { ExternalLink } from "../external-link" import { SettingsListV2 } from "./parts/list" import { SettingsRowV2 } from "./parts/row" @@ -119,6 +119,59 @@ const ShellSetting: Component<{ controller: ShellSettingsController }> = (props) ) } +const navigationModeOptions: NavigationMode[] = ["tabs", "sidebar"] +const sidebarSessionDayOptions = [0, 1, 3, 7, 30] + +const NavigationModeSetting: Component = () => { + const language = useLanguage() + const settings = useSettings() + return ( + + option === settings.general.navigationMode())} + placement="bottom-end" + gutter={6} + label={(option) => + option === "tabs" + ? language.t("settings.general.row.navigation.tabs") + : language.t("settings.general.row.navigation.sidebar") + } + onSelect={(option) => option && settings.general.setNavigationMode(option)} + /> + + ) +} + +const SidebarSessionDaysSetting: Component = () => { + const language = useLanguage() + const settings = useSettings() + return ( + + option === settings.general.sidebarSessionDays())} + placement="bottom-end" + gutter={6} + label={(option) => + option ? String(option) : language.t("settings.general.row.sidebarSessions.always") + } + onSelect={(option) => option !== null && settings.general.setSidebarSessionDays(option)} + /> + + ) +} + const AppearanceSection: Component<{ controller: AppearanceSettingsController }> = (props) => { const language = useLanguage() return ( @@ -333,6 +386,13 @@ export const SettingsGeneralV2: Component<{ + + + + + + + settings.general.newLayoutDesigns()) const mobile = createMediaQuery("(max-width: 767px)") + // Sidebar navigation mode replaces the tab strip on desktop widths; mobile keeps tabs. + const sidebarNavigation = createMemo( + () => useV2Titlebar() && !mobile() && settings.general.navigationMode() === "sidebar", + ) const bottom = createMemo(() => useV2Titlebar() && mobile() && settings.general.mobileTitlebarPosition() === "bottom") const mac = createMemo(() => platform.platform === "desktop" && platform.os === "macos") @@ -395,40 +399,42 @@ export function Titlebar(props: { update?: TitlebarUpdate; debugTools?: { visibl /> - { - tabs.select(tab) - el?.scrollIntoView({ behavior: "instant" }) - }} - onClose={(tab) => { - const index = tabsStore.findIndex((item) => tabKey(item) === tabKey(tab)) - if (index !== -1) tabsStoreActions.closeTab(index) - }} - onReorder={(keys) => tabsStoreActions.reorder(keys)} - /> - - {language.t("command.session.new")} - - - } - > - } - onClick={openNewTab} - aria-label={language.t("command.session.new")} + + { + tabs.select(tab) + el?.scrollIntoView({ behavior: "instant" }) + }} + onClose={(tab) => { + const index = tabsStore.findIndex((item) => tabKey(item) === tabKey(tab)) + if (index !== -1) tabsStoreActions.closeTab(index) + }} + onReorder={(keys) => tabsStoreActions.reorder(keys)} /> - + + {language.t("command.session.new")} + + + } + > + } + onClick={openNewTab} + aria-label={language.t("command.session.new")} + /> + +
diff --git a/packages/app/src/context/settings.tsx b/packages/app/src/context/settings.tsx index 1a118b654479..ccf6423579b8 100644 --- a/packages/app/src/context/settings.tsx +++ b/packages/app/src/context/settings.tsx @@ -19,6 +19,8 @@ export interface SoundSettings { errors: string } +export type NavigationMode = "tabs" | "sidebar" + export interface Settings { general: { autoSave: boolean @@ -34,6 +36,8 @@ export interface Settings { editToolPartsExpanded: boolean showCustomAgents: boolean mobileTitlebarPosition: "top" | "bottom" + navigationMode?: NavigationMode + sidebarSessionDays?: number newLayoutDesigns?: boolean layoutTransitionEligible?: boolean agentVisibilityInitialized?: boolean @@ -195,6 +199,8 @@ const defaultSettings: Settings = { editToolPartsExpanded: false, showCustomAgents: false, mobileTitlebarPosition: "top", + navigationMode: "tabs", + sidebarSessionDays: 3, }, appearance: { fontSize: 14, @@ -428,6 +434,17 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont setMobileTitlebarPosition(value: "top" | "bottom") { setStore("general", "mobileTitlebarPosition", value) }, + navigationMode: withFallback(() => store.general?.navigationMode, defaultSettings.general.navigationMode), + setNavigationMode(value: NavigationMode) { + setStore("general", "navigationMode", value) + }, + sidebarSessionDays: withFallback( + () => store.general?.sidebarSessionDays, + defaultSettings.general.sidebarSessionDays, + ), + setSidebarSessionDays(value: number) { + setStore("general", "sidebarSessionDays", value) + }, newLayoutDesigns, setNewLayoutDesigns(value: boolean) { const next = oldInterfaceRetired() ? true : value diff --git a/packages/app/src/context/tabs.tsx b/packages/app/src/context/tabs.tsx index b6608e868112..10e0b97921df 100644 --- a/packages/app/src/context/tabs.tsx +++ b/packages/app/src/context/tabs.tsx @@ -3,6 +3,8 @@ import { createSimpleContext } from "@opencode-ai/ui/context" import { createStore, produce } from "solid-js/store" import { Persist, persisted, removePersisted, draftPersistedKeys } from "@/utils/persist" import { ServerConnection, useServer } from "./server" +import { useSettings } from "./settings" +import { createMediaQuery } from "@solid-primitives/media" import { createEffect, getOwner, onCleanup, startTransition } from "solid-js" import { useLocation, useNavigate, useParams } from "@solidjs/router" import { usePlatform } from "./platform" @@ -73,6 +75,26 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({ const location = useLocation() const memory = createTabMemory(getOwner()) + const settings = useSettings() + const mobile = createMediaQuery("(max-width: 767px)") + let pruned = false + createEffect(() => { + if (pruned || !ready()) return + pruned = true + // The tab-strip paradigm reopens and prefetches every persisted tab at startup; sidebar + // navigation only needs the tab you were actually on, so drop the rest once on launch. + if (settings.general.navigationMode() !== "sidebar" || mobile()) return + const sessionID = location.pathname.match(/\/session\/([^/]+)$/)?.[1] + const draftID = new URLSearchParams(location.search).get("draftId") + setStore((tabs) => + tabs.filter( + (tab) => + (tab.type === "session" && tab.sessionId === sessionID) || + (tab.type === "draft" && tab.draftID === draftID), + ), + ) + }) + const closing = new Set() let recentWrite = 0 let recentValue: string | undefined diff --git a/packages/app/src/i18n/am.ts b/packages/app/src/i18n/am.ts index bda48350e532..f4dfb541f9dc 100644 --- a/packages/app/src/i18n/am.ts +++ b/packages/app/src/i18n/am.ts @@ -860,6 +860,15 @@ export const dict = { "sidebar.project.clearNotifications": "ማሳወቂያዎችን አጽዳ", "sidebar.empty.title": "ምንም ክፍት ፕሮጀክቶች የሉም", "sidebar.empty.description": "ለመጀመር ፕሮጀክት ይክፈቱ", + "sidebar.settled": "የተረጉ", + "sidebar.settle": "ርን አጋ", + "sidebar.unsettle": "ርን መልስ", + "sidebar.thread.new": "አዲስ ክር", + "sidebar.thread.pin": "ክርን ሰካ", + "sidebar.thread.unpin": "ኪውን አውልቅ", + "sidebar.status.working": "በስራ ላይ", + "sidebar.status.done": "ተጠናቀቀ", + "sidebar.status.attention": "ግቤት ያስልጋል", "debugBar.ariaLabel": "የልማት አፈጻጸም ምርመራዎች", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -906,6 +915,12 @@ export const dict = { "settings.general.section.display": "ማሳያ", "settings.general.row.language.title": "ቋንቋ", "settings.general.row.language.description": "የማሳያ ቋንቋውን ለOpenCode", + "settings.general.row.navigation.description": "በርዕስ አሞሌ ውስጥ ትሮችን ወይም ቋሚ የጎን አሞሌ ይጠቀሙ", + "settings.general.row.navigation.tabs": "ትሮች", + "settings.general.row.navigation.sidebar": "የጎን አሞሌ", + "settings.general.row.sidebarSessions.title": "ንቁ ያልሆኑ ክሮችን የማረጋት ጊዜ", + "settings.general.row.sidebarSessions.description": "ንቁ ያልሆኑ ክሮች ወደ የተረጉ ሄዳ። በስራ ላይ ያሉ ክሮች ይታያሉ።", + "settings.general.row.sidebarSessions.always": "ሁልጊዜ አሳይ", "settings.general.row.shell.title": "ተርሚናል ሼል", "settings.general.row.shell.description": "ሼል በተርሚናል እና ወኪል መሳሪያዎች ጥቅም ላይ የዋለ", "settings.general.row.shell.autoDefault": "ራስ-ሰር (ነባሪ)", diff --git a/packages/app/src/i18n/ar.ts b/packages/app/src/i18n/ar.ts index 3f55b3084088..5a48a319b8d2 100644 --- a/packages/app/src/i18n/ar.ts +++ b/packages/app/src/i18n/ar.ts @@ -827,6 +827,15 @@ export const dict = { "sidebar.project.clearNotifications": "مسح الإشعارات", "sidebar.empty.title": "لا توجد مشاريع مفتوحة", "sidebar.empty.description": "افتح مشروعًا للبدء", + "sidebar.settled": "المنتهية", + "sidebar.settle": "إنهاء المحادثة", + "sidebar.unsettle": "إعادة المحادثة", + "sidebar.thread.new": "محادثة جديدة", + "sidebar.thread.pin": "تثبيت المحادثة", + "sidebar.thread.unpin": "إلغاء تثبيت المحادثة", + "sidebar.status.working": "يعمل", + "sidebar.status.done": "تم", + "sidebar.status.attention": "يحتاج إدخال", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "سطح المكتب", "settings.section.server": "الخادم", @@ -844,6 +853,12 @@ export const dict = { "settings.general.section.display": "العرض", "settings.general.row.language.title": "اللغة", "settings.general.row.language.description": "تغيير لغة العرض لـ OpenCode", + "settings.general.row.navigation.description": "استخدم علامات التبويب في شريط العنوان أو الشريط الجانبي الثابت", + "settings.general.row.navigation.tabs": "علامات التبويب", + "settings.general.row.navigation.sidebar": "الشريط الجانبي", + "settings.general.row.sidebarSessions.title": "إنهاء المحادثات الخاملة بعد", + "settings.general.row.sidebarSessions.description": "تنتقل المحادثات الخاملة إلى المنتهية. المحادثات العاملة تبقى ظاهرة.", + "settings.general.row.sidebarSessions.always": "الإظهار دائمًا", "settings.general.row.shell.title": "Shell المحطة الطرفية", "settings.general.row.shell.description": "اختر shell المستخدم في المحطة الطرفية. تُستخدم واجهات shell المتوافقة أيضًا في استدعاءات أدوات الوكيل.", diff --git a/packages/app/src/i18n/az.ts b/packages/app/src/i18n/az.ts index d818ae57fd6c..e2e6a311ae61 100644 --- a/packages/app/src/i18n/az.ts +++ b/packages/app/src/i18n/az.ts @@ -886,6 +886,15 @@ export const dict = { "sidebar.project.clearNotifications": "Bildirişləri təmizlə", "sidebar.empty.title": "Heç bir layihə açılmayıb", "sidebar.empty.description": "Başlamaq üçün bir layihə açın", + "sidebar.settled": "Bağlanan", + "sidebar.settle": "Mövzunu bağla", + "sidebar.unsettle": "Mövzunu yenidən aç", + "sidebar.thread.new": "Yeni mövzu", + "sidebar.thread.pin": "Mövzunu bərkid", + "sidebar.thread.unpin": "Bərkitməni ləğv et", + "sidebar.status.working": "İşləyir", + "sidebar.status.done": "Hazır", + "sidebar.status.attention": "Giriş lazımdır", "debugBar.ariaLabel": "Tərtibatçı performans diaqnostikası", "debugBar.na": "yox", "debugBar.nav.label": "NAV", @@ -934,6 +943,12 @@ export const dict = { "settings.general.section.display": "Ekran", "settings.general.row.language.title": "Dil", "settings.general.row.language.description": "OpenCode üçün ekran dilini dəyişdirin", + "settings.general.row.navigation.description": "Başlıq panelində tablar və ya daimi yan panel istifadə et", + "settings.general.row.navigation.tabs": "Tablar", + "settings.general.row.navigation.sidebar": "Yan panel", + "settings.general.row.sidebarSessions.title": "Boş mövzuları bağlama müddəti", + "settings.general.row.sidebarSessions.description": "Boş mövzular bağlananlara daşınır. İşləyən mövzular görünür qalır.", + "settings.general.row.sidebarSessions.always": "Həmişə göstər", "settings.general.row.shell.title": "Terminal qabığı", "settings.general.row.shell.description": "Terminal və agent alətləri tərəfindən istifadə edilən qabıq", "settings.general.row.shell.autoDefault": "Avtomatik (Standart)", diff --git a/packages/app/src/i18n/bg.ts b/packages/app/src/i18n/bg.ts index 7f63d1fa4b3e..d41fac121af3 100644 --- a/packages/app/src/i18n/bg.ts +++ b/packages/app/src/i18n/bg.ts @@ -882,6 +882,15 @@ export const dict = { "sidebar.project.clearNotifications": "Изчистване на известията", "sidebar.empty.title": "Няма отворени проекти", "sidebar.empty.description": "Отворете проект, за да започнете", + "sidebar.settled": "Отложени", + "sidebar.settle": "Отложи нишка", + "sidebar.unsettle": "Върни нишка", + "sidebar.thread.new": "Нова нишка", + "sidebar.thread.pin": "Закачи нишка", + "sidebar.thread.unpin": "Откачи нишка", + "sidebar.status.working": "В процес", + "sidebar.status.done": "Готово", + "sidebar.status.attention": "Нужен е вход", "debugBar.ariaLabel": "Диагностика на ефективността на разработката", "debugBar.na": "няма", "debugBar.nav.label": "NAV", @@ -931,6 +940,12 @@ export const dict = { "settings.general.section.display": "Дисплей", "settings.general.row.language.title": "език", "settings.general.row.language.description": "Променете езика на дисплея за OpenCode", + "settings.general.row.navigation.description": "Използвайте раздели в заглавната лента или постоянна странична лента", + "settings.general.row.navigation.tabs": "Раздели", + "settings.general.row.navigation.sidebar": "Странична лента", + "settings.general.row.sidebarSessions.title": "Отложи неактивни нишки след", + "settings.general.row.sidebarSessions.description": "Неактивните нишки отиват в отложените. Активните нишки остават видими.", + "settings.general.row.sidebarSessions.always": "Винаги показвай", "settings.general.row.shell.title": "Терминал shell", "settings.general.row.shell.description": "Shell използвани от инструментите на терминала и агента", "settings.general.row.shell.autoDefault": "Автоматично (по подразбиране)", diff --git a/packages/app/src/i18n/bn.ts b/packages/app/src/i18n/bn.ts index 5f0698ab64f1..23db30d134dc 100644 --- a/packages/app/src/i18n/bn.ts +++ b/packages/app/src/i18n/bn.ts @@ -876,6 +876,15 @@ export const dict: Record = { "sidebar.project.clearNotifications": "বিজ্ঞপ্তিগুলি সাফ করুন", "sidebar.empty.title": "কোনো প্রকল্প খোলা নেই", "sidebar.empty.description": "শুরু করতে একটি প্রকল্প খুলুন", + "sidebar.settled": "নিষ্পত্তি হওয়া", + "sidebar.settle": "থ্রেড নিষ্পত্তি করুন", + "sidebar.unsettle": "থ্রেড পুনরুদ্ধার করুন", + "sidebar.thread.new": "নতুন থ্রেড", + "sidebar.thread.pin": "থ্রেড পিন করুন", + "sidebar.thread.unpin": "পিন সরান", + "sidebar.status.working": "কাজ চলছে", + "sidebar.status.done": "সম্পন্ন", + "sidebar.status.attention": "ইনপুট প্রয়োজন", "debugBar.ariaLabel": "উন্নয়ন কর্মক্ষমতা ডায়গনিস্টিক", "debugBar.na": "n/a", "debugBar.nav.label": "এনএভি", @@ -923,6 +932,12 @@ export const dict: Record = { "settings.general.section.display": "প্রদর্শন", "settings.general.row.language.title": "ভাষা", "settings.general.row.language.description": "OpenCode-এর জন্য প্রদর্শনের ভাষা পরিবর্তন করুন", + "settings.general.row.navigation.description": "শিরোনাম বারে ট্যাব বা স্থায়ী সাইডবার ব্যবহার করুন", + "settings.general.row.navigation.tabs": "ট্যাব", + "settings.general.row.navigation.sidebar": "সাইডবার", + "settings.general.row.sidebarSessions.title": "নিষ্ক্রিয় থ্রেড নিষ্পত্তির সময়", + "settings.general.row.sidebarSessions.description": "নিষ্ক্রিয় থ্রেড নিষ্পত্তি হওয়াতে চলে যায়। কাজ চলমান থ্রেড দৃশ্যমান থাকে।", + "settings.general.row.sidebarSessions.always": "সবসময় দেখান", "settings.general.row.shell.title": "টার্মিনাল শেল", "settings.general.row.shell.description": "টার্মিনাল এবং এজেন্ট সরঞ্জাম দ্বারা ব্যবহৃত শেল", "settings.general.row.shell.autoDefault": "স্বয়ংক্রিয় (ডিফল্ট)", diff --git a/packages/app/src/i18n/br.ts b/packages/app/src/i18n/br.ts index 09da845ccb53..7eec488d1ab9 100644 --- a/packages/app/src/i18n/br.ts +++ b/packages/app/src/i18n/br.ts @@ -830,6 +830,15 @@ export const dict = { "sidebar.project.clearNotifications": "Limpar notificações", "sidebar.empty.title": "Nenhum projeto aberto", "sidebar.empty.description": "Abra um projeto para começar", + "sidebar.settled": "Reoliet", + "sidebar.settle": "Reoliañ an neudenn", + "sidebar.unsettle": "Adkrouiñ an neudenn", + "sidebar.thread.new": "Neudenn nevez", + "sidebar.thread.pin": "Spilhennañ an neudenn", + "sidebar.thread.unpin": "Dibilhennañ an neudenn", + "sidebar.status.working": "O labourat", + "sidebar.status.done": "Echu", + "sidebar.status.attention": "Ezhomm moned", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "Desktop", "settings.section.server": "Servidor", @@ -847,6 +856,12 @@ export const dict = { "settings.general.section.display": "Tela", "settings.general.row.language.title": "Idioma", "settings.general.row.language.description": "Alterar o idioma de exibição do OpenCode", + "settings.general.row.navigation.description": "Implijit abadennoù er varenn ditl pe ur varrenn gostez padus", + "settings.general.row.navigation.tabs": "Abadennoù", + "settings.general.row.navigation.sidebar": "Barrenn gostez", + "settings.general.row.sidebarSessions.title": "Reoliañ an neudennoù diober goude", + "settings.general.row.sidebarSessions.description": "An neudennoù diober a ya d'ar reoliet. An neudennoù o labourat a chom gwelus.", + "settings.general.row.sidebarSessions.always": "Diskouez bepred", "settings.general.row.shell.title": "Shell do terminal", "settings.general.row.shell.description": "Escolha o shell usado no terminal. Os shells compatíveis também são usados nas chamadas de ferramentas do agente.", diff --git a/packages/app/src/i18n/bs.ts b/packages/app/src/i18n/bs.ts index feb41c651a87..2a7cb67ffb4e 100644 --- a/packages/app/src/i18n/bs.ts +++ b/packages/app/src/i18n/bs.ts @@ -891,6 +891,15 @@ export const dict = { "sidebar.project.clearNotifications": "Očisti obavijesti", "sidebar.empty.title": "Nema otvorenih projekata", "sidebar.empty.description": "Otvori projekat za početak", + "sidebar.settled": "Odložene", + "sidebar.settle": "Odloži nit", + "sidebar.unsettle": "Vrati nit", + "sidebar.thread.new": "Nova nit", + "sidebar.thread.pin": "Prikvači nit", + "sidebar.thread.unpin": "Otkvači nit", + "sidebar.status.working": "U toku", + "sidebar.status.done": "Gotovo", + "sidebar.status.attention": "Potreban unos", "app.name.desktop": "OpenCode Desktop", @@ -912,6 +921,12 @@ export const dict = { "settings.general.row.language.title": "Jezik", "settings.general.row.language.description": "Promijeni jezik prikaza u OpenCode-u", + "settings.general.row.navigation.description": "Koristite kartice u traci naslova ili stalnu bočnu traku", + "settings.general.row.navigation.tabs": "Kartice", + "settings.general.row.navigation.sidebar": "Bočna traka", + "settings.general.row.sidebarSessions.title": "Odloži neaktivne niti nakon", + "settings.general.row.sidebarSessions.description": "Neaktivne niti prelaze u odložene. Aktivne niti ostaju vidljive.", + "settings.general.row.sidebarSessions.always": "Uvijek prikaži", "settings.general.row.shell.title": "Shell terminala", "settings.general.row.shell.description": "Odaberi shell koji se koristi za terminal. Kompatibilni shellovi koriste se i za pozive alata agenta.", diff --git a/packages/app/src/i18n/ca.ts b/packages/app/src/i18n/ca.ts index 21ad325607a6..16c9f96f29d8 100644 --- a/packages/app/src/i18n/ca.ts +++ b/packages/app/src/i18n/ca.ts @@ -886,6 +886,15 @@ export const dict = { "sidebar.project.clearNotifications": "Esborra les notificacions", "sidebar.empty.title": "No hi ha projectes oberts", "sidebar.empty.description": "Obriu un projecte per començar", + "sidebar.settled": "Tancats", + "sidebar.settle": "Tanca el fil", + "sidebar.unsettle": "Reobre el fil", + "sidebar.thread.new": "Fil nou", + "sidebar.thread.pin": "Fixa el fil", + "sidebar.thread.unpin": "Desfixa el fil", + "sidebar.status.working": "Treballant", + "sidebar.status.done": "Fet", + "sidebar.status.attention": "Cal entrada", "debugBar.ariaLabel": "Diagnòstic de rendiment del desenvolupament", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -934,6 +943,12 @@ export const dict = { "settings.general.section.display": "Mostra", "settings.general.row.language.title": "Llengua", "settings.general.row.language.description": "Canvia l'idioma de visualització per a OpenCode", + "settings.general.row.navigation.description": "Usa pestanyes a la barra de títol o una barra lateral persistent", + "settings.general.row.navigation.tabs": "Pestanyes", + "settings.general.row.navigation.sidebar": "Barra lateral", + "settings.general.row.sidebarSessions.title": "Tanca els fils inactius després de", + "settings.general.row.sidebarSessions.description": "Els fils inactius passen a Tancats. Els fils actius continuen visibles.", + "settings.general.row.sidebarSessions.always": "Mostra sempre", "settings.general.row.shell.title": "Carcassa terminal", "settings.general.row.shell.description": "Shell utilitzat pel terminal i les eines d'agent", "settings.general.row.shell.autoDefault": "Automàtic (per defecte)", diff --git a/packages/app/src/i18n/cs.ts b/packages/app/src/i18n/cs.ts index d79d4eb5a7f8..0c85f6ca9a84 100644 --- a/packages/app/src/i18n/cs.ts +++ b/packages/app/src/i18n/cs.ts @@ -882,6 +882,15 @@ export const dict = { "sidebar.project.clearNotifications": "Vymazat oznámení", "sidebar.empty.title": "Nejsou otevřeny žádné projekty", "sidebar.empty.description": "Chcete-li začít, otevřete projekt", + "sidebar.settled": "Odložené", + "sidebar.settle": "Odložit vlákno", + "sidebar.unsettle": "Vrátit vlákno", + "sidebar.thread.new": "Nové vlákno", + "sidebar.thread.pin": "Připnout vlákno", + "sidebar.thread.unpin": "Odepnout vlákno", + "sidebar.status.working": "Pracuje", + "sidebar.status.done": "Hotovo", + "sidebar.status.attention": "Vyžaduje vstup", "debugBar.ariaLabel": "Diagnostika vývoje výkonnosti", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -930,6 +939,12 @@ export const dict = { "settings.general.section.display": "Displej", "settings.general.row.language.title": "Jazyk", "settings.general.row.language.description": "Změnit jazyk zobrazení pro OpenCode", + "settings.general.row.navigation.description": "Použijte karty na titulním panelu nebo trvalý postranní panel", + "settings.general.row.navigation.tabs": "Karty", + "settings.general.row.navigation.sidebar": "Postranní panel", + "settings.general.row.sidebarSessions.title": "Odložit nečinná vlákna po", + "settings.general.row.sidebarSessions.description": "Nečinná vlákna se přesunou do Odložené. Pracující vlákna zůstanou viditelná.", + "settings.general.row.sidebarSessions.always": "Vždy zobrazit", "settings.general.row.shell.title": "Shell terminálu", "settings.general.row.shell.description": "Shell používaný terminálem a nástroji agenta", "settings.general.row.shell.autoDefault": "Auto (výchozí)", diff --git a/packages/app/src/i18n/da.ts b/packages/app/src/i18n/da.ts index 87737b094240..278ae779aa1d 100644 --- a/packages/app/src/i18n/da.ts +++ b/packages/app/src/i18n/da.ts @@ -768,6 +768,15 @@ export const dict = { "sidebar.project.clearNotifications": "Ryd notifikationer", "sidebar.empty.title": "Ingen åbne projekter", "sidebar.empty.description": "Åbn et projekt for at komme i gang", + "sidebar.settled": "Afsluttede", + "sidebar.settle": "Afslut tråd", + "sidebar.unsettle": "Genåbn tråd", + "sidebar.thread.new": "Ny tråd", + "sidebar.thread.pin": "Fastgør tråd", + "sidebar.thread.unpin": "Frigør tråd", + "sidebar.status.working": "Arbejder", + "sidebar.status.done": "Færdig", + "sidebar.status.attention": "Kræver input", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "Desktop", @@ -788,6 +797,12 @@ export const dict = { "settings.general.row.language.title": "Sprog", "settings.general.row.language.description": "Ændr visningssproget for OpenCode", + "settings.general.row.navigation.description": "Brug faner i titellinjen eller et fast sidepanel", + "settings.general.row.navigation.tabs": "Faner", + "settings.general.row.navigation.sidebar": "Sidepanel", + "settings.general.row.sidebarSessions.title": "Afslut inaktive tråde efter", + "settings.general.row.sidebarSessions.description": "Inaktive tråde flyttes til Afsluttede. Aktive tråde forbliver synlige.", + "settings.general.row.sidebarSessions.always": "Vis altid", "settings.general.row.shell.title": "Terminalshell", "settings.general.row.shell.description": "Vælg den shell, der bruges i din terminal. Kompatible shells bruges også til agentens værktøjskald.", diff --git a/packages/app/src/i18n/de.ts b/packages/app/src/i18n/de.ts index 00849598c5c5..06d26d040b74 100644 --- a/packages/app/src/i18n/de.ts +++ b/packages/app/src/i18n/de.ts @@ -721,6 +721,15 @@ export const dict = { "sidebar.project.clearNotifications": "Benachrichtigungen löschen", "sidebar.empty.title": "Keine Projekte geöffnet", "sidebar.empty.description": "Öffnen Sie ein Projekt, um loszulegen", + "sidebar.settled": "Abgelegt", + "sidebar.settle": "Thread ablegen", + "sidebar.unsettle": "Thread wiederherstellen", + "sidebar.thread.new": "Neuer Thread", + "sidebar.thread.pin": "Thread anheften", + "sidebar.thread.unpin": "Thread loslösen", + "sidebar.status.working": "In Arbeit", + "sidebar.status.done": "Fertig", + "sidebar.status.attention": "Eingabe erforderlich", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "Desktop", "settings.section.server": "Server", @@ -738,6 +747,12 @@ export const dict = { "settings.general.section.display": "Anzeige", "settings.general.row.language.title": "Sprache", "settings.general.row.language.description": "Die Anzeigesprache für OpenCode ändern", + "settings.general.row.navigation.description": "Tabs in der Titelleiste oder eine dauerhafte Seitenleiste verwenden", + "settings.general.row.navigation.tabs": "Tabs", + "settings.general.row.navigation.sidebar": "Seitenleiste", + "settings.general.row.sidebarSessions.title": "Inaktive Threads ablegen nach", + "settings.general.row.sidebarSessions.description": "Inaktive Threads werden abgelegt. Aktive Threads bleiben sichtbar.", + "settings.general.row.sidebarSessions.always": "Immer anzeigen", "settings.general.row.shell.title": "Terminal-Shell", "settings.general.row.shell.description": "Wählen Sie die Shell für Ihr Terminal aus. Kompatible Shells werden auch für Tool-Aufrufe von Agenten verwendet.", diff --git a/packages/app/src/i18n/dv.ts b/packages/app/src/i18n/dv.ts index 27b5fea86999..73398393a7f9 100644 --- a/packages/app/src/i18n/dv.ts +++ b/packages/app/src/i18n/dv.ts @@ -890,6 +890,15 @@ export const dict = { "sidebar.project.clearNotifications": "ނޮޓިފިކޭޝަންތައް ސާފުކުރުން", "sidebar.empty.title": "އެއްވެސް މަޝްރޫއެއް ނުހުޅުވޭ", "sidebar.empty.description": "ފަށަން ޕްރޮޖެކްޓެއް ހުޅުވާށެވެ", + "sidebar.settled": "ނިންމައިފައިވާ", + "sidebar.settle": "ތްރެޑް ނިންމައިލާ", + "sidebar.unsettle": "ތްރެޑް އަލުން ފައުލާ", + "sidebar.thread.new": "އާ ތްރެޑް", + "sidebar.thread.pin": "ތްރެޑް ޕިން ކުރާ", + "sidebar.thread.unpin": "ޕިން ނަގާ", + "sidebar.status.working": "މަސައްކަތް ކުރަމުން", + "sidebar.status.done": "ނިމިއްޖެ", + "sidebar.status.attention": "އިންޕުޓް ބޭނުން", "debugBar.ariaLabel": "ޑިވެލޮޕްމަންޓް ޕާފޯމަންސް ޑައިގްނޯސްޓިކްސް", "debugBar.na": "n/a", "debugBar.nav.label": "NAV އެވެ", @@ -939,6 +948,12 @@ export const dict = { "settings.general.section.display": "ޑިސްޕްލޭ", "settings.general.row.language.title": "ބަސް", "settings.general.row.language.description": "OpenCode އަށް ޑިސްޕްލޭ ލޭންގުއޭޖް ބަދަލުކުރުން", + "settings.general.row.navigation.description": "ސިރުސްތޮށުގައި ޓެބްތައް ނުވަތަ ސައިޑްބާރެއް ބޭނުން ކުރޭ", + "settings.general.row.navigation.tabs": "ޓެބްތައް", + "settings.general.row.navigation.sidebar": "ސައިޑްބާރް", + "settings.general.row.sidebarSessions.title": "ނިސްކްރިއ ތްރެޑްތައް ނިންމައިލުމަށް ފަހު", + "settings.general.row.sidebarSessions.description": "ނިސްކްރިއ ތްރެޑްތައް ނިންމައިފައިވާ އަށް ބަދަލުވޭ. މަސައްކަތް ކުރަމުންދާ ތްރެޑްތައް ފެންނަން ހުންނާނެ.", + "settings.general.row.sidebarSessions.always": "އެންމެހާ ވަގުތު ދައްކާ", "settings.general.row.shell.title": "ޓާމިނަލް ޝެލް އެވެ", "settings.general.row.shell.description": "ޓާމިނަލް އާއި އޭޖެންޓް ޓޫލްސް އިން ބޭނުންކުރާ ޝެލް", "settings.general.row.shell.autoDefault": "އޮޓޯ (ޑިފޯލްޓް)", diff --git a/packages/app/src/i18n/dz.ts b/packages/app/src/i18n/dz.ts index 3b2ad46ca304..50c9d8d1a17c 100644 --- a/packages/app/src/i18n/dz.ts +++ b/packages/app/src/i18n/dz.ts @@ -891,6 +891,15 @@ export const dict: Record = { "sidebar.project.clearNotifications": "བརྡ་བསྐུལ་ཚུ་གསལ་བཟོ།", "sidebar.empty.title": "ལས་འགུལ་ཁ་ཕྱེ་མེད།", "sidebar.empty.description": "འགོ་བཙུགས་ནིའི་དོན་ལུ་ལས་འགུལ་ཅིག་ཁ་ཕྱེ།", + "sidebar.settled": "བསྒུབས་ཟིན་པ།", + "sidebar.settle": "གླེང་མོལ་བསྒྲུབས།", + "sidebar.unsettle": "གླེང་མོ་སོར་ུད།", + "sidebar.thread.new": "གླེང་མོལ་གསརཔ།", + "sidebar.thread.pin": "གླེང་མོལ་བཀག་སྒྲིལ།", + "sidebar.thread.unpin": "བཀག་སྒྲིལ་བཏོན།", + "sidebar.status.working": "ལཱ་འབད་བཞིན།", + "sidebar.status.done": "འགྲུབ་ཅི།", + "sidebar.status.attention": "ནང་བྱུག་དགོས།", "debugBar.ariaLabel": "གོང་འཕེལ་གྱི་ལས་དོན་བརྟག་དཔྱད།", "debugBar.na": "ན/ཨེ།", "debugBar.nav.label": "NAV", @@ -940,6 +949,12 @@ export const dict: Record = { "settings.general.section.display": "གསལ༌སྟོན", "settings.general.row.language.title": "སྐད༌ཡིག", "settings.general.row.language.description": "OpenCodeགི་དོན་ལུ་ བཀྲམ་སྟོན་སྐད་ཡིག་བསྒྱུར་བཅོས་འབད།", + "settings.general.row.navigation.description": "མགོ་བརྗོད་ནང་ མཆོང་ལྡེ་ ཡང་ན་ ཟུར་ཕྲེང་ ལག་ལེན་འཐབ།", + "settings.general.row.navigation.tabs": "མཆོང་ལྡེ།", + "settings.general.row.navigation.sidebar": "ཟུར་ཕྲེང་།", + "settings.general.row.sidebarSessions.title": "་ལཱ་བའི་གླེང་མོལ་བསྒྲུབས་ཚེ།", + "settings.general.row.sidebarSessions.description": "མ་ཱ་བི་གེང་མོལ་བསྒྲུབས་ཟིན་རུ་སོང་། ལཱ་འབད་བཞིན་པ་སྟོན།", + "settings.general.row.sidebarSessions.always": "ད་ལྟོ་རང་ སྟོན།", "settings.general.row.shell.title": "ཊར་མི་ནཱལ་ Shell", "settings.general.row.shell.description": "ཊར་མི་ནཱལ་དང་ལས་ཚབ་ལག་ཆས་ཚུ་གིས་ལག་ལེན་འཐབ་མི་ Shell", "settings.general.row.shell.autoDefault": "རང་བཞིན་ (སྔོན་སྒྲིག)", diff --git a/packages/app/src/i18n/el.ts b/packages/app/src/i18n/el.ts index 8f91b46af010..5bd26e954efc 100644 --- a/packages/app/src/i18n/el.ts +++ b/packages/app/src/i18n/el.ts @@ -885,6 +885,15 @@ export const dict = { "sidebar.project.clearNotifications": "Διαγραφή ειδοποιήσεων", "sidebar.empty.title": "Δεν υπάρχουν ανοιχτά έργα", "sidebar.empty.description": "Ανοίξτε ένα έργο για να ξεκινήσετε", + "sidebar.settled": "Τακτοποιημένες", + "sidebar.settle": "Τακτοποίηση νήματος", + "sidebar.unsettle": "Επαναφορά νήματος", + "sidebar.thread.new": "Νέο νήμα", + "sidebar.thread.pin": "Καρφίτσωμα νήματος", + "sidebar.thread.unpin": "Ξεκαρφίτσωμα νήματος", + "sidebar.status.working": "Σε εργασία", + "sidebar.status.done": "Ολοκληρώθηκε", + "sidebar.status.attention": "Απαιτεί είσοδο", "debugBar.ariaLabel": "Διαγνωστικά απόδοσης ανάπτυξης", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -935,6 +944,12 @@ export const dict = { "settings.general.section.display": "Εμφάνιση", "settings.general.row.language.title": "Γλώσσα", "settings.general.row.language.description": "Αλλαγή της γλώσσας εμφάνισης για το OpenCode", + "settings.general.row.navigation.description": "Χρησιμοποιήστε καρτέλες στη γραμμή τίτλου ή μια μόνιμη πλευρική γραμμή", + "settings.general.row.navigation.tabs": "Καρτέλες", + "settings.general.row.navigation.sidebar": "Πλευρική γραμμή", + "settings.general.row.sidebarSessions.title": "Τακτοποίηση αδρανών νημάτων μετά", + "settings.general.row.sidebarSessions.description": "Τα αδρανή νήματα μεταφέρονται στα τακτοποιημένα. Τα νήματα σε εργασία παραμένουν ορατά.", + "settings.general.row.sidebarSessions.always": "Να εμφανίζονται πάντα", "settings.general.row.shell.title": "Τερματικό κέλυφος", "settings.general.row.shell.description": "Κέλυφος που χρησιμοποιείται από το τερματικό και τα εργαλεία του πράκτορα", "settings.general.row.shell.autoDefault": "Αυτόματο (Προεπιλογή)", diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index 62d4dc1ae6e9..3714d1b696fb 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -854,6 +854,15 @@ export const dict = { "sidebar.project.clearNotifications": "Clear notifications", "sidebar.empty.title": "No projects open", "sidebar.empty.description": "Open a project to get started", + "sidebar.settled": "Settled", + "sidebar.settle": "Settle thread", + "sidebar.unsettle": "Unsettle thread", + "sidebar.thread.new": "New thread", + "sidebar.thread.pin": "Pin thread", + "sidebar.thread.unpin": "Unpin thread", + "sidebar.status.working": "Working", + "sidebar.status.done": "Done", + "sidebar.status.attention": "Needs input", "debugBar.ariaLabel": "Development performance diagnostics", "debugBar.na": "n/a", @@ -907,6 +916,12 @@ export const dict = { "settings.general.row.language.title": "Language", "settings.general.row.language.description": "Change the display language for OpenCode", + "settings.general.row.navigation.description": "Use title bar tabs or a persistent sidebar", + "settings.general.row.navigation.tabs": "Tabs", + "settings.general.row.navigation.sidebar": "Sidebar", + "settings.general.row.sidebarSessions.title": "Settle idle sessions after", + "settings.general.row.sidebarSessions.description": "Idle sessions move to Settled. Working sessions stay visible.", + "settings.general.row.sidebarSessions.always": "Always show", "settings.general.row.shell.title": "Terminal shell", "settings.general.row.shell.description": "Shell used by the terminal and agent tools", "settings.general.row.shell.autoDefault": "Auto (Default)", diff --git a/packages/app/src/i18n/es.ts b/packages/app/src/i18n/es.ts index 9e9ff2c36750..b76bdd023fe5 100644 --- a/packages/app/src/i18n/es.ts +++ b/packages/app/src/i18n/es.ts @@ -896,6 +896,15 @@ export const dict = { "sidebar.project.clearNotifications": "Borrar notificaciones", "sidebar.empty.title": "No hay proyectos abiertos", "sidebar.empty.description": "Abre un proyecto para empezar", + "sidebar.settled": "Finalizados", + "sidebar.settle": "Finalizar hilo", + "sidebar.unsettle": "Reactivar hilo", + "sidebar.thread.new": "Nuevo hilo", + "sidebar.thread.pin": "Fijar hilo", + "sidebar.thread.unpin": "Desfijar hilo", + "sidebar.status.working": "Trabajando", + "sidebar.status.done": "Listo", + "sidebar.status.attention": "Requiere entrada", "app.name.desktop": "OpenCode Desktop", @@ -917,6 +926,12 @@ export const dict = { "settings.general.row.language.title": "Idioma", "settings.general.row.language.description": "Cambiar el idioma de visualización para OpenCode", + "settings.general.row.navigation.description": "Usa pestañas en la barra de título o una barra lateral persistente", + "settings.general.row.navigation.tabs": "Pestañas", + "settings.general.row.navigation.sidebar": "Barra lateral", + "settings.general.row.sidebarSessions.title": "Finalizar hilos inactivos después de", + "settings.general.row.sidebarSessions.description": "Los hilos inactivos pasan a Finalizados. Los hilos activos siguen visibles.", + "settings.general.row.sidebarSessions.always": "Mostrar siempre", "settings.general.row.shell.title": "Shell del terminal", "settings.general.row.shell.description": "Shell que usan el terminal y las herramientas del agente", "settings.general.row.shell.autoDefault": "Automático (predeterminado)", diff --git a/packages/app/src/i18n/et.ts b/packages/app/src/i18n/et.ts index d78296675e3d..37dc9d2003d0 100644 --- a/packages/app/src/i18n/et.ts +++ b/packages/app/src/i18n/et.ts @@ -872,6 +872,15 @@ export const dict = { "sidebar.project.clearNotifications": "Tühjenda märguanded", "sidebar.empty.title": "Avatud projekte pole", "sidebar.empty.description": "Alustamiseks avage projekt", + "sidebar.settled": "Paigutatud", + "sidebar.settle": "Paiguta lõim", + "sidebar.unsettle": "Taasta lõim", + "sidebar.thread.new": "Uus lõim", + "sidebar.thread.pin": "Kinnita lõim", + "sidebar.thread.unpin": "Eemalda kinnitus", + "sidebar.status.working": "Töötab", + "sidebar.status.done": "Valmis", + "sidebar.status.attention": "Vajab sisendit", "debugBar.ariaLabel": "Arendustegevuse diagnostika", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -921,6 +930,12 @@ export const dict = { "settings.general.section.display": "Ekraan", "settings.general.row.language.title": "Keel", "settings.general.row.language.description": "Muutke OpenCode kuvakeelt", + "settings.general.row.navigation.description": "Kasuta tiitliriba vahekaarte või püsivat külgriba", + "settings.general.row.navigation.tabs": "Vahekaardid", + "settings.general.row.navigation.sidebar": "Külgriba", + "settings.general.row.sidebarSessions.title": "Paiguta jõude lõimed pärast", + "settings.general.row.sidebarSessions.description": "Jõude lõimed liiguvad paigutatute hulka. Töötavad lõimed jäävad nähtavale.", + "settings.general.row.sidebarSessions.always": "Kuva alati", "settings.general.row.shell.title": "Terminali shell", "settings.general.row.shell.description": "Terminali ja agenditööriistade kasutatav shell", "settings.general.row.shell.autoDefault": "Automaatne (vaikimisi)", diff --git a/packages/app/src/i18n/fa.ts b/packages/app/src/i18n/fa.ts index 0d3d721b5324..12ac08c5bdaa 100644 --- a/packages/app/src/i18n/fa.ts +++ b/packages/app/src/i18n/fa.ts @@ -875,6 +875,15 @@ export const dict = { "sidebar.project.clearNotifications": "پرامپت ها را پاک کنید", "sidebar.empty.title": "هیچ پروژه ای باز نشده است", "sidebar.empty.description": "برای شروع یک پروژه باز کنید", + "sidebar.settled": "سامان‌یافته", + "sidebar.settle": "سامان دادن رشته", + "sidebar.unsettle": "بازگرداندن رشته", + "sidebar.thread.new": "رشته جدید", + "sidebar.thread.pin": "سنجاق کردن رشته", + "sidebar.thread.unpin": "برداشتن سنجاق", + "sidebar.status.working": "در حال کار", + "sidebar.status.done": "انجام شد", + "sidebar.status.attention": "ورودی لازم است", "debugBar.ariaLabel": "تشخیص عملکرد توسعه", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -922,6 +931,12 @@ export const dict = { "settings.general.section.display": "نمایش", "settings.general.row.language.title": "زبان", "settings.general.row.language.description": "زبان نمایش را برای OpenCode تغییر دهید", + "settings.general.row.navigation.description": "از برگه‌های نوار عنوان یا نوار کناری ثابت استفاده کنید", + "settings.general.row.navigation.tabs": "برگه‌ها", + "settings.general.row.navigation.sidebar": "نوار کناری", + "settings.general.row.sidebarSessions.title": "سامان دادن رشته‌های غیرفعال پس از", + "settings.general.row.sidebarSessions.description": "رشته‌های غیرفعال به سامان‌یافته می‌روند. رشته‌های در حال کار نمایان می‌مانند.", + "settings.general.row.sidebarSessions.always": "همیشه نمایش بده", "settings.general.row.shell.title": "پوسته ترمینال", "settings.general.row.shell.description": "پوسته مورد استفاده ترمینال و ابزار عامل", "settings.general.row.shell.autoDefault": "خودکار (پیش‌فرض)", diff --git a/packages/app/src/i18n/fi.ts b/packages/app/src/i18n/fi.ts index aa9c92574cff..2941ac139866 100644 --- a/packages/app/src/i18n/fi.ts +++ b/packages/app/src/i18n/fi.ts @@ -776,6 +776,15 @@ export const dict = { "sidebar.project.clearNotifications": "Tyhjennä ilmoitukset", "sidebar.empty.title": "Ei avoimia projekteja", "sidebar.empty.description": "Aloita avaamalla projekti", + "sidebar.settled": "Suljetut", + "sidebar.settle": "Sulje ketju", + "sidebar.unsettle": "Palauta ketju", + "sidebar.thread.new": "Uusi ketju", + "sidebar.thread.pin": "Kiinnitä ketju", + "sidebar.thread.unpin": "Irrota ketju", + "sidebar.status.working": "Käynnissä", + "sidebar.status.done": "Valmis", + "sidebar.status.attention": "Tarvitsee syötteen", "debugBar.ariaLabel": "Kehityksen suorituskyvyn diagnostiikka", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -824,6 +833,12 @@ export const dict = { "settings.general.section.display": "Näyttö", "settings.general.row.language.title": "Kieli", "settings.general.row.language.description": "Vaihda OpenCoden näyttökieli", + "settings.general.row.navigation.description": "Käytä välilehtiä otsikkopalkissa tai pysyvää sivupalkkia", + "settings.general.row.navigation.tabs": "Välilehdet", + "settings.general.row.navigation.sidebar": "Sivupalkki", + "settings.general.row.sidebarSessions.title": "Sulje joutilaat ketjut ajan jälkeen", + "settings.general.row.sidebarSessions.description": "Joutilaat ketjut siirtyvät Suljetut-osioon. Käynnissä olevat ketjut pysyvät näkyvissä.", + "settings.general.row.sidebarSessions.always": "Näytä aina", "settings.general.row.shell.title": "Terminaalin komentotulkki", "settings.general.row.shell.description": "Terminaalin ja agenttityökalujen käyttämä komentotulkki", "settings.general.row.shell.autoDefault": "Automaattinen (oletus)", diff --git a/packages/app/src/i18n/fo.ts b/packages/app/src/i18n/fo.ts index 4329a35b4247..49c653c6534d 100644 --- a/packages/app/src/i18n/fo.ts +++ b/packages/app/src/i18n/fo.ts @@ -877,6 +877,15 @@ export const dict = { "sidebar.project.clearNotifications": "Rudda fráboðanir", "sidebar.empty.title": "Ongar verkætlanir lata upp", "sidebar.empty.description": "Opna eina verkætlan fyri at koma í gongd", + "sidebar.settled": "Avgreidd", + "sidebar.settle": "Avgreið tráð", + "sidebar.unsettle": "Enduropna tráð", + "sidebar.thread.new": "Nýggjur tráður", + "sidebar.thread.pin": "Festa tráð", + "sidebar.thread.unpin": "Losa tráð", + "sidebar.status.working": "Arbeiðir", + "sidebar.status.done": "Liðugt", + "sidebar.status.attention": "Krevur inndata", "debugBar.ariaLabel": "Menningar avriksdiagnostikk", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -924,6 +933,12 @@ export const dict = { "settings.general.section.display": "Sýn", "settings.general.row.language.title": "Mál", "settings.general.row.language.description": "Broyt sýnismálið fyri OpenCode", + "settings.general.row.navigation.description": "Brúka flipar í heitinum ella eitt fast síðupanel", + "settings.general.row.navigation.tabs": "Flipar", + "settings.general.row.navigation.sidebar": "Síðupanel", + "settings.general.row.sidebarSessions.title": "Avgreið óvirknar tráðir eftir", + "settings.general.row.sidebarSessions.description": "Óvirknir tráðir fara í avgreidd. Virknir tráðir haldast sjónligir.", + "settings.general.row.sidebarSessions.always": "Vís altíð", "settings.general.row.shell.title": "Terminal-shell", "settings.general.row.shell.description": "Shell, sum terminal- og agenttólini brúka", "settings.general.row.shell.autoDefault": "Sjálvvirkandi (Standard)", diff --git a/packages/app/src/i18n/fr.ts b/packages/app/src/i18n/fr.ts index 3c89860a4490..1c4a7d5de48b 100644 --- a/packages/app/src/i18n/fr.ts +++ b/packages/app/src/i18n/fr.ts @@ -835,6 +835,15 @@ export const dict = { "sidebar.project.clearNotifications": "Effacer les notifications", "sidebar.empty.title": "Aucun projet ouvert", "sidebar.empty.description": "Ouvrez un projet pour commencer", + "sidebar.settled": "Classés", + "sidebar.settle": "Classer le fil", + "sidebar.unsettle": "Rétablir le fil", + "sidebar.thread.new": "Nouveau fil", + "sidebar.thread.pin": "Épingler le fil", + "sidebar.thread.unpin": "Désépingler le fil", + "sidebar.status.working": "En cours", + "sidebar.status.done": "Terminé", + "sidebar.status.attention": "Saisie requise", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "Application de bureau", "settings.section.server": "Serveur", @@ -852,6 +861,12 @@ export const dict = { "settings.general.section.display": "Affichage", "settings.general.row.language.title": "Langue", "settings.general.row.language.description": "Changer la langue d'affichage pour OpenCode", + "settings.general.row.navigation.description": "Utiliser des onglets dans la barre de titre ou une barre latérale permanente", + "settings.general.row.navigation.tabs": "Onglets", + "settings.general.row.navigation.sidebar": "Barre latérale", + "settings.general.row.sidebarSessions.title": "Classer les fils inactifs après", + "settings.general.row.sidebarSessions.description": "Les fils inactifs sont classés. Les fils en cours restent visibles.", + "settings.general.row.sidebarSessions.always": "Toujours afficher", "settings.general.row.shell.title": "Interpréteur de commandes du terminal", "settings.general.row.shell.description": "Choisissez le shell utilisé par votre terminal. Les shells compatibles sont également utilisés pour les appels d'outils de l'agent.", diff --git a/packages/app/src/i18n/hi.ts b/packages/app/src/i18n/hi.ts index 0aaf8e14dc6d..a67df43db66c 100644 --- a/packages/app/src/i18n/hi.ts +++ b/packages/app/src/i18n/hi.ts @@ -886,6 +886,15 @@ export const dict = { "sidebar.project.clearNotifications": "सूचनाएँ साफ़ करें", "sidebar.empty.title": "कोई प्रोजेक्ट खुला नहीं", "sidebar.empty.description": "आरंभ करने के लिए एक प्रोजेक्ट खोलें", + "sidebar.settled": "निपटाए गए", + "sidebar.settle": "थ्रेड निपटाएँ", + "sidebar.unsettle": "थ्रेड पुनः सक्रिय करें", + "sidebar.thread.new": "नया थ्रेड", + "sidebar.thread.pin": "थ्रेड पिन करें", + "sidebar.thread.unpin": "पिन हटाएँ", + "sidebar.status.working": "कार्य में", + "sidebar.status.done": "पूर्ण", + "sidebar.status.attention": "इनपुट आवश्यक", "debugBar.ariaLabel": "विकास प्रदर्शन निदान", "debugBar.na": "एन/ए", "debugBar.nav.label": "NAV", @@ -933,6 +942,12 @@ export const dict = { "settings.general.section.display": "प्रदर्शन", "settings.general.row.language.title": "भाषा", "settings.general.row.language.description": "OpenCode के लिए प्रदर्शन भाषा बदलें", + "settings.general.row.navigation.description": "शीर्षक बार में टैब या स्थायी साइडबार का उपयोग करें", + "settings.general.row.navigation.tabs": "टैब", + "settings.general.row.navigation.sidebar": "साइडबार", + "settings.general.row.sidebarSessions.title": "निष्क्रिय थ्रेड निपटाने की अवधि", + "settings.general.row.sidebarSessions.description": "निष्क्रिय थ्रेड निपटाए गए में चले जाते हैं। सक्रिय थ्रेड दिखाई देते रहते हैं।", + "settings.general.row.sidebarSessions.always": "हमेशा दिखाएं", "settings.general.row.shell.title": "टर्मिनल शेल", "settings.general.row.shell.description": "शेल का उपयोग टर्मिनल और एजेंट टूल द्वारा किया जाता है", "settings.general.row.shell.autoDefault": "स्वतः (डिफ़ॉल्ट)", diff --git a/packages/app/src/i18n/hr.ts b/packages/app/src/i18n/hr.ts index 2130c88ada2d..6e185bde7e58 100644 --- a/packages/app/src/i18n/hr.ts +++ b/packages/app/src/i18n/hr.ts @@ -885,6 +885,15 @@ export const dict = { "sidebar.project.clearNotifications": "Očistite obavijesti", "sidebar.empty.title": "Nema otvorenih projekata", "sidebar.empty.description": "Otvorite projekt da biste započeli", + "sidebar.settled": "Odložene", + "sidebar.settle": "Odloži nit", + "sidebar.unsettle": "Vrati nit", + "sidebar.thread.new": "Nova nit", + "sidebar.thread.pin": "Prikvači nit", + "sidebar.thread.unpin": "Otkvači nit", + "sidebar.status.working": "U tijeku", + "sidebar.status.done": "Gotovo", + "sidebar.status.attention": "Potreban unos", "debugBar.ariaLabel": "Dijagnostika izvedbe razvoja", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -933,6 +942,12 @@ export const dict = { "settings.general.section.display": "Prikaz", "settings.general.row.language.title": "Jezik", "settings.general.row.language.description": "Promijenite jezik prikaza za OpenCode", + "settings.general.row.navigation.description": "Koristite kartice u naslovnoj traci ili trajnu bočnu traku", + "settings.general.row.navigation.tabs": "Kartice", + "settings.general.row.navigation.sidebar": "Bočna traka", + "settings.general.row.sidebarSessions.title": "Odloži neaktivne niti nakon", + "settings.general.row.sidebarSessions.description": "Neaktivne niti prelaze u odložene. Aktivne niti ostaju vidljive.", + "settings.general.row.sidebarSessions.always": "Uvijek prikaži", "settings.general.row.shell.title": "Terminal školjka", "settings.general.row.shell.description": "Ljuska koju koriste alati terminala i agenta", "settings.general.row.shell.autoDefault": "Automatski (zadano)", diff --git a/packages/app/src/i18n/hu.ts b/packages/app/src/i18n/hu.ts index 664abf8ee4c0..343ccf1223ed 100644 --- a/packages/app/src/i18n/hu.ts +++ b/packages/app/src/i18n/hu.ts @@ -884,6 +884,15 @@ export const dict = { "sidebar.project.clearNotifications": "Értesítések törlése", "sidebar.empty.title": "Nincs nyitott projekt", "sidebar.empty.description": "A kezdéshez nyisson meg egy projektet", + "sidebar.settled": "Lezárt", + "sidebar.settle": "Szál lezárása", + "sidebar.unsettle": "Szál visszaállítása", + "sidebar.thread.new": "Új szál", + "sidebar.thread.pin": "Szál rögzítése", + "sidebar.thread.unpin": "Rögzítés feloldása", + "sidebar.status.working": "Dolgozik", + "sidebar.status.done": "Kész", + "sidebar.status.attention": "Bemenet szükséges", "debugBar.ariaLabel": "Fejlesztési teljesítmény diagnosztika", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -933,6 +942,12 @@ export const dict = { "settings.general.section.display": "Kijelző", "settings.general.row.language.title": "Nyelv", "settings.general.row.language.description": "Módosítsa a OpenCode kijelző nyelvét", + "settings.general.row.navigation.description": "Lapok a címsorban vagy rögzített oldalsáv", + "settings.general.row.navigation.tabs": "Lapok", + "settings.general.row.navigation.sidebar": "Oldalsáv", + "settings.general.row.sidebarSessions.title": "Tétlen szálak lezárása ennyi idő után", + "settings.general.row.sidebarSessions.description": "A tétlen szálak a lezártak közé kerülnek. A dolgozó szálak láthatók maradnak.", + "settings.general.row.sidebarSessions.always": "Mindig látszódjon", "settings.general.row.shell.title": "Terminál shellje", "settings.general.row.shell.description": "A terminál és az ügynökeszközök által használt shell", "settings.general.row.shell.autoDefault": "Automatikus (alapértelmezett)", diff --git a/packages/app/src/i18n/hy.ts b/packages/app/src/i18n/hy.ts index 6eac43b5e6dd..1c2a2ca9e957 100644 --- a/packages/app/src/i18n/hy.ts +++ b/packages/app/src/i18n/hy.ts @@ -883,6 +883,15 @@ export const dict = { "sidebar.project.clearNotifications": "Մաքրել ծանուցումները", "sidebar.empty.title": "Ոչ մի նախագիծ բաց", "sidebar.empty.description": "Բացեք նախագիծ՝ սկսելու համար", + "sidebar.settled": "Կարգավորված", + "sidebar.settle": "Թելը կարգավորել", + "sidebar.unsettle": "Թելը վերականգնել", + "sidebar.thread.new": "Նոր թել", + "sidebar.thread.pin": "Թելը գամել", + "sidebar.thread.unpin": "Գամը հանել", + "sidebar.status.working": "Աշխատում է", + "sidebar.status.done": "Պատրաստ է", + "sidebar.status.attention": "Պահանջում է ներածում", "debugBar.ariaLabel": "Զարգացման կատարողականի ախտորոշում", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -932,6 +941,12 @@ export const dict = { "settings.general.section.display": "Ցուցադրել", "settings.general.row.language.title": "Լեզու", "settings.general.row.language.description": "Փոխել ցուցադրման լեզուն OpenCode", + "settings.general.row.navigation.description": "Օգտագործեք ներդիրներ վերնագրի տողում կամ մշտական կողային վահանակ", + "settings.general.row.navigation.tabs": "Ներդիրներ", + "settings.general.row.navigation.sidebar": "Կողային վահանակ", + "settings.general.row.sidebarSessions.title": "Ոչ ակտիվ թելերը կարգավորելու ժամկետ", + "settings.general.row.sidebarSessions.description": "Ոչ ակտիվ թելերը տեղափոխվում են կարգավորվածներ։ Աշխատող թելերը մնում են տեսանելի։", + "settings.general.row.sidebarSessions.always": "Միշտ ցուցադրել", "settings.general.row.shell.title": "Տերմինալի Shell", "settings.general.row.shell.description": "Shell-ն օգտագործվում է տերմինալի և գործակալի գործիքների կողմից", "settings.general.row.shell.autoDefault": "Ավտոմատ (կանխադրված)", diff --git a/packages/app/src/i18n/id.ts b/packages/app/src/i18n/id.ts index 96dc3c7592e4..358b1a79867b 100644 --- a/packages/app/src/i18n/id.ts +++ b/packages/app/src/i18n/id.ts @@ -953,6 +953,15 @@ export const dict = { "sidebar.project.clearNotifications": "Hapus notifikasi", "sidebar.empty.title": "Tidak ada proyek terbuka", "sidebar.empty.description": "Buka proyek untuk memulai", + "sidebar.settled": "Diselesaikan", + "sidebar.settle": "Selesaikan thread", + "sidebar.unsettle": "Pulihkan thread", + "sidebar.thread.new": "Thread baru", + "sidebar.thread.pin": "Sematkan thread", + "sidebar.thread.unpin": "Lepaskan sematan", + "sidebar.status.working": "Sedang bekerja", + "sidebar.status.done": "Selesai", + "sidebar.status.attention": "Perlu masukan", "debugBar.ariaLabel": "Diagnostik kinerja pengembangan", "debugBar.na": "n/a", @@ -1005,6 +1014,12 @@ export const dict = { "settings.general.row.language.title": "Bahasa", "settings.general.row.language.description": "Ubah bahasa tampilan untuk OpenCode", + "settings.general.row.navigation.description": "Gunakan tab di bilah judul atau bilah sisi tetap", + "settings.general.row.navigation.tabs": "Tab", + "settings.general.row.navigation.sidebar": "Bilah sisi", + "settings.general.row.sidebarSessions.title": "Selesaikan thread menganggur setelah", + "settings.general.row.sidebarSessions.description": "Thread menganggur pindah ke Diselesaikan. Thread yang bekerja tetap terlihat.", + "settings.general.row.sidebarSessions.always": "Selalu tampilkan", "settings.general.row.shell.title": "Shell terminal", "settings.general.row.shell.description": "Shell yang digunakan oleh terminal dan alat agen", "settings.general.row.shell.autoDefault": "Otomatis (Bawaan)", diff --git a/packages/app/src/i18n/is.ts b/packages/app/src/i18n/is.ts index a45ed9a40cb0..ff20fac92667 100644 --- a/packages/app/src/i18n/is.ts +++ b/packages/app/src/i18n/is.ts @@ -880,6 +880,15 @@ export const dict = { "sidebar.project.clearNotifications": "Hreinsaðu tilkynningar", "sidebar.empty.title": "Engin verkefni opin", "sidebar.empty.description": "Opnaðu verkefni til að byrja", + "sidebar.settled": "Frágengin", + "sidebar.settle": "Fráganga þráð", + "sidebar.unsettle": "Enduropna þráð", + "sidebar.thread.new": "Nýr þráður", + "sidebar.thread.pin": "Festa þráð", + "sidebar.thread.unpin": "Losa þráð", + "sidebar.status.working": "Í vinnslu", + "sidebar.status.done": "Lokið", + "sidebar.status.attention": "Þarf inntak", "debugBar.ariaLabel": "Þróunarárangursgreiningar", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -927,6 +936,12 @@ export const dict = { "settings.general.section.display": "Skjár", "settings.general.row.language.title": "Tungumál", "settings.general.row.language.description": "Breyttu skjátungumálinu fyrir OpenCode", + "settings.general.row.navigation.description": "Nota flipa í titilstiku eða varanlega hliðarstiku", + "settings.general.row.navigation.tabs": "Flipar", + "settings.general.row.navigation.sidebar": "Hliðarstika", + "settings.general.row.sidebarSessions.title": "Fráganga óvirkja þræði eftir", + "settings.general.row.sidebarSessions.description": "Óvirkir þræði fara í frágengin. Virkir þræði haldast sýnilegir.", + "settings.general.row.sidebarSessions.always": "Sýna alltaf", "settings.general.row.shell.title": "Skel skjáhermis", "settings.general.row.shell.description": "Skelin sem skjáhermirinn og verkfæri fulltrúans nota", "settings.general.row.shell.autoDefault": "Sjálfvirkt (sjálfgefið)", diff --git a/packages/app/src/i18n/it.ts b/packages/app/src/i18n/it.ts index a093e11485a3..c33696371eff 100644 --- a/packages/app/src/i18n/it.ts +++ b/packages/app/src/i18n/it.ts @@ -796,6 +796,15 @@ export const dict = { "sidebar.project.clearNotifications": "Cancella notifiche", "sidebar.empty.title": "Nessun progetto aperto", "sidebar.empty.description": "Apri un progetto per iniziare", + "sidebar.settled": "Sistemati", + "sidebar.settle": "Sistema il thread", + "sidebar.unsettle": "Ripristina il thread", + "sidebar.thread.new": "Nuovo thread", + "sidebar.thread.pin": "Fissa il thread", + "sidebar.thread.unpin": "Rimuovi fissaggio", + "sidebar.status.working": "In lavorazione", + "sidebar.status.done": "Fatto", + "sidebar.status.attention": "Richiede input", "debugBar.ariaLabel": "Diagnostica delle prestazioni di sviluppo", "debugBar.na": "n/d", "debugBar.nav.label": "NAV", @@ -845,6 +854,12 @@ export const dict = { "settings.general.section.display": "Visualizzazione", "settings.general.row.language.title": "Lingua", "settings.general.row.language.description": "Cambia la lingua di visualizzazione per OpenCode", + "settings.general.row.navigation.description": "Usa schede nella barra del titolo o una barra laterale fissa", + "settings.general.row.navigation.tabs": "Schede", + "settings.general.row.navigation.sidebar": "Barra laterale", + "settings.general.row.sidebarSessions.title": "Sistema i thread inattivi dopo", + "settings.general.row.sidebarSessions.description": "I thread inattivi passano a Sistemati. I thread in lavorazione restano visibili.", + "settings.general.row.sidebarSessions.always": "Mostra sempre", "settings.general.row.shell.title": "Shell del terminale", "settings.general.row.shell.description": "Shell utilizzata dal terminale e dagli strumenti dell'agente", "settings.general.row.shell.autoDefault": "Automatico (predefinito)", diff --git a/packages/app/src/i18n/ja.ts b/packages/app/src/i18n/ja.ts index b96e8b544b2b..09516347df8b 100644 --- a/packages/app/src/i18n/ja.ts +++ b/packages/app/src/i18n/ja.ts @@ -815,6 +815,15 @@ export const dict = { "sidebar.project.clearNotifications": "通知をクリア", "sidebar.empty.title": "開いているプロジェクトはありません", "sidebar.empty.description": "プロジェクトを開いて始めましょう", + "sidebar.settled": "整理済み", + "sidebar.settle": "スレッドを整理", + "sidebar.unsettle": "スレッドを復元", + "sidebar.thread.new": "新しいスレッド", + "sidebar.thread.pin": "スレッドをピン留め", + "sidebar.thread.unpin": "ピン留めを解除", + "sidebar.status.working": "作業中", + "sidebar.status.done": "完了", + "sidebar.status.attention": "入力が必要", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "デスクトップ", "settings.section.server": "サーバー", @@ -832,6 +841,12 @@ export const dict = { "settings.general.section.display": "ディスプレイ", "settings.general.row.language.title": "言語", "settings.general.row.language.description": "OpenCodeの表示言語を変更します", + "settings.general.row.navigation.description": "タイトルバーのタブまたは常時表示のサイドバーを使用します", + "settings.general.row.navigation.tabs": "タブ", + "settings.general.row.navigation.sidebar": "サイドバー", + "settings.general.row.sidebarSessions.title": "無操作のスレッドを整理するまでの期間", + "settings.general.row.sidebarSessions.description": "無操作のスレッドは整理済みに移動します。作業中のスレッドは表示されたままです。", + "settings.general.row.sidebarSessions.always": "常に表示", "settings.general.row.shell.title": "ターミナルシェル", "settings.general.row.shell.description": "ターミナルで使用するシェルを選択します。互換性のあるシェルはエージェントのツール呼び出しにも使用されます。", diff --git a/packages/app/src/i18n/ka.ts b/packages/app/src/i18n/ka.ts index be052930a2ec..d339d34e89ee 100644 --- a/packages/app/src/i18n/ka.ts +++ b/packages/app/src/i18n/ka.ts @@ -876,6 +876,15 @@ export const dict = { "sidebar.project.clearNotifications": "შეტყობინებების გასუფთავება", "sidebar.empty.title": "პროექტები არ არის გახსნილი", "sidebar.empty.description": "გახსენით პროექტი დასაწყებად", + "sidebar.settled": "მოწესრიგებული", + "sidebar.settle": "თემის მოწესრიგება", + "sidebar.unsettle": "თემის აღდგენა", + "sidebar.thread.new": "ახალი თემა", + "sidebar.thread.pin": "თემის მიმაგრება", + "sidebar.thread.unpin": "მიმაგრების მოხსნა", + "sidebar.status.working": "მუშაობს", + "sidebar.status.done": "შესრულდა", + "sidebar.status.attention": "საჭიროებს შეყვანას", "debugBar.ariaLabel": "განვითარების შესრულების დიაგნოსტიკა", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -924,6 +933,12 @@ export const dict = { "settings.general.section.display": "ჩვენება", "settings.general.row.language.title": "ენა", "settings.general.row.language.description": "შეცვალეთ ჩვენების ენა OpenCode", + "settings.general.row.navigation.description": "გამოიყენეთ ჩანართები სათაურის ზოლში ან მუდმივი გვერდითი პანელი", + "settings.general.row.navigation.tabs": "ჩანართები", + "settings.general.row.navigation.sidebar": "გვერდითი პანელი", + "settings.general.row.sidebarSessions.title": "უმოქმედო თემების მოწესრიგების ვადა", + "settings.general.row.sidebarSessions.description": "უმოქმედო თემები გადადის მოწესრიგებულებში. მომუშავე თემები ხილული რჩება.", + "settings.general.row.sidebarSessions.always": "ყოველთვის ჩვენება", "settings.general.row.shell.title": "ტერმინალის გარსი", "settings.general.row.shell.description": "Shell გამოიყენება ტერმინალის და აგენტის ხელსაწყოების მიერ", "settings.general.row.shell.autoDefault": "ავტომატური (ნაგულისხმევი)", diff --git a/packages/app/src/i18n/km.ts b/packages/app/src/i18n/km.ts index 7f1b61fe3667..682a6d0a05cb 100644 --- a/packages/app/src/i18n/km.ts +++ b/packages/app/src/i18n/km.ts @@ -873,6 +873,15 @@ export const dict = { "sidebar.project.clearNotifications": "ជម្រះការជូនដំណឹង", "sidebar.empty.title": "គ្មានគម្រោងបើកទេ។", "sidebar.empty.description": "បើកគម្រោងដើម្បីចាប់ផ្តើម", + "sidebar.settled": "បានសម្រាក", + "sidebar.settle": "សម្រាកសន្ទនា", + "sidebar.unsettle": "ដកការសម្រាកសន្ទនា", + "sidebar.thread.new": "សន្ទនាថ្មី", + "sidebar.thread.pin": "ខ្ទាស់សន្ទនា", + "sidebar.thread.unpin": "ដកខ្ទាស់សន្ទនា", + "sidebar.status.working": "កំពុងធ្វើការ", + "sidebar.status.done": "រួចរាល់", + "sidebar.status.attention": "ត្រូវការការបញ្ចូល", "debugBar.ariaLabel": "ការវិនិច្ឆ័យដំណើរការអភិវឌ្ឍន៍", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -922,6 +931,12 @@ export const dict = { "settings.general.section.display": "បង្ហាញ", "settings.general.row.language.title": "ភាសា", "settings.general.row.language.description": "ប្តូរភាសាបង្ហាញសម្រាប់ OpenCode", + "settings.general.row.navigation.description": "ប្រើផ្ទាំងក្នុងរបារចំណងជើង ឬរបារចំហៀងអចិន្ត្រៃយ៍", + "settings.general.row.navigation.tabs": "ផ្ទាំង", + "settings.general.row.navigation.sidebar": "របារចំហៀង", + "settings.general.row.sidebarSessions.title": "សម្រាកសន្ទនាដែលស្ងាត់បន្ទាប់ពី", + "settings.general.row.sidebarSessions.description": "សន្ទនាដែលស្ងាត់នឹងផ្លាស់ទៅកន្លែងសម្រាក។ សន្ទនាដែលកំពុងធ្វើការនៅតែបង្ហាញ។", + "settings.general.row.sidebarSessions.always": "បង្ហាញជានិច្ច", "settings.general.row.shell.title": "សែលស្ថានីយ", "settings.general.row.shell.description": "សែលប្រើដោយឧបករណ៍ស្ថានីយ និងភ្នាក់ងារ", "settings.general.row.shell.autoDefault": "ស្វ័យប្រវត្តិ (លំនាំដើម)\nស្ថានីយ", diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts index b96fb4c59471..c30733b20747 100644 --- a/packages/app/src/i18n/ko.ts +++ b/packages/app/src/i18n/ko.ts @@ -592,6 +592,12 @@ export const dict = { "settings.general.section.display": "디스플레이", "settings.general.row.language.title": "언어", "settings.general.row.language.description": "OpenCode 표시 언어 변경", + "settings.general.row.navigation.description": "제목 표시줄 탭 또는 고정 사이드바 사용", + "settings.general.row.navigation.tabs": "탭", + "settings.general.row.navigation.sidebar": "사이드바", + "settings.general.row.sidebarSessions.title": "유휴 스레드 정리 기준 시간", + "settings.general.row.sidebarSessions.description": "유휴 스레드는 정리됨으로 이동합니다. 작업 중인 스레드는 계속 표시됩니다.", + "settings.general.row.sidebarSessions.always": "항상 표시", "settings.general.row.appearance.title": "모양", "settings.general.row.appearance.description": "기기에서 OpenCode가 보이는 방식 사용자 지정", "settings.general.row.colorScheme.title": "색상 테마", @@ -1016,6 +1022,15 @@ export const dict = { "sidebar.empty.title": "열린 프로젝트 없음", "sidebar.empty.description": "프로젝트를 열어 시작하세요", + "sidebar.settled": "정리됨", + "sidebar.settle": "스레드 정리", + "sidebar.unsettle": "스레드 복원", + "sidebar.thread.new": "새 스레드", + "sidebar.thread.pin": "스레드 고정", + "sidebar.thread.unpin": "스레드 고정 해제", + "sidebar.status.working": "작업 중", + "sidebar.status.done": "완료", + "sidebar.status.attention": "입력 필요", "settings.general.section.advanced": "고급", "settings.general.row.shell.title": "터미널 셸", diff --git a/packages/app/src/i18n/lo.ts b/packages/app/src/i18n/lo.ts index acdc26df08aa..a3fb1893da5d 100644 --- a/packages/app/src/i18n/lo.ts +++ b/packages/app/src/i18n/lo.ts @@ -871,6 +871,15 @@ export const dict = { "sidebar.project.clearNotifications": "ລຶບການແຈ້ງເຕືອນ", "sidebar.empty.title": "ບໍ່ມີໂຄງການເປີດ", "sidebar.empty.description": "ເປີດໂຄງການເພື່ອເລີ່ມຕົ້ນ", + "sidebar.settled": "ທີ່ພັກໄວ້", + "sidebar.settle": "ພັກເຣັດ", + "sidebar.unsettle": "ຍົກເລີກການພັກເຣັດ", + "sidebar.thread.new": "ເຣັດໃໝ່", + "sidebar.thread.pin": "ປັກໝຸດເຣັດ", + "sidebar.thread.unpin": "ຍົກເລີກການປັກໝຸດ", + "sidebar.status.working": "ກຳລັງເຮັດວຽກ", + "sidebar.status.done": "ສຳເລັດ", + "sidebar.status.attention": "ຕ້ອງການຂໍ້ມູນປ້ອນ", "debugBar.ariaLabel": "ການວິນິດໄສປະສິດທິພາບການພັດທະນາ", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -919,6 +928,12 @@ export const dict = { "settings.general.section.display": "ຈໍສະແດງຜົນ", "settings.general.row.language.title": "ພາສາ", "settings.general.row.language.description": "ປ່ຽນພາສາສະແດງສໍາລັບ OpenCode", + "settings.general.row.navigation.description": "ໃຊ້ແຖບຢູ່ແຖບຫົວຂໍ້ ຫຼືແຖບດ້ານຂ້າງຖາວອນ", + "settings.general.row.navigation.tabs": "ແຖບ", + "settings.general.row.navigation.sidebar": "ແຖບດ້ານຂ້າງ", + "settings.general.row.sidebarSessions.title": "ພັກເຣັດທີ່ງຽບຫຼັງຈາກ", + "settings.general.row.sidebarSessions.description": "ເຣັດທີ່ງຽບຈະຍ້າຍໄປທີ່ພັກໄວ້. ເັດທີ່ກລັງເຮັດວຽກຍັງສະແດງຢູ່.", + "settings.general.row.sidebarSessions.always": "ສະແດງສະເໝີ", "settings.general.row.shell.title": "Shell ຂອງເທີມິນອນ", "settings.general.row.shell.description": "Shell ທີ່ໃຊ້ໂດຍເຄື່ອງໃຊ້ປາຍທາງ ແລະຕົວແທນ", "settings.general.row.shell.autoDefault": "ອັດຕະໂນມັດ (ຄ່າເລີ່ມຕົ້ນ)", diff --git a/packages/app/src/i18n/lt.ts b/packages/app/src/i18n/lt.ts index ba161eb31879..dbd2a23bfa33 100644 --- a/packages/app/src/i18n/lt.ts +++ b/packages/app/src/i18n/lt.ts @@ -890,6 +890,15 @@ export const dict = { "sidebar.project.clearNotifications": "Išvalyti pranešimus", "sidebar.empty.title": "Jokių atvirų projektų", "sidebar.empty.description": "Norėdami pradėti, atidarykite projektą", + "sidebar.settled": "Sutvarkytos", + "sidebar.settle": "Sutvarkyti giją", + "sidebar.unsettle": "Atkurti giją", + "sidebar.thread.new": "Nauja gija", + "sidebar.thread.pin": "Prisegti giją", + "sidebar.thread.unpin": "Atsegti giją", + "sidebar.status.working": "Veikia", + "sidebar.status.done": "Atlikta", + "sidebar.status.attention": "Reikia įvesties", "debugBar.ariaLabel": "Vystymosi veiklos diagnostika", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -939,6 +948,12 @@ export const dict = { "settings.general.section.display": "Ekranas", "settings.general.row.language.title": "Kalba", "settings.general.row.language.description": "Pakeiskite OpenCode ekrano kalbą", + "settings.general.row.navigation.description": "Naudoti skirtukus pavadinimo juostoje arba nuolatinę šoninę juostą", + "settings.general.row.navigation.tabs": "Skirtukai", + "settings.general.row.navigation.sidebar": "Šoninė juosta", + "settings.general.row.sidebarSessions.title": "Sutvarkyti neveiklias gijas po", + "settings.general.row.sidebarSessions.description": "Neveiklios gijos perkeliamos į sutvarkytas. Veikiančios gijos lieka matomos.", + "settings.general.row.sidebarSessions.always": "Visada rodyti", "settings.general.row.shell.title": "Terminalo apvalkalas", "settings.general.row.shell.description": "Terminalo ir agento įrankių naudojamas apvalkalas", "settings.general.row.shell.autoDefault": "Automatinis (numatytasis)", diff --git a/packages/app/src/i18n/lv.ts b/packages/app/src/i18n/lv.ts index df4c5b2dcd91..dc79c14b7071 100644 --- a/packages/app/src/i18n/lv.ts +++ b/packages/app/src/i18n/lv.ts @@ -882,6 +882,15 @@ export const dict = { "sidebar.project.clearNotifications": "Notīrīt paziņojumus", "sidebar.empty.title": "Nav atvērts neviens projekts", "sidebar.empty.description": "Atveriet projektu, lai sāktu", + "sidebar.settled": "Nokārtotās", + "sidebar.settle": "Nokārtot pavedienu", + "sidebar.unsettle": "Atjaunot pavedienu", + "sidebar.thread.new": "Jauns pavediens", + "sidebar.thread.pin": "Piespraust pavedienu", + "sidebar.thread.unpin": "Atspraust pavedienu", + "sidebar.status.working": "Strādā", + "sidebar.status.done": "Gatavs", + "sidebar.status.attention": "Nepieciešama ievade", "debugBar.ariaLabel": "Izstrādes veiktspējas diagnostika", "debugBar.na": "nav", "debugBar.nav.label": "NAV", @@ -930,6 +939,12 @@ export const dict = { "settings.general.section.display": "Displejs", "settings.general.row.language.title": "Valoda", "settings.general.row.language.description": "Mainīt OpenCode saskarnes valodu", + "settings.general.row.navigation.description": "Izmantot cilnes virsraksta joslā vai pastāvīgu sānjoslu", + "settings.general.row.navigation.tabs": "Cilnes", + "settings.general.row.navigation.sidebar": "Sānjosla", + "settings.general.row.sidebarSessions.title": "Nokārtot neaktīvos pavedienus pēc", + "settings.general.row.sidebarSessions.description": "Neaktīvie pavedieni pāriet uz nokārtotajiem. Strādājošie pavedieni paliek redzami.", + "settings.general.row.sidebarSessions.always": "Rādīt vienmēr", "settings.general.row.shell.title": "Termināļa čaula", "settings.general.row.shell.description": "Čaula, ko izmanto terminālis un aģenta rīki", "settings.general.row.shell.autoDefault": "Automātiski (noklusējums)", diff --git a/packages/app/src/i18n/mk.ts b/packages/app/src/i18n/mk.ts index 01e60baa408b..9a504725138f 100644 --- a/packages/app/src/i18n/mk.ts +++ b/packages/app/src/i18n/mk.ts @@ -880,6 +880,15 @@ export const dict = { "sidebar.project.clearNotifications": "Исчистете ги известувањата", "sidebar.empty.title": "Нема отворени проекти", "sidebar.empty.description": "Отворете проект за да започнете", + "sidebar.settled": "Одложени", + "sidebar.settle": "Одложи нишка", + "sidebar.unsettle": "Врати нишка", + "sidebar.thread.new": "Нова нишка", + "sidebar.thread.pin": "Прикачи нишка", + "sidebar.thread.unpin": "Откачи нишка", + "sidebar.status.working": "Во тек", + "sidebar.status.done": "Готово", + "sidebar.status.attention": "Потребен е внес", "debugBar.ariaLabel": "Дијагностика на перформансите на развојот", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -929,6 +938,12 @@ export const dict = { "settings.general.section.display": "Приказ", "settings.general.row.language.title": "Јазик", "settings.general.row.language.description": "Променете го јазикот на прикажување за OpenCode", + "settings.general.row.navigation.description": "Користете картички во насловната лента или постојана странична лента", + "settings.general.row.navigation.tabs": "Картички", + "settings.general.row.navigation.sidebar": "Странична лента", + "settings.general.row.sidebarSessions.title": "Одложи неактивни нишки по", + "settings.general.row.sidebarSessions.description": "Неактивните нишки преминуваат во одложени. Активните нишки остануваат видливи.", + "settings.general.row.sidebarSessions.always": "Секогаш прикажувај", "settings.general.row.shell.title": "Терминал shell", "settings.general.row.shell.description": "Школката ја користат алатките за терминал и агент", "settings.general.row.shell.autoDefault": "Автоматски (стандардно)", diff --git a/packages/app/src/i18n/mn.ts b/packages/app/src/i18n/mn.ts index 41c4fa085d1a..671cacf51bd5 100644 --- a/packages/app/src/i18n/mn.ts +++ b/packages/app/src/i18n/mn.ts @@ -884,6 +884,15 @@ export const dict = { "sidebar.project.clearNotifications": "Мэдэгдлийг арилгах", "sidebar.empty.title": "Нээлттэй төсөл байхгүй", "sidebar.empty.description": "Эхлэхийн тулд төсөл нээнэ үү", + "sidebar.settled": "Намссан", + "sidebar.settle": "Хэлэлцүүлгийг намсаах", + "sidebar.unsettle": "Хэлэлцүүлгийг сэргээх", + "sidebar.thread.new": "Шинэ хэлэлцүүлэг", + "sidebar.thread.pin": "Хэлэлцүүлгийг зүүэх", + "sidebar.thread.unpin": "Зүүсийг авах", + "sidebar.status.working": "Ажиллаж байна", + "sidebar.status.done": "Дууссан", + "sidebar.status.attention": "Оролт шаардлагатай", "debugBar.ariaLabel": "Хөгжлийн гүйцэтгэлийн оношлогоо", "debugBar.na": "үгүй", "debugBar.nav.label": "NAV", @@ -932,6 +941,12 @@ export const dict = { "settings.general.section.display": "Дэлгэц", "settings.general.row.language.title": "Хэл", "settings.general.row.language.description": "OpenCode дэлгэцийн хэлийг өөрчлөх", + "settings.general.row.navigation.description": "Гарчгийн мөрөнд таб ашиглах эсвэл байнгын хажуу самбар", + "settings.general.row.navigation.tabs": "Табууд", + "settings.general.row.navigation.sidebar": "Хажуу самбар", + "settings.general.row.sidebarSessions.title": "Идэвхгүй хэлэлцүүлгийг намсаах хугацаа", + "settings.general.row.sidebarSessions.description": "Идэвхгүй хэлэлцүүлэг намссан руу шилжинэ. Ажиллаж буй хэлэлцүүлэг харагдсаар байна.", + "settings.general.row.sidebarSessions.always": "Үргэлж харуулах", "settings.general.row.shell.title": "Терминал shell", "settings.general.row.shell.description": "Shell нь терминал болон агентын хэрэгслүүдэд ашиглагддаг", "settings.general.row.shell.autoDefault": "Автомат (Өгөгдмөл)", diff --git a/packages/app/src/i18n/ms.ts b/packages/app/src/i18n/ms.ts index 2c3783d43b7d..9e1e878896b4 100644 --- a/packages/app/src/i18n/ms.ts +++ b/packages/app/src/i18n/ms.ts @@ -876,6 +876,15 @@ export const dict = { "sidebar.project.clearNotifications": "Kosongkan notifikasi", "sidebar.empty.title": "Tiada projek dibuka", "sidebar.empty.description": "Buka projek untuk bermula", + "sidebar.settled": "Selesai", + "sidebar.settle": "Selesaikan bebenang", + "sidebar.unsettle": "Pulihkan bebenang", + "sidebar.thread.new": "Bebenang baharu", + "sidebar.thread.pin": "Sematkan bebenang", + "sidebar.thread.unpin": "Nyahsematkan bebenang", + "sidebar.status.working": "Sedang bekerja", + "sidebar.status.done": "Siap", + "sidebar.status.attention": "Perlu input", "debugBar.ariaLabel": "Diagnostik prestasi pembangunan", "debugBar.na": "tiada", "debugBar.nav.label": "NAV", @@ -924,6 +933,12 @@ export const dict = { "settings.general.section.display": "Paparan", "settings.general.row.language.title": "Bahasa", "settings.general.row.language.description": "Tukar bahasa paparan untuk OpenCode", + "settings.general.row.navigation.description": "Guna tab pada bar tajuk atau bar sisi kekal", + "settings.general.row.navigation.tabs": "Tab", + "settings.general.row.navigation.sidebar": "Bar sisi", + "settings.general.row.sidebarSessions.title": "Selesaikan bebenang terbiar selepas", + "settings.general.row.sidebarSessions.description": "Bebenang terbiar berpindah ke Selesai. Bebenang yang bekerja kekal kelihatan.", + "settings.general.row.sidebarSessions.always": "Sentiasa tunjuk", "settings.general.row.shell.title": "Shell terminal", "settings.general.row.shell.description": "Shell yang digunakan oleh terminal dan alat ejen", "settings.general.row.shell.autoDefault": "Auto (Lalai)", diff --git a/packages/app/src/i18n/my.ts b/packages/app/src/i18n/my.ts index 6046f337ff06..acba84762967 100644 --- a/packages/app/src/i18n/my.ts +++ b/packages/app/src/i18n/my.ts @@ -886,6 +886,15 @@ export const dict = { "sidebar.project.clearNotifications": "အကြောင်းကြားချက်များကို ရှင်းလင်းပါ။", "sidebar.empty.title": "မည်သည့်ပရောဂျက်မှ ဖွင့်ထားခြင်းမရှိပါ။", "sidebar.empty.description": "စတင်ရန် ပရောဂျက်တစ်ခုကို ဖွင့်ပါ။", + "sidebar.settled": "အနားယူထားသည်", + "sidebar.settle": "ဆွေးနွေးမှုကို အနားယူစေ", + "sidebar.unsettle": "အနားယူခြင်းကို ပယ်ဖျက်", + "sidebar.thread.new": "ဆွေးနွေးမှုအသစ်", + "sidebar.thread.pin": "ဆွေးနွေးမှုကို ပင်ထိုး", + "sidebar.thread.unpin": "ပင်ထိုးခြင်းကို ဖယ်ရှား", + "sidebar.status.working": "လုပ်ဆောင်နေသည်", + "sidebar.status.done": "ပြီးစီး", + "sidebar.status.attention": "အဝင်လိုအပ်သည်", "debugBar.ariaLabel": "ဖွံ့ဖြိုးတိုးတက်မှု စွမ်းဆောင်ရည် အဖြေရှာခြင်း", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -937,6 +946,12 @@ export const dict = { "settings.general.section.display": "မျက်နှာပြင်", "settings.general.row.language.title": "ဘာသာစကား", "settings.general.row.language.description": "OpenCode အတွက် ဖော်ပြသည့် ဘာသာစကားကို ပြောင်းပါ။", + "settings.general.row.navigation.description": "ခေါင်းစီးတန်းတွင် တဘ်များ သို့မဟုတ် အမြဲတမ်း ဘေးတန်း သုံးပါ", + "settings.general.row.navigation.tabs": "တဘ်များ", + "settings.general.row.navigation.sidebar": "ဘေးတန်း", + "settings.general.row.sidebarSessions.title": "အသုံးမပြုသော ဆွေးနွေးမှုများ အနားယူစေရန် အချိန်", + "settings.general.row.sidebarSessions.description": "အသုံးမပြုသော ဆွေးနွေးမှုများသည် အနားယူထားသည်ထဲသို့ ရွှေ့မည်။ လုပ်ဆောင်နေသော ဆွေးနွေးမှုများ ဆက်ပြနေမည်။", + "settings.general.row.sidebarSessions.always": "အမြဲပြသ", "settings.general.row.shell.title": "Terminal Shell", "settings.general.row.shell.description": "terminal နှင့် agent tools မှအသုံးပြုသော Shell", "settings.general.row.shell.autoDefault": "အလိုအလျောက် (ပုံသေ)", diff --git a/packages/app/src/i18n/ne.ts b/packages/app/src/i18n/ne.ts index cc60bff9f400..5f106482334f 100644 --- a/packages/app/src/i18n/ne.ts +++ b/packages/app/src/i18n/ne.ts @@ -877,6 +877,15 @@ export const dict: Record = { "sidebar.project.clearNotifications": "सूचनाहरू खाली गर्नुहोस्", "sidebar.empty.title": "कुनै पनि आयोजना खुलेका छैनन्", "sidebar.empty.description": "सुरु गर्न एउटा परियोजना खोल्नुहोस्", + "sidebar.settled": "टुंग्याइएका", + "sidebar.settle": "थ्रेड टुंग्याउनुहोस्", + "sidebar.unsettle": "थ्रेड पुनः खोल्नुहोस्", + "sidebar.thread.new": "नयाँ थ्रेड", + "sidebar.thread.pin": "थ्रेड पिन गर्नुहोस्", + "sidebar.thread.unpin": "पिन हटाउनुहोस्", + "sidebar.status.working": "काम हुँदै", + "sidebar.status.done": "सम्पन्न", + "sidebar.status.attention": "इनपुट आवश्यक", "debugBar.ariaLabel": "विकास प्रदर्शन निदान", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -924,6 +933,12 @@ export const dict: Record = { "settings.general.section.display": "प्रदर्शन", "settings.general.row.language.title": "भाषा", "settings.general.row.language.description": "OpenCode को लागि प्रदर्शन भाषा परिवर्तन गर्नुहोस्", + "settings.general.row.navigation.description": "शीर्षक पट्टीमा ट्याब वा स्थायी साइडबार प्रयोग गर्नुहोस्", + "settings.general.row.navigation.tabs": "ट्याबहरू", + "settings.general.row.navigation.sidebar": "साइडबार", + "settings.general.row.sidebarSessions.title": "निष्क्रिय थ्रेड टुंग्याउने समय", + "settings.general.row.sidebarSessions.description": "निष्क्रिय थ्रेड टुंग्याइएका मा जान्छन्। काम भइरहेका थ्रेड देखि रहन्छन्।", + "settings.general.row.sidebarSessions.always": "सधैँ देखाउनुहोस्", "settings.general.row.shell.title": "टर्मिनल शेल", "settings.general.row.shell.description": "टर्मिनल र एजेन्ट उपकरणहरू द्वारा प्रयोग गरिएको शेल", "settings.general.row.shell.autoDefault": "स्वतः (पूर्वनिर्धारित)", diff --git a/packages/app/src/i18n/nl.ts b/packages/app/src/i18n/nl.ts index 6fb1dc09f24b..0eaca3ec4281 100644 --- a/packages/app/src/i18n/nl.ts +++ b/packages/app/src/i18n/nl.ts @@ -886,6 +886,15 @@ export const dict = { "sidebar.project.clearNotifications": "Meldingen wissen", "sidebar.empty.title": "Geen projecten geopend", "sidebar.empty.description": "Open een project om aan de slag te gaan", + "sidebar.settled": "Afgerond", + "sidebar.settle": "Thread afronden", + "sidebar.unsettle": "Thread herstellen", + "sidebar.thread.new": "Nieuwe thread", + "sidebar.thread.pin": "Thread vastmaken", + "sidebar.thread.unpin": "Thread losmaken", + "sidebar.status.working": "Bezig", + "sidebar.status.done": "Klaar", + "sidebar.status.attention": "Invoer nodig", "debugBar.ariaLabel": "Diagnostiek voor ontwikkelprestaties", "debugBar.na": "n.v.t.", "debugBar.nav.label": "NAV", @@ -934,6 +943,12 @@ export const dict = { "settings.general.section.display": "Weergave", "settings.general.row.language.title": "Taal", "settings.general.row.language.description": "Wijzig de weergavetaal voor OpenCode", + "settings.general.row.navigation.description": "Gebruik tabbladen in de titelbalk of een vaste zijbalk", + "settings.general.row.navigation.tabs": "Tabbladen", + "settings.general.row.navigation.sidebar": "Zijbalk", + "settings.general.row.sidebarSessions.title": "Inactieve threads afronden na", + "settings.general.row.sidebarSessions.description": "Inactieve threads gaan naar Afgerond. Actieve threads blijven zichtbaar.", + "settings.general.row.sidebarSessions.always": "Altijd tonen", "settings.general.row.shell.title": "Terminalshell", "settings.general.row.shell.description": "Shell gebruikt door de terminal- en agenttools", "settings.general.row.shell.autoDefault": "Automatisch (standaard)", diff --git a/packages/app/src/i18n/no.ts b/packages/app/src/i18n/no.ts index 11958029dc38..0a4830576ac3 100644 --- a/packages/app/src/i18n/no.ts +++ b/packages/app/src/i18n/no.ts @@ -774,6 +774,12 @@ export const dict = { "settings.general.row.language.title": "Språk", "settings.general.row.language.description": "Endre visningsspråket for OpenCode", + "settings.general.row.navigation.description": "Bruk faner i tittellinjen eller et fast sidefelt", + "settings.general.row.navigation.tabs": "Faner", + "settings.general.row.navigation.sidebar": "Sidefelt", + "settings.general.row.sidebarSessions.title": "Avslutt inaktive tråder etter", + "settings.general.row.sidebarSessions.description": "Inaktive tråder flyttes til Avsluttede. Aktive tråder forblir synlige.", + "settings.general.row.sidebarSessions.always": "Vis alltid", "settings.general.row.appearance.title": "Utseende", "settings.general.row.appearance.description": "Tilpass hvordan OpenCode ser ut på enheten din", "settings.general.row.colorScheme.title": "Fargevalg", @@ -1229,6 +1235,15 @@ export const dict = { "sidebar.empty.title": "Ingen åpne prosjekter", "sidebar.empty.description": "Åpne et prosjekt for å komme i gang", + "sidebar.settled": "Avsluttede", + "sidebar.settle": "Avslutt tråd", + "sidebar.unsettle": "Gjenåpne tråd", + "sidebar.thread.new": "Ny tråd", + "sidebar.thread.pin": "Fest tråd", + "sidebar.thread.unpin": "Løsne tråd", + "sidebar.status.working": "Arbeider", + "sidebar.status.done": "Ferdig", + "sidebar.status.attention": "Trenger inndata", "settings.general.section.advanced": "Avansert", "settings.general.row.shell.title": "Terminalskall", diff --git a/packages/app/src/i18n/pa.ts b/packages/app/src/i18n/pa.ts index 6298581c0aab..41680bc32de5 100644 --- a/packages/app/src/i18n/pa.ts +++ b/packages/app/src/i18n/pa.ts @@ -884,6 +884,15 @@ export const dict = { "sidebar.project.clearNotifications": "نوٹیفکیشن صاف کرو", "sidebar.empty.title": "کوئی پروجیکٹ نئیں کھلیا", "sidebar.empty.description": "شروع کرن لئی کوئی پروجیکٹ کھولو", + "sidebar.settled": "ਨਿਪਟਾਏ ਗਏ", + "sidebar.settle": "ਥਰੈਡ ਨਿਪਟਾਓ", + "sidebar.unsettle": "ਥਰੈਡ ਬਹਾਲ ਕਰੋ", + "sidebar.thread.new": "ਨਵਾਂ ਥਰੈਡ", + "sidebar.thread.pin": "ਥਰੈਡ ਪਿੰਨ ਕਰੋ", + "sidebar.thread.unpin": "ਪਿੰਨ ਹਟਾਓ", + "sidebar.status.working": "ਕੰਮ ਚੱਲ ਰਿਹਾ", + "sidebar.status.done": "ਮੁਕੰਮਲ", + "sidebar.status.attention": "ਇਨਪੁਟ ਚਾਹੀਦਾ", "debugBar.ariaLabel": "ترقی دی کارکردگی دی تشخیص", "debugBar.na": "لاگو نئیں", "debugBar.nav.label": "NAV", @@ -931,6 +940,12 @@ export const dict = { "settings.general.section.display": "ڈسپلے", "settings.general.row.language.title": "بولی", "settings.general.row.language.description": "OpenCode لئی ڈسپلے دی بولی بدلو", + "settings.general.row.navigation.description": "ਟਾਈਟਲ ਬਾਰ ਵਿੱਚ ਟੈਬਾਂ ਜਾਂ ਸਥਾਈ ਸਾਈਡਬਾਰ ਵਰਤੋ", + "settings.general.row.navigation.tabs": "ਟੈਬਾਂ", + "settings.general.row.navigation.sidebar": "ਸਾਈਡਬਾਰ", + "settings.general.row.sidebarSessions.title": "ਬੇਕਾਰ ਥਰੈਡ ਨਿਪਟਾਉਣ ਦਾ ਸਮਾਂ", + "settings.general.row.sidebarSessions.description": "ਬੇਕਾਰ ਥਰੈਡ ਨਿਪਟਾਏ ਗਏ ਵਿੱਚ ਚਲੇ ਜਾਂਦੇ ਹਨ। ਕੰਮ ਕਰਦੇ ਥਰੈਡ ਦਿਖਦੇ ਰਹਿੰਦੇ ਹਨ।", + "settings.general.row.sidebarSessions.always": "ਹਮੇਸ਼ਾ ਦਿਖਾਓ", "settings.general.row.shell.title": "شیل", "settings.general.row.shell.description": "Shell ٹرمینل تے ایجنٹ ٹولز دے ذریعہ استعمال کیتا جاندا اے", "settings.general.row.shell.autoDefault": "آٹو (پہلے توں طے شدہ)", diff --git a/packages/app/src/i18n/pl.ts b/packages/app/src/i18n/pl.ts index 9b3c927498d8..4180ef09552a 100644 --- a/packages/app/src/i18n/pl.ts +++ b/packages/app/src/i18n/pl.ts @@ -831,6 +831,15 @@ export const dict = { "sidebar.project.clearNotifications": "Wyczyść powiadomienia", "sidebar.empty.title": "Brak otwartych projektów", "sidebar.empty.description": "Otwórz projekt, aby rozpocząć", + "sidebar.settled": "Odłożone", + "sidebar.settle": "Odłóż wątek", + "sidebar.unsettle": "Przywróć wątek", + "sidebar.thread.new": "Nowy wątek", + "sidebar.thread.pin": "Przypnij wątek", + "sidebar.thread.unpin": "Odepnij wątek", + "sidebar.status.working": "W trakcie", + "sidebar.status.done": "Gotowe", + "sidebar.status.attention": "Wymaga danych", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "Aplikacja komputerowa", "settings.section.server": "Serwer", @@ -848,6 +857,12 @@ export const dict = { "settings.general.section.display": "Ekran", "settings.general.row.language.title": "Język", "settings.general.row.language.description": "Zmień język wyświetlania dla OpenCode", + "settings.general.row.navigation.description": "Używaj kart na pasku tytułu lub stałego paska bocznego", + "settings.general.row.navigation.tabs": "Karty", + "settings.general.row.navigation.sidebar": "Pasek boczny", + "settings.general.row.sidebarSessions.title": "Odkładaj nieaktywne wątki po", + "settings.general.row.sidebarSessions.description": "Nieaktywne wątki trafiają do odłożonych. Aktywne wątki pozostają widoczne.", + "settings.general.row.sidebarSessions.always": "Zawsze pokazuj", "settings.general.row.shell.title": "Powłoka terminala", "settings.general.row.shell.description": "Wybierz powłokę używaną w terminalu. Zgodne powłoki są również używane przez wywołania narzędzi agenta.", diff --git a/packages/app/src/i18n/ro.ts b/packages/app/src/i18n/ro.ts index c84f9a4ee76e..2ad3d49fa8b9 100644 --- a/packages/app/src/i18n/ro.ts +++ b/packages/app/src/i18n/ro.ts @@ -881,6 +881,15 @@ export const dict = { "sidebar.project.clearNotifications": "Șterge notificările", "sidebar.empty.title": "Niciun proiect deschis", "sidebar.empty.description": "Deschide un proiect pentru a începe", + "sidebar.settled": "Încheiate", + "sidebar.settle": "Încheie firul", + "sidebar.unsettle": "Redeschide firul", + "sidebar.thread.new": "Fir nou", + "sidebar.thread.pin": "Fixează firul", + "sidebar.thread.unpin": "Anulează fixarea", + "sidebar.status.working": "Lucrează", + "sidebar.status.done": "Gata", + "sidebar.status.attention": "Necesită introducere", "debugBar.ariaLabel": "Diagnosticare performanță dezvoltare", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -929,6 +938,12 @@ export const dict = { "settings.general.section.display": "Afișare", "settings.general.row.language.title": "Limbă", "settings.general.row.language.description": "Schimbă limba de afișare pentru OpenCode", + "settings.general.row.navigation.description": "Folosește file în bara de titlu sau o bară laterală permanentă", + "settings.general.row.navigation.tabs": "File", + "settings.general.row.navigation.sidebar": "Bară laterală", + "settings.general.row.sidebarSessions.title": "Încheie firele inactive după", + "settings.general.row.sidebarSessions.description": "Firele inactive trec la încheiate. Firele active rămân vizibile.", + "settings.general.row.sidebarSessions.always": "Afișează mereu", "settings.general.row.shell.title": "Shell terminal", "settings.general.row.shell.description": "Shell folosit de terminal și instrumentele agentului", "settings.general.row.shell.autoDefault": "Auto (implicit)", diff --git a/packages/app/src/i18n/ru.ts b/packages/app/src/i18n/ru.ts index cf4fa8d8f4ca..135b6be0bc0f 100644 --- a/packages/app/src/i18n/ru.ts +++ b/packages/app/src/i18n/ru.ts @@ -894,6 +894,15 @@ export const dict = { "sidebar.project.clearNotifications": "Очистить уведомления", "sidebar.empty.title": "Нет открытых проектов", "sidebar.empty.description": "Откройте проект, чтобы начать", + "sidebar.settled": "Отложенные", + "sidebar.settle": "Отложить тред", + "sidebar.unsettle": "Вернуть тред", + "sidebar.thread.new": "Новый тред", + "sidebar.thread.pin": "Закрепить тред", + "sidebar.thread.unpin": "Открепить тред", + "sidebar.status.working": "В работе", + "sidebar.status.done": "Готово", + "sidebar.status.attention": "Нужен ввод", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "Приложение", @@ -914,6 +923,12 @@ export const dict = { "settings.general.row.language.title": "Язык", "settings.general.row.language.description": "Изменить язык отображения OpenCode", + "settings.general.row.navigation.description": "Вкладки в заголовке или постоянная боковая панель", + "settings.general.row.navigation.tabs": "Вкладки", + "settings.general.row.navigation.sidebar": "Боковая панель", + "settings.general.row.sidebarSessions.title": "Откладывать неактивные треды через", + "settings.general.row.sidebarSessions.description": "Неактивные треды переносятся в отложенные. Активные треды остаются видимыми.", + "settings.general.row.sidebarSessions.always": "Всегда показывать", "settings.general.row.shell.title": "Оболочка терминала", "settings.general.row.shell.description": "Выберите оболочку для терминала. Совместимые оболочки также используются агентом при вызове инструментов.", diff --git a/packages/app/src/i18n/si.ts b/packages/app/src/i18n/si.ts index 00ca188b1581..434379b60894 100644 --- a/packages/app/src/i18n/si.ts +++ b/packages/app/src/i18n/si.ts @@ -874,6 +874,15 @@ export const dict: Record = { "sidebar.project.clearNotifications": "දැනුම්දීම් හිස් කරන්න", "sidebar.empty.title": "ව්‍යාපෘති විවෘත නැත", "sidebar.empty.description": "ආරම්භ කිරීමට ව්‍යාපෘතියක් විවෘත කරන්න", + "sidebar.settled": "නිශ්චල කළ", + "sidebar.settle": "සාකච්ඡාව නිශ්චල කරන්න", + "sidebar.unsettle": "සාකච්ඡාව යළි සක්‍රිය කරන්න", + "sidebar.thread.new": "නව සාකච්ඡාව", + "sidebar.thread.pin": "සාකච්ඡාව අමුණන්න", + "sidebar.thread.unpin": "ඇමුණුම ඉවත් කරන්න", + "sidebar.status.working": "ක්‍රියාත්මකයි", + "sidebar.status.done": "අවසන්", + "sidebar.status.attention": "ඇතුළත් කිරීමක් අවශ්‍යයි", "debugBar.ariaLabel": "සංවර්ධන කාර්ය සාධන රෝග විනිශ්චය", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -921,6 +930,12 @@ export const dict: Record = { "settings.general.section.display": "ප්රදර්ශනය කරන්න", "settings.general.row.language.title": "භාෂාව", "settings.general.row.language.description": "OpenCode සඳහා සංදර්ශක භාෂාව වෙනස් කරන්න", + "settings.general.row.navigation.description": "මාතෘකා තීරුවේ ටැබ් හෝ ස්ථිර පැති තීරුව භාවිත කරන්න", + "settings.general.row.navigation.tabs": "ටැබ්", + "settings.general.row.navigation.sidebar": "පැති තීරුව", + "settings.general.row.sidebarSessions.title": "අක්‍රිය සාකච්ඡා නිශ්චල කිරීමේ කාලය", + "settings.general.row.sidebarSessions.description": "අක්‍රිය සාකච්ඡා නිශ්චල කළ ඒවාට යයි. ක්‍රියාත්මක සාකච්ඡා දිස්වේ.", + "settings.general.row.sidebarSessions.always": "සැමවිටම පෙන්වන්න", "settings.general.row.shell.title": "පර්යන්ත ෂෙල්", "settings.general.row.shell.description": "පර්යන්තය සහ නියෝජිත මෙවලම් භාවිතා කරන ෂෙල්", "settings.general.row.shell.autoDefault": "ස්වයංක්‍රීය (පෙරනිමි)", diff --git a/packages/app/src/i18n/sk.ts b/packages/app/src/i18n/sk.ts index 9992e06cc4af..b815225bab8e 100644 --- a/packages/app/src/i18n/sk.ts +++ b/packages/app/src/i18n/sk.ts @@ -880,6 +880,15 @@ export const dict = { "sidebar.project.clearNotifications": "Vymazať oznámenia", "sidebar.empty.title": "Nie sú otvorené žiadne projekty", "sidebar.empty.description": "Otvorte projekt pre začiatok", + "sidebar.settled": "Odložené", + "sidebar.settle": "Odložiť vlákno", + "sidebar.unsettle": "Vrátiť vlákno", + "sidebar.thread.new": "Nové vlákno", + "sidebar.thread.pin": "Pripnúť vlákno", + "sidebar.thread.unpin": "Odopnúť vlákno", + "sidebar.status.working": "Pracuje", + "sidebar.status.done": "Hotovo", + "sidebar.status.attention": "Vyžaduje vstup", "debugBar.ariaLabel": "Diagnostika výkonu vývoja", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -928,6 +937,12 @@ export const dict = { "settings.general.section.display": "Zobrazenie", "settings.general.row.language.title": "Jazyk", "settings.general.row.language.description": "Zmeniť jazyk rozhrania pre OpenCode", + "settings.general.row.navigation.description": "Použiť karty na titulnom paneli alebo trvalý bočný panel", + "settings.general.row.navigation.tabs": "Karty", + "settings.general.row.navigation.sidebar": "Bočný panel", + "settings.general.row.sidebarSessions.title": "Odložiť nečinné vlákna po", + "settings.general.row.sidebarSessions.description": "Nečinné vlákna sa presunú do Odložené. Pracujúce vlákna zostanú viditeľné.", + "settings.general.row.sidebarSessions.always": "Vždy zobraziť", "settings.general.row.shell.title": "Terminálový shell", "settings.general.row.shell.description": "Shell používaný terminálom a nástrojmi agenta", "settings.general.row.shell.autoDefault": "Automaticky (predvolené)", diff --git a/packages/app/src/i18n/sl.ts b/packages/app/src/i18n/sl.ts index 3c23fcd7f708..ebebba67007b 100644 --- a/packages/app/src/i18n/sl.ts +++ b/packages/app/src/i18n/sl.ts @@ -881,6 +881,15 @@ export const dict = { "sidebar.project.clearNotifications": "Počisti obvestila", "sidebar.empty.title": "Ni odprtih projektov", "sidebar.empty.description": "Za začetek odprite projekt", + "sidebar.settled": "Odložene", + "sidebar.settle": "Odloži nit", + "sidebar.unsettle": "Vrni nit", + "sidebar.thread.new": "Nova nit", + "sidebar.thread.pin": "Pripni nit", + "sidebar.thread.unpin": "Odpni nit", + "sidebar.status.working": "V teku", + "sidebar.status.done": "Končano", + "sidebar.status.attention": "Potreben vnos", "debugBar.ariaLabel": "Diagnostika uspešnosti razvoja", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -929,6 +938,12 @@ export const dict = { "settings.general.section.display": "Zaslon", "settings.general.row.language.title": "Jezik", "settings.general.row.language.description": "Spremenite jezik prikaza za OpenCode", + "settings.general.row.navigation.description": "Uporabite zavihke v naslovni vrstici ali trajno stransko vrstico", + "settings.general.row.navigation.tabs": "Zavihki", + "settings.general.row.navigation.sidebar": "Stranska vrstica", + "settings.general.row.sidebarSessions.title": "Odloži nedejavne niti po", + "settings.general.row.sidebarSessions.description": "Nedejavne niti se premaknejo med odložene. Dejavne niti ostanejo vidne.", + "settings.general.row.sidebarSessions.always": "Vedno prikaži", "settings.general.row.shell.title": "Končna lupina", "settings.general.row.shell.description": "Lupina, ki jo uporabljajo terminalska in agentska orodja", "settings.general.row.shell.autoDefault": "Samodejno (privzeto)", diff --git a/packages/app/src/i18n/sq.ts b/packages/app/src/i18n/sq.ts index ca94793ab0e6..d1c9b6203ba8 100644 --- a/packages/app/src/i18n/sq.ts +++ b/packages/app/src/i18n/sq.ts @@ -879,6 +879,15 @@ export const dict = { "sidebar.project.clearNotifications": "Pastro njoftimet", "sidebar.empty.title": "Asnjë projekt i hapur", "sidebar.empty.description": "Hapni një projekt për të filluar", + "sidebar.settled": "Të mbyllura", + "sidebar.settle": "Mbyll rrjedhën", + "sidebar.unsettle": "Rihap rrjedhën", + "sidebar.thread.new": "Rrjedhë e re", + "sidebar.thread.pin": "Kapëse rrjedhën", + "sidebar.thread.unpin": "Hiq kapësen", + "sidebar.status.working": "Po punon", + "sidebar.status.done": "Përfundoi", + "sidebar.status.attention": "Kërkon input", "debugBar.ariaLabel": "Diagnostifikimi i performancës së zhvillimit", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -928,6 +937,12 @@ export const dict = { "settings.general.section.display": "Ekrani", "settings.general.row.language.title": "Gjuha", "settings.general.row.language.description": "Ndryshoni gjuhën e ekranit për OpenCode", + "settings.general.row.navigation.description": "Përdor skeda në shiritin e titullit ose një shirit anësor të përhershëm", + "settings.general.row.navigation.tabs": "Skeda", + "settings.general.row.navigation.sidebar": "Shiriti anësor", + "settings.general.row.sidebarSessions.title": "Mbyll rrjedhat joaktive pas", + "settings.general.row.sidebarSessions.description": "Rrjedhat joaktive kalojnë te të mbyllurat. Rrjedhat aktive mbeten të dukshme.", + "settings.general.row.sidebarSessions.always": "Shfaq gjithmonë", "settings.general.row.shell.title": "Predha e terminalit", "settings.general.row.shell.description": "Predha e përdorur nga terminali dhe mjetet e agjentit", "settings.general.row.shell.autoDefault": "Auto (e parazgjedhur)", diff --git a/packages/app/src/i18n/sr.ts b/packages/app/src/i18n/sr.ts index f059160087d8..1dd7a64b8a42 100644 --- a/packages/app/src/i18n/sr.ts +++ b/packages/app/src/i18n/sr.ts @@ -880,6 +880,15 @@ export const dict = { "sidebar.project.clearNotifications": "Обришите обавештења", "sidebar.empty.title": "Нема отворених пројеката", "sidebar.empty.description": "Отворите пројекат да бисте започели", + "sidebar.settled": "Одложене", + "sidebar.settle": "Одложи нит", + "sidebar.unsettle": "Врати нит", + "sidebar.thread.new": "Нова нит", + "sidebar.thread.pin": "Прикачи нит", + "sidebar.thread.unpin": "Откачи нит", + "sidebar.status.working": "У току", + "sidebar.status.done": "Готово", + "sidebar.status.attention": "Потребан унос", "debugBar.ariaLabel": "Дијагностика перформанси развоја", "debugBar.na": "н/а", "debugBar.nav.label": "NAV", @@ -928,6 +937,12 @@ export const dict = { "settings.general.section.display": "Приказ", "settings.general.row.language.title": "Језик", "settings.general.row.language.description": "Промените језик приказа за OpenCode", + "settings.general.row.navigation.description": "Користите картице у насловној траци или трајну бочну траку", + "settings.general.row.navigation.tabs": "Картице", + "settings.general.row.navigation.sidebar": "Бочна трака", + "settings.general.row.sidebarSessions.title": "Одложи неактивне нити након", + "settings.general.row.sidebarSessions.description": "Неактивне нити прелазе у одложене. Активне нити остају видљиве.", + "settings.general.row.sidebarSessions.always": "Увек прикажи", "settings.general.row.shell.title": "Терминал shell", "settings.general.row.shell.description": "Shell који користе алати терминала и агента", "settings.general.row.shell.autoDefault": "аутоматски (подразумевано)", diff --git a/packages/app/src/i18n/sv.ts b/packages/app/src/i18n/sv.ts index 39b363c6b657..7121eea22bfe 100644 --- a/packages/app/src/i18n/sv.ts +++ b/packages/app/src/i18n/sv.ts @@ -881,6 +881,15 @@ export const dict = { "sidebar.project.clearNotifications": "Rensa aviseringar", "sidebar.empty.title": "Inga projekt öppna", "sidebar.empty.description": "Öppna ett projekt för att komma igång", + "sidebar.settled": "Avslutade", + "sidebar.settle": "Avsluta tråd", + "sidebar.unsettle": "Återaktivera tråd", + "sidebar.thread.new": "Ny tråd", + "sidebar.thread.pin": "Fäst tråd", + "sidebar.thread.unpin": "Lossa tråd", + "sidebar.status.working": "Arbetar", + "sidebar.status.done": "Klar", + "sidebar.status.attention": "Kräver indata", "debugBar.ariaLabel": "Utvecklingsprestandadiagnostik", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -930,6 +939,12 @@ export const dict = { "settings.general.section.display": "Visning", "settings.general.row.language.title": "Språk", "settings.general.row.language.description": "Ändra visningsspråket för OpenCode", + "settings.general.row.navigation.description": "Använd flikar i namnlisten eller ett fast sidofält", + "settings.general.row.navigation.tabs": "Flikar", + "settings.general.row.navigation.sidebar": "Sidofält", + "settings.general.row.sidebarSessions.title": "Avsluta inaktiva trådar efter", + "settings.general.row.sidebarSessions.description": "Inaktiva trådar flyttas till Avslutade. Aktiva trådar förblir synliga.", + "settings.general.row.sidebarSessions.always": "Visa alltid", "settings.general.row.shell.title": "Terminalskal", "settings.general.row.shell.description": "Skal som används av terminalen och agentverktygen", "settings.general.row.shell.autoDefault": "Auto (standard)", diff --git a/packages/app/src/i18n/tg.ts b/packages/app/src/i18n/tg.ts index ffa08409f684..c8aeb3b9e0bf 100644 --- a/packages/app/src/i18n/tg.ts +++ b/packages/app/src/i18n/tg.ts @@ -880,6 +880,15 @@ export const dict = { "sidebar.project.clearNotifications": "Огоҳиҳоро тоза кунед", "sidebar.empty.title": "Ягон лоиҳа кушода нест", "sidebar.empty.description": "Барои оғоз кардани лоиҳа лоиҳа кушоед", + "sidebar.settled": "Анҷомёфта", + "sidebar.settle": "Риштаро анҷом додан", + "sidebar.unsettle": "Риштаро барқарор кардан", + "sidebar.thread.new": "Риштаи нав", + "sidebar.thread.pin": "Риштаро маҳкам кардан", + "sidebar.thread.unpin": "Маҳкамро бекор кардан", + "sidebar.status.working": "Дар ҳоли кор", + "sidebar.status.done": "Тайёр", + "sidebar.status.attention": "Ворид лозим", "debugBar.ariaLabel": "Ташхиси самаранокии рушд", "debugBar.na": "не", "debugBar.nav.label": "NAV", @@ -928,6 +937,12 @@ export const dict = { "settings.general.section.display": "Намоиш", "settings.general.row.language.title": "Забон", "settings.general.row.language.description": "Забони намоишро барои OpenCode иваз кунед", + "settings.general.row.navigation.description": "Дар сарлавҳа варақаҳо ё панели паҳлуии доимӣ истифода баред", + "settings.general.row.navigation.tabs": "Варақаҳо", + "settings.general.row.navigation.sidebar": "Панели паҳлуӣ", + "settings.general.row.sidebarSessions.title": "Риштаҳои ғайрифаъолро анҷом додан пас аз", + "settings.general.row.sidebarSessions.description": "Риштаҳои ғайрифаъол ба анҷомёфта мегузаранд. Риштаҳои корӣ намоён мемонанд.", + "settings.general.row.sidebarSessions.always": "Ҳамеша нишон додан", "settings.general.row.shell.title": "Терминал shell", "settings.general.row.shell.description": "Shell воситаи терминал ва агент истифода мешавад", "settings.general.row.shell.autoDefault": "Авто (Пешфарз)", diff --git a/packages/app/src/i18n/th.ts b/packages/app/src/i18n/th.ts index 1a0e9db72b1b..bed0c804ebe3 100644 --- a/packages/app/src/i18n/th.ts +++ b/packages/app/src/i18n/th.ts @@ -878,6 +878,15 @@ export const dict = { "sidebar.project.clearNotifications": "ล้างการแจ้งเตือน", "sidebar.empty.title": "ไม่มีโปรเจกต์ที่เปิดอยู่", "sidebar.empty.description": "เปิดโปรเจกต์เพื่อเริ่มต้น", + "sidebar.settled": "ที่พักไว้", + "sidebar.settle": "พักเธรด", + "sidebar.unsettle": "ยกเลิกการพักเธรด", + "sidebar.thread.new": "เธรดใหม่", + "sidebar.thread.pin": "ปักหมุดเธรด", + "sidebar.thread.unpin": "ยกเลิกการปักหมุด", + "sidebar.status.working": "กำลังทำงาน", + "sidebar.status.done": "เสร็จ", + "sidebar.status.attention": "ต้องการข้อมูลป้อน", "app.name.desktop": "OpenCode Desktop", @@ -899,6 +908,12 @@ export const dict = { "settings.general.row.language.title": "ภาษา", "settings.general.row.language.description": "เปลี่ยนภาษาที่แสดงสำหรับ OpenCode", + "settings.general.row.navigation.description": "ใช้แท็บในแถบชื่อเรื่องหรือแถบด้านข้างถาวร", + "settings.general.row.navigation.tabs": "แท็บ", + "settings.general.row.navigation.sidebar": "แถบด้านข้าง", + "settings.general.row.sidebarSessions.title": "พักเธรดที่เงียบหลังจาก", + "settings.general.row.sidebarSessions.description": "เธรดที่เงียบจะย้ายไปที่ที่พักไว้ เธรดที่กำลังทำงานยังแสดงอยู่", + "settings.general.row.sidebarSessions.always": "แสดงเสมอ", "settings.general.row.shell.title": "เชลล์เทอร์มินัล", "settings.general.row.shell.description": "เลือกเชลล์ที่จะใช้กับเทอร์มินัล เชลล์ที่เข้ากันได้จะใช้สำหรับการเรียกเครื่องมือของเอเจนต์ด้วย", diff --git a/packages/app/src/i18n/tk.ts b/packages/app/src/i18n/tk.ts index 2b144c6a26c7..644cb92c49d1 100644 --- a/packages/app/src/i18n/tk.ts +++ b/packages/app/src/i18n/tk.ts @@ -877,6 +877,15 @@ export const dict = { "sidebar.project.clearNotifications": "Duýduryşlary arassalaň", "sidebar.empty.title": "Taslama açylmaýar", "sidebar.empty.description": "Başlamak üçin taslama açyň", + "sidebar.settled": "Tamamlanan", + "sidebar.settle": "Temany tamamla", + "sidebar.unsettle": "Temany gaýtadan aç", + "sidebar.thread.new": "Täze tema", + "sidebar.thread.pin": "Temany berkit", + "sidebar.thread.unpin": "Berkitmeni aýyr", + "sidebar.status.working": "Işleýär", + "sidebar.status.done": "Taýýar", + "sidebar.status.attention": "Giriş gerek", "debugBar.ariaLabel": "Ösüş öndürijiligini anyklaýyş", "debugBar.na": "n / a", "debugBar.nav.label": "NAV", @@ -925,6 +934,12 @@ export const dict = { "settings.general.section.display": "Ekran", "settings.general.row.language.title": "Dil", "settings.general.row.language.description": "OpenCode üçin displeý dilini üýtgediň", + "settings.general.row.navigation.description": "Sözbaşy zolagynda goýmalar ýa-da hemişelik gapdal panel ulanyň", + "settings.general.row.navigation.tabs": "Goýmalar", + "settings.general.row.navigation.sidebar": "Gapdal panel", + "settings.general.row.sidebarSessions.title": "Işjeň bolmadyk temalary tamamlama möhleti", + "settings.general.row.sidebarSessions.description": "Işjeň bolmadyk temalar tamamlananlara geçýär. Işleýän temalar görünýär.", + "settings.general.row.sidebarSessions.always": "Elmydama görkez", "settings.general.row.shell.title": "Terminal shell-i", "settings.general.row.shell.description": "Terminal we agent gurallary tarapyndan ulanylýan shell", "settings.general.row.shell.autoDefault": "Awto (Bellenilen)", diff --git a/packages/app/src/i18n/tr.ts b/packages/app/src/i18n/tr.ts index 85623036e429..a81715678899 100644 --- a/packages/app/src/i18n/tr.ts +++ b/packages/app/src/i18n/tr.ts @@ -896,6 +896,15 @@ export const dict = { "sidebar.project.clearNotifications": "Bildirimleri temizle", "sidebar.empty.title": "Açık proje yok", "sidebar.empty.description": "Başlamak için bir proje açın", + "sidebar.settled": "Kapatılan", + "sidebar.settle": "Konuyu kapat", + "sidebar.unsettle": "Konuyu yeniden aç", + "sidebar.thread.new": "Yeni konu", + "sidebar.thread.pin": "Konuyu sabitle", + "sidebar.thread.unpin": "Sabitlemeyi kaldır", + "sidebar.status.working": "Çalışıyor", + "sidebar.status.done": "Bitti", + "sidebar.status.attention": "Girdi gerekiyor", "app.name.desktop": "OpenCode Masaüstü", @@ -917,6 +926,12 @@ export const dict = { "settings.general.row.language.title": "Dil", "settings.general.row.language.description": "OpenCode'un görünüm dilini değiştirin", + "settings.general.row.navigation.description": "Başlık çubuğunda sekmeler veya kalıcı bir kenar çubuğu kullan", + "settings.general.row.navigation.tabs": "Sekmeler", + "settings.general.row.navigation.sidebar": "Kenar çubuğu", + "settings.general.row.sidebarSessions.title": "Boştaki konuları kapatma süresi", + "settings.general.row.sidebarSessions.description": "Boştaki konular kapatılanlara taşınır. Çalışan konular görünür kalır.", + "settings.general.row.sidebarSessions.always": "Her zaman göster", "settings.general.row.shell.title": "Terminal Kabuğu", "settings.general.row.shell.description": "Terminalinizde kullanılacak kabuğu seçin. Uyumlu kabuklar, ajan araç çağrılarında da kullanılır.", diff --git a/packages/app/src/i18n/uk.ts b/packages/app/src/i18n/uk.ts index 54732a87b7eb..068fa3f0a192 100644 --- a/packages/app/src/i18n/uk.ts +++ b/packages/app/src/i18n/uk.ts @@ -966,6 +966,15 @@ export const dict = { "sidebar.project.clearNotifications": "Очистити сповіщення", "sidebar.empty.title": "Немає відкритих проєктів", "sidebar.empty.description": "Відкрийте проєкт, щоб почати", + "sidebar.settled": "Відкладені", + "sidebar.settle": "Відкласти тред", + "sidebar.unsettle": "Повернути тред", + "sidebar.thread.new": "Новий тред", + "sidebar.thread.pin": "Закріпити тред", + "sidebar.thread.unpin": "Відкріпити тред", + "sidebar.status.working": "У роботі", + "sidebar.status.done": "Готово", + "sidebar.status.attention": "Потрібне введення", "debugBar.ariaLabel": "Діагностика продуктивності розробки", "debugBar.na": "н/д", @@ -1019,6 +1028,12 @@ export const dict = { "settings.general.row.language.title": "Мова", "settings.general.row.language.description": "Змінити мову інтерфейсу OpenCode", + "settings.general.row.navigation.description": "Вкладки в заголовку або постійна бічна панель", + "settings.general.row.navigation.tabs": "Вкладки", + "settings.general.row.navigation.sidebar": "Бічна панель", + "settings.general.row.sidebarSessions.title": "Відкладати неактивні треди через", + "settings.general.row.sidebarSessions.description": "Неактивні треди переходять у відкладені. Активні треди залишаються видимими.", + "settings.general.row.sidebarSessions.always": "Завжди показувати", "settings.general.row.shell.title": "Командна оболонка термінала", "settings.general.row.shell.description": "Виберіть оболонку для термінала. Сумісні оболонки також використовуються для викликів інструментів агента.", diff --git a/packages/app/src/i18n/ur.ts b/packages/app/src/i18n/ur.ts index 2ab69e7aec71..de7f634897bb 100644 --- a/packages/app/src/i18n/ur.ts +++ b/packages/app/src/i18n/ur.ts @@ -887,6 +887,15 @@ export const dict = { "sidebar.project.clearNotifications": "اطلاعات کو صاف کریں۔", "sidebar.empty.title": "کوئی پروجیکٹ نہیں کھلا۔", "sidebar.empty.description": "شروع کرنے کے لیے ایک پروجیکٹ کھولیں۔", + "sidebar.settled": "طے شدہ", + "sidebar.settle": "تھریڈ طے کریں", + "sidebar.unsettle": "تھریڈ بحال کریں", + "sidebar.thread.new": "نیا تھریڈ", + "sidebar.thread.pin": "تھریڈ پن کریں", + "sidebar.thread.unpin": "پن ہٹائیں", + "sidebar.status.working": "کام جاری", + "sidebar.status.done": "مکمل", + "sidebar.status.attention": "ان پٹ درکار", "debugBar.ariaLabel": "ترقیاتی کارکردگی کی تشخیص", "debugBar.na": "n/a", "debugBar.nav.label": "NAV", @@ -934,6 +943,12 @@ export const dict = { "settings.general.section.display": "ڈسپلے", "settings.general.row.language.title": "زبان", "settings.general.row.language.description": "OpenCode کے لیے ڈسپلے کی زبان تبدیل کریں۔", + "settings.general.row.navigation.description": "ٹائٹل بار میں ٹیبز یا مستقل سائیڈ بار استعمال کریں", + "settings.general.row.navigation.tabs": "ٹیبز", + "settings.general.row.navigation.sidebar": "سائیڈ بار", + "settings.general.row.sidebarSessions.title": "غیر فعال تھریڈز طے کرنے کی مدت", + "settings.general.row.sidebarSessions.description": "غیر فعال تھریڈز طے شدہ میں چلے جاتے ہیں۔ کام کرتے تھریڈز نظر آتے رہتے ہیں۔", + "settings.general.row.sidebarSessions.always": "ہمیشہ دکھائیں", "settings.general.row.shell.title": "ٹرمینل شیل", "settings.general.row.shell.description": "ٹرمینل اور ایجنٹ ٹولز کے ذریعے استعمال ہونے والا شیل", "settings.general.row.shell.autoDefault": "خودکار (پہلے سے طے شدہ)", diff --git a/packages/app/src/i18n/uz.ts b/packages/app/src/i18n/uz.ts index 8cb7097fc07a..526e2bf9c43c 100644 --- a/packages/app/src/i18n/uz.ts +++ b/packages/app/src/i18n/uz.ts @@ -884,6 +884,15 @@ export const dict = { "sidebar.project.clearNotifications": "Bildirishnomalarni tozalash", "sidebar.empty.title": "Hech qanday loyiha ochiq emas", "sidebar.empty.description": "Boshlash uchun loyihani oching", + "sidebar.settled": "Yakunlangan", + "sidebar.settle": "Trevni yakunlash", + "sidebar.unsettle": "Trevni qayta ochish", + "sidebar.thread.new": "Yangi trev", + "sidebar.thread.pin": "Trevni mahkamlash", + "sidebar.thread.unpin": "Mahkamlashni bekor qilish", + "sidebar.status.working": "Ishlamoqda", + "sidebar.status.done": "Tayyor", + "sidebar.status.attention": "Kiritish kerak", "debugBar.ariaLabel": "Rivojlanish samaradorligi diagnostikasi", "debugBar.na": "yo'q", "debugBar.nav.label": "NAV", @@ -932,6 +941,12 @@ export const dict = { "settings.general.section.display": "Displey", "settings.general.row.language.title": "Til", "settings.general.row.language.description": "OpenCode uchun ekran tilini o'zgartiring", + "settings.general.row.navigation.description": "Sarlavha panelida tablardan yoki doimiy yon paneldan foydalaning", + "settings.general.row.navigation.tabs": "Tablar", + "settings.general.row.navigation.sidebar": "Yon panel", + "settings.general.row.sidebarSessions.title": "Bo'sh trevlarni yakunlash muddati", + "settings.general.row.sidebarSessions.description": "Bo'sh trevlar yakunlanganlarga ko'chadi. Ishlayotgan trevlar ko'rinib turadi.", + "settings.general.row.sidebarSessions.always": "Har doim ko'rsatish", "settings.general.row.shell.title": "Terminal qobig'i", "settings.general.row.shell.description": "Terminal va agent vositalari tomonidan ishlatiladigan qobiq", "settings.general.row.shell.autoDefault": "Avtomatik (standart)", diff --git a/packages/app/src/i18n/vi.ts b/packages/app/src/i18n/vi.ts index 06fda4ce707c..566513c4491e 100644 --- a/packages/app/src/i18n/vi.ts +++ b/packages/app/src/i18n/vi.ts @@ -888,6 +888,15 @@ export const dict = { "sidebar.project.clearNotifications": "Xóa thông báo", "sidebar.empty.title": "Không có dự án nào mở", "sidebar.empty.description": "Mở một dự án để bắt đầu", + "sidebar.settled": "Đã xếp", + "sidebar.settle": "Xếp chuỗi", + "sidebar.unsettle": "Khôi phục chuỗi", + "sidebar.thread.new": "Chuỗi mới", + "sidebar.thread.pin": "Ghim chuỗi", + "sidebar.thread.unpin": "Bỏ ghim chuỗi", + "sidebar.status.working": "Đang làm", + "sidebar.status.done": "Xong", + "sidebar.status.attention": "Cần nhập", "debugBar.ariaLabel": "Chẩn đoán hiệu suất phát triển", "debugBar.na": "không có", "debugBar.nav.label": "NAV", @@ -936,6 +945,12 @@ export const dict = { "settings.general.section.display": "Hiển thị", "settings.general.row.language.title": "Ngôn ngữ", "settings.general.row.language.description": "Thay đổi ngôn ngữ hiển thị cho OpenCode", + "settings.general.row.navigation.description": "Dùng thẻ trên thanh tiêu đề hoặc thanh bên cố định", + "settings.general.row.navigation.tabs": "Thẻ", + "settings.general.row.navigation.sidebar": "Thanh bên", + "settings.general.row.sidebarSessions.title": "Xếp các chuỗi nhàn rỗi sau", + "settings.general.row.sidebarSessions.description": "Các chuỗi nhàn rỗi chuyển sang Đã xếp. Các chuỗi đang làm vẫn hiển thị.", + "settings.general.row.sidebarSessions.always": "Luôn hiển thị", "settings.general.row.shell.title": "Shell terminal", "settings.general.row.shell.description": "Shell được terminal và các công cụ của tác nhân sử dụng", "settings.general.row.shell.autoDefault": "Tự động (Mặc định)", diff --git a/packages/app/src/i18n/zh.ts b/packages/app/src/i18n/zh.ts index b0ba0453479b..7e2ac5d30b90 100644 --- a/packages/app/src/i18n/zh.ts +++ b/packages/app/src/i18n/zh.ts @@ -874,6 +874,15 @@ export const dict = { "sidebar.project.clearNotifications": "清除通知", "sidebar.empty.title": "没有打开的项目", "sidebar.empty.description": "打开一个项目以开始使用", + "sidebar.settled": "已搁置", + "sidebar.settle": "搁置话题", + "sidebar.unsettle": "恢复话题", + "sidebar.thread.new": "新建话题", + "sidebar.thread.pin": "固定话题", + "sidebar.thread.unpin": "取消固定", + "sidebar.status.working": "工作中", + "sidebar.status.done": "已完成", + "sidebar.status.attention": "需要输入", "app.name.desktop": "OpenCode Desktop", @@ -896,6 +905,12 @@ export const dict = { "settings.general.section.display": "显示", "settings.general.row.language.title": "语言", "settings.general.row.language.description": "更改 OpenCode 的显示语言", + "settings.general.row.navigation.description": "在标题栏使用标签页,或使用常驻侧边栏", + "settings.general.row.navigation.tabs": "标签页", + "settings.general.row.navigation.sidebar": "侧边栏", + "settings.general.row.sidebarSessions.title": "闲置话题搁置时间", + "settings.general.row.sidebarSessions.description": "闲置话题会移入已搁置。工作中的话题保持显示。", + "settings.general.row.sidebarSessions.always": "始终显示", "settings.general.row.shell.title": "终端 Shell", "settings.general.row.shell.description": "选择终端使用的 shell。兼容的 shell 也会用于智能体工具调用。", "settings.general.row.shell.autoDefault": "自动(默认)", diff --git a/packages/app/src/i18n/zht.ts b/packages/app/src/i18n/zht.ts index 6cc3d555289d..2e789cfcd668 100644 --- a/packages/app/src/i18n/zht.ts +++ b/packages/app/src/i18n/zht.ts @@ -871,6 +871,15 @@ export const dict = { "sidebar.project.clearNotifications": "清除通知", "sidebar.empty.title": "未開啟任何專案", "sidebar.empty.description": "開啟專案以開始使用", + "sidebar.settled": "已擱置", + "sidebar.settle": "擱置話題", + "sidebar.unsettle": "還原話題", + "sidebar.thread.new": "新增話題", + "sidebar.thread.pin": "釘選話題", + "sidebar.thread.unpin": "取消釘選", + "sidebar.status.working": "工作中", + "sidebar.status.done": "已完成", + "sidebar.status.attention": "需要輸入", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "桌面", @@ -891,6 +900,12 @@ export const dict = { "settings.general.row.language.title": "語言", "settings.general.row.language.description": "變更 OpenCode 的顯示語言", + "settings.general.row.navigation.description": "在標題列使用分頁,或使用常駐側邊欄", + "settings.general.row.navigation.tabs": "分頁", + "settings.general.row.navigation.sidebar": "側邊欄", + "settings.general.row.sidebarSessions.title": "閒置話題擱置時間", + "settings.general.row.sidebarSessions.description": "閒置話題會移入已擱置。工作中的話題保持顯示。", + "settings.general.row.sidebarSessions.always": "一律顯示", "settings.general.row.shell.title": "終端機 Shell", "settings.general.row.shell.description": "選擇終端機使用的 Shell。相容的 Shell 也會用於代理程式工具呼叫。", "settings.general.row.shell.autoDefault": "自動(預設)", diff --git a/packages/app/src/pages/layout-new.tsx b/packages/app/src/pages/layout-new.tsx index 6d76ca840178..c0a2512621ec 100644 --- a/packages/app/src/pages/layout-new.tsx +++ b/packages/app/src/pages/layout-new.tsx @@ -1,17 +1,28 @@ -import { createEffect, Suspense, type ParentProps } from "solid-js" +import { createEffect, createMemo, lazy, Show, Suspense, type ParentProps } from "solid-js" import { createStore } from "solid-js/store" +import { createMediaQuery } from "@solid-primitives/media" import { DebugBar } from "@/components/debug-bar" import { TabsInfoPopup } from "@/components/help-button" import { Titlebar, type TitlebarUpdate } from "@/components/titlebar" import { usePlatform } from "@/context/platform" +import { useSettings } from "@/context/settings" import { setV2Toast, ToastRegion } from "@/utils/toast" +const NavigationSidebar = lazy(() => + import("@/pages/layout/navigation-sidebar").then((mod) => ({ default: mod.NavigationSidebar })), +) + export default function NewLayout(props: ParentProps) { const platform = usePlatform() + const settings = useSettings() + const mobile = createMediaQuery("(max-width: 767px)") const [state, setState] = createStore({ debugTools: true }) createEffect(() => setV2Toast(true)) + // Sidebar navigation mode replaces the titlebar tab strip on desktop widths. + const sidebarNavigation = createMemo(() => !mobile() && settings.general.navigationMode() === "sidebar") + const update: TitlebarUpdate = { version: () => { const state = platform.updater?.state() @@ -38,9 +49,16 @@ export default function NewLayout(props: ParentProps) { : undefined } /> -
- {props.children} -
+
+ + + + + +
+ {props.children} +
+
{import.meta.env.DEV && state.debugTools && } diff --git a/packages/app/src/pages/layout/navigation-sidebar-visibility.test.ts b/packages/app/src/pages/layout/navigation-sidebar-visibility.test.ts new file mode 100644 index 000000000000..0fc9415c2b6f --- /dev/null +++ b/packages/app/src/pages/layout/navigation-sidebar-visibility.test.ts @@ -0,0 +1,105 @@ +import { describe, expect, test } from "bun:test" +import { type Session } from "@opencode-ai/sdk/v2/client" +import type { LocalProject } from "@/context/layout" +import { + buildSidebarRecords, + groupSidebarRecords, + matchesSidebarFilter, + partitionSidebarRecords, + SIDEBAR_SESSION_DAY, +} from "./navigation-sidebar-visibility" + +const session = (input: Partial & Pick) => + ({ + title: "", + version: "v2", + parentID: undefined, + messageCount: 0, + permissions: { session: {}, share: {} }, + time: { created: 0, updated: 0, archived: undefined }, + ...input, + }) as Session + +const project = (worktree: string): LocalProject => + ({ worktree, expanded: false, id: worktree, name: worktree.split("/").pop() }) as LocalProject + +const DAY = SIDEBAR_SESSION_DAY +const NOW = 100 * DAY + +describe("navigation sidebar visibility", () => { + test("buildSidebarRecords keeps only root sessions inside project directories", () => { + const projects = [project("/src/a"), project("/src/b")] + const records = buildSidebarRecords({ + projects, + sessions: [ + session({ id: "1", directory: "/src/a", time: { created: 10, updated: 20, archived: undefined } }), + session({ id: "2", directory: "/src/other" }), + session({ id: "3", directory: "/src/a", parentID: "1" }), + session({ id: "1", directory: "/src/a", time: { created: 10, updated: 30, archived: undefined } }), + ], + }) + expect(records).toHaveLength(1) + expect(records[0]?.session.id).toBe("1") + }) + + test("groupSidebarRecords groups records by project worktree", () => { + const projects = [project("/src/a"), project("/src/b")] + const groups = groupSidebarRecords( + buildSidebarRecords({ + projects, + sessions: [ + session({ id: "1", directory: "/src/a", time: { created: 2, updated: 5, archived: undefined } }), + session({ id: "2", directory: "/src/b", time: { created: 3, updated: 9, archived: undefined } }), + session({ id: "3", directory: "/src/a", time: { created: 1, updated: 2, archived: undefined } }), + ], + }), + ) + expect(groups.map((group) => group.key)).toEqual(["/src/b", "/src/a"]) + expect(groups[0]?.records.map((record) => record.session.id)).toEqual(["2"]) + expect(groups[1]?.records.map((record) => record.session.id)).toEqual(["1", "3"]) + }) + + test("partitions by age while keeping pinned records visible", () => { + const fresh = session({ id: "fresh", directory: "/src/a", time: { created: NOW - DAY, updated: NOW - DAY, archived: undefined } }) + const stale = session({ id: "stale", directory: "/src/a", time: { created: NOW - 10 * DAY, updated: NOW - 10 * DAY, archived: undefined } }) + const staleWorking = session({ id: "working", directory: "/src/a", time: { created: NOW - 10 * DAY, updated: NOW - 10 * DAY, archived: undefined } }) + const result = partitionSidebarRecords({ + records: [ + { key: fresh.id, session: fresh, project: project("/src/a"), name: "a" }, + { key: stale.id, session: stale, project: project("/src/a"), name: "a" }, + { key: staleWorking.id, session: staleWorking, project: project("/src/a"), name: "a" }, + ], + pinned: (record) => record.session.id === "working", + days: 3, + now: NOW, + }) + expect(result.visible.map((record) => record.session.id)).toEqual(["fresh", "working"]) + expect(result.hidden.map((record) => record.session.id)).toEqual(["stale"]) + }) + + test("days of zero keeps every session visible", () => { + const ancient = session({ id: "ancient", directory: "/src/a", time: { created: 0, updated: 0, archived: undefined } }) + const result = partitionSidebarRecords({ + records: [{ key: ancient.id, session: ancient, project: project("/src/a"), name: "a" }], + pinned: () => false, + days: 0, + now: NOW, + }) + expect(result.visible).toHaveLength(1) + expect(result.hidden).toHaveLength(0) + }) + + test("matchesSidebarFilter checks project name and session title", () => { + const filtered = session({ id: "1", directory: "/src/a", title: "Fix login bug" }) + const record = { + key: filtered.id, + session: filtered, + project: project("/src/a"), + name: "Web App", + } + expect(matchesSidebarFilter(record, "")).toBe(true) + expect(matchesSidebarFilter(record, "web")).toBe(true) + expect(matchesSidebarFilter(record, "login")).toBe(true) + expect(matchesSidebarFilter(record, "missing")).toBe(false) + }) +}) diff --git a/packages/app/src/pages/layout/navigation-sidebar-visibility.ts b/packages/app/src/pages/layout/navigation-sidebar-visibility.ts new file mode 100644 index 000000000000..20da1e46227b --- /dev/null +++ b/packages/app/src/pages/layout/navigation-sidebar-visibility.ts @@ -0,0 +1,95 @@ +import type { Session } from "@opencode-ai/sdk/v2/client" +import type { LocalProject } from "@/context/layout" +import { displayName, projectForSession } from "@/pages/layout/helpers" +import { pathKey } from "@/utils/path-key" + +export const SIDEBAR_SESSION_DAY = 86_400_000 + +export type SidebarSessionRecord = { + key: string + session: Session + project: LocalProject + name: string +} + +export type SidebarProjectGroup = { + key: string + project: LocalProject + name: string + records: SidebarSessionRecord[] +} + +// Creation order keeps rows stable while threads stream; sorting by last activity would make +// working threads trade places on every update. +function compareSessionCreated(a: Session, b: Session) { + if (b.time.created !== a.time.created) return b.time.created - a.time.created + if (a.id === b.id) return 0 + return a.id < b.id ? -1 : 1 +} + +export function buildSidebarRecords(input: { sessions: Session[]; projects: LocalProject[] }) { + const projectByID = new Map(input.projects.flatMap((project) => (project.id ? [[project.id, project]] : []))) + const directories = new Set( + input.projects.flatMap((project) => [project.worktree, ...(project.sandboxes ?? [])]).map(pathKey), + ) + const sessions = input.sessions + .filter((session) => directories.has(pathKey(session.directory))) + .filter((session) => !session.parentID) + const unique = [...new Map(sessions.map((session) => [session.id, session] as const)).values()].sort( + compareSessionCreated, + ) + return unique.flatMap((session): SidebarSessionRecord[] => { + const directory = pathKey(session.directory) + const project = + input.projects.find( + (item) => pathKey(item.worktree) === directory || item.sandboxes?.some((sandbox) => pathKey(sandbox) === directory), + ) ?? projectForSession(session, input.projects, projectByID) + if (!project) return [] + return [{ key: session.id, session, project, name: displayName(project) }] + }) +} + +export function groupSidebarRecords(records: SidebarSessionRecord[]): SidebarProjectGroup[] { + return [ + ...records + .reduce((groups, record) => { + const key = pathKey(record.project.worktree) + const group = groups.get(key) + if (group) group.records.push(record) + if (!group) groups.set(key, { key, project: record.project, name: record.name, records: [record] }) + return groups + }, new Map()) + .values(), + ] +} + +export function sidebarSessionAge(session: Session, now: number) { + return Math.max(0, now - (session.time.updated || session.time.created)) +} + +/** + * Working, open and currently viewed sessions stay pinned regardless of age so the sidebar never + * hides a session the user is actively waiting on. + */ +export function partitionSidebarRecords(input: { + records: SidebarSessionRecord[] + pinned: (record: SidebarSessionRecord) => boolean + days: number + now: number +}) { + const cutoff = input.days <= 0 ? Number.POSITIVE_INFINITY : input.days * SIDEBAR_SESSION_DAY + return input.records.reduce( + (groups, record) => { + const visible = input.pinned(record) || sidebarSessionAge(record.session, input.now) <= cutoff + groups[visible ? "visible" : "hidden"].push(record) + return groups + }, + { visible: [] as SidebarSessionRecord[], hidden: [] as SidebarSessionRecord[] }, + ) +} + +export function matchesSidebarFilter(record: SidebarSessionRecord, query: string) { + const needle = query.trim().toLowerCase() + if (!needle) return true + return record.name.toLowerCase().includes(needle) || (record.session.title ?? "").toLowerCase().includes(needle) +} diff --git a/packages/app/src/pages/layout/navigation-sidebar.tsx b/packages/app/src/pages/layout/navigation-sidebar.tsx new file mode 100644 index 000000000000..de56d95bdf72 --- /dev/null +++ b/packages/app/src/pages/layout/navigation-sidebar.tsx @@ -0,0 +1,1325 @@ +import { createEffect, createMemo, createSignal, For, onCleanup, Show, startTransition } from "solid-js" +import { createStore, produce, reconcile } from "solid-js/store" +import { useQuery } from "@tanstack/solid-query" +import type { GlobalSession } from "@opencode-ai/sdk/v2/client" +import { Binary } from "@opencode-ai/core/util/binary" +import { Spinner } from "@opencode-ai/ui/spinner" +import { ScrollView } from "@opencode-ai/ui/scroll-view" +import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" +import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" +import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2" +import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2" +import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" +import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2" +import { DialogFooter, DialogHeader, DialogTitleGroup, DialogV2 } from "@opencode-ai/ui/v2/dialog-v2" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { ProviderIcon } from "@opencode-ai/ui/provider-icon" +import { + loadHomeSessionIndex, + retainHomeSessions, + type HomeSessionEvents, +} from "@/context/global-sync/home-session-index" +import type { LocalProject } from "@/context/layout" +import { useLayout } from "@/context/layout" +import { useLanguage } from "@/context/language" +import { ServerConnection } from "@/context/server" +import { useSettings } from "@/context/settings" +import { usePlatform } from "@/context/platform" +import { useCommand } from "@/context/command" +import { useDirectoryPicker } from "@/components/directory-picker" +import { sessionHasOpenTab, useTabs } from "@/context/tabs" +import { createHomeController } from "@/pages/home/home-controller" +import { createHomeProjectsController } from "@/pages/home/home-projects-controller" +import { archiveHomeSession } from "@/pages/home-session-archive" +import { shouldOpenSessionInBackground } from "@/pages/home-session-open" +import { displayName, errorMessage, homeProjectDirectories } from "@/pages/layout/helpers" +import { + buildSidebarRecords, + groupSidebarRecords, + matchesSidebarFilter, + partitionSidebarRecords, + type SidebarProjectGroup, + type SidebarSessionRecord, +} from "@/pages/layout/navigation-sidebar-visibility" +import { useSessionTabAvatarState } from "@/pages/layout/project-avatar-state" +import { SessionTabAvatarView } from "@/pages/layout/session-tab-avatar" +import { fileManagerApp } from "@/utils/file-manager" +import { pathKey } from "@/utils/path-key" +import { Persist, persisted } from "@/utils/persist" +import { + downloadSessionExport, + fetchSessionExport, + sessionExportFilename, +} from "@/utils/session-export" +import { sessionTitle, withTimestampedFallback } from "@/utils/session-title" +import { showToast } from "@/utils/toast" + +type SidebarProjectSection = SidebarProjectGroup & { + visible: SidebarSessionRecord[] + hidden: SidebarSessionRecord[] +} + +type SettledGroup = { + key: string + project: LocalProject + name: string + local: SidebarSessionRecord[] + archived: SidebarSessionRecord[] +} + +type SessionAction = (record: SidebarSessionRecord) => void + +const SESSION_LIMIT = 64 +const ARCHIVED_LIMIT = 100 +const AGE_TICK = 60_000 +const STATUS_TICK = 1_000 +const SECTION_LABEL = "px-3 pb-1 pt-3 text-v2-text-text-muted [font-weight:440]" +const ROW = + "group/row relative flex h-7 min-w-0 w-full shrink-0 cursor-default items-center gap-2 rounded-[6px] bg-transparent px-1.5 text-start text-v2-text-text-muted [font-weight:440] transition-[background-color,color,box-shadow] duration-[120ms] ease-in-out hover:bg-v2-background-bg-layer-01 hover:text-v2-text-text-base data-[selected=true]:bg-v2-background-bg-layer-03 data-[selected=true]:text-v2-text-text-base data-[selected=true]:hover:bg-v2-background-bg-layer-03 focus-visible:bg-v2-background-bg-layer-01 focus-visible:text-v2-text-text-base focus-visible:outline-none focus-visible:[box-shadow:inset_0_0_0_0.5px_var(--v2-border-border-muted)]" +// Trailing padding reserves the hover action zone so titles never sit under the buttons and +// rows keep identical geometry with or without hover. +const ROW_SESSION = `${ROW} pe-24` +const ROW_PROJECT = `${ROW} pe-14` +const ROW_ACTIONS = + "hover-reveal absolute end-1 top-1/2 flex -translate-y-1/2 items-center gap-0.5 rounded-[6px] bg-v2-background-bg-layer-02 p-0.5 opacity-0 shadow-[var(--v2-elevation-raised)] group-hover/row:opacity-100 focus-within:opacity-100 data-[menu=true]:opacity-100" +const COUNT = "absolute end-2 top-1/2 -translate-y-1/2 text-xs text-v2-text-text-faint" +const NAME = "flex min-w-0 flex-1 items-center gap-1.5" + +function titleOf(session: { title?: string; parentID?: string; time: { created: number } }) { + return sessionTitle(session.title) ?? withTimestampedFallback(session) +} + +function isBackgroundOpen(event: MouseEvent) { + return shouldOpenSessionInBackground({ + button: event.button, + mac: typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform), + meta: event.metaKey, + ctrl: event.ctrlKey, + shift: event.shiftKey, + alt: event.altKey, + }) +} + +export function NavigationSidebar() { + const language = useLanguage() + const layout = useLayout() + const settings = useSettings() + const tabs = useTabs() + const command = useCommand() + const dialog = useDialog() + const home = createHomeController() + const projects = createHomeProjectsController(home) + const pickDirectory = useDirectoryPicker() + + const [filter, setFilter] = createSignal("") + const [now, setNow] = createSignal(Date.now()) + const [tick, setTick] = createSignal(Date.now()) + const [state, setState] = persisted( + Persist.global("sidebar.navigation", ["sidebar.navigation.v1"]), + createStore({ + collapsed: {} as Record, + settled: false, + settledOpen: {} as Record, + pins: {} as Record, + }), + ) + const [status, setStatus] = createStore({ + started: {} as Record, + done: {} as Record, + }) + // Projects added during this app session keep an empty row until their first thread exists; + // older projects whose threads are all settled stay out of the Projects section. + const [fresh, setFresh] = createStore>({}) + + const ticker = setInterval(() => setNow(Date.now()), AGE_TICK) + onCleanup(() => clearInterval(ticker)) + + const homeSessions = () => home.server.focusedSync().homeSessions + + const sessionEvents = useQuery(() => ({ + queryKey: homeSessions().eventsKey, + queryFn: async (): Promise => ({ sequence: 0, entries: [] }), + initialData: { sequence: 0, entries: [] } satisfies HomeSessionEvents, + enabled: false, + })) + + const sessionIndex = useQuery(() => ({ + queryKey: homeSessions().indexKey, + enabled: !!home.server.focusedContext(), + queryFn: async ({ signal }) => { + const ctx = home.server.focusedContext() + if (!ctx) return { sessions: [], eventSequence: 0 } + const cache = homeSessions() + const eventSequence = cache.eventSequence() + const index = await loadHomeSessionIndex( + (input, options) => ctx.sdk.client.v2.session.list(input, options), + eventSequence, + signal, + ) + cache.complete(eventSequence) + return index + }, + retry: false, + staleTime: 30_000, + refetchOnMount: true, + refetchOnReconnect: true, + })) + + // The shared index cache only refreshes on mount; the per-directory sync stores are the live + // source of truth, so overlay them to pick up renames, settles and deletes immediately. + const sessions = createMemo(() => { + const sync = home.server.focusedSync() + const indexed = retainHomeSessions( + homeSessions().sessions(sessionIndex.data, sessionEvents.data), + SESSION_LIMIT, + now(), + ) + return indexed.flatMap((session) => { + const [store] = sync.child(session.directory, { bootstrap: false }) + if (store.status === "loading") return [session] + const match = Binary.search(store.session, session.id, (item) => item.id) + if (!match.found) return [] + return [store.session[match.index]] + }) + }) + + const serverKey = createMemo(() => home.selection.value().server ?? ServerConnection.Key.make("")) + const route = createMemo(() => layout.route()) + const currentSession = createMemo(() => { + const value = route() + return value.type === "session" ? value.sessionId : undefined + }) + const working = (sessionID: string) => home.server.focusedSync().session.data.session_working(sessionID) + + const anyWorking = createMemo(() => sessions().some((session) => working(session.id))) + createEffect(() => { + if (!anyWorking()) return + const timer = setInterval(() => setTick(Date.now()), STATUS_TICK) + onCleanup(() => clearInterval(timer)) + }) + + createEffect(() => { + for (const session of sessions()) { + const started = status.started[session.id] + if (working(session.id) && started === undefined) setStatus("started", session.id, Date.now()) + if (!working(session.id) && started !== undefined) + setStatus( + produce((draft) => { + delete draft.started[session.id] + draft.done[session.id] = Date.now() + }), + ) + } + }) + + createEffect(() => { + const current = currentSession() + if (!current || status.done[current] === undefined) return + setStatus( + produce((draft) => { + delete draft.done[current] + }), + ) + }) + + createEffect(() => { + const ids = new Set(sessions().map((session) => session.id)) + const stale = [...Object.keys(status.started), ...Object.keys(status.done)].filter((id) => !ids.has(id)) + if (stale.length === 0) return + setStatus( + produce((draft) => { + for (const id of stale) { + delete draft.started[id] + delete draft.done[id] + } + }), + ) + }) + + // Open tabs whose session is missing from the index mean the cache lagged behind a promotion. + const [missingKey, setMissingKey] = createSignal("") + createEffect(() => { + const known = new Set(sessions().map((session) => session.id)) + const missing = tabs.store + .flatMap((tab) => + tab.type === "session" && tab.server === serverKey() && !known.has(tab.sessionId) ? [tab.sessionId] : [], + ) + .sort() + .join(",") + if (!missing || missing === missingKey()) return + setMissingKey(missing) + void sessionIndex.refetch() + }) + + const computedSections = createMemo((): SidebarProjectSection[] => { + const records = buildSidebarRecords({ sessions: sessions(), projects: home.project.list() }).filter((record) => + matchesSidebarFilter(record, filter()), + ) + const grouped = groupSidebarRecords(records).map((group) => { + const parts = partitionSidebarRecords({ + records: group.records, + pinned: (record) => alwaysVisible(record), + days: settings.general.sidebarSessionDays() ?? 3, + now: now(), + }) + return { + ...group, + // Pinned threads stay at the top of their project regardless of recency. + visible: [...parts.visible].sort( + (a, b) => Number(isPinned(b.session.id)) - Number(isPinned(a.session.id)), + ), + hidden: parts.hidden, + } + }) + // Projects added during this session keep an empty row until their first thread exists. + const known = new Set(grouped.map((group) => group.key)) + const opened = home.project.list().flatMap((project): SidebarProjectSection[] => { + const key = pathKey(project.worktree) + if (known.has(key) || fresh[key] !== true) return [] + return [{ key, project, name: displayName(project), records: [], visible: [], hidden: [] }] + }) + return [...grouped, ...opened] + }) + + // reconcile keeps group/record object identity stable across recomputes so Solid's For does + // not destroy and recreate every row component on each streaming event (which orphaned open + // menu/tooltip portals and rebuilt the whole subtree constantly). + const [sections, setSections] = createStore([]) + createEffect(() => { + setSections( + reconcile(computedSections(), { key: "key" }), + ) + }) + + const settled = createMemo(() => sections.flatMap((group) => group.hidden)) + const visibleGroups = createMemo(() => { + if (filter()) return sections.filter((group) => group.visible.length > 0) + return sections + }) + const empty = createMemo(() => visibleGroups().length === 0 && settled().length === 0) + + const archived = useQuery(() => ({ + queryKey: ["sidebar", "settled", serverKey()], + enabled: state.settled && !!home.server.focusedContext(), + queryFn: async ({ signal }): Promise => { + const ctx = home.server.focusedContext() + if (!ctx) return [] + const response = await ctx.sdk.client.experimental.session.list( + { archived: true, roots: true, limit: ARCHIVED_LIMIT }, + { signal }, + ) + return response.data ?? [] + }, + retry: false, + staleTime: 300_000, + })) + + const computedSettledGroups = createMemo((): SettledGroup[] => { + const map = new Map() + const push = (record: SidebarSessionRecord, kind: "local" | "archived") => { + const key = pathKey(record.project.worktree) + const group = map.get(key) ?? { key, project: record.project, name: record.name, local: [], archived: [] } + group[kind].push(record) + map.set(key, group) + } + settled().forEach((record) => push(record, "local")) + ;(archived.data ?? []).forEach((session) => push(archivedRecord(session), "archived")) + return [...map.values()] + }) + const [settledGroups, setSettledGroups] = createStore([]) + createEffect(() => { + setSettledGroups(reconcile(computedSettledGroups(), { key: "key" })) + }) + const settledCount = createMemo(() => settled().length + (archived.data ?? []).length) + + function archivedRecord(session: GlobalSession): SidebarSessionRecord { + const project: LocalProject = + projectOf(session) ?? { + id: session.project?.id, + name: session.project?.name, + worktree: session.directory, + expanded: false, + } + return { key: session.id, session, project, name: displayName(project) } + } + + function isPinned(sessionID: string) { + return state.pins[sessionID] === true + } + + function alwaysVisible(record: SidebarSessionRecord) { + if (isPinned(record.session.id)) return true + if (record.session.id === currentSession()) return true + if (working(record.session.id)) return true + return sessionHasOpenTab(tabs.store, serverKey(), record.session) + } + + function projectOf(session: { directory: string }) { + const directory = pathKey(session.directory) + return home.project.list().find((item) => pathKey(item.worktree) === directory) + } + + function branchOf(directory: string) { + return home.server.focusedSync().child(directory)[0].vcs?.branch + } + + function open(session: { id: string; directory: string }, project: LocalProject | undefined, event?: MouseEvent) { + const conn = home.server.focused() + const ctx = home.server.focusedContext() + if (!conn || !ctx) return + const directory = project?.worktree ?? session.directory + ctx.projects.open(directory) + if (event && isBackgroundOpen(event)) { + tabs.addSessionTab({ server: ServerConnection.key(conn), sessionId: session.id }) + return + } + ctx.projects.touch(directory) + void startTransition(() => { + const tab = tabs.addSessionTab({ server: ServerConnection.key(conn), sessionId: session.id }) + tabs.select(tab) + }) + } + + function requestFailed(cause: unknown) { + showToast({ + title: language.t("common.requestFailed"), + description: errorMessage(cause, language.t("common.requestFailed")), + }) + } + + function settle(record: SidebarSessionRecord) { + void (async () => { + const conn = home.server.focused() + const ctx = home.server.focusedContext() + if (!conn || !ctx) return + if ((await ctx.sdk.protocol) !== "v1") return + const [, setStore] = ctx.sync.child(record.session.directory) + await archiveHomeSession({ + server: ServerConnection.key(conn), + session: record.session, + archive: (sessionID) => + ctx.sdk.client.session.update({ + sessionID, + directory: record.session.directory, + time: { archived: Date.now() }, + }), + remove: () => { + setStore( + produce((draft) => { + const match = Binary.search(draft.session, record.session.id, (item) => item.id) + if (match.found) draft.session.splice(match.index, 1) + }), + ) + homeSessions().remove(record.session.id) + }, + onError: requestFailed, + }) + })() + } + + function unsettle(session: { id: string; directory: string }) { + void (async () => { + const conn = home.server.focused() + const ctx = home.server.focusedContext() + if (!conn || !ctx) return + if ((await ctx.sdk.protocol) !== "v1") return + const result = await ctx.sdk.client.session + .update({ + sessionID: session.id, + directory: session.directory, + // The server clears the archive timestamp on null; the generated type only models the + // positive case because the OpenAPI emitter drops nullable members of optional fields. + time: { archived: null as unknown as number }, + }) + .catch((cause) => { + requestFailed(cause) + return undefined + }) + if (!result) return + void sessionIndex.refetch() + void archived.refetch() + })() + } + + async function removeSession(record: SidebarSessionRecord) { + const conn = home.server.focused() + const ctx = home.server.focusedContext() + if (!conn || !ctx) return + const key = ServerConnection.key(conn) + const id = record.session.id + const directory = record.session.directory + const wasCurrent = currentSession() === id + const others = tabs.store.filter((tab) => tab.type === "session" && tab.sessionId !== id) + const result = await ctx.sdk.api.session + .remove({ sessionID: id }) + .catch((cause) => { + showToast({ + title: language.t("session.delete.failed.title"), + description: errorMessage(cause, language.t("session.delete.failed.title")), + }) + return undefined + }) + if (!result) return + const [, setStore] = ctx.sync.child(directory) + setStore( + produce((draft) => { + const match = Binary.search(draft.session, id, (item) => item.id) + if (match.found) draft.session.splice(match.index, 1) + }), + ) + homeSessions().remove(id) + tabs.removeSessionTab({ server: key, sessionId: id }) + if (wasCurrent && others.length === 0) void tabs.newDraft({ server: key, directory }) + } + + function confirmDelete(record: SidebarSessionRecord) { + dialog.show(() => ( + removeSession(record)} /> + )) + } + + function rename(record: SidebarSessionRecord, title: string) { + void (async () => { + const ctx = home.server.focusedContext() + if (!ctx) return + const result = await ctx.sdk.api.session + .rename({ sessionID: record.session.id, title }) + .catch((cause) => { + requestFailed(cause) + return undefined + }) + if (!result) return + })() + } + + function confirmRename(record: SidebarSessionRecord) { + dialog.show(() => ( + rename(record, title)} /> + )) + } + + const canShare = createMemo(() => home.server.focusedSync().data.config.share !== "disabled") + + function share(record: SidebarSessionRecord) { + void (async () => { + const ctx = home.server.focusedContext() + if (!ctx) return + const [store] = ctx.sync.child(record.session.directory, { bootstrap: false }) + const match = Binary.search(store.session, record.session.id, (item) => item.id) + const existing = match.found ? store.session[match.index].share?.url : undefined + const url = + existing ?? + (await ctx.sdk.client.session + .share({ sessionID: record.session.id }) + .then((response) => response.data?.share?.url) + .catch(() => undefined)) + if (!url) { + showToast({ + title: language.t("toast.session.share.failed.title"), + description: language.t("toast.session.share.failed.description"), + }) + return + } + const copied = await navigator.clipboard.writeText(url).then( + () => true, + () => false, + ) + showToast( + copied + ? { + title: language.t("toast.session.share.success.title"), + description: language.t("toast.session.share.success.description"), + } + : { title: language.t("toast.session.share.copyFailed.title") }, + ) + })() + } + + function exportSession(record: SidebarSessionRecord) { + void (async () => { + const ctx = home.server.focusedContext() + if (!ctx) return + const data = await fetchSessionExport({ sessionID: record.session.id, client: ctx.sdk.client }).catch( + (cause) => { + requestFailed(cause) + return undefined + }, + ) + if (!data) return + const filename = sessionExportFilename(data.info) + downloadSessionExport(filename, data) + showToast({ + title: language.t("toast.session.export.success.title"), + description: language.t("toast.session.export.success.description", { filename }), + }) + })() + } + + function closeTab(record: SidebarSessionRecord) { + tabs.removeSessionTab({ server: serverKey(), sessionId: record.session.id }) + } + + function togglePin(sessionID: string) { + setState("pins", sessionID, (value) => value !== true) + } + + const canCreate = createMemo(() => !!home.project.newSession()) + const connection = createMemo(() => home.server.focused()) + + function newThread() { + const conn = connection() + const current = currentSession() + const directory = current ? sessions().find((session) => session.id === current)?.directory : undefined + const target = directory ?? home.selection.value().directory + if (!conn || !target) { + home.project.openNewSession() + return + } + home.project.openProjectNewSession(conn, target) + } + + function addProject() { + const conn = connection() + if (!conn || home.server.health(conn)?.healthy === false) return + pickDirectory({ + server: conn, + title: language.t("command.project.open"), + multiple: true, + onSelect: (result) => { + const directories = homeProjectDirectories(result) + if (directories.length === 0) return + directories.forEach((directory) => setFresh(pathKey(directory), true)) + home.project.add(conn, directories) + home.project.openProjectNewSession(conn, directories[0]) + }, + }) + } + + command.register(() => [ + { + id: "sidebar.thread.new", + title: language.t("sidebar.thread.new"), + category: language.t("command.category.session"), + keybind: "mod+shift+n", + disabled: !canCreate(), + onSelect: () => newThread(), + }, + ]) + + const rowActions = { + onRename: confirmRename, + onShare: share, + onExport: exportSession, + onSettle: settle, + onUnsettleArchive: unsettle, + onUnsettlePin: togglePin, + onDelete: confirmDelete, + onCloseTab: closeTab, + onTogglePin: togglePin, + canShare, + } + + return ( + + ) +} + +type SessionActions = { + onRename: SessionAction + onShare: SessionAction + onExport: SessionAction + onSettle: SessionAction + onUnsettleArchive: (session: { id: string; directory: string }) => void + onUnsettlePin: (sessionID: string) => void + onDelete: SessionAction + onCloseTab: SessionAction + onTogglePin: (sessionID: string) => void + canShare: () => boolean +} + +function SidebarProject(props: { + group: SidebarProjectSection + server: ServerConnection.Key + collapsed: boolean + current: string | undefined + pinned: (sessionID: string) => boolean + started: (sessionID: string) => number | undefined + done: (sessionID: string) => number | undefined + working: (sessionID: string) => boolean + tick: () => number + branch: (directory: string) => string | undefined + actions: SessionActions + unseen: () => number + canReveal: () => boolean + onToggleCollapsed: () => void + onOpen: (session: { id: string; directory: string }, project: LocalProject | undefined, event?: MouseEvent) => void + onNewSession: () => void + onEdit: () => void + onReveal: () => void + onClearNotifications: () => void + onClose: () => void +}) { + const language = useLanguage() + const platform = usePlatform() + const [menuOpen, setMenuOpen] = createSignal(false) + + return ( +
+
+ +
+ + } + aria-label={language.t("sidebar.thread.new")} + onClick={props.onNewSession} + /> + + setMenuOpen(open)} + > + } + aria-label={language.t("common.moreOptions")} + /> + + + {language.t("sidebar.thread.new")} + {language.t("dialog.project.edit.title")} + + + {language.t( + fileManagerApp(platform.platform === "desktop" ? (platform.os ?? "unknown") : "unknown") + .actionLabel, + )} + + + + {language.t("sidebar.project.clearNotifications")} + + + {language.t("common.close")} + + + +
+
+ + +
+ + {(record) => ( + props.started(record.session.id)} + done={() => props.done(record.session.id)} + working={() => props.working(record.session.id)} + tick={props.tick} + branch={props.branch} + actions={props.actions} + onOpen={props.onOpen} + /> + )} + +
+
+
+ ) +} + +function SidebarSettledGroup(props: { + group: SettledGroup + server: ServerConnection.Key + open: boolean + current: string | undefined + tick: () => number + branch: (directory: string) => string | undefined + actions: SessionActions + onToggle: () => void + onOpen: (session: { id: string; directory: string }, project: LocalProject | undefined, event?: MouseEvent) => void +}) { + const count = () => props.group.local.length + props.group.archived.length + return ( +
+ + +
+ + {(record) => ( + + )} + + + {(record) => ( + + )} + +
+
+
+ ) +} + +function SidebarSessionRow(props: { + record: SidebarSessionRecord + server: ServerConnection.Key + current: boolean + settled?: boolean + serverArchived?: boolean + pinned?: boolean + started?: () => number | undefined + done?: () => number | undefined + working?: () => boolean + tick: () => number + branch: (directory: string) => string | undefined + actions: SessionActions + onOpen: (session: { id: string; directory: string }, project: LocalProject | undefined, event?: MouseEvent) => void +}) { + const language = useLanguage() + const tabs = useTabs() + const [menuOpen, setMenuOpen] = createSignal(false) + const server = createMemo(() => props.server) + const directory = createMemo(() => props.record.session.directory) + const sessionID = createMemo(() => props.record.session.id) + const status = useSessionTabAvatarState(server, directory, sessionID) + const open = createMemo(() => sessionHasOpenTab(tabs.store, props.server, props.record.session)) + const title = createMemo(() => titleOf(props.record.session)) + const live = createMemo(() => { + if (props.settled) return undefined + // A pending question or permission outranks the working timer so the user notices input is needed. + if (status.attention()) return { kind: "attention" as const, label: language.t("sidebar.status.attention") } + const started = props.started?.() + if (started !== undefined && props.working?.()) + return { kind: "working" as const, label: language.t("sidebar.status.working"), time: elapsed(started) } + const done = props.done?.() + if (done !== undefined) return { kind: "done" as const, label: language.t("sidebar.status.done") } + return undefined + }) + + function elapsed(since: number) { + const seconds = Math.max(0, Math.round((props.tick() - since) / 1000)) + if (seconds < 60) return `${seconds}s` + const minutes = Math.floor(seconds / 60) + if (minutes < 60) return `${minutes}m` + return `${Math.floor(minutes / 60)}h` + } + + // Fade the tail of long titles under the status badge instead of colliding with it. + const titleMask = createMemo(() => { + if (props.settled || (!live() && !props.pinned)) return "" + return "[mask-image:linear-gradient(to_right,black,black_calc(100%-24px),transparent)] group-hover/row:[mask-image:none]" + }) + + const badge = () => ( + + {(value) => ( + + + {value().label} + + } + > + + + {value().label} + + + } + > + + + {value().label} + {value().time} + + + )} + + ) + + return ( +
+ props.branch(props.record.session.directory)} />} + placement="right-start" + gutter={10} + > + + + + + + + + {badge()} + + +
+ + + } + aria-label={language.t("sidebar.settle")} + onClick={() => props.actions.onSettle(props.record)} + /> + + + + + } + aria-label={language.t("sidebar.unsettle")} + onClick={() => + props.serverArchived + ? props.actions.onUnsettleArchive(props.record.session) + : props.actions.onUnsettlePin(props.record.session.id) + } + /> + + + setMenuOpen(open)} + > + } + aria-label={language.t("common.moreOptions")} + /> + + + props.actions.onRename(props.record)}> + {language.t("common.rename")} + + + props.actions.onShare(props.record)}> + {language.t("session.share.action.share")} + + + props.actions.onExport(props.record)}> + {language.t("common.export")} + + + props.actions.onTogglePin(props.record.session.id)}> + {language.t(props.pinned ? "sidebar.thread.unpin" : "sidebar.thread.pin")} + + + + props.actions.onDelete(props.record)}> + {language.t("common.delete")} + + + + + + + } + aria-label={language.t("command.tab.close")} + onClick={() => props.actions.onCloseTab(props.record)} + /> + + +
+
+ ) +} + +function SessionInfo(props: { record: SidebarSessionRecord; branch: () => string | undefined }) { + return ( +
+ {titleOf(props.record.session)} +
+ + {props.record.name} +
+
+ + {props.record.session.directory} +
+ + {(branch) => ( +
+ + {branch()} +
+ )} +
+ + {(model) => ( +
+ + {model().id} +
+ )} +
+
+ ) +} + +function DialogRenameSession(props: { initial: string; onConfirm: (title: string) => void }) { + const language = useLanguage() + const dialog = useDialog() + const [value, setValue] = createSignal(props.initial) + const submit = () => { + const title = value().trim() + if (!title) return + props.onConfirm(title) + dialog.close() + } + return ( + + + + +
+ setValue(event.currentTarget.value)} + onKeyDown={(event) => { + if (event.key === "Enter") submit() + }} + /> +
+ + dialog.close()}> + {language.t("common.cancel")} + + {language.t("common.rename")} + +
+ ) +} + +function DialogDeleteSession(props: { name: string; onDelete: () => Promise }) { + const language = useLanguage() + const dialog = useDialog() + return ( + + + + + + dialog.close()}> + {language.t("common.cancel")} + + { + void props.onDelete().then(() => dialog.close()) + }} + > + {language.t("session.delete.button")} + + + + ) +} diff --git a/packages/app/src/pages/layout/project-avatar-state.ts b/packages/app/src/pages/layout/project-avatar-state.ts index 236f6bd40531..a85d62c06448 100644 --- a/packages/app/src/pages/layout/project-avatar-state.ts +++ b/packages/app/src/pages/layout/project-avatar-state.ts @@ -45,5 +45,5 @@ export function useSessionTabAvatarState( if (needsAttention()) return false return serverSync.session.data.session_working(sessionId()) }) - return { unread, loading } + return { unread, loading, attention: needsAttention } } diff --git a/packages/core/src/session/projector.ts b/packages/core/src/session/projector.ts index 792067017d14..a06f62966db9 100644 --- a/packages/core/src/session/projector.ts +++ b/packages/core/src/session/projector.ts @@ -69,8 +69,9 @@ function sessionRow(info: SessionV1.SessionInfo): typeof SessionTable.$inferInse permission: info.permission ? [...info.permission] : undefined, time_created: info.time.created, time_updated: info.time.updated, - time_compacting: info.time.compacting, - time_archived: info.time.archived, + time_compacting: info.time.compacting ?? null, + // Explicit null so updates can clear the archive timestamp; drizzle skips undefined. + time_archived: info.time.archived ?? null, } } diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts index 959a303dc964..8848fdb350da 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts @@ -52,7 +52,10 @@ export const UpdatePayload = Schema.Struct({ permission: Schema.optional(PermissionV1.Ruleset), time: Schema.optional( Schema.Struct({ - archived: Schema.optional(Session.ArchivedTimestamp), + // null clears the archive timestamp (unarchive); a number sets it. + // Note: the OpenAPI emitter renders optional+nullable as plain number, + // so SDK callers pass null through a documented cast. + archived: Schema.optional(Schema.NullOr(Session.ArchivedTimestamp)), }), ), }) diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts index 662585020a64..f5636ac275ee 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts @@ -198,7 +198,8 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", }) } if (ctx.payload.time?.archived !== undefined) { - yield* session.setArchived({ sessionID: ctx.params.sessionID, time: ctx.payload.time.archived }) + // null unarchives; numbers archive. + yield* session.setArchived({ sessionID: ctx.params.sessionID, time: ctx.payload.time.archived ?? undefined }) } return yield* requireSession(ctx.params.sessionID) }) diff --git a/packages/opencode/src/session/session.ts b/packages/opencode/src/session/session.ts index a2a91cd47b5e..ce8e96da6bd7 100644 --- a/packages/opencode/src/session/session.ts +++ b/packages/opencode/src/session/session.ts @@ -19,6 +19,7 @@ import { eq } from "drizzle-orm" import { and } from "drizzle-orm" import { gte } from "drizzle-orm" import { isNull } from "drizzle-orm" +import { isNotNull } from "drizzle-orm" import { desc } from "drizzle-orm" import { like } from "drizzle-orm" import { sql } from "drizzle-orm" @@ -559,7 +560,9 @@ const layer: Layer.Layer< if (input?.start) conditions.push(gte(SessionTable.time_updated, input.start)) if (input?.cursor) conditions.push(lt(SessionTable.time_updated, input.cursor)) if (input?.search) conditions.push(like(SessionTable.title, `%${input.search}%`)) - if (!input?.archived) conditions.push(isNull(SessionTable.time_archived)) + // archived=true lists only archived sessions; default excludes them. + if (input?.archived === true) conditions.push(isNotNull(SessionTable.time_archived)) + else conditions.push(isNull(SessionTable.time_archived)) const query = conditions.length > 0 diff --git a/packages/ui/src/v2/components/icon.tsx b/packages/ui/src/v2/components/icon.tsx index b22d3140fe58..0046df8f1836 100644 --- a/packages/ui/src/v2/components/icon.tsx +++ b/packages/ui/src/v2/components/icon.tsx @@ -149,6 +149,10 @@ const icons = { viewBox: "0 0 16 16", body: ``, }, + pin: { + viewBox: "0 0 24 24", + body: ``, + }, } const spriteID = "opencode-v2-icon-sprite" diff --git a/packages/ui/src/v2/components/text-input-v2.css b/packages/ui/src/v2/components/text-input-v2.css index d503830b4491..ebaf63798e20 100644 --- a/packages/ui/src/v2/components/text-input-v2.css +++ b/packages/ui/src/v2/components/text-input-v2.css @@ -27,6 +27,11 @@ height: 32px; } +[data-component="text-input-v2"][data-fluid="true"] { + width: 100%; + flex: 1 1 auto; +} + [data-component="text-input-v2"]:where(:hover):not([data-disabled], [data-invalid]):not(:focus-within) { background: linear-gradient(0deg, var(--v2-overlay-simple-overlay-hover), var(--v2-overlay-simple-overlay-hover)), diff --git a/packages/ui/src/v2/components/text-input-v2.tsx b/packages/ui/src/v2/components/text-input-v2.tsx index 8b1e748a3bf7..e30e8cc1094e 100644 --- a/packages/ui/src/v2/components/text-input-v2.tsx +++ b/packages/ui/src/v2/components/text-input-v2.tsx @@ -22,6 +22,8 @@ export interface TextInputV2Props extends Omit, "type"> invalid?: boolean /** `base` is 28px tall; `large` is 32px tall. */ appearance?: "base" | "large" + /** Stretch to the parent width instead of the fixed 280px field width. */ + fluid?: boolean type?: ComponentProps<"input">["type"] } @@ -40,6 +42,7 @@ export function TextInputV2(props: TextInputV2Props) { "numeric", "invalid", "appearance", + "fluid", "disabled", ]) @@ -50,6 +53,7 @@ export function TextInputV2(props: TextInputV2Props) { data-invalid={local.invalid ? "" : undefined} data-numeric={local.numeric ? "" : undefined} data-appearance={local.appearance ?? "base"} + data-fluid={local.fluid ? "true" : undefined} data-leading-icon={local.leadingIcon ? "" : undefined} classList={{ ...local.classList,