Skip to content

Add-project: typeable, browsable destination path (create-if-missing, per environment) instead of an OS folder dialog #609

Closed

Description

@currentbits

What T3 does

Add Project is a typed path with an in-app browser, not an OS folder dialog. The palette keeps a query that is simultaneously the path input and the browse cursor: getAddProjectInitialQuery seeds it with ~/, filterFilesystemBrowseEntries lists the directory server-side, arrow keys descend (appendBrowsePathSegment), and Enter on a path that does not exist still works because project.create carries createWorkspaceRootIfMissing: true (apps/web/src/components/CommandPalette.tsx:1771, packages/contracts/src/orchestration.ts:642).

The clone flow reuses that same control for step 2 instead of inventing a dialog: once a repository is chosen, the repo folder is pinned onto the browsed path, so the proposed destination reads <folder you are browsing>/<repo> live (getCloneDestinationPath, getCloneDestinationBrowsePath, packages/client-runtime/src/operations/projects.ts:216-248). Picking a directory that already has the repo's name uses it directly rather than producing repo/repo. Validation is shared with manual add: ~ expansion, explicit-relative paths need an active project, Windows-style paths rejected off Windows (resolveAddProjectPath).

Because the browse is an RPC against the environment, the same UI works for a project on a remote machine. A native dialog cannot do that.

Solenta today

projects:addViaDialog (electron/ipc.js:263) opens dialog.showOpenDialog and passes result.filePaths[0] to addProject. That is the whole flow. Consequences:

Why it matters

This is the prerequisite for two things we already want. #459 needs a destination picker that can pin a repo folder onto a chosen parent; #245 needs any project path UI that is not showOpenDialog. Doing it once, as an IPC-backed browse, serves both, and the OS dialog can stay as a "Browse..." shortcut for the local case.

Scope suggestion

  • fs:browse({environment, path}) IPC returning directories (+ a bounded frecency listing for the empty query).
  • Add-project input: typeable path, ~ expansion, keyboard descend/ascend, entries filtered by what is typed, create-if-missing on submit, existing-project detection that opens the project instead of erroring.
  • Keep showOpenDialog as a secondary button on local.
  • Land it ahead of the clone flow in Clone from URL and publish a local repo in add-project #459 so the destination step is a reuse, not a second control.

Activity

  1. added
    enhancementNew feature or request
    and removed on Aug 20, 2026
  2. currentbits commented on Aug 20, 2026

    @currentbits
    OwnerAuthor

    Started on the typed/browsable add-project path (thread 2a0cd518). Plan: shared browse-path helpers (T3-shaped, including clone destination pinning for #459 reuse), fs:browse({environment, path}) IPC (local + SSH), create-if-missing + existing-project open on add, PathBrowser in the add-project modal, native dialog kept as Browse… on local.

  3. currentbits commented on Aug 20, 2026

    @currentbits
    OwnerAuthor

    Implemented on coder/fork-add-project-typeable-browsable-dest-2a0cd5.

    • fs:browse({environment, path, cwd}) — local readdir or ls over SSH (environment = user@host). Empty/~/~/ prepends up to 8 recent project paths.
    • PathBrowser in Add project (and Create-in): typed path seeded with ~/, keyboard descend/ascend, client-side filter. Native Browse… stays as a local showOpenDialog shortcut (hidden on web).
    • addProject: ~ expansion, existing-project match returns the same id, create-if-missing (mkdir + git init) only when the path does not exist. Existing non-git dirs still rejected.
    • Clone destination helpers (getCloneDestinationPath, pinned folder) are in src/browsePath.ts for Clone from URL and publish a local repo in add-project #459 reuse — no clone UI in this PR.
  4. added and removed on Aug 20, 2026
  5. currentbits commented on Aug 20, 2026

    @currentbits
    OwnerAuthor

    Landed on main in b701a0d.

    Add-existing is now a typed path with an in-app browser (PathBrowser + fs:browse); the OS folder dialog stays as a local-only Browse… shortcut. Missing paths are mkdir'd + git-init'd, existing non-repos are git-init'd (main's #6xx behaviour, kept through the merge), and an already-added path returns the existing project instead of duplicating it. SSH hosts browse over ssh.

    Merge conflict with the 'not a git folder' work was resolved in favour of ensureGitWorkTree for both the existing and created paths; mkdir rollback only fires for a directory the call created. Verified: 26/26 renderer (browsePath, addProjectBrowse, addProjectCreate, webDegrade, windowsDoctor), 78/78 electron (services, fs-browse, ipc-seam), tsc clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions