mirror of
https://github.com/stablyai/orca.git
synced 2026-10-18 00:03:20 +00:00
Clean host copy in onboarding flows
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -242,3 +242,4 @@ Done means: reviewers and future agents can understand the vision, implementatio
|
||||
- [x] 2026-06-12: Routed GitHub issue reads, PR check reads/details, PR comments, review replies, and review-thread resolution through explicit `TaskSourceContext` in the store/preload/main IPC boundary, and source-scoped their comment/check caches; verified with GitHub slice regressions (106 tests), focused oxlint, `git diff --check`, and full `pnpm run typecheck`.
|
||||
- [x] 2026-06-12: Guarded remaining GitLab path-only fallbacks by making `workItemByPath` use the same repoId/source-context selector as the rest of GitLab IPC, passing repoId from URL picker and right-sidebar GitLab review actions, and verifying source-host routing with GitLab IPC regressions plus focused oxlint and full `pnpm run typecheck`.
|
||||
- [x] 2026-06-12: Guarded GitHub label and assignable-user metadata lookups with the same repo/source-context selector as task mutations, so drawer edit metadata cannot bypass source-host validation; verified with GitHub IPC regressions (17 tests), focused oxlint, and full `pnpm run typecheck`.
|
||||
- [x] 2026-06-12: Continued the Host copy audit through onboarding, remote folder-add, attachment import, Settings SSH copy, and remote file browser catalog text; extracted `RepoStepNestedImportPanel` to keep the touched onboarding component under max-lines, and verified with stale-copy scans, focused onboarding/repos tests, focused oxlint, full `pnpm run typecheck`, and `git diff --check`.
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
ArrowLeft,
|
||||
ArrowRight,
|
||||
CircleStop,
|
||||
FolderOpen,
|
||||
@@ -10,12 +9,10 @@ import {
|
||||
} from 'lucide-react'
|
||||
import type { Dispatch, SetStateAction } from 'react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { NestedRepoChecklist } from '@/components/repo/NestedRepoChecklist'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import type { NestedRepoScanResult } from '../../../../shared/types'
|
||||
import { NestedRepoScanLimitNotice } from '../repo/NestedRepoScanLimitNotice'
|
||||
import { getRuntimePathBasename } from '../../../../shared/cross-platform-path'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { RepoStepNestedImportPanel } from './RepoStepNestedImportPanel'
|
||||
|
||||
type RepoStepProps = {
|
||||
cloneUrl: string
|
||||
@@ -65,92 +62,20 @@ export function RepoStep({
|
||||
error
|
||||
}: RepoStepProps) {
|
||||
const disabled = Boolean(busyLabel)
|
||||
const nestedImportDisabled = disabled || nestedScanInProgress
|
||||
if (nestedScan) {
|
||||
const folderName = getRuntimePathBasename(nestedScan.selectedPath) || nestedScan.selectedPath
|
||||
return (
|
||||
<div className="flex h-full min-h-0 min-w-0 flex-col gap-3">
|
||||
<div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-lg border border-border bg-muted/30 p-5">
|
||||
<div className="flex min-w-0 shrink-0 items-center gap-4">
|
||||
<div className="grid size-11 shrink-0 place-items-center rounded-lg bg-muted text-foreground">
|
||||
<FolderOpen className="size-5" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-base font-semibold text-foreground">{translate("auto.components.onboarding.RepoStep.2d20200346", "Import repositories")}</div>
|
||||
<div className="mt-0.5 flex min-w-0 items-center gap-1.5 text-[13px] text-muted-foreground">
|
||||
{nestedScanInProgress ? (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon-xs"
|
||||
className="group text-muted-foreground hover:bg-destructive/10 hover:text-destructive focus-visible:bg-destructive/10 focus-visible:text-destructive focus-visible:ring-destructive/40"
|
||||
aria-label={translate("auto.components.onboarding.RepoStep.c3d9d44ca2", "Stop scan")}
|
||||
title={translate("auto.components.onboarding.RepoStep.c7af322fc3", "Stop scanning")}
|
||||
onClick={onStopNestedScan}
|
||||
>
|
||||
<Loader2 className="size-3.5 animate-spin text-annotation-highlight group-hover:hidden group-focus-visible:hidden" />
|
||||
<CircleStop className="hidden size-3.5 group-hover:block group-focus-visible:block" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={4}>
|
||||
{translate("auto.components.onboarding.RepoStep.e8fdb36338", "Scanning repositories. Click to stop.")}</TooltipContent>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
<span className="min-w-0 truncate">
|
||||
{translate("auto.components.onboarding.RepoStep.2e6438dd34", "{{value0}}Found {{value1}} {{value2}} in this folder.", { value0: nestedScanInProgress ? 'Scanning... ' : '', value1: nestedScan.repos.length, value2: nestedScan.repos.length === 1 ? 'repository' : 'repositories' })}
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-0.5 truncate text-[11px] text-muted-foreground">
|
||||
{translate("auto.components.onboarding.RepoStep.cecd6593fa", "Scanned folder:")} {folderName} - {nestedScan.selectedPath}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<NestedRepoChecklist
|
||||
scan={nestedScan}
|
||||
selectedPaths={nestedSelectedPaths}
|
||||
onSelectedPathsChange={onNestedSelectedPathsChange}
|
||||
disabled={nestedImportDisabled}
|
||||
className="mt-4 flex-1"
|
||||
/>
|
||||
{nestedScanInProgress ||
|
||||
nestedScan.truncated ||
|
||||
nestedScan.timedOut ||
|
||||
nestedScan.stopped ? (
|
||||
<div className="mt-2 shrink-0">
|
||||
<NestedRepoScanLimitNotice scan={nestedScan} />
|
||||
</div>
|
||||
) : null}
|
||||
<div className="mt-4 flex shrink-0 flex-wrap items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex items-center gap-1 rounded-lg px-3 py-3 text-sm text-muted-foreground hover:bg-muted/60 hover:text-foreground disabled:opacity-40"
|
||||
disabled={disabled && !nestedScanInProgress}
|
||||
onClick={onCancelNested}
|
||||
>
|
||||
<ArrowLeft className="size-3.5" />
|
||||
{translate("auto.components.onboarding.RepoStep.27ca610db1", "Back")}</button>
|
||||
<button
|
||||
type="button"
|
||||
className="ml-auto rounded-lg bg-primary px-4 py-3 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-40"
|
||||
disabled={nestedImportDisabled || nestedSelectedPaths.size === 0}
|
||||
onClick={onImportNested}
|
||||
>
|
||||
{translate("auto.components.onboarding.RepoStep.2d20200346", "Import repositories")}</button>
|
||||
</div>
|
||||
</div>
|
||||
{busyLabel && (
|
||||
<div className="shrink-0 rounded-lg border border-blue-400/30 bg-blue-400/10 px-4 py-2.5 text-sm text-blue-700 dark:text-blue-200">
|
||||
{busyLabel}
|
||||
</div>
|
||||
)}
|
||||
{error && (
|
||||
<div className="shrink-0 rounded-lg border border-red-400/30 bg-red-400/10 px-4 py-2.5 text-sm text-red-700 dark:text-red-200">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<RepoStepNestedImportPanel
|
||||
nestedScan={nestedScan}
|
||||
nestedScanInProgress={nestedScanInProgress}
|
||||
nestedSelectedPaths={nestedSelectedPaths}
|
||||
onNestedSelectedPathsChange={onNestedSelectedPathsChange}
|
||||
onImportNested={onImportNested}
|
||||
onCancelNested={onCancelNested}
|
||||
onStopNestedScan={onStopNestedScan}
|
||||
busyLabel={busyLabel}
|
||||
error={error}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return (
|
||||
@@ -168,15 +93,27 @@ export function RepoStep({
|
||||
<FolderOpen className="size-5" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-base font-semibold text-foreground">{translate("auto.components.onboarding.RepoStep.8cab104e3c", "Open a server project")}</div>
|
||||
<div className="text-base font-semibold text-foreground">
|
||||
{translate(
|
||||
'auto.components.onboarding.RepoStep.8cab104e3c',
|
||||
'Open a project on this host'
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-0.5 text-[13px] text-muted-foreground">
|
||||
{translate("auto.components.onboarding.RepoStep.466108ab89", "Enter a path that exists on the runtime server.")}</div>
|
||||
{translate(
|
||||
'auto.components.onboarding.RepoStep.466108ab89',
|
||||
'Enter a path that exists on the selected host.'
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 flex flex-col gap-2 sm:flex-row">
|
||||
<input
|
||||
className="min-w-0 flex-1 rounded-lg border border-border bg-background px-4 py-3 font-mono text-sm text-foreground outline-none transition focus:border-foreground/50 focus:ring-2 focus:ring-foreground/15"
|
||||
placeholder={translate("auto.components.onboarding.RepoStep.2ebbc26343", "/home/user/project")}
|
||||
placeholder={translate(
|
||||
'auto.components.onboarding.RepoStep.2ebbc26343',
|
||||
'/home/user/project'
|
||||
)}
|
||||
value={serverPath}
|
||||
disabled={disabled}
|
||||
spellCheck={false}
|
||||
@@ -187,14 +124,16 @@ export function RepoStep({
|
||||
className="shrink-0 rounded-lg bg-primary px-4 py-3 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-40"
|
||||
disabled={!serverPath.trim() || disabled}
|
||||
>
|
||||
{translate("auto.components.onboarding.RepoStep.3863747c56", "Add Git Project")}</button>
|
||||
{translate('auto.components.onboarding.RepoStep.3863747c56', 'Add Git Project')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="shrink-0 rounded-lg border border-border bg-background px-4 py-3 text-sm font-medium text-foreground hover:bg-muted/60 disabled:opacity-40"
|
||||
disabled={!serverPath.trim() || disabled}
|
||||
onClick={() => onOpenServerFolder('folder')}
|
||||
>
|
||||
{translate("auto.components.onboarding.RepoStep.e8214aa632", "Open as Folder")}</button>
|
||||
{translate('auto.components.onboarding.RepoStep.e8214aa632', 'Open as Folder')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
) : (
|
||||
@@ -212,18 +151,31 @@ export function RepoStep({
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<div className="min-w-0 text-base font-semibold text-foreground">
|
||||
{translate("auto.components.onboarding.RepoStep.f4e9c8dcf8", "Browse for a folder")}</div>
|
||||
{translate(
|
||||
'auto.components.onboarding.RepoStep.f4e9c8dcf8',
|
||||
'Browse for a folder'
|
||||
)}
|
||||
</div>
|
||||
<ArrowRight className="size-4 shrink-0 text-muted-foreground transition group-hover:translate-x-0.5 group-hover:text-foreground" />
|
||||
</div>
|
||||
<div className="mt-0.5 text-[13px] text-muted-foreground">
|
||||
{translate("auto.components.onboarding.RepoStep.831524961f", "Choose any local directory, git repo or not.")}</div>
|
||||
{translate(
|
||||
'auto.components.onboarding.RepoStep.831524961f',
|
||||
'Choose any local directory, git repo or not.'
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-[3.75rem] mt-3 flex w-fit max-w-[calc(100%-3.75rem)] items-center gap-2 rounded-lg border border-border bg-muted px-3 py-2 text-[12px] text-muted-foreground">
|
||||
<span className="grid size-6 shrink-0 place-items-center rounded-md border border-border bg-background text-foreground">
|
||||
<Lightbulb className="size-3.5" />
|
||||
</span>
|
||||
<span>{translate("auto.components.onboarding.RepoStep.6558d50c69", "Want to import many repos at once? Select the parent folder.")}</span>
|
||||
<span>
|
||||
{translate(
|
||||
'auto.components.onboarding.RepoStep.6558d50c69',
|
||||
'Want to import many repos at once? Select the parent folder.'
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
)}
|
||||
@@ -240,15 +192,24 @@ export function RepoStep({
|
||||
<GitBranch className="size-5" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-base font-semibold text-foreground">{translate("auto.components.onboarding.RepoStep.132425a3e3", "Clone a repo")}</div>
|
||||
<div className="text-base font-semibold text-foreground">
|
||||
{translate('auto.components.onboarding.RepoStep.132425a3e3', 'Clone a repo')}
|
||||
</div>
|
||||
<div className="mt-0.5 text-[13px] text-muted-foreground">
|
||||
{translate("auto.components.onboarding.RepoStep.288d8444b7", "Paste an HTTPS or SSH URL.")}</div>
|
||||
{translate(
|
||||
'auto.components.onboarding.RepoStep.288d8444b7',
|
||||
'Paste an HTTPS or SSH URL.'
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 flex gap-2">
|
||||
<input
|
||||
className="min-w-0 flex-1 rounded-lg border border-border bg-background px-4 py-3 font-mono text-sm text-foreground outline-none transition focus:border-foreground/50 focus:ring-2 focus:ring-foreground/15"
|
||||
placeholder={translate("auto.components.onboarding.RepoStep.955134915e", "git@github.com:org/repo.git")}
|
||||
placeholder={translate(
|
||||
'auto.components.onboarding.RepoStep.955134915e',
|
||||
'git@github.com:org/repo.git'
|
||||
)}
|
||||
value={cloneUrl}
|
||||
disabled={disabled}
|
||||
onChange={(event) => onCloneUrlChange(event.target.value)}
|
||||
@@ -258,15 +219,20 @@ export function RepoStep({
|
||||
className="shrink-0 rounded-lg bg-primary px-5 py-3 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-40"
|
||||
disabled={!cloneUrl.trim() || (runtimeActive && !cloneDestination.trim()) || disabled}
|
||||
>
|
||||
{translate("auto.components.onboarding.RepoStep.7932e95f68", "Clone")}</button>
|
||||
{translate('auto.components.onboarding.RepoStep.7932e95f68', 'Clone')}
|
||||
</button>
|
||||
</div>
|
||||
{runtimeActive && (
|
||||
<div className="mt-2 space-y-1">
|
||||
<label className="text-[11px] font-medium text-muted-foreground">
|
||||
{translate("auto.components.onboarding.RepoStep.24c7c8696c", "Clone into server path")}</label>
|
||||
{translate('auto.components.onboarding.RepoStep.24c7c8696c', 'Clone into host path')}
|
||||
</label>
|
||||
<input
|
||||
className="w-full rounded-lg border border-border bg-background px-4 py-3 font-mono text-sm text-foreground outline-none transition focus:border-foreground/50 focus:ring-2 focus:ring-foreground/15"
|
||||
placeholder={translate("auto.components.onboarding.RepoStep.7ec3f48820", "/home/user")}
|
||||
placeholder={translate(
|
||||
'auto.components.onboarding.RepoStep.7ec3f48820',
|
||||
'/home/user'
|
||||
)}
|
||||
value={cloneDestination}
|
||||
disabled={disabled}
|
||||
spellCheck={false}
|
||||
@@ -278,15 +244,19 @@ export function RepoStep({
|
||||
|
||||
<div className="flex flex-wrap items-center justify-between gap-3 px-1 pt-1 text-xs text-muted-foreground">
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<span>{translate("auto.components.onboarding.RepoStep.7b679207e4", "Workspace")}</span>
|
||||
<span>{translate('auto.components.onboarding.RepoStep.7b679207e4', 'Workspace')}</span>
|
||||
<span className="truncate font-mono text-foreground">
|
||||
{runtimeActive ? translate("auto.components.onboarding.RepoStep.cf23006ba7", "Runtime server") : workspaceDir}
|
||||
{runtimeActive
|
||||
? translate('auto.components.onboarding.RepoStep.cf23006ba7', 'Selected host')
|
||||
: workspaceDir}
|
||||
</span>
|
||||
</div>
|
||||
{runtimeActive ? (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Server className="size-3.5" />
|
||||
<span>{translate("auto.components.onboarding.RepoStep.c33b190ca3", "Server paths only")}</span>
|
||||
<span>
|
||||
{translate('auto.components.onboarding.RepoStep.c33b190ca3', 'Host paths only')}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
@@ -296,7 +266,12 @@ export function RepoStep({
|
||||
onClick={onOpenSshSettings}
|
||||
>
|
||||
<Server className="size-3.5 shrink-0" />
|
||||
<span className="truncate">{translate("auto.components.onboarding.RepoStep.b7c4da0504", "SSH? Set hosts up in Settings")}</span>
|
||||
<span className="truncate">
|
||||
{translate(
|
||||
'auto.components.onboarding.RepoStep.b7c4da0504',
|
||||
'SSH? Set hosts up in Settings'
|
||||
)}
|
||||
</span>
|
||||
<ArrowRight className="size-3.5 shrink-0" />
|
||||
</button>
|
||||
)}
|
||||
@@ -313,8 +288,14 @@ export function RepoStep({
|
||||
variant="ghost"
|
||||
size="icon-xs"
|
||||
className="group text-muted-foreground hover:bg-destructive/10 hover:text-destructive focus-visible:bg-destructive/10 focus-visible:text-destructive focus-visible:ring-destructive/40"
|
||||
aria-label={translate("auto.components.onboarding.RepoStep.c3d9d44ca2", "Stop scan")}
|
||||
title={translate("auto.components.onboarding.RepoStep.c7af322fc3", "Stop scanning")}
|
||||
aria-label={translate(
|
||||
'auto.components.onboarding.RepoStep.c3d9d44ca2',
|
||||
'Stop scan'
|
||||
)}
|
||||
title={translate(
|
||||
'auto.components.onboarding.RepoStep.c7af322fc3',
|
||||
'Stop scanning'
|
||||
)}
|
||||
onClick={onStopNestedScan}
|
||||
>
|
||||
<Loader2 className="size-3.5 animate-spin text-annotation-highlight group-hover:hidden group-focus-visible:hidden" />
|
||||
@@ -322,7 +303,11 @@ export function RepoStep({
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={4}>
|
||||
{translate("auto.components.onboarding.RepoStep.e8fdb36338", "Scanning repositories. Click to stop.")}</TooltipContent>
|
||||
{translate(
|
||||
'auto.components.onboarding.RepoStep.e8fdb36338',
|
||||
'Scanning repositories. Click to stop.'
|
||||
)}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
import { ArrowLeft, CircleStop, FolderOpen, Loader2 } from 'lucide-react'
|
||||
import type { Dispatch, SetStateAction } from 'react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { NestedRepoChecklist } from '@/components/repo/NestedRepoChecklist'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import type { NestedRepoScanResult } from '../../../../shared/types'
|
||||
import { getRuntimePathBasename } from '../../../../shared/cross-platform-path'
|
||||
import { NestedRepoScanLimitNotice } from '../repo/NestedRepoScanLimitNotice'
|
||||
|
||||
type RepoStepNestedImportPanelProps = {
|
||||
nestedScan: NestedRepoScanResult
|
||||
nestedScanInProgress: boolean
|
||||
nestedSelectedPaths: Set<string>
|
||||
onNestedSelectedPathsChange: Dispatch<SetStateAction<Set<string>>>
|
||||
onImportNested: () => void
|
||||
onCancelNested: () => void
|
||||
onStopNestedScan: () => void
|
||||
busyLabel: string | null
|
||||
error: string | null
|
||||
disabled: boolean
|
||||
}
|
||||
|
||||
export function RepoStepNestedImportPanel({
|
||||
nestedScan,
|
||||
nestedScanInProgress,
|
||||
nestedSelectedPaths,
|
||||
onNestedSelectedPathsChange,
|
||||
onImportNested,
|
||||
onCancelNested,
|
||||
onStopNestedScan,
|
||||
busyLabel,
|
||||
error,
|
||||
disabled
|
||||
}: RepoStepNestedImportPanelProps) {
|
||||
const folderName = getRuntimePathBasename(nestedScan.selectedPath) || nestedScan.selectedPath
|
||||
const nestedImportDisabled = disabled || nestedScanInProgress
|
||||
return (
|
||||
<div className="flex h-full min-h-0 min-w-0 flex-col gap-3">
|
||||
<div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-lg border border-border bg-muted/30 p-5">
|
||||
<div className="flex min-w-0 shrink-0 items-center gap-4">
|
||||
<div className="grid size-11 shrink-0 place-items-center rounded-lg bg-muted text-foreground">
|
||||
<FolderOpen className="size-5" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-base font-semibold text-foreground">
|
||||
{translate('auto.components.onboarding.RepoStep.2d20200346', 'Import repositories')}
|
||||
</div>
|
||||
<div className="mt-0.5 flex min-w-0 items-center gap-1.5 text-[13px] text-muted-foreground">
|
||||
{nestedScanInProgress ? (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon-xs"
|
||||
className="group text-muted-foreground hover:bg-destructive/10 hover:text-destructive focus-visible:bg-destructive/10 focus-visible:text-destructive focus-visible:ring-destructive/40"
|
||||
aria-label={translate(
|
||||
'auto.components.onboarding.RepoStep.c3d9d44ca2',
|
||||
'Stop scan'
|
||||
)}
|
||||
title={translate(
|
||||
'auto.components.onboarding.RepoStep.c7af322fc3',
|
||||
'Stop scanning'
|
||||
)}
|
||||
onClick={onStopNestedScan}
|
||||
>
|
||||
<Loader2 className="size-3.5 animate-spin text-annotation-highlight group-hover:hidden group-focus-visible:hidden" />
|
||||
<CircleStop className="hidden size-3.5 group-hover:block group-focus-visible:block" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={4}>
|
||||
{translate(
|
||||
'auto.components.onboarding.RepoStep.e8fdb36338',
|
||||
'Scanning repositories. Click to stop.'
|
||||
)}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
<span className="min-w-0 truncate">
|
||||
{translate(
|
||||
'auto.components.onboarding.RepoStep.2e6438dd34',
|
||||
'{{value0}}Found {{value1}} {{value2}} in this folder.',
|
||||
{
|
||||
value0: nestedScanInProgress ? 'Scanning... ' : '',
|
||||
value1: nestedScan.repos.length,
|
||||
value2: nestedScan.repos.length === 1 ? 'repository' : 'repositories'
|
||||
}
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-0.5 truncate text-[11px] text-muted-foreground">
|
||||
{translate('auto.components.onboarding.RepoStep.cecd6593fa', 'Scanned folder:')}{' '}
|
||||
{folderName} - {nestedScan.selectedPath}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<NestedRepoChecklist
|
||||
scan={nestedScan}
|
||||
selectedPaths={nestedSelectedPaths}
|
||||
onSelectedPathsChange={onNestedSelectedPathsChange}
|
||||
disabled={nestedImportDisabled}
|
||||
className="mt-4 flex-1"
|
||||
/>
|
||||
{nestedScanInProgress ||
|
||||
nestedScan.truncated ||
|
||||
nestedScan.timedOut ||
|
||||
nestedScan.stopped ? (
|
||||
<div className="mt-2 shrink-0">
|
||||
<NestedRepoScanLimitNotice scan={nestedScan} />
|
||||
</div>
|
||||
) : null}
|
||||
<div className="mt-4 flex shrink-0 flex-wrap items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex items-center gap-1 rounded-lg px-3 py-3 text-sm text-muted-foreground hover:bg-muted/60 hover:text-foreground disabled:opacity-40"
|
||||
disabled={disabled && !nestedScanInProgress}
|
||||
onClick={onCancelNested}
|
||||
>
|
||||
<ArrowLeft className="size-3.5" />
|
||||
{translate('auto.components.onboarding.RepoStep.27ca610db1', 'Back')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="ml-auto rounded-lg bg-primary px-4 py-3 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-40"
|
||||
disabled={nestedImportDisabled || nestedSelectedPaths.size === 0}
|
||||
onClick={onImportNested}
|
||||
>
|
||||
{translate('auto.components.onboarding.RepoStep.2d20200346', 'Import repositories')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{busyLabel ? (
|
||||
<div className="shrink-0 rounded-lg border border-blue-400/30 bg-blue-400/10 px-4 py-2.5 text-sm text-blue-700 dark:text-blue-200">
|
||||
{busyLabel}
|
||||
</div>
|
||||
) : null}
|
||||
{error ? (
|
||||
<div className="shrink-0 rounded-lg border border-red-400/30 bg-red-400/10 px-4 py-2.5 text-sm text-red-700 dark:text-red-200">
|
||||
{error}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -705,7 +705,7 @@ export function useOnboardingFlow(
|
||||
if (settings?.activeRuntimeEnvironmentId?.trim()) {
|
||||
const path = serverPath.trim()
|
||||
if (!path) {
|
||||
const message = 'Enter a server path.'
|
||||
const message = 'Enter a path on the selected host.'
|
||||
setError(message)
|
||||
return
|
||||
}
|
||||
@@ -996,7 +996,7 @@ export function useOnboardingFlow(
|
||||
const destination =
|
||||
target.kind === 'environment' ? cloneDestination.trim() : settings.workspaceDir
|
||||
if (!destination) {
|
||||
const message = 'Enter a server path for the clone destination.'
|
||||
const message = 'Enter a host path for the clone destination.'
|
||||
setError(message)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1388,7 +1388,7 @@ function Settings(): React.JSX.Element {
|
||||
title={translate('auto.components.settings.Settings.9b02492d1f', 'SSH Hosts')}
|
||||
description={translate(
|
||||
'auto.components.settings.Settings.c2ee313198',
|
||||
'Remote SSH hosts for files, terminals, and git.'
|
||||
'SSH host access for files, terminals, and git.'
|
||||
)}
|
||||
searchEntries={getSectionSearchEntries('ssh')}
|
||||
>
|
||||
|
||||
@@ -73,7 +73,7 @@ const NonGitFolderDialog = React.memo(function NonGitFolderDialog() {
|
||||
? err.message
|
||||
: translate(
|
||||
'auto.components.sidebar.NonGitFolderDialog.c49fb13492',
|
||||
'Failed to add remote folder'
|
||||
'Failed to add folder on this host'
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1578,7 +1578,7 @@ export function useComposerState(options: UseComposerStateOptions): UseComposerS
|
||||
toast.error(
|
||||
translate(
|
||||
'auto.hooks.useComposerState.3db83fc58a',
|
||||
'No remote project path is available for attachments.'
|
||||
'No project path is available on this host for attachments.'
|
||||
)
|
||||
)
|
||||
return { filePaths: [], folderPaths: [] }
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
},
|
||||
"repos": {
|
||||
"b7e14472ae": "Failed to add folder",
|
||||
"e649269645": "Use a server path to add projects from a remote runtime.",
|
||||
"e649269645": "Use Add Project to enter a path on the selected host.",
|
||||
"c6e022ddfc": "Failed to add project",
|
||||
"90d129b48b": "Folder added",
|
||||
"8bb3ad7935": "Project added",
|
||||
@@ -475,7 +475,7 @@
|
||||
"7eb3f44ff7": "Selected agent is disabled. Choose an enabled agent before creating.",
|
||||
"b2ead86962": "Failed to resolve PR base.",
|
||||
"a9ff236145": "Some attachments could not be uploaded.",
|
||||
"3db83fc58a": "No remote project path is available for attachments.",
|
||||
"3db83fc58a": "No project path is available on this host for attachments.",
|
||||
"ba6cb77082": "Failed to connect to project."
|
||||
},
|
||||
"useGlobalFileDrop": {
|
||||
@@ -3233,7 +3233,7 @@
|
||||
"e52454b7f6": "Open as Folder",
|
||||
"05b33a17a9": "Cancel",
|
||||
"8fba4b8cbb": "This folder isn't a Git repository. You'll have the editor, terminal, and search, but Git-based features won't be available.",
|
||||
"c49fb13492": "Failed to add remote folder"
|
||||
"c49fb13492": "Failed to add folder on this host"
|
||||
},
|
||||
"OrcaYamlTrustDialog": {
|
||||
"f3e2b868fb": "Run hooks",
|
||||
@@ -3279,7 +3279,7 @@
|
||||
"9e060f5815": "Select folder",
|
||||
"f8b1deb1a4": "Cancel",
|
||||
"51001182e3": "Empty directory",
|
||||
"971d85cc84": "Opens as a remote project · {{value0}}",
|
||||
"971d85cc84": "Opens as a project on this host · {{value0}}",
|
||||
"00c4235c10": "No matches for '{{value0}}'"
|
||||
},
|
||||
"RemoveFolderDialog": {
|
||||
@@ -8576,9 +8576,9 @@
|
||||
"RepoStep": {
|
||||
"e8fdb36338": "Scanning repositories. Click to stop.",
|
||||
"b7c4da0504": "SSH? Set hosts up in Settings",
|
||||
"c33b190ca3": "Server paths only",
|
||||
"c33b190ca3": "Host paths only",
|
||||
"7b679207e4": "Workspace",
|
||||
"24c7c8696c": "Clone into server path",
|
||||
"24c7c8696c": "Clone into host path",
|
||||
"7932e95f68": "Clone",
|
||||
"955134915e": "git@github.com:org/repo.git",
|
||||
"288d8444b7": "Paste an HTTPS or SSH URL.",
|
||||
@@ -8589,14 +8589,14 @@
|
||||
"e8214aa632": "Open as Folder",
|
||||
"3863747c56": "Add Git Project",
|
||||
"2ebbc26343": "/home/user/project",
|
||||
"466108ab89": "Enter a path that exists on the runtime server.",
|
||||
"8cab104e3c": "Open a server project",
|
||||
"466108ab89": "Enter a path that exists on the selected host.",
|
||||
"8cab104e3c": "Open a project on this host",
|
||||
"2d20200346": "Import repositories",
|
||||
"27ca610db1": "Back",
|
||||
"cecd6593fa": "Scanned folder:",
|
||||
"c7af322fc3": "Stop scanning",
|
||||
"c3d9d44ca2": "Stop scan",
|
||||
"cf23006ba7": "Runtime server",
|
||||
"cf23006ba7": "Selected host",
|
||||
"7ec3f48820": "/home/user",
|
||||
"2e6438dd34": "{{value0}}Found {{value1}} {{value2}} in this folder."
|
||||
},
|
||||
|
||||
@@ -1391,11 +1391,11 @@ export const createRepoSlice: StateCreator<AppState, [], [], RepoSlice> = (set,
|
||||
const target = getActiveRuntimeTarget(get().settings)
|
||||
if (target.kind !== 'local') {
|
||||
// Why: OS folder pickers return client-local paths. Remote environments
|
||||
// need an explicit server path, which the Add Project dialog handles.
|
||||
// need an explicit host path, which the Add Project dialog handles.
|
||||
toast.error(
|
||||
translate(
|
||||
'auto.store.slices.repos.e649269645',
|
||||
'Use a server path to add projects from a remote runtime.'
|
||||
'Use Add Project to enter a path on the selected host.'
|
||||
)
|
||||
)
|
||||
return null
|
||||
|
||||
Reference in New Issue
Block a user