diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx index ec072e7be..b6d9b518f 100644 --- a/packages/app/src/context/global-sync.tsx +++ b/packages/app/src/context/global-sync.tsx @@ -119,6 +119,22 @@ function createGlobalSync() { if (!owner) throw new Error("GlobalSync must be created within owner") const vcsCache = new Map() const metaCache = new Map() + + const [projectCache, setProjectCache, , projectCacheReady] = persisted( + Persist.global("globalSync.project", ["globalSync.project.v1"]), + createStore({ value: [] as Project[] }), + ) + + const sanitizeProject = (project: Project) => { + if (!project.icon?.url) return project + return { + ...project, + icon: { + ...project.icon, + url: undefined, + }, + } + } const [globalStore, setGlobalStore] = createStore<{ ready: boolean error?: InitError @@ -131,7 +147,7 @@ function createGlobalSync() { }>({ ready: false, path: { state: "", config: "", worktree: "", directory: "", home: "" }, - project: [], + project: projectCache.value, provider: { all: [], connected: [], default: {} }, provider_auth: {}, config: {}, @@ -139,6 +155,20 @@ function createGlobalSync() { }) let bootstrapQueue: string[] = [] + createEffect(() => { + if (!projectCacheReady()) return + if (globalStore.project.length !== 0) return + const cached = projectCache.value + if (cached.length === 0) return + setGlobalStore("project", cached) + }) + + createEffect(() => { + if (!projectCacheReady()) return + if (globalStore.project.length === 0 && projectCache.value.length !== 0) return + setProjectCache("value", globalStore.project.map(sanitizeProject)) + }) + createEffect(async () => { if (globalStore.reload !== "complete") return if (bootstrapQueue.length) { @@ -178,7 +208,7 @@ function createGlobalSync() { metaCache.set(directory, { store: meta[0], setStore: meta[1], ready: meta[3] }) const init = () => { - children[directory] = createStore({ + const child = createStore({ project: "", projectMeta: meta[0].value, provider: { all: [], connected: [], default: {} }, @@ -201,6 +231,12 @@ function createGlobalSync() { message: {}, part: {}, }) + + children[directory] = child + + createEffect(() => { + child[1]("projectMeta", meta[0].value) + }) } runWithOwner(owner, init) @@ -300,12 +336,7 @@ function createGlobalSync() { setStore("vcs", (value) => value ?? cached) }) - createEffect(() => { - if (!meta.ready()) return - const cached = meta.store.value - if (!cached) return - setStore("projectMeta", (value) => value ?? cached) - }) + // projectMeta is synced from persisted storage in ensureChild. const blockingRequests = { project: () => sdk.project.current().then((x) => setStore("project", x.data!.id)), diff --git a/packages/app/src/context/layout.tsx b/packages/app/src/context/layout.tsx index 3c544b069..9db03b25f 100644 --- a/packages/app/src/context/layout.tsx +++ b/packages/app/src/context/layout.tsx @@ -223,6 +223,13 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( ? globalSync.data.project.find((x) => x.id === projectID) : globalSync.data.project.find((x) => x.worktree === project.worktree) + const local = childStore.projectMeta + const localOverride = + local?.name !== undefined || + local?.commands?.start !== undefined || + local?.icon?.override !== undefined || + local?.icon?.color !== undefined + const base = { ...(metadata ?? {}), ...project, @@ -233,11 +240,12 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( }, } - if (projectID !== "global") return base + const isGlobal = projectID === "global" || (metadata?.id === undefined && localOverride) + if (!isGlobal) return base - const local = childStore.projectMeta return { ...base, + id: base.id ?? "global", name: local?.name, commands: local?.commands, icon: { @@ -306,10 +314,12 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( for (const project of projects) { if (project.icon?.color) continue - if (colors[project.worktree]) continue - const color = pickAvailableColor(used) - used.add(color) - setColors(project.worktree, color) + const existing = colors[project.worktree] + const color = existing ?? pickAvailableColor(used) + if (!existing) { + used.add(color) + setColors(project.worktree, color) + } if (!project.id) continue if (project.id === "global") { globalSync.project.meta(project.worktree, { icon: { color } })