Clean host copy in onboarding flows

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jinwoo-H
2026-06-12 21:34:00 -07:00
co-authored by Orca
parent dd51c750ed
commit 0fcd896dd1
9 changed files with 256 additions and 125 deletions
@@ -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'
)
)
}
+1 -1
View File
@@ -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: [] }
+9 -9
View File
@@ -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."
},
+2 -2
View File
@@ -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