feat(desktop): reflect saved project colors (#46787)

This commit is contained in:
usrnk1
2026-09-03 16:37:57 +02:00
committed by GitHub
Unverified
parent b3b08c9a04
commit de365ecbaa
4 changed files with 58 additions and 3 deletions
@@ -1,6 +1,12 @@
import { describe, expect, test } from "bun:test"
import type { AgentListOutput, ModelListOutput, Project, ProviderListOutput } from "@opencode-ai/client/promise"
import { directoryKey, normalizeAgentList, normalizeProjectInfo, normalizeProviderList } from "./utils"
import {
directoryKey,
normalizeAgentList,
normalizeProjectInfo,
normalizeProviderList,
updateProjectInfo,
} from "./utils"
describe("normalizeAgentList", () => {
test("adapts current agents to the app agent shape", () => {
@@ -110,3 +116,34 @@ describe("directoryKey", () => {
expect(String(directoryKey("/"))).toBe("/")
})
})
describe("updateProjectInfo", () => {
test("applies saved metadata without losing workspace inventory", () => {
const update = {
id: "project",
canonical: "/repo",
name: "Repo",
icon: { color: "purple" },
time: { created: 1, updated: 2 },
sandboxes: ["/repo-sandbox"],
} satisfies Project
expect(
updateProjectInfo(
{
...update,
name: "Old name",
icon: { color: "gray" },
worktree: "/old-repo",
worktrees: [{ directory: "/repo", strategy: "git" }],
},
update,
),
).toMatchObject({
name: "Repo",
icon: { color: "purple" },
worktree: "/repo",
worktrees: [{ directory: "/repo", strategy: "git" }],
})
})
})
@@ -137,3 +137,12 @@ export function normalizeProjectInfo(project: Project | CurrentProject): Project
worktrees: "worktrees" in project ? project.worktrees : [{ directory: worktree }],
}
}
export function updateProjectInfo(project: Project, update: CurrentProject): Project {
return {
...project,
...update,
worktree: update.canonical,
worktrees: project.worktrees,
}
}
+9 -1
View File
@@ -11,7 +11,7 @@ import type { ProjectMeta } from "./global-sync/types"
import { formatServerError } from "@/runtime/server/errors"
import { queryOptions, useMutation, useQueries, useQuery, useQueryClient } from "@tanstack/solid-query"
import { createRefreshQueue } from "./global-sync/queue"
import { directoryKey } from "./global-sync/utils"
import { directoryKey, updateProjectInfo } from "./global-sync/utils"
import { PathKey } from "@/workspaces/path-key"
import type { ServerScope } from "@/runtime/server/scope"
import { persisted } from "@/runtime/persistence/storage"
@@ -215,8 +215,15 @@ export function createServerSyncContextInner(serverSDK: ServerSDK, data: Data) {
return promise
}
function applyProjectUpdate(update: Parameters<typeof updateProjectInfo>[1]) {
setProjects((projects) =>
projects.map((project) => (project.id === update.id ? updateProjectInfo(project, update) : project)),
)
}
const unsub = serverSDK.event.listen((event) => {
connection.handleEvent({ type: event.type })
if (event.type === "project.updated") applyProjectUpdate(event.data)
if (!event.location) {
if (event.type === "config.updated" || event.type === "agent.updated" || event.type === "worktree.updated")
@@ -243,6 +250,7 @@ export function createServerSyncContextInner(serverSDK: ServerSDK, data: Data) {
})
const projectApi = {
update: applyProjectUpdate,
meta(directory: string, patch: ProjectMeta) {
children.projectMeta(directory, patch)
},
@@ -70,12 +70,13 @@ export function createEditProjectModel(props: { project: LocalProject; server: S
const start = store.startup.trim()
if (props.project.id && props.project.id !== "global") {
await serverCtx().sdk.api.project.update({
const project = await serverCtx().sdk.api.project.update({
projectID: props.project.id,
name,
icon: { color: store.color ?? "", override: store.iconOverride ?? "" },
commands: { start },
})
serverCtx().sync.project.update(project)
dialog.close()
return
}