Skip to content

Commit d0eee1e

Browse files
authored
feat(project): add icon_url_override field to projects (anomalyco#23955)
1 parent 3f497bf commit d0eee1e

10 files changed

Lines changed: 1545 additions & 77 deletions

File tree

packages/app/src/context/global-sync.tsx

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ import type {
1010
import { showToast } from "@opencode-ai/ui/toast"
1111
import { getFilename } from "@opencode-ai/shared/util/path"
1212
import { batch, createContext, getOwner, onCleanup, onMount, type ParentProps, untrack, useContext } from "solid-js"
13-
import { createStore, produce, reconcile, unwrap } from "solid-js/store"
13+
import { createStore, produce, reconcile } from "solid-js/store"
1414
import { useLanguage } from "@/context/language"
15-
import { Persist, persisted } from "@/utils/persist"
1615
import type { InitError } from "../pages/error"
1716
import { useGlobalSDK } from "./global-sdk"
1817
import { bootstrapDirectory, bootstrapGlobal, clearProviderRev } from "./global-sync/bootstrap"
@@ -24,7 +23,6 @@ import { estimateRootSessionTotal, loadRootSessionsWithFallback } from "./global
2423
import { trimSessions } from "./global-sync/session-trim"
2524
import type { ProjectMeta } from "./global-sync/types"
2625
import { SESSION_RECENT_LIMIT } from "./global-sync/types"
27-
import { sanitizeProject } from "./global-sync/utils"
2826
import { formatServerError } from "@/utils/server-errors"
2927
import { queryOptions, skipToken, useQueryClient } from "@tanstack/solid-query"
3028

@@ -56,15 +54,10 @@ function createGlobalSync() {
5654
const sessionLoads = new Map<string, Promise<void>>()
5755
const sessionMeta = new Map<string, { limit: number }>()
5856

59-
const [projectCache, setProjectCache, projectInit] = persisted(
60-
Persist.global("globalSync.project", ["globalSync.project.v1"]),
61-
createStore({ value: [] as Project[] }),
62-
)
63-
6457
const [globalStore, setGlobalStore] = createStore<GlobalStore>({
6558
ready: false,
6659
path: { state: "", config: "", worktree: "", directory: "", home: "" },
67-
project: projectCache.value,
60+
project: [],
6861
session_todo: {},
6962
provider: { all: [], connected: [], default: {} },
7063
provider_auth: {},
@@ -73,32 +66,18 @@ function createGlobalSync() {
7366
})
7467
const queryClient = useQueryClient()
7568

76-
let active = true
77-
let projectWritten = false
7869
let bootedAt = 0
7970
let bootingRoot = false
8071
let eventFrame: number | undefined
8172
let eventTimer: ReturnType<typeof setTimeout> | undefined
8273

83-
onCleanup(() => {
84-
active = false
85-
})
8674
onCleanup(() => {
8775
if (eventFrame !== undefined) cancelAnimationFrame(eventFrame)
8876
if (eventTimer !== undefined) clearTimeout(eventTimer)
8977
})
9078

91-
const cacheProjects = () => {
92-
setProjectCache(
93-
"value",
94-
untrack(() => globalStore.project.map(sanitizeProject)),
95-
)
96-
}
97-
9879
const setProjects = (next: Project[] | ((draft: Project[]) => Project[])) => {
99-
projectWritten = true
10080
setGlobalStore("project", next)
101-
cacheProjects()
10281
}
10382

10483
const setBootStore = ((...input: unknown[]) => {
@@ -117,16 +96,6 @@ function createGlobalSync() {
11796
return (setGlobalStore as (...args: unknown[]) => unknown)(...input)
11897
}) as typeof setGlobalStore
11998

120-
if (projectInit instanceof Promise) {
121-
void projectInit.then(() => {
122-
if (!active) return
123-
if (projectWritten) return
124-
const cached = projectCache.value
125-
if (cached.length === 0) return
126-
setGlobalStore("project", cached)
127-
})
128-
}
129-
13099
const setSessionTodo = (sessionID: string, todos: Todo[] | undefined) => {
131100
if (!sessionID) return
132101
if (!todos) {

packages/app/src/context/global-sync/child-store.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,12 @@ export function createChildStoreManager(input: {
156156

157157
const init = () =>
158158
createRoot((dispose) => {
159-
const initialMeta = meta[0].value
160159
const initialIcon = icon[0].value
161160

162161
const pathQuery = useQuery(() => loadPathQuery(directory))
163162
const child = createStore<State>({
164163
project: "",
165-
projectMeta: initialMeta,
164+
projectMeta: undefined,
166165
icon: initialIcon,
167166
provider_ready: false,
168167
provider: { all: [], connected: [], default: {} },
@@ -208,11 +207,6 @@ export function createChildStoreManager(input: {
208207
child[1]("vcs", (value) => value ?? cached)
209208
})
210209

211-
onPersistedInit(meta[2], () => {
212-
if (child[0].projectMeta !== initialMeta) return
213-
child[1]("projectMeta", meta[0].value)
214-
})
215-
216210
onPersistedInit(icon[2], () => {
217211
if (child[0].icon !== initialIcon) return
218212
child[1]("icon", icon[0].value)

packages/app/src/context/layout.tsx

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -391,37 +391,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
391391
? globalSync.data.project.find((x) => x.id === projectID)
392392
: globalSync.data.project.find((x) => x.worktree === project.worktree)
393393

394-
const local = childStore.projectMeta
395-
const localOverride =
396-
local?.name !== undefined ||
397-
local?.commands?.start !== undefined ||
398-
local?.icon?.override !== undefined ||
399-
local?.icon?.color !== undefined
400-
401-
const base = {
402-
...metadata,
403-
...project,
404-
icon: {
405-
url: metadata?.icon?.url,
406-
override: metadata?.icon?.override ?? childStore.icon,
407-
color: metadata?.icon?.color,
408-
},
409-
}
410-
411-
const isGlobal = projectID === "global" || (metadata?.id === undefined && localOverride)
412-
if (!isGlobal) return base
413-
414-
return {
415-
...base,
416-
id: base.id ?? "global",
417-
name: local?.name,
418-
commands: local?.commands,
419-
icon: {
420-
url: base.icon?.url,
421-
override: local?.icon?.override,
422-
color: local?.icon?.color,
423-
},
424-
}
394+
return { ...metadata, ...project }
425395
}
426396

427397
const roots = createMemo(() => {
@@ -516,7 +486,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
516486
}
517487

518488
for (const project of projects) {
519-
if (project.icon?.color || project.icon.url) continue
489+
if (project.icon?.color || project.icon?.override || project.icon?.url) continue
520490
const worktree = project.worktree
521491
const existing = colors[worktree]
522492
const color = existing ?? pickAvailableColor(used)

packages/app/src/pages/layout/sidebar-items.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ const OPENCODE_PROJECT_ID = "4b0ea68d7af9a6031a7ffda7ad66e0cb83315750"
2222
export function getProjectAvatarSource(id?: string, icon?: { color?: string; url?: string; override?: string }) {
2323
return id === OPENCODE_PROJECT_ID
2424
? "https://opencode.ai/favicon.svg"
25-
: icon?.color
26-
? undefined
27-
: icon?.override || icon?.url
25+
: (icon?.override ?? (icon?.color ? undefined : icon?.url))
2826
}
2927

3028
export const ProjectIcon = (props: { project: LocalProject; class?: string; notify?: boolean }): JSX.Element => {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE `project` ADD `icon_url_override` text;
2+
UPDATE `project` SET `icon_url_override` = `icon_url` WHERE `icon_url` IS NOT NULL;

0 commit comments

Comments
 (0)