From 0ac0acef332583f2250b3ed15fd06d37ba2d338f Mon Sep 17 00:00:00 2001 From: Jinwoo-H Date: Fri, 12 Jun 2026 22:16:47 -0700 Subject: [PATCH] Show host context in task source picker Co-authored-by: Orca --- .../host-context-implementation-checklist.md | 1 + src/renderer/src/components/TaskPage.tsx | 11 ++++++++ .../components/ui/repo-multi-combobox.test.ts | 28 +++++++++++++++++++ .../src/components/ui/repo-multi-combobox.tsx | 18 ++++++------ 4 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 src/renderer/src/components/ui/repo-multi-combobox.test.ts diff --git a/notes/host-context-implementation-checklist.md b/notes/host-context-implementation-checklist.md index a4f3411cbe7..80a36ca1162 100644 --- a/notes/host-context-implementation-checklist.md +++ b/notes/host-context-implementation-checklist.md @@ -248,3 +248,4 @@ Done means: reviewers and future agents can understand the vision, implementatio - [x] 2026-06-12: Added a reusable Tasks source availability notice and wired unavailable source-host/account states into the Tasks source chrome, so disconnected/auth-needed/blocked hosts show an inline status, fully unavailable sources disable their icon, and partial multi-host failures remain selectable with warning copy; verified with focused source-summary tests, targeted oxlint, and full `pnpm run typecheck`. - [x] 2026-06-12: Added explicit remote-runtime Host model capability names for project setup, task source context, and workspace run context, then surfaced a Settings saved-server summary that says whether Host model support is ready, unknown, or requires a server update for specific missing capabilities; verified with focused RuntimeEnvironmentsPane tests, targeted oxlint, and full `pnpm run typecheck`. - [x] 2026-06-12: Continued the Host copy audit by replacing the SSH disconnected dialog's stale "remote repository" message with SSH-host wording; verified with a stale-copy scan, targeted oxlint, and full `pnpm run typecheck`. +- [x] 2026-06-12: Improved the Tasks project/source picker by removing the repo-row `SSH` tag and showing host-aware project detail (`Host · path`) when the picker is fed host context, so same-project-on-multiple-hosts is distinguishable without implying the project itself is SSH; verified with focused combobox tests, targeted oxlint, and full `pnpm run typecheck`. diff --git a/src/renderer/src/components/TaskPage.tsx b/src/renderer/src/components/TaskPage.tsx index c88d61a8f0e..78973e8022b 100644 --- a/src/renderer/src/components/TaskPage.tsx +++ b/src/renderer/src/components/TaskPage.tsx @@ -2882,6 +2882,15 @@ export default function TaskPage(): React.JSX.Element { ), [repos, settings, sshConnectionStates, sshTargetLabels, runtimeStatusByEnvironmentId] ) + const getTaskPickerRepoHostLabel = useCallback( + (repo: Repo): string | null => { + const provider = taskSource === 'gitlab' ? 'gitlab' : 'github' + const context = getTaskPageRepoSourceContext(repo, provider) + const hostId = context?.hostId ?? repo.executionHostId ?? 'local' + return hostRegistryById.get(hostId)?.label ?? null + }, + [hostRegistryById, taskSource] + ) const taskSourceHostAvailability = useMemo( () => taskSource === 'github' || taskSource === 'gitlab' @@ -7508,6 +7517,7 @@ export default function TaskPage(): React.JSX.Element { { setRepoSelection(next) void updateSettings({ defaultRepoSelection: [...next] }).catch(() => { @@ -8215,6 +8225,7 @@ export default function TaskPage(): React.JSX.Element { { setRepoSelection(next) void updateSettings({ defaultRepoSelection: [...next] }).catch(() => { diff --git a/src/renderer/src/components/ui/repo-multi-combobox.test.ts b/src/renderer/src/components/ui/repo-multi-combobox.test.ts new file mode 100644 index 00000000000..a0a4a747e31 --- /dev/null +++ b/src/renderer/src/components/ui/repo-multi-combobox.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from 'vitest' +import type { Repo } from '../../../../shared/types' +import { getRepoMultiComboboxDetail } from './repo-multi-combobox' + +function repo(overrides: Partial = {}): Repo { + return { + id: 'repo-1', + path: '/Users/jinwoo/orca', + displayName: 'orca', + badgeColor: '#999999', + addedAt: 1, + ...overrides + } +} + +describe('getRepoMultiComboboxDetail', () => { + it('shows host context before the path when available', () => { + expect(getRepoMultiComboboxDetail(repo(), 'Local Mac')).toBe('Local Mac · /Users/jinwoo/orca') + expect(getRepoMultiComboboxDetail(repo({ path: '/home/orca/orca' }), 'openclaw 2')).toBe( + 'openclaw 2 · /home/orca/orca' + ) + }) + + it('keeps the existing path-only detail when no host label is provided', () => { + expect(getRepoMultiComboboxDetail(repo(), null)).toBe('/Users/jinwoo/orca') + expect(getRepoMultiComboboxDetail(repo(), ' ')).toBe('/Users/jinwoo/orca') + }) +}) diff --git a/src/renderer/src/components/ui/repo-multi-combobox.tsx b/src/renderer/src/components/ui/repo-multi-combobox.tsx index 0b89a5bda10..6334f74179e 100644 --- a/src/renderer/src/components/ui/repo-multi-combobox.tsx +++ b/src/renderer/src/components/ui/repo-multi-combobox.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useMemo, useState } from 'react' -import { Check, ChevronsUpDown, Server } from 'lucide-react' +import { Check, ChevronsUpDown } from 'lucide-react' import { Button } from '@/components/ui/button' import { Command, @@ -28,6 +28,7 @@ type RepoMultiComboboxProps = { * signal, so the caller can persist `null` (sticky-all) rather than a * frozen snapshot that would exclude repos added later. */ onSelectAll: () => void + getRepoHostLabel?: (repo: Repo) => string | null | undefined triggerClassName?: string } @@ -63,11 +64,17 @@ function renderTriggerLabel(repos: Repo[], selected: ReadonlySet): React ) } +export function getRepoMultiComboboxDetail(repo: Repo, hostLabel?: string | null): string { + const trimmedHostLabel = hostLabel?.trim() + return trimmedHostLabel ? `${trimmedHostLabel} · ${repo.path}` : repo.path +} + export default function RepoMultiCombobox({ repos, selected, onChange, onSelectAll, + getRepoHostLabel, triggerClassName }: RepoMultiComboboxProps): React.JSX.Element { const [open, setOpen] = useState(false) @@ -188,6 +195,7 @@ export default function RepoMultiCombobox({ {filteredRepos.map((repo) => { const isSelected = selected.has(repo.id) const isLastSelected = isSelected && selected.size <= 1 + const detail = getRepoMultiComboboxDetail(repo, getRepoHostLabel?.(repo)) return ( - {repo.connectionId && ( - - - {translate('auto.components.ui.repo.multi.combobox.286ce70256', 'SSH')} - - )} -

{repo.path}

+

{detail}

)