Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion packages/app/src/components/settings-general.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, createMemo, type JSX } from "solid-js"
import { Component, createMemo, Show, type JSX } from "solid-js"
import { createStore } from "solid-js/store"
import { Button } from "@opencode-ai/ui/button"
import { Select } from "@opencode-ai/ui/select"
Expand All @@ -7,6 +7,7 @@ import { useTheme, type ColorScheme } from "@opencode-ai/ui/theme"
import { showToast } from "@opencode-ai/ui/toast"
import { useLanguage } from "@/context/language"
import { usePlatform } from "@/context/platform"
import { useServer } from "@/context/server"
import { useSettings, monoFontFamily } from "@/context/settings"
import { playSound, SOUND_OPTIONS } from "@/utils/sound"
import { Link } from "./link"
Expand Down Expand Up @@ -35,6 +36,7 @@ export const SettingsGeneral: Component = () => {
const language = useLanguage()
const platform = usePlatform()
const settings = useSettings()
const server = useServer()

const [store, setStore] = createStore({
checking: false,
Expand Down Expand Up @@ -410,6 +412,27 @@ export const SettingsGeneral: Component = () => {
</SettingsRow>
</div>
</div>

{/* Desktop Section - Desktop only */}
<Show when={platform.platform === "desktop"}>
<div class="flex flex-col gap-1">
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.desktop")}</h3>

<div class="bg-surface-raised-base px-4 rounded-lg">
<SettingsRow
title={language.t("settings.general.desktop.dynamicSort.title")}
description={language.t("settings.general.desktop.dynamicSort.description")}
>
<div data-action="settings-dynamic-sort">
<Switch
checked={server.dynamicSort.enabled()}
onChange={(checked) => server.dynamicSort.set(checked)}
/>
</div>
</SettingsRow>
</div>
</div>
</Show>
</div>
</div>
)
Expand Down
7 changes: 7 additions & 0 deletions packages/app/src/context/global-sync.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { bootstrapDirectory, bootstrapGlobal } from "./global-sync/bootstrap"
import { sanitizeProject } from "./global-sync/utils"
import type { ProjectMeta } from "./global-sync/types"
import { SESSION_RECENT_LIMIT } from "./global-sync/types"
import { useServer } from "./server"

type GlobalStore = {
ready: boolean
Expand All @@ -51,6 +52,7 @@ function createGlobalSync() {
const globalSDK = useGlobalSDK()
const platform = usePlatform()
const language = useLanguage()
const server = useServer()
const owner = getOwner()
if (!owner) throw new Error("GlobalSync must be created within owner")

Expand Down Expand Up @@ -280,6 +282,11 @@ function createGlobalSync() {
.lsp.status()
.then((x) => setStore("lsp", x.data ?? []))
},
onSessionBusy: (sessionID) => {
if (!server.dynamicSort.enabled()) return
server.projects.bringToTop(directory)
setStore("session_active", sessionID, Date.now())
},
})
})

Expand Down
1 change: 1 addition & 0 deletions packages/app/src/context/global-sync/child-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ export function createChildStoreManager(input: {
session: [],
sessionTotal: 0,
session_status: {},
session_active: {},
session_diff: {},
todo: {},
permission: {},
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/context/global-sync/event-reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export function applyDirectoryEvent(input: {
directory: string
loadLsp: () => void
vcsCache?: VcsCache
onSessionBusy?: (sessionID: string) => void
}) {
const event = input.event
switch (event.type) {
Expand Down Expand Up @@ -154,6 +155,7 @@ export function applyDirectoryEvent(input: {
case "session.status": {
const props = event.properties as { sessionID: string; status: SessionStatus }
input.setStore("session_status", props.sessionID, reconcile(props.status))
if (props.status.type === "busy") input.onSessionBusy?.(props.sessionID)
break
}
case "message.updated": {
Expand Down
3 changes: 3 additions & 0 deletions packages/app/src/context/global-sync/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ export type State = {
session_status: {
[sessionID: string]: SessionStatus
}
session_active: {
[sessionID: string]: number
}
session_diff: {
[sessionID: string]: FileDiff[]
}
Expand Down
49 changes: 48 additions & 1 deletion packages/app/src/context/server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { usePlatform } from "@/context/platform"
import { Persist, persisted } from "@/utils/persist"
import { checkServerHealth } from "@/utils/server-health"

type StoredProject = { worktree: string; expanded: boolean }
type StoredProject = { worktree: string; expanded: boolean; lastUsed?: number; pinned?: boolean }

export function normalizeServerUrl(input: string) {
const trimmed = input.trim()
Expand Down Expand Up @@ -37,6 +37,7 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
list: [] as string[],
projects: {} as Record<string, StoredProject[]>,
lastProject: {} as Record<string, string>,
dynamicSort: true,
}),
)

Expand Down Expand Up @@ -202,6 +203,52 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
if (!key) return
setStore("lastProject", key, directory)
},
bringToTop(directory: string) {
if (!store.dynamicSort) return
const key = origin()
if (!key) return
const current = store.projects[key] ?? []
const index = current.findIndex((x) => x.worktree === directory)
if (index <= 0) return
if (current[index].pinned) return
const project = { ...current[index], lastUsed: Date.now() }
const rest = current.filter((_, i) => i !== index)
const insertAt = rest.findIndex((x) => !x.pinned)
const result = [...rest]
result.splice(insertAt === -1 ? rest.length : insertAt, 0, project)
setStore("projects", key, result)
},
pin(directory: string) {
const key = origin()
if (!key) return
const current = store.projects[key] ?? []
const index = current.findIndex((x) => x.worktree === directory)
if (index === -1) return
const project = { ...current[index], pinned: true }
const rest = current.filter((_, i) => i !== index)
const lastPinned = rest.findLastIndex((x) => x.pinned)
const result = [...rest]
result.splice(lastPinned + 1, 0, project)
setStore("projects", key, result)
},
unpin(directory: string) {
const key = origin()
if (!key) return
const current = store.projects[key] ?? []
const index = current.findIndex((x) => x.worktree === directory)
if (index === -1) return
setStore("projects", key, index, "pinned", false)
},
isPinned(directory: string) {
const current = store.projects[origin()] ?? []
return current.find((x) => x.worktree === directory)?.pinned ?? false
},
},
dynamicSort: {
enabled: createMemo(() => store.dynamicSort ?? true),
set(value: boolean) {
setStore("dynamicSort", value)
},
},
}
},
Expand Down
6 changes: 6 additions & 0 deletions packages/app/src/i18n/ar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,8 @@ export const dict = {
"sidebar.nav.projectsAndSessions": "المشاريع والجلسات",
"sidebar.settings": "الإعدادات",
"sidebar.help": "مساعدة",
"sidebar.project.pin": "تثبيت في الأعلى",
"sidebar.project.unpin": "إلغاء التثبيت",
"sidebar.workspaces.enable": "تمكين مساحات العمل",
"sidebar.workspaces.disable": "تعطيل مساحات العمل",
"sidebar.gettingStarted.title": "البدء",
Expand All @@ -512,6 +514,10 @@ export const dict = {
"settings.general.section.notifications": "إشعارات النظام",
"settings.general.section.updates": "التحديثات",
"settings.general.section.sounds": "المؤثرات الصوتية",
"settings.general.section.desktop": "Desktop",

"settings.general.desktop.dynamicSort.title": "ترتيب ديناميكي للشريط الجانبي",
"settings.general.desktop.dynamicSort.description": "نقل المشاريع النشطة مؤخراً إلى الأعلى",

"settings.general.row.language.title": "اللغة",
"settings.general.row.language.description": "تغيير لغة العرض لـ OpenCode",
Expand Down
6 changes: 6 additions & 0 deletions packages/app/src/i18n/br.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,8 @@ export const dict = {
"sidebar.nav.projectsAndSessions": "Projetos e sessões",
"sidebar.settings": "Configurações",
"sidebar.help": "Ajuda",
"sidebar.project.pin": "Fixar no topo",
"sidebar.project.unpin": "Desafixar",
"sidebar.workspaces.enable": "Habilitar espaços de trabalho",
"sidebar.workspaces.disable": "Desabilitar espaços de trabalho",
"sidebar.gettingStarted.title": "Começando",
Expand All @@ -516,6 +518,10 @@ export const dict = {
"settings.general.section.notifications": "Notificações do sistema",
"settings.general.section.updates": "Atualizações",
"settings.general.section.sounds": "Efeitos sonoros",
"settings.general.section.desktop": "Desktop",

"settings.general.desktop.dynamicSort.title": "Ordenação dinâmica da barra lateral",
"settings.general.desktop.dynamicSort.description": "Mover projetos recentemente ativos para o topo",

"settings.general.row.language.title": "Idioma",
"settings.general.row.language.description": "Alterar o idioma de exibição do OpenCode",
Expand Down
6 changes: 6 additions & 0 deletions packages/app/src/i18n/da.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,8 @@ export const dict = {
"sidebar.nav.projectsAndSessions": "Projekter og sessioner",
"sidebar.settings": "Indstillinger",
"sidebar.help": "Hjælp",
"sidebar.project.pin": "Fastgør øverst",
"sidebar.project.unpin": "Frigør",
"sidebar.workspaces.enable": "Aktiver arbejdsområder",
"sidebar.workspaces.disable": "Deaktiver arbejdsområder",
"sidebar.gettingStarted.title": "Kom i gang",
Expand All @@ -516,6 +518,10 @@ export const dict = {
"settings.general.section.notifications": "Systemmeddelelser",
"settings.general.section.updates": "Opdateringer",
"settings.general.section.sounds": "Lydeffekter",
"settings.general.section.desktop": "Desktop",

"settings.general.desktop.dynamicSort.title": "Dynamisk sidebjælkesortering",
"settings.general.desktop.dynamicSort.description": "Flyt nyligt aktive projekter til toppen",

"settings.general.row.language.title": "Sprog",
"settings.general.row.language.description": "Ændr visningssproget for OpenCode",
Expand Down
6 changes: 6 additions & 0 deletions packages/app/src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,8 @@ export const dict = {
"sidebar.nav.projectsAndSessions": "Projekte und Sitzungen",
"sidebar.settings": "Einstellungen",
"sidebar.help": "Hilfe",
"sidebar.project.pin": "Oben anheften",
"sidebar.project.unpin": "Loslösen",
"sidebar.workspaces.enable": "Arbeitsbereiche aktivieren",
"sidebar.workspaces.disable": "Arbeitsbereiche deaktivieren",
"sidebar.gettingStarted.title": "Erste Schritte",
Expand All @@ -560,6 +562,10 @@ export const dict = {
"settings.general.section.notifications": "Systembenachrichtigungen",
"settings.general.section.updates": "Updates",
"settings.general.section.sounds": "Soundeffekte",
"settings.general.section.desktop": "Desktop",

"settings.general.desktop.dynamicSort.title": "Dynamische Seitenleisten-Sortierung",
"settings.general.desktop.dynamicSort.description": "Kürzlich aktive Projekte nach oben verschieben",

"settings.general.row.language.title": "Sprache",
"settings.general.row.language.description": "Die Anzeigesprache für OpenCode ändern",
Expand Down
6 changes: 6 additions & 0 deletions packages/app/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,8 @@ export const dict = {
"sidebar.nav.projectsAndSessions": "Projects and sessions",
"sidebar.settings": "Settings",
"sidebar.help": "Help",
"sidebar.project.pin": "Pin to top",
"sidebar.project.unpin": "Unpin",
"sidebar.workspaces.enable": "Enable workspaces",
"sidebar.workspaces.disable": "Disable workspaces",
"sidebar.gettingStarted.title": "Getting started",
Expand All @@ -588,6 +590,10 @@ export const dict = {
"settings.general.section.notifications": "System notifications",
"settings.general.section.updates": "Updates",
"settings.general.section.sounds": "Sound effects",
"settings.general.section.desktop": "Desktop",

"settings.general.desktop.dynamicSort.title": "Dynamic sidebar sorting",
"settings.general.desktop.dynamicSort.description": "Move recently active projects to the top",

"settings.general.row.language.title": "Language",
"settings.general.row.language.description": "Change the display language for OpenCode",
Expand Down
6 changes: 6 additions & 0 deletions packages/app/src/i18n/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,8 @@ export const dict = {
"sidebar.nav.projectsAndSessions": "Proyectos y sesiones",
"sidebar.settings": "Ajustes",
"sidebar.help": "Ayuda",
"sidebar.project.pin": "Fijar arriba",
"sidebar.project.unpin": "Desfijar",
"sidebar.workspaces.enable": "Habilitar espacios de trabajo",
"sidebar.workspaces.disable": "Deshabilitar espacios de trabajo",
"sidebar.gettingStarted.title": "Empezando",
Expand All @@ -519,6 +521,10 @@ export const dict = {
"settings.general.section.notifications": "Notificaciones del sistema",
"settings.general.section.updates": "Actualizaciones",
"settings.general.section.sounds": "Efectos de sonido",
"settings.general.section.desktop": "Desktop",

"settings.general.desktop.dynamicSort.title": "Ordenación dinámica de la barra lateral",
"settings.general.desktop.dynamicSort.description": "Mover proyectos recientemente activos a la parte superior",

"settings.general.row.language.title": "Idioma",
"settings.general.row.language.description": "Cambiar el idioma de visualización para OpenCode",
Expand Down
6 changes: 6 additions & 0 deletions packages/app/src/i18n/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,8 @@ export const dict = {
"sidebar.nav.projectsAndSessions": "Projets et sessions",
"sidebar.settings": "Paramètres",
"sidebar.help": "Aide",
"sidebar.project.pin": "Épingler en haut",
"sidebar.project.unpin": "Désépingler",
"sidebar.workspaces.enable": "Activer les espaces de travail",
"sidebar.workspaces.disable": "Désactiver les espaces de travail",
"sidebar.gettingStarted.title": "Commencer",
Expand All @@ -526,6 +528,10 @@ export const dict = {
"settings.general.section.notifications": "Notifications système",
"settings.general.section.updates": "Mises à jour",
"settings.general.section.sounds": "Effets sonores",
"settings.general.section.desktop": "Desktop",

"settings.general.desktop.dynamicSort.title": "Tri dynamique de la barre latérale",
"settings.general.desktop.dynamicSort.description": "Déplacer les projets récemment actifs vers le haut",

"settings.general.row.language.title": "Langue",
"settings.general.row.language.description": "Changer la langue d'affichage pour OpenCode",
Expand Down
6 changes: 6 additions & 0 deletions packages/app/src/i18n/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,8 @@ export const dict = {
"sidebar.nav.projectsAndSessions": "プロジェクトとセッション",
"sidebar.settings": "設定",
"sidebar.help": "ヘルプ",
"sidebar.project.pin": "上部に固定",
"sidebar.project.unpin": "固定を解除",
"sidebar.workspaces.enable": "ワークスペースを有効化",
"sidebar.workspaces.disable": "ワークスペースを無効化",
"sidebar.gettingStarted.title": "はじめに",
Expand All @@ -511,6 +513,10 @@ export const dict = {
"settings.general.section.notifications": "システム通知",
"settings.general.section.updates": "アップデート",
"settings.general.section.sounds": "効果音",
"settings.general.section.desktop": "Desktop",

"settings.general.desktop.dynamicSort.title": "サイドバーの動的ソート",
"settings.general.desktop.dynamicSort.description": "最近アクティブなプロジェクトを上部に移動",

"settings.general.row.language.title": "言語",
"settings.general.row.language.description": "OpenCodeの表示言語を変更します",
Expand Down
6 changes: 6 additions & 0 deletions packages/app/src/i18n/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,8 @@ export const dict = {
"sidebar.nav.projectsAndSessions": "프로젝트 및 세션",
"sidebar.settings": "설정",
"sidebar.help": "도움말",
"sidebar.project.pin": "상단에 고정",
"sidebar.project.unpin": "고정 해제",
"sidebar.workspaces.enable": "작업 공간 활성화",
"sidebar.workspaces.disable": "작업 공간 비활성화",
"sidebar.gettingStarted.title": "시작하기",
Expand All @@ -517,6 +519,10 @@ export const dict = {
"settings.general.section.notifications": "시스템 알림",
"settings.general.section.updates": "업데이트",
"settings.general.section.sounds": "효과음",
"settings.general.section.desktop": "Desktop",

"settings.general.desktop.dynamicSort.title": "사이드바 동적 정렬",
"settings.general.desktop.dynamicSort.description": "최근 활성 프로젝트를 상단으로 이동",

"settings.general.row.language.title": "언어",
"settings.general.row.language.description": "OpenCode 표시 언어 변경",
Expand Down
6 changes: 6 additions & 0 deletions packages/app/src/i18n/no.ts
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,8 @@ export const dict = {
"sidebar.nav.projectsAndSessions": "Prosjekter og sesjoner",
"sidebar.settings": "Innstillinger",
"sidebar.help": "Hjelp",
"sidebar.project.pin": "Fest øverst",
"sidebar.project.unpin": "Løsne",
"sidebar.workspaces.enable": "Aktiver arbeidsområder",
"sidebar.workspaces.disable": "Deaktiver arbeidsområder",
"sidebar.gettingStarted.title": "Kom i gang",
Expand All @@ -519,6 +521,10 @@ export const dict = {
"settings.general.section.notifications": "Systemvarsler",
"settings.general.section.updates": "Oppdateringer",
"settings.general.section.sounds": "Lydeffekter",
"settings.general.section.desktop": "Desktop",

"settings.general.desktop.dynamicSort.title": "Dynamisk sidefeltssortering",
"settings.general.desktop.dynamicSort.description": "Flytt nylig aktive prosjekter til toppen",

"settings.general.row.language.title": "Språk",
"settings.general.row.language.description": "Endre visningsspråket for OpenCode",
Expand Down
Loading
Loading