import type { NativeStackNavigationProp } from "@react-navigation/native-stack"; import { useSelectWorkspaceDetail } from "../workspace/useSelectWorkspaceDetail"; import * as Dialog from "../../components/ui/Dialog"; import { AppActivityIndicator } from "../../components/ui/AppActivityIndicator"; import { NavigationRow } from "../../components/ui/NavigationRow"; import { SettingsScreen } from "../settings/components/SettingsScreen"; import { ScreenScrollView as ScrollView } from "../../components/ui/ScreenScrollView"; import { Button } from "../../components/ui/Button"; import { addProjectRemoteSourceLabel, addProjectRemoteSourcePathHint, addProjectRemoteSourceProvider, buildAddProjectRemoteSourceReadiness, buildProjectCreateCommand, canCreateProjectInEnvironment, findExistingAddProject, getAddProjectInitialQuery, getCloneDestinationBrowsePath, getCloneDestinationPath, getCloneDirectoryName, getDefaultCloneUrl, getNewProjectPathPreview, getNewProjectPublishTarget, getNewProjectPublishTargets, getNewProjectRepository, defaultHostCloneUrl, normalizePastedCloneUrl, parseAddProjectRemoteSource, resolveAddProjectPath, sortAddProjectProviderSources, type AddProjectRemoteSource, } from "@t3tools/client-runtime/operations/projects"; import { connectionStatusText, type EnvironmentConnectionPhase, } from "@t3tools/client-runtime/connection"; import { canPreloadBrowsePath, createBrowseNavigationCoordinator, filterFilesystemBrowseEntries, getFilesystemBrowsePath, resolveFilesystemReadAccess, } from "@t3tools/client-runtime/state/filesystem"; import { appendBrowsePathSegment, inferProjectTitleFromPath, isWindowsPlatform, } from "@t3tools/client-runtime/state/projects"; import { AuthOrchestrationOperateScope, AuthSourceControlWriteScope, AuthFilesystemReadScope, CommandId, type EnvironmentId, type EnvironmentMachineKind, ProjectId, resolveEnvironmentMachineKind, SourceControlProviderKind, } from "@t3tools/contracts"; import { StackActions, useNavigation, type NavigationState, type ParamListBase, } from "@react-navigation/native"; import { SymbolView } from "../../components/ui/AppSymbol"; import { useEffect, useRef, useState, type ReactNode } from "react"; import { Platform, Pressable, View } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import * as Arr from "effect/Array"; import * as Cause from "effect/Cause"; import * as Order from "effect/Order"; import { AsyncResult } from "effect/reactivity"; import { cn } from "../../lib/cn"; import { useProjects, useServerConfigs, waitForProject } from "../../state/entities"; import { filesystemEnvironment } from "../../state/filesystem"; import { projectEnvironment } from "../../state/projects"; import { useEnvironmentQuery } from "../../state/query"; import { environmentSession, useEnvironmentScope, readEnvironmentScope } from "../../state/session"; import { useEnvironmentPresentation } from "../../state/presentation"; import { sourceControlEnvironment } from "../../state/sourceControl"; import { AppText as Text, AppTextInput as TextInput } from "../../components/ui/AppText"; import { EnvironmentMachineSymbol } from "../../components/EnvironmentMachineSymbol"; import { ErrorBanner } from "../../components/ui/ErrorBanner"; import { SourceControlIcon } from "./SourceControlIcon"; import { sourceControlClients } from "@t3tools/client-runtime/source-control-clients"; import { ThemedSwitch } from "../../components/ui/ThemedSwitch"; import { uuidv4 } from "../../lib/uuid"; import { useAtomCommand } from "../../state/use-atom-command"; import { suggestAppAccessForRemote } from "./suggestAppAccess"; import { useAtomQueryRunner } from "../../state/use-atom-query-runner"; import { useRemoteConnectionStatus, useRemoteEnvironmentRuntime, useSavedRemoteConnections, } from "../../state/use-remote-environment-registry"; import { resolveAddProjectEnvironment } from "./AddProjectScreen.logic"; import { createNewTaskDraft, setComposerDraftText, waitForComposerDraftsLoaded, } from "../../state/use-composer-drafts"; interface EnvironmentOption { readonly environmentId: EnvironmentId; readonly label: string; readonly platform: string; readonly machine: EnvironmentMachineKind; readonly baseDirectory: string | null; readonly newProjectsRoot: string | null; readonly connectionState: EnvironmentConnectionPhase; readonly connectionError: string | null; readonly connectionErrorTraceId: string | null; } const environmentOptionOrder = Order.mapInput( Order.Struct({ label: Order.String, }), (environment: EnvironmentOption) => ({ label: environment.label }), ); function platformFromOs(os: string | null | undefined): string { if (os === "windows") return "Win32"; if (os === "darwin") return "MacIntel"; if (os === "linux") return "Linux"; return ""; } function errorMessage(error: unknown): string { return error instanceof Error && error.message.trim().length > 0 ? error.message : "An error occurred."; } function stringParam(value: string | string[] | undefined): string | null { if (Array.isArray(value)) return value[0] ?? null; return value ?? null; } function sourceFromParam(value: string | string[] | undefined): AddProjectRemoteSource { return parseAddProjectRemoteSource(stringParam(value)); } function SectionTitle(props: { readonly children: string }) { return ( {props.children} ); } function AddProjectShell(props: { readonly children: ReactNode; readonly title: string }) { const insets = useSafeAreaInsets(); return ( // A collapsible wrapper lets formSheet resizing mistake the full-height view for a header and collapse the ScrollView. {props.children} ); } function ListSection(props: { readonly children: ReactNode }) { return ( {props.children} ); } function ListRow(props: { readonly title: string; readonly subtitle?: string | null; readonly icon: ReactNode; readonly disabled?: boolean; readonly selected?: boolean; readonly isFirst?: boolean; readonly right?: ReactNode; readonly onPress?: () => void; }) { if (Platform.OS === "android") { return ( ); } return ( {props.icon} {props.title} {props.subtitle ? ( {props.subtitle} ) : null} {"right" in props ? ( props.right ) : !props.disabled ? ( ) : null} ); } function PrimaryActionButton(props: { readonly label: string; readonly disabled?: boolean; readonly loading?: boolean; readonly onPress: () => void; }) { return