mirror of
https://github.com/stablyai/orca.git
synced 2026-10-19 00:03:20 +00:00
Show host context in task source picker
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -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`.
|
||||
|
||||
@@ -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<TaskSourceHostAvailability[]>(
|
||||
() =>
|
||||
taskSource === 'github' || taskSource === 'gitlab'
|
||||
@@ -7508,6 +7517,7 @@ export default function TaskPage(): React.JSX.Element {
|
||||
<RepoMultiCombobox
|
||||
repos={eligibleRepos}
|
||||
selected={repoSelection}
|
||||
getRepoHostLabel={getTaskPickerRepoHostLabel}
|
||||
onChange={(next) => {
|
||||
setRepoSelection(next)
|
||||
void updateSettings({ defaultRepoSelection: [...next] }).catch(() => {
|
||||
@@ -8215,6 +8225,7 @@ export default function TaskPage(): React.JSX.Element {
|
||||
<RepoMultiCombobox
|
||||
repos={eligibleRepos}
|
||||
selected={repoSelection}
|
||||
getRepoHostLabel={getTaskPickerRepoHostLabel}
|
||||
onChange={(next) => {
|
||||
setRepoSelection(next)
|
||||
void updateSettings({ defaultRepoSelection: [...next] }).catch(() => {
|
||||
|
||||
@@ -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> = {}): 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')
|
||||
})
|
||||
})
|
||||
@@ -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<string>): 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 (
|
||||
<CommandItem
|
||||
key={repo.id}
|
||||
@@ -209,14 +217,8 @@ export default function RepoMultiCombobox({
|
||||
color={repo.badgeColor}
|
||||
className="max-w-full"
|
||||
/>
|
||||
{repo.connectionId && (
|
||||
<span className="shrink-0 inline-flex items-center gap-0.5 rounded bg-muted px-1 py-0.5 text-[9px] font-medium leading-none text-muted-foreground">
|
||||
<Server className="size-2.5" />
|
||||
{translate('auto.components.ui.repo.multi.combobox.286ce70256', 'SSH')}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
<p className="mt-0.5 truncate text-[10px] text-muted-foreground">{repo.path}</p>
|
||||
<p className="mt-0.5 truncate text-[10px] text-muted-foreground">{detail}</p>
|
||||
</div>
|
||||
</CommandItem>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user