mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-22 16:25:58 +00:00
feat(desktop): let inherited projects set color and icon
Auto-detected git repos ("inherited" projects) have no projects.db row, so
their menu hid appearance/rename/etc. entirely and they could never be
themed. Add appearance to the auto-project menu: the first color/icon choice
adopts the repo as a real project (folder = repo root, name = its label)
carrying that look, after which it themes in place like any explicit
project. Routes both explicit and auto edits through one setProjectAppearance
helper; the picker closes on adopt so a stale second write can't double-create.
This commit is contained in:
parent
667b98b5cf
commit
7710485c04
2 changed files with 67 additions and 8 deletions
|
|
@ -24,7 +24,7 @@ import {
|
|||
openProjectRename,
|
||||
revealPath,
|
||||
setActiveProject,
|
||||
updateProject
|
||||
setProjectAppearance
|
||||
} from '@/store/projects'
|
||||
|
||||
import type { SidebarProjectTree } from './workspace-groups'
|
||||
|
|
@ -110,6 +110,26 @@ export function ProjectMenu({
|
|||
}
|
||||
}
|
||||
|
||||
// Appearance writes route through the adopt-aware helper: an auto project is
|
||||
// materialized on its first change (its id then changes), so close the picker
|
||||
// when that happens to avoid a second write double-creating from a stale node.
|
||||
const applyAppearance = (patch: { color?: null | string; icon?: null | string }) => {
|
||||
void setProjectAppearance(project, patch).then(adopted => {
|
||||
if (adopted) {
|
||||
setAppearanceOpen(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Set color / pick an icon — shown for explicit projects and for auto ones
|
||||
// (where selecting adopts the repo as a real project so the look sticks).
|
||||
const appearanceItem = (
|
||||
<DropdownMenuItem onSelect={() => setAppearanceOpen(true)}>
|
||||
<Codicon name="symbol-color" size="0.875rem" />
|
||||
<span>{p.menuAppearance}</span>
|
||||
</DropdownMenuItem>
|
||||
)
|
||||
|
||||
const trigger = (
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
|
|
@ -144,16 +164,23 @@ export function ProjectMenu({
|
|||
onCloseAutoFocus={event => event.preventDefault()}
|
||||
sideOffset={6}
|
||||
>
|
||||
{!project.isAuto && (
|
||||
{project.isAuto ? (
|
||||
// Inherited (auto) repos can still be themed — the change adopts the
|
||||
// repo as a real project. Rename / add-folder / set-active stay out
|
||||
// until then (they need the materialized record).
|
||||
project.path ? (
|
||||
<>
|
||||
{appearanceItem}
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
) : null
|
||||
) : (
|
||||
<>
|
||||
<DropdownMenuItem onSelect={() => openProjectRename(target)}>
|
||||
<Codicon name="edit" size="0.875rem" />
|
||||
<span>{p.menuRename}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onSelect={() => setAppearanceOpen(true)}>
|
||||
<Codicon name="symbol-color" size="0.875rem" />
|
||||
<span>{p.menuAppearance}</span>
|
||||
</DropdownMenuItem>
|
||||
{appearanceItem}
|
||||
<DropdownMenuItem onSelect={() => openProjectAddFolder(target)}>
|
||||
<Codicon name="new-folder" size="0.875rem" />
|
||||
<span>{p.menuAddFolder}</span>
|
||||
|
|
@ -197,7 +224,7 @@ export function ProjectMenu({
|
|||
<ColorSwatches
|
||||
clearIcon="circle-slash"
|
||||
clearLabel={p.noColor}
|
||||
onChange={color => void updateProject(project.id, { color })}
|
||||
onChange={color => applyAppearance({ color })}
|
||||
swatches={PROFILE_SWATCHES}
|
||||
value={project.color ?? null}
|
||||
/>
|
||||
|
|
@ -212,7 +239,7 @@ export function ProjectMenu({
|
|||
project.icon === name && 'bg-(--ui-control-active-background) text-foreground'
|
||||
)}
|
||||
key={name}
|
||||
onClick={() => void updateProject(project.id, { icon: project.icon === name ? null : name })}
|
||||
onClick={() => applyAppearance({ icon: project.icon === name ? null : name })}
|
||||
style={project.icon === name && project.color ? { color: project.color } : undefined}
|
||||
type="button"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -573,6 +573,38 @@ export async function updateProject(
|
|||
)
|
||||
}
|
||||
|
||||
// Appearance for an AUTO (inherited git-repo) project has no projects.db row to
|
||||
// write to — its id is just the repo path. So the first color/icon change ADOPTS
|
||||
// the repo as a real project (folder = repo root, name = its label) carrying the
|
||||
// chosen look; from then on it patches in place like any explicit project.
|
||||
// Returns true when an adoption happened, so an incremental picker can close
|
||||
// (the node's id changes on adopt, and a second stale write would double-create).
|
||||
export async function setProjectAppearance(
|
||||
project: Pick<SidebarProjectTree, 'color' | 'icon' | 'id' | 'isAuto' | 'label' | 'path'>,
|
||||
patch: { color?: null | string; icon?: null | string }
|
||||
): Promise<boolean> {
|
||||
if (!project.isAuto) {
|
||||
await updateProject(project.id, patch)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
if (!project.path) {
|
||||
return false
|
||||
}
|
||||
|
||||
await createProject({
|
||||
name: project.label,
|
||||
folders: [project.path],
|
||||
primaryPath: project.path,
|
||||
// Carry any already-set look so setting one field doesn't wipe the other.
|
||||
color: (patch.color ?? project.color) || undefined,
|
||||
icon: (patch.icon ?? project.icon) || undefined
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export async function addProjectFolder(
|
||||
id: string,
|
||||
path: string,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue