mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-27 17:58:07 +00:00
perf(desktop): defer model-row submenu bodies until hover
ModelMenuPanel mounts a ModelEditSubmenu per model row, and each body ran its hooks and built its JSX eagerly on menu open — ~90 rows of switches, radio groups, and preset lookups nobody hovered yet, the largest app-code slice in the open-latency profile. Wrap the body in a child component under SubContent so Radix's presence gate leaves it unrendered until the submenu actually opens; open latency drops roughly in half on a 91-model catalog.
This commit is contained in:
parent
be00a7176c
commit
667758ac24
1 changed files with 53 additions and 44 deletions
|
|
@ -96,7 +96,20 @@ interface ModelEditSubmenuProps {
|
|||
requestGateway: <T>(method: string, params?: Record<string, unknown>) => Promise<T>
|
||||
}
|
||||
|
||||
export function ModelEditSubmenu({
|
||||
export function ModelEditSubmenu(props: ModelEditSubmenuProps) {
|
||||
// The panel mounts one of these per model row; only the hovered row's
|
||||
// submenu is ever open. Keep this wrapper hook-free and render the body as
|
||||
// a CHILD of SubContent so Radix's Presence gate leaves it unrendered until
|
||||
// the sub actually opens — eagerly running the body's hooks/JSX for every
|
||||
// row made opening the menu itself lag on large catalogs.
|
||||
return (
|
||||
<DropdownMenuSubContent className="w-52 p-0" sideOffset={4}>
|
||||
<ModelEditSubmenuBody {...props} />
|
||||
</DropdownMenuSubContent>
|
||||
)
|
||||
}
|
||||
|
||||
function ModelEditSubmenuBody({
|
||||
effort,
|
||||
fastControl,
|
||||
isActive,
|
||||
|
|
@ -213,50 +226,46 @@ export function ModelEditSubmenu({
|
|||
const hasFast = fastControl.kind !== 'none'
|
||||
const fastOn = fastControl.kind === 'none' ? false : fastControl.on
|
||||
|
||||
return (
|
||||
<DropdownMenuSubContent className="w-52 p-0" sideOffset={4}>
|
||||
{!hasFast && !reasoning ? (
|
||||
<div className="px-2.5 py-3 text-xs text-(--ui-text-tertiary)">{copy.noOptions}</div>
|
||||
) : (
|
||||
return !hasFast && !reasoning ? (
|
||||
<div className="px-2.5 py-3 text-xs text-(--ui-text-tertiary)">{copy.noOptions}</div>
|
||||
) : (
|
||||
<>
|
||||
<DropdownMenuLabel className={dropdownMenuSectionLabel}>{copy.options}</DropdownMenuLabel>
|
||||
{reasoning ? (
|
||||
<DropdownMenuItem className={dropdownMenuRow} onSelect={event => event.preventDefault()}>
|
||||
{copy.thinking}
|
||||
<Switch
|
||||
checked={thinkingOn}
|
||||
className="ml-auto"
|
||||
onCheckedChange={checked => void patchReasoning(checked ? effortValue || defaultEffort : 'none')}
|
||||
size="xs"
|
||||
/>
|
||||
</DropdownMenuItem>
|
||||
) : null}
|
||||
{hasFast ? (
|
||||
<DropdownMenuItem className={dropdownMenuRow} onSelect={event => event.preventDefault()}>
|
||||
{copy.fast}
|
||||
<Switch checked={fastOn} className="ml-auto" onCheckedChange={toggleFast} size="xs" />
|
||||
</DropdownMenuItem>
|
||||
) : null}
|
||||
{reasoning ? (
|
||||
<>
|
||||
<DropdownMenuLabel className={dropdownMenuSectionLabel}>{copy.options}</DropdownMenuLabel>
|
||||
{reasoning ? (
|
||||
<DropdownMenuItem className={dropdownMenuRow} onSelect={event => event.preventDefault()}>
|
||||
{copy.thinking}
|
||||
<Switch
|
||||
checked={thinkingOn}
|
||||
className="ml-auto"
|
||||
onCheckedChange={checked => void patchReasoning(checked ? effortValue || defaultEffort : 'none')}
|
||||
size="xs"
|
||||
/>
|
||||
</DropdownMenuItem>
|
||||
) : null}
|
||||
{hasFast ? (
|
||||
<DropdownMenuItem className={dropdownMenuRow} onSelect={event => event.preventDefault()}>
|
||||
{copy.fast}
|
||||
<Switch checked={fastOn} className="ml-auto" onCheckedChange={toggleFast} size="xs" />
|
||||
</DropdownMenuItem>
|
||||
) : null}
|
||||
{reasoning ? (
|
||||
<>
|
||||
<DropdownMenuSeparator className="mx-0" />
|
||||
<DropdownMenuLabel className={dropdownMenuSectionLabel}>{copy.effort}</DropdownMenuLabel>
|
||||
<DropdownMenuRadioGroup onValueChange={value => void patchReasoning(value)} value={effortValue}>
|
||||
{REASONING_EFFORTS.map(value => (
|
||||
<DropdownMenuRadioItem
|
||||
className={dropdownMenuRow}
|
||||
key={value}
|
||||
onSelect={event => event.preventDefault()}
|
||||
value={value}
|
||||
>
|
||||
{copy[value]}
|
||||
</DropdownMenuRadioItem>
|
||||
))}
|
||||
</DropdownMenuRadioGroup>
|
||||
</>
|
||||
) : null}
|
||||
<DropdownMenuSeparator className="mx-0" />
|
||||
<DropdownMenuLabel className={dropdownMenuSectionLabel}>{copy.effort}</DropdownMenuLabel>
|
||||
<DropdownMenuRadioGroup onValueChange={value => void patchReasoning(value)} value={effortValue}>
|
||||
{REASONING_EFFORTS.map(value => (
|
||||
<DropdownMenuRadioItem
|
||||
className={dropdownMenuRow}
|
||||
key={value}
|
||||
onSelect={event => event.preventDefault()}
|
||||
value={value}
|
||||
>
|
||||
{copy[value]}
|
||||
</DropdownMenuRadioItem>
|
||||
))}
|
||||
</DropdownMenuRadioGroup>
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuSubContent>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue