Files
orca/src/shared/worktree/host-context-labels.ts
T
Neil 1b4159a318 perf(sidebar): stop building host projections the row model throws away (#18638)
* perf(sidebar): stop building host projections the row model throws away

getMixedHostContextLabels built a label map for every visible worktree and then
returned undefined unless two distinct hosts existed — so a single-host install,
the common case, paid the whole build on every buildRows rebuild. Decide first,
then build only when it is mixed.

getHostWorktreeCounts repeated getHostWorktreeIds' dedupe walk to compute a
number that is exactly the id list's length, and both loops built the identity
string twice per row. Derive the counts and hoist the identity.

* fix(test): correct the worktree types import path and drop an unused parameter
2026-09-04 14:33:17 -07:00

113 lines
3.7 KiB
TypeScript

import {
getExecutionHostLabel,
getLocalExecutionHostLabel,
normalizeExecutionHostId,
parseExecutionHostId,
toSshExecutionHostId,
type ExecutionHostId
} from '../execution-host'
import type { GlobalSettings } from '../global-settings-types'
import { getHostDisplayLabelOverrides } from '../host-setting-overrides'
/** Inputs used by every client when spelling a host in a workspace row. */
export type HostContextLabelSources = {
/** Explicit labels (SSH target names and per-host display overrides). */
hostLabelById?: ReadonlyMap<string, string>
/** The execution host's platform; clients must not use the device platform. */
hostPlatform?: NodeJS.Platform | null
}
/** Canonical user-facing host label used by desktop and mobile workspace rows. */
export function getHostContextLabel(
hostId: ExecutionHostId,
sources: HostContextLabelSources = {}
): string {
const override = sources.hostLabelById?.get(hostId)?.trim()
if (override) {
return override
}
if (parseExecutionHostId(hostId)?.kind === 'local') {
// An explicit null means the paired host platform is unknown (mobile); an
// omitted platform means use the current process (desktop).
if (sources.hostPlatform === null) {
return 'This computer'
}
return sources.hostPlatform !== undefined
? getLocalExecutionHostLabel(sources.hostPlatform)
: getExecutionHostLabel(hostId)
}
return getExecutionHostLabel(hostId)
}
/**
* Build labels for SSH targets and apply persisted display-name overrides.
* Target summaries have appeared both as raw target ids and canonical `ssh:` ids
* across protocol versions, so accept either representation.
*/
export function buildHostLabelById(args: {
sshTargets: readonly { id: string; label: string }[]
hostSettingOverrides: unknown
}): Map<ExecutionHostId, string> {
const labels = new Map<ExecutionHostId, string>()
for (const target of args.sshTargets) {
const label = target.label.trim()
if (!target.id.trim() || !label) {
continue
}
const hostId = normalizeExecutionHostId(target.id) ?? toSshExecutionHostId(target.id)
if (hostId) {
labels.set(hostId, label)
}
}
const overrides =
args.hostSettingOverrides && typeof args.hostSettingOverrides === 'object'
? getHostDisplayLabelOverrides({
hostSettingOverrides: args.hostSettingOverrides as GlobalSettings['hostSettingOverrides']
})
: new Map<ExecutionHostId, string>()
for (const [hostId, label] of overrides) {
const normalized = normalizeExecutionHostId(hostId) ?? toSshExecutionHostId(hostId)
if (normalized) {
labels.set(normalized, label)
}
}
return labels
}
/** Generic mixed-host projection shared by desktop grouping and mobile sections. */
export function getMixedHostContextLabels<T>(
items: readonly T[],
args: {
getHostId: (item: T) => ExecutionHostId
getIdentity: (item: T) => string
sources?: HostContextLabelSources
}
): Map<string, string> | undefined {
// Why two passes: on a single-host install the map is built for every item and then discarded.
// Deciding first costs one getHostId per item and skips the label work entirely.
let firstHostId: ExecutionHostId | undefined
let isMixed = false
for (const item of items) {
const hostId = args.getHostId(item)
if (firstHostId === undefined) {
firstHostId = hostId
continue
}
if (hostId !== firstHostId) {
isMixed = true
break
}
}
if (!isMixed) {
return undefined
}
const labelsByIdentity = new Map<string, string>()
for (const item of items) {
labelsByIdentity.set(
args.getIdentity(item),
getHostContextLabel(args.getHostId(item), args.sources)
)
}
return labelsByIdentity
}