mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 08:03:39 +00:00
fix(cmd-j): align badges with filter ownership
This commit is contained in:
@@ -230,6 +230,10 @@ describe('WorktreeJumpPalette', () => {
|
||||
it('renders the owning host badge on worktree and tab rows', async () => {
|
||||
await renderPalette({
|
||||
...makeRecentTabState(),
|
||||
worktreesByRepo: {
|
||||
...makeRecentTabState().worktreesByRepo,
|
||||
folder: [makeWorktree('folder', 'Folder', { repoId: 'folder', hostId: 'ssh:ssh-1' })]
|
||||
},
|
||||
repos: [makeRepo(), { ...makeRepo(), id: 'ssh-repo', connectionId: 'ssh-1' }],
|
||||
sshTargetLabels: new Map([['ssh-1', 'Builder']]),
|
||||
sshConnectionStates: new Map([
|
||||
@@ -238,7 +242,9 @@ describe('WorktreeJumpPalette', () => {
|
||||
})
|
||||
|
||||
const badge = `[aria-label="Host: ${getExecutionHostLabel('local')}"]`
|
||||
expect(testContainer.querySelector(`[data-command-item*="worktree:"] ${badge}`)).not.toBeNull()
|
||||
expect(
|
||||
testContainer.querySelector('[data-command-item*="folder"] [aria-label="Host: Builder"]')
|
||||
).not.toBeNull()
|
||||
expect(
|
||||
testContainer.querySelector(`[data-command-item*="workspace-tab:"] ${badge}`)
|
||||
).not.toBeNull()
|
||||
|
||||
@@ -154,7 +154,11 @@ import { buildPaletteListEntryRenderKeys } from '@/components/cmd-j/palette-list
|
||||
import { formatPaletteSessionAge } from '@/components/cmd-j/palette-session-age'
|
||||
import PaletteFilterMenu from '@/components/cmd-j/PaletteFilterMenu'
|
||||
import PaletteFilterChips from '@/components/cmd-j/PaletteFilterChips'
|
||||
import { buildPaletteFilterModel } from '@/components/cmd-j/palette-filter-options'
|
||||
import {
|
||||
buildPaletteFilterModel,
|
||||
resolveRepoFilterHostId,
|
||||
resolveWorktreeFilterHostId
|
||||
} from '@/components/cmd-j/palette-filter-options'
|
||||
import { getProjectGroupExecutionHostIdForRows } from '@/components/sidebar/worktree-list/listing/host-filtering'
|
||||
import {
|
||||
buildPaletteFilterPredicate,
|
||||
@@ -895,6 +899,17 @@ function WorktreeJumpPaletteContent({
|
||||
}, [filterModel])
|
||||
const filterActive = isPaletteFilterActive(filter)
|
||||
const hostFilterActive = filter.hostIds.length > 0
|
||||
const getWorktreeHostBadge = useCallback(
|
||||
(worktree: Worktree | undefined, fallbackHostId?: ExecutionHostId) =>
|
||||
getPaletteHostBadge(
|
||||
worktree
|
||||
? resolveWorktreeFilterHostId(worktree, filterModel.hostIdByRepoId, defaultHostId)
|
||||
: fallbackHostId,
|
||||
hostOptions,
|
||||
hostFilterActive
|
||||
),
|
||||
[defaultHostId, filterModel.hostIdByRepoId, hostFilterActive, hostOptions]
|
||||
)
|
||||
const filterPredicate = useMemo(
|
||||
() => buildPaletteFilterPredicate(filter, filterModel),
|
||||
[filter, filterModel]
|
||||
@@ -1102,17 +1117,13 @@ function WorktreeJumpPaletteContent({
|
||||
const hostLabelByWorktreeId = useMemo(() => {
|
||||
const labels = new Map<string, string>()
|
||||
for (const worktree of allWorktrees) {
|
||||
const badge = getPaletteHostBadge(
|
||||
resolveRepoForWorktree(worktree),
|
||||
hostOptions,
|
||||
hostFilterActive
|
||||
)
|
||||
const badge = getWorktreeHostBadge(worktree)
|
||||
if (badge) {
|
||||
labels.set(getWorktreeHostIdentity(worktree), badge.label)
|
||||
}
|
||||
}
|
||||
return labels
|
||||
}, [allWorktrees, hostFilterActive, hostOptions, resolveRepoForWorktree])
|
||||
}, [allWorktrees, getWorktreeHostBadge])
|
||||
|
||||
// Why keyed on the unsorted list: normalized documents depend only on text
|
||||
// inputs, so re-sorting for recency re-ranks without re-normalizing anything.
|
||||
@@ -3222,7 +3233,7 @@ function WorktreeJumpPaletteContent({
|
||||
: null
|
||||
const isSshDisconnected = sshStatus != null && sshStatus !== 'connected'
|
||||
const sessionAge = formatPaletteSessionAge(worktree.lastActivityAt, paletteNowMs)
|
||||
const hostBadge = getPaletteHostBadge(repo, hostOptions, hostFilterActive)
|
||||
const hostBadge = getWorktreeHostBadge(worktree)
|
||||
return (
|
||||
<CommandItem
|
||||
key={renderKey}
|
||||
@@ -3354,7 +3365,15 @@ function WorktreeJumpPaletteContent({
|
||||
const result = entry.result
|
||||
const isProject = result.kind === 'project'
|
||||
const hostBadge = isProject
|
||||
? getPaletteHostBadge(result.repo, hostOptions, hostFilterActive)
|
||||
? getPaletteHostBadge(
|
||||
resolveRepoFilterHostId(
|
||||
result.repo.id,
|
||||
filterModel.hostIdByRepoId,
|
||||
defaultHostId
|
||||
),
|
||||
hostOptions,
|
||||
hostFilterActive
|
||||
)
|
||||
: null
|
||||
const badgeLabel = isProject
|
||||
? translate('auto.components.WorktreeJumpPalette.projectBadge', 'Project')
|
||||
@@ -3441,10 +3460,9 @@ function WorktreeJumpPaletteContent({
|
||||
? resolveRepoForWorktree(workspaceTabWorktree)
|
||||
: undefined
|
||||
const workspaceTabRepoName = workspaceTabRepo?.displayName ?? result.repoName
|
||||
const workspaceTabHostBadge = getPaletteHostBadge(
|
||||
workspaceTabRepo,
|
||||
hostOptions,
|
||||
hostFilterActive
|
||||
const workspaceTabHostBadge = getWorktreeHostBadge(
|
||||
workspaceTabWorktree,
|
||||
result.executionHostId
|
||||
)
|
||||
const workspaceTabFallback =
|
||||
result.contentType === 'terminal' && result.occupantAgent ? (
|
||||
@@ -3542,10 +3560,9 @@ function WorktreeJumpPaletteContent({
|
||||
? resolveRepoForWorktree(simulatorWorktree)
|
||||
: undefined
|
||||
const simulatorRepoName = simulatorRepo?.displayName ?? result.repoName
|
||||
const simulatorHostBadge = getPaletteHostBadge(
|
||||
simulatorRepo,
|
||||
hostOptions,
|
||||
hostFilterActive
|
||||
const simulatorHostBadge = getWorktreeHostBadge(
|
||||
simulatorWorktree,
|
||||
result.executionHostId
|
||||
)
|
||||
const sessionAge = formatPaletteSessionAge(
|
||||
result.lastActiveAt ?? null,
|
||||
@@ -3629,11 +3646,7 @@ function WorktreeJumpPaletteContent({
|
||||
? resolveRepoForWorktree(browserWorktree)
|
||||
: undefined
|
||||
const browserRepoName = browserRepo?.displayName ?? result.repoName
|
||||
const browserHostBadge = getPaletteHostBadge(
|
||||
browserRepo,
|
||||
hostOptions,
|
||||
hostFilterActive
|
||||
)
|
||||
const browserHostBadge = getWorktreeHostBadge(browserWorktree, result.executionHostId)
|
||||
const sessionAge = formatPaletteSessionAge(result.lastActiveAt ?? null, paletteNowMs)
|
||||
|
||||
return (
|
||||
|
||||
@@ -20,7 +20,7 @@ describe('getPaletteHostBadge', () => {
|
||||
settings: { activeRuntimeEnvironmentId: null }
|
||||
})
|
||||
|
||||
expect(getPaletteHostBadge({ connectionId: null }, hosts)).toBeNull()
|
||||
expect(getPaletteHostBadge('local', hosts)).toBeNull()
|
||||
})
|
||||
|
||||
it('returns null when the only non-local host is configured but disconnected', () => {
|
||||
@@ -32,7 +32,7 @@ describe('getPaletteHostBadge', () => {
|
||||
|
||||
// No connection state -> the SSH host is 'disconnected', so there's nothing
|
||||
// live to disambiguate from and rows stay badge-free.
|
||||
expect(getPaletteHostBadge({ connectionId: null }, hosts)).toBeNull()
|
||||
expect(getPaletteHostBadge('local', hosts)).toBeNull()
|
||||
})
|
||||
|
||||
it('badges a disconnected host anyway when a host filter is applied', () => {
|
||||
@@ -44,7 +44,7 @@ describe('getPaletteHostBadge', () => {
|
||||
|
||||
// Why: with a host filter on, the badge is the only thing explaining which
|
||||
// rows survived, so liveness must not suppress it.
|
||||
expect(getPaletteHostBadge({ connectionId: 'ssh-1' }, hosts, true)).toEqual({
|
||||
expect(getPaletteHostBadge('ssh:ssh-1', hosts, true)).toEqual({
|
||||
hostId: 'ssh:ssh-1',
|
||||
label: 'Builder'
|
||||
})
|
||||
@@ -58,7 +58,7 @@ describe('getPaletteHostBadge', () => {
|
||||
settings: { activeRuntimeEnvironmentId: null }
|
||||
})
|
||||
|
||||
expect(getPaletteHostBadge({ connectionId: null }, hosts)).toEqual({
|
||||
expect(getPaletteHostBadge('local', hosts)).toEqual({
|
||||
hostId: 'local',
|
||||
label: LOCAL_HOST_LABEL
|
||||
})
|
||||
@@ -72,7 +72,7 @@ describe('getPaletteHostBadge', () => {
|
||||
settings: { activeRuntimeEnvironmentId: null }
|
||||
})
|
||||
|
||||
expect(getPaletteHostBadge({ connectionId: 'ssh-1' }, hosts)).toEqual({
|
||||
expect(getPaletteHostBadge('ssh:ssh-1', hosts)).toEqual({
|
||||
hostId: 'ssh:ssh-1',
|
||||
label: 'Builder'
|
||||
})
|
||||
@@ -104,7 +104,7 @@ describe('getPaletteHostBadge', () => {
|
||||
])
|
||||
})
|
||||
|
||||
expect(getPaletteHostBadge({ executionHostId: 'runtime:env-1' }, hosts)).toEqual({
|
||||
expect(getPaletteHostBadge('runtime:env-1', hosts)).toEqual({
|
||||
hostId: 'runtime:env-1',
|
||||
label: 'env-1'
|
||||
})
|
||||
@@ -117,10 +117,10 @@ describe('getPaletteHostBadge', () => {
|
||||
settings: { activeRuntimeEnvironmentId: null }
|
||||
})
|
||||
|
||||
expect(getPaletteHostBadge({ connectionId: null }, hosts)).toBeNull()
|
||||
expect(getPaletteHostBadge('local', hosts)).toBeNull()
|
||||
})
|
||||
|
||||
it('maps repos with no executionHostId/connectionId to local', () => {
|
||||
it('uses the local host label for local identities', () => {
|
||||
const hosts = buildSidebarHostOptions({
|
||||
repos: [{ connectionId: 'ssh-1' }],
|
||||
sshTargetLabels: new Map([['ssh-1', 'Builder']]),
|
||||
@@ -128,13 +128,13 @@ describe('getPaletteHostBadge', () => {
|
||||
settings: { activeRuntimeEnvironmentId: null }
|
||||
})
|
||||
|
||||
expect(getPaletteHostBadge({}, hosts)).toEqual({
|
||||
expect(getPaletteHostBadge('local', hosts)).toEqual({
|
||||
hostId: 'local',
|
||||
label: LOCAL_HOST_LABEL
|
||||
})
|
||||
})
|
||||
|
||||
it('returns null when the repo is missing', () => {
|
||||
it('returns null when the host identity is missing', () => {
|
||||
const hosts = buildSidebarHostOptions({
|
||||
repos: [{ connectionId: 'ssh-1' }],
|
||||
sshTargetLabels: new Map([['ssh-1', 'Builder']]),
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import type { Repo } from '../../../../shared/repo-types'
|
||||
import {
|
||||
getRepoExecutionHostId,
|
||||
LOCAL_EXECUTION_HOST_ID,
|
||||
type ExecutionHostId
|
||||
} from '../../../../shared/execution-host'
|
||||
import { LOCAL_EXECUTION_HOST_ID, type ExecutionHostId } from '../../../../shared/execution-host'
|
||||
import type { SidebarHostOption } from '../sidebar/sidebar-host-options'
|
||||
|
||||
export type PaletteHostBadge = {
|
||||
@@ -22,16 +17,15 @@ function hasActiveRemoteHost(hostOptions: readonly SidebarHostOption[]): boolean
|
||||
}
|
||||
|
||||
export function getPaletteHostBadge(
|
||||
repo: Pick<Repo, 'connectionId' | 'executionHostId'> | null | undefined,
|
||||
hostId: ExecutionHostId | null | undefined,
|
||||
hostOptions: readonly SidebarHostOption[],
|
||||
// Why: with a host filter applied the badge is the only thing explaining which
|
||||
// rows survived, so it must show even when every remote is disconnected.
|
||||
alwaysShowHostLabel = false
|
||||
): PaletteHostBadge | null {
|
||||
if (!repo || (!alwaysShowHostLabel && !hasActiveRemoteHost(hostOptions))) {
|
||||
if (!hostId || (!alwaysShowHostLabel && !hasActiveRemoteHost(hostOptions))) {
|
||||
return null
|
||||
}
|
||||
const hostId = getRepoExecutionHostId(repo)
|
||||
const host = hostOptions.find((option) => option.id === hostId)
|
||||
if (!host) {
|
||||
return null
|
||||
|
||||
Reference in New Issue
Block a user