Skip to content

fix: allow v2 project setup on selected remote host#4665

Merged
Kitenite merged 1 commit into
superset-sh:mainfrom
rifqi2320:fix/remote-host-project-setup
May 17, 2026
Merged

fix: allow v2 project setup on selected remote host#4665
Kitenite merged 1 commit into
superset-sh:mainfrom
rifqi2320:fix/remote-host-project-setup

Conversation

@rifqi2320
Copy link
Copy Markdown
Contributor

@rifqi2320 rifqi2320 commented May 17, 2026

Fixes the remote/headless host setup gap where the New Workspace modal detects that a project is not registered on the selected host, but project setup opens local-only settings.

This change:

  • threads selected host context from the New Workspace setup CTA into v2 project settings
  • resolves the selected host URL/name in project settings and uses that host client for project setup, conflict checks, and scripts
  • adds remote path entry for headless hosts instead of using the local directory picker for remote setup
  • supports superset projects setup --project <projectId> --path <path> while keeping existing positional/--import usage
  • enhances superset projects list with per-host setup status and path

Verification:

  • bunx biome check packages/cli/src/commands/projects/list/command.ts packages/cli/src/commands/projects/setup/command.ts apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/PromptGroup/PromptGroup.tsx apps/desktop/src/renderer/routes/_authenticated/settings/projects/\$projectId/page.tsx apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/\$projectId/components/V2ProjectSettings/V2ProjectSettings.tsx apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/\$projectId/components/V2ProjectSettings/components/ProjectLocationSection/ProjectLocationSection.tsx
  • bun run --cwd packages/cli typecheck
  • bun run --cwd apps/desktop typecheck
  • git diff --check

Note: initial bun install failed rebuilding native node-pty because node-gyp is not installed in this environment; reran bun install --ignore-scripts to install JS tooling for typecheck.


Open in Stage

Summary by cubic

Fixes v2 project setup so a selected remote/headless host is honored end-to-end. The New Workspace flow now opens project settings for that host and runs setup, conflict checks, and scripts on that host.

  • Bug Fixes

    • Thread hostId from New Workspace to v2 project settings and resolve target host URL/name.
    • Use the target host client for project fetch, setup, conflict checks, and scripts.
    • For remote/headless hosts, replace the local directory picker with inputs for remote import path and clone parent directory.
    • Clarify UI copy (e.g., “this device” vs the remote host name).
  • New Features

    • superset projects setup supports --project <id> and --path <path> (alias for --import), with stricter argument validation; existing positional ID and --parentDir still work.
    • superset projects list adds per-host setup status and path columns and supports --host <machineId> or --local filters.

Written for commit 3bb34e3. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features
    • Remote host support for project settings and configuration management
    • CLI projects list now displays per-host setup status and repository paths
    • CLI projects setup command now supports --project flag and --path option for flexible project registration

Review Change Stack

@capy-ai
Copy link
Copy Markdown

capy-ai Bot commented May 17, 2026

Capy auto-review is paused for this organization because the monthly auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 17, 2026

📝 Walkthrough

Walkthrough

This PR extends multi-host project management across the desktop application and CLI. The desktop workflow now routes host context through project settings navigation, resolves target host details in settings components, and handles remote project import and clone operations with conditional UI and conflict detection. The CLI gains per-host project status reporting and flexible project ID input via optional flags.

Changes

Multi-host project management via desktop settings and CLI

Layer / File(s) Summary
Route navigation and search parameter flow
apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/PromptGroup/PromptGroup.tsx, apps/desktop/src/renderer/routes/_authenticated/settings/projects/$projectId/page.tsx
PromptGroup passes hostId via search parameter on project settings navigation. Route validates and exposes hostId search parameter, and V2ProjectSettings receives hostId as a prop.
V2ProjectSettings host target resolution
apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/V2ProjectSettings.tsx
V2ProjectSettings accepts hostId, derives targetHostUrl and targetHostId with fallback to local machineId, fetches target host display name via useLiveQuery, and updates host-project queries to use target host. ProjectLocationSection and Scripts section receive host details.
ProjectLocationSection remote host operations
apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/ProjectLocationSection/ProjectLocationSection.tsx
ProjectLocationSection accepts hostUrl, hostName, and isRemoteTarget props. Helper functions (runSetup, runClone, pickPath) require hostUrl with error messages referencing hostName. handleImport and handleClone add remote-target branches for direct path inputs with backfill conflict detection. Remote UI renders path input fields instead of local directory pickers.
CLI projects list with per-host status
packages/cli/src/commands/projects/list/command.ts
Projects list command adds --host and --local options, queries both organization and host-specific projects, and augments organization projects with setUp and path fields from host project lookup. Table output includes new SET UP and PATH columns.
CLI projects setup with flexible project ID and path alias
packages/cli/src/commands/projects/setup/command.ts
Projects setup command makes positional id optional and adds --project flag for project UUID input with validation. Adds --path as alias for --import with mutual-exclusion validation. Restricts --allow-relocate to import/register mode. Host target resolution uses resolveHostFilter.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Multi-host dreams take flight, so right!
Search params dance, routes unite,
Remote clones sing, paths rearrange,
CLI commands grant the gift of change. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main fix: allowing v2 project setup on a selected remote host, which directly matches the primary objective of the changeset.
Description check ✅ Passed The PR description comprehensively covers the changes, includes a clear summary of what was fixed, lists verification steps, and provides implementation details. It exceeds the basic template requirements.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@stage-review
Copy link
Copy Markdown

stage-review Bot commented May 17, 2026

Ready to review this PR? Stage has broken it down into 4 individual chapters for you:

Title
1 Enhance CLI project list and setup commands
2 Pass host context to project settings
3 Resolve target host in V2 settings
4 Support remote path entry for headless hosts
Open in Stage

Chapters generated by Stage for commit 3bb34e3 on May 17, 2026 2:13pm UTC.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 17, 2026

Greptile Summary

This PR threads the selected remote host context from the New Workspace modal into v2 project settings, so that clicking "Set up project…" on a remote host opens the correct host-aware settings page. The CLI gains --project/--path flags for projects setup and per-host setup status columns for projects list.

  • Desktop: hostId is passed as a URL search param through page.tsxV2ProjectSettingsProjectLocationSection; remote hosts get text inputs instead of the native directory picker; useHostUrl resolves the correct relay URL for all host-specific queries.
  • CLI setup: The positional project ID becomes optional, --project is added as an alias, --path aliases --import, and requireHostTarget is relaxed to default to the local host.
  • CLI list: Adds SET UP and PATH columns by querying the target host, but the host query runs unconditionally even when no --host/--local flag is passed, making a previously API-only command fail when the local host service is not running.

Confidence Score: 3/5

The desktop changes are safe; the CLI list change breaks bare invocations when the host service is not running.

The desktop side correctly threads host context end-to-end and handles remote vs local UI branching well. The CLI setup refactor is clean. However, projects list now unconditionally contacts the local host service manifest — any environment where the host service is not running (CI, scripting, a fresh machine) will receive a hard error from a command that previously worked offline. That regression is the main concern in an otherwise solid PR.

packages/cli/src/commands/projects/list/command.ts — the host query should be conditional on explicit --host/--local flags

Important Files Changed

Filename Overview
packages/cli/src/commands/projects/list/command.ts Adds per-host setup status columns but unconditionally calls resolveHostTarget even without --host/--local flags, breaking bare invocations when the local host service is not running
packages/cli/src/commands/projects/setup/command.ts Adds --project flag and --path alias for --import; changes requireHostTarget to resolveHostFilter so host defaults to local; conflict-detection and error messages look correct
apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/PromptGroup/PromptGroup.tsx Threads draft.hostId into the project settings navigation so the correct remote host context is preserved when opening setup from the workspace modal
apps/desktop/src/renderer/routes/_authenticated/settings/projects/$projectId/page.tsx Adds validateSearch for hostId query param and passes it through to V2ProjectSettings; correct and straightforward
apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/V2ProjectSettings.tsx Resolves target host URL/name from the passed hostId and passes it downstream; logic for local vs remote distinction and query key updating looks correct
apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/ProjectLocationSection/ProjectLocationSection.tsx Remote path input UI and import/clone handlers look correct; conflict-dialog Open project navigation loses hostId context

Sequence Diagram

sequenceDiagram
    participant Modal as New Workspace Modal
    participant Page as /settings/projects/$projectId
    participant V2Settings as V2ProjectSettings
    participant PLS as ProjectLocationSection
    participant Host as Host Service (local or relay)

    Modal->>Page: "navigate({ hostId })"
    Page->>Page: validateSearch to hostId
    Page->>V2Settings: V2ProjectSettings hostId
    V2Settings->>V2Settings: useHostUrl(hostId) to targetHostUrl
    V2Settings->>Host: project.get.query
    V2Settings->>PLS: hostUrl, hostName, isRemoteTarget
    alt isRemoteTarget
        PLS->>PLS: show text inputs
        PLS->>Host: project.findBackfillConflict.query
        PLS->>Host: project.setup.mutate
    else local
        PLS->>PLS: show native directory picker
        PLS->>Host: project.findBackfillConflict.query
        PLS->>Host: project.setup.mutate
    end
Loading

Comments Outside Diff (1)

  1. apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/ProjectLocationSection/ProjectLocationSection.tsx, line 373-384 (link)

    P2 Conflict-dialog "Open project" navigation drops host context

    When handleImport (remote path) finds a conflict and the user clicks "Open project", the navigation navigates to the conflicting project's settings page without a search: { hostId } param. This means the conflicting project opens in local/default host context. If the user was configuring a remote host, they now need to manually re-select that host in the opened project's settings, which is confusing and inconsistent with the flow that brought them here.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/ProjectLocationSection/ProjectLocationSection.tsx
    Line: 373-384
    
    Comment:
    **Conflict-dialog "Open project" navigation drops host context**
    
    When `handleImport` (remote path) finds a conflict and the user clicks "Open project", the navigation navigates to the conflicting project's settings page without a `search: { hostId }` param. This means the conflicting project opens in local/default host context. If the user was configuring a remote host, they now need to manually re-select that host in the opened project's settings, which is confusing and inconsistent with the flow that brought them here.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
packages/cli/src/commands/projects/list/command.ts:28-33
**`list` now always requires a running host service**

`resolveHostTarget` unconditionally reads the local host manifest and throws `CLIError("Host service for this machine isn't running")` when the service is not up. Before this PR, `superset projects list` only contacted the API and worked regardless of host state. Any user who runs `superset projects list` without `--host`/`--local` and without a running host service will now get a confusing error even though they only wanted a project listing. The `SET UP` and `PATH` columns should only be populated when a host filter is explicitly requested, keeping the no-flag path purely API-backed.

### Issue 2 of 2
apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/ProjectLocationSection/ProjectLocationSection.tsx:373-384
**Conflict-dialog "Open project" navigation drops host context**

When `handleImport` (remote path) finds a conflict and the user clicks "Open project", the navigation navigates to the conflicting project's settings page without a `search: { hostId }` param. This means the conflicting project opens in local/default host context. If the user was configuring a remote host, they now need to manually re-select that host in the opened project's settings, which is confusing and inconsistent with the flow that brought them here.

Reviews (1): Last reviewed commit: "fix: allow project setup on selected hos..." | Re-trigger Greptile

Comment on lines +28 to +33
const target = resolveHostTarget({
requestedHostId: hostId,
organizationId,
userJwt: ctx.bearer,
});
const hostProjects = await target.client.project.list.query();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 list now always requires a running host service

resolveHostTarget unconditionally reads the local host manifest and throws CLIError("Host service for this machine isn't running") when the service is not up. Before this PR, superset projects list only contacted the API and worked regardless of host state. Any user who runs superset projects list without --host/--local and without a running host service will now get a confusing error even though they only wanted a project listing. The SET UP and PATH columns should only be populated when a host filter is explicitly requested, keeping the no-flag path purely API-backed.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/cli/src/commands/projects/list/command.ts
Line: 28-33

Comment:
**`list` now always requires a running host service**

`resolveHostTarget` unconditionally reads the local host manifest and throws `CLIError("Host service for this machine isn't running")` when the service is not up. Before this PR, `superset projects list` only contacted the API and worked regardless of host state. Any user who runs `superset projects list` without `--host`/`--local` and without a running host service will now get a confusing error even though they only wanted a project listing. The `SET UP` and `PATH` columns should only be populated when a host filter is explicitly requested, keeping the no-flag path purely API-backed.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/ProjectLocationSection/ProjectLocationSection.tsx (1)

26-33: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve target host context when opening a conflicting project.

The conflict action navigates without hostId, so remote setup conflicts can reopen project settings on the wrong (local) host context.

🔧 Proposed fix
 interface ProjectLocationSectionProps {
 	projectId: string;
 	currentPath: string | null;
 	repoCloneUrl: string | null;
+	hostId: string | null;
 	hostUrl: string | null;
 	hostName: string;
 	isRemoteTarget: boolean;
 	onChanged?: () => void;
 }

 export function ProjectLocationSection({
 	projectId,
 	currentPath,
 	repoCloneUrl,
+	hostId,
 	hostUrl,
 	hostName,
 	isRemoteTarget,
 	onChanged,
 }: ProjectLocationSectionProps) {
@@
 								navigate({
 									to: "/settings/projects/$projectId",
 									params: { projectId: target.id },
+									search: { hostId: hostId ?? undefined },
 								});

Also pass hostId={targetHostId ?? null} from V2ProjectSettings when rendering ProjectLocationSection.

Also applies to: 36-44, 380-383

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/`$projectId/components/V2ProjectSettings/components/ProjectLocationSection/ProjectLocationSection.tsx
around lines 26 - 33, The ProjectLocationSection currently lacks a hostId prop
so conflict navigation loses remote host context; update the
ProjectLocationSectionProps interface to include hostId: string | null, update
the ProjectLocationSection component to accept and use that prop when
constructing the conflict navigation action, and when V2ProjectSettings renders
<ProjectLocationSection> pass hostId={targetHostId ?? null} (and likewise where
else ProjectLocationSection is instantiated around the indicated ranges) so the
conflict handler preserves hostId during navigation.
🧹 Nitpick comments (1)
packages/cli/src/commands/projects/list/command.ts (1)

23-45: ⚡ Quick win

Gracefully degrade when the host project lookup fails.

Line 33 makes projects list fail hard if the selected host is offline or unreachable, even though the organization projects were already fetched on Line 23. Catching that lookup and rendering setup/path as unknown would preserve the old listing behavior while still enriching the happy path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/commands/projects/list/command.ts` around lines 23 - 45, The
host-side project lookup (target.client.project.list.query invoked after
resolveHostTarget) can throw and should be caught so the command still returns
the organization projects; wrap the host lookup in a try/catch (around the call
to target.client.project.list.query and subsequent hostProjects mapping) and on
error set hostProjects to an empty array (or keep hostProjectById empty) and
optionally log/debug the error; ensure the final returned mapping in the
projects.map still runs and uses "unknown"/"-" or the existing "no"/"-"
semantics (setUp: "no" or "unknown" and path: "-" or "unknown") when hostProject
is missing so the list gracefully degrades when the host is unreachable.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/`$projectId/components/V2ProjectSettings/components/ProjectLocationSection/ProjectLocationSection.tsx:
- Around line 365-369: The AlertDialogDescription text in ProjectLocationSection
is not selectable due to global user-select: none; update the
AlertDialogDescription element (in the ProjectLocationSection component) to
include explicit selectable classes (e.g., add "select-text cursor-text" or your
project's equivalent class names) so the conflict/error message text can be
copied by users; ensure the class is applied to the same element rendering the
string "{conflict?.name ?? ""}" so the entire message becomes selectable.

In `@packages/cli/src/commands/projects/setup/command.ts`:
- Around line 27-38: The current validation allows both options.project and
args.id to be provided if they match; change the logic in the project ID
validation so that if both sources are present (options.project and args.id) you
always throw a CLIError indicating duplicate project ID sources (regardless of
equality), ensuring exactly one source is used; keep the existing projectId
extraction (const projectId = (options.project ?? args.id) as string |
undefined) and replace the conditional that checks options.project && args.id &&
options.project !== args.id with a simple options.project && args.id check that
throws the same "Project ID specified twice" CLIError.

---

Outside diff comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/`$projectId/components/V2ProjectSettings/components/ProjectLocationSection/ProjectLocationSection.tsx:
- Around line 26-33: The ProjectLocationSection currently lacks a hostId prop so
conflict navigation loses remote host context; update the
ProjectLocationSectionProps interface to include hostId: string | null, update
the ProjectLocationSection component to accept and use that prop when
constructing the conflict navigation action, and when V2ProjectSettings renders
<ProjectLocationSection> pass hostId={targetHostId ?? null} (and likewise where
else ProjectLocationSection is instantiated around the indicated ranges) so the
conflict handler preserves hostId during navigation.

---

Nitpick comments:
In `@packages/cli/src/commands/projects/list/command.ts`:
- Around line 23-45: The host-side project lookup
(target.client.project.list.query invoked after resolveHostTarget) can throw and
should be caught so the command still returns the organization projects; wrap
the host lookup in a try/catch (around the call to
target.client.project.list.query and subsequent hostProjects mapping) and on
error set hostProjects to an empty array (or keep hostProjectById empty) and
optionally log/debug the error; ensure the final returned mapping in the
projects.map still runs and uses "unknown"/"-" or the existing "no"/"-"
semantics (setUp: "no" or "unknown" and path: "-" or "unknown") when hostProject
is missing so the list gracefully degrades when the host is unreachable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dd9bd28e-71ed-4f79-b80b-6b8a83790330

📥 Commits

Reviewing files that changed from the base of the PR and between 8f9a8ea and 3bb34e3.

📒 Files selected for processing (6)
  • apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/PromptGroup/PromptGroup.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/projects/$projectId/page.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/V2ProjectSettings.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/ProjectLocationSection/ProjectLocationSection.tsx
  • packages/cli/src/commands/projects/list/command.ts
  • packages/cli/src/commands/projects/setup/command.ts

Comment on lines 365 to 369
<AlertDialogDescription>
This repository is already linked to project "
{conflict?.name ?? ""}" in this organization. Open that project to
set it up on this device.
set it up on {hostName}.
</AlertDialogDescription>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make conflict/error dialog text selectable.

Add explicit selectable text classes to the dialog error description so users can copy it.

🎯 Proposed fix
-						<AlertDialogDescription>
+						<AlertDialogDescription className="select-text cursor-text">
 							This repository is already linked to project "
 							{conflict?.name ?? ""}" in this organization. Open that project to
 							set it up on {hostName}.
 						</AlertDialogDescription>

As per coding guidelines, apps/desktop/**/*.{tsx,jsx}: Error text must be selectable by users with explicit select-text cursor-text classes; renderer sets user-select: none on body.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/`$projectId/components/V2ProjectSettings/components/ProjectLocationSection/ProjectLocationSection.tsx
around lines 365 - 369, The AlertDialogDescription text in
ProjectLocationSection is not selectable due to global user-select: none; update
the AlertDialogDescription element (in the ProjectLocationSection component) to
include explicit selectable classes (e.g., add "select-text cursor-text" or your
project's equivalent class names) so the conflict/error message text can be
copied by users; ensure the class is applied to the same element rendering the
string "{conflict?.name ?? ""}" so the entire message becomes selectable.

Comment on lines +27 to +38
const projectId = (options.project ?? args.id) as string | undefined;
if (!projectId) {
throw new CLIError(
"Project ID required",
"Pass --project <projectId>, or provide the project ID as the first argument.",
);
}
if (options.project && args.id && options.project !== args.id) {
throw new CLIError(
"Project ID specified twice",
"Use either --project <projectId> or the positional project ID, not both.",
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Reject duplicate project IDs even when both values match.

Line 34 only errors when the two inputs differ, so --project <id> <id> still passes even though this command now requires exactly one project ID source. That leaves the new validation incomplete.

Proposed fix
 		const projectId = (options.project ?? args.id) as string | undefined;
 		if (!projectId) {
 			throw new CLIError(
 				"Project ID required",
 				"Pass --project <projectId>, or provide the project ID as the first argument.",
 			);
 		}
-		if (options.project && args.id && options.project !== args.id) {
+		if (options.project && args.id) {
 			throw new CLIError(
 				"Project ID specified twice",
 				"Use either --project <projectId> or the positional project ID, not both.",
 			);
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/commands/projects/setup/command.ts` around lines 27 - 38,
The current validation allows both options.project and args.id to be provided if
they match; change the logic in the project ID validation so that if both
sources are present (options.project and args.id) you always throw a CLIError
indicating duplicate project ID sources (regardless of equality), ensuring
exactly one source is used; keep the existing projectId extraction (const
projectId = (options.project ?? args.id) as string | undefined) and replace the
conditional that checks options.project && args.id && options.project !==
args.id with a simple options.project && args.id check that throws the same
"Project ID specified twice" CLIError.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 6 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/cli/src/commands/projects/list/command.ts">

<violation number="1" location="packages/cli/src/commands/projects/list/command.ts:24">
P1: `projects list` hard-fails on host resolution/RPC errors, regressing previously available API-only listing behavior. The command now unconditionally calls `resolveHostTarget()` and `target.client.project.list.query()` with no fallback. If the local host service isn't running (no manifest/stale PID) or the remote host is unreachable, the entire command throws instead of returning the cloud project list. The `setUp`/`path` metadata is additive and should be gracefully omitted when host data is unavailable.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Re-trigger cubic


return ctx.api.v2Project.list.query({ organizationId });
const projects = await ctx.api.v2Project.list.query({ organizationId });
const hostId = resolveHostFilter({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: projects list hard-fails on host resolution/RPC errors, regressing previously available API-only listing behavior. The command now unconditionally calls resolveHostTarget() and target.client.project.list.query() with no fallback. If the local host service isn't running (no manifest/stale PID) or the remote host is unreachable, the entire command throws instead of returning the cloud project list. The setUp/path metadata is additive and should be gracefully omitted when host data is unavailable.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/commands/projects/list/command.ts, line 24:

<comment>`projects list` hard-fails on host resolution/RPC errors, regressing previously available API-only listing behavior. The command now unconditionally calls `resolveHostTarget()` and `target.client.project.list.query()` with no fallback. If the local host service isn't running (no manifest/stale PID) or the remote host is unreachable, the entire command throws instead of returning the cloud project list. The `setUp`/`path` metadata is additive and should be gracefully omitted when host data is unavailable.</comment>

<file context>
@@ -1,20 +1,47 @@
 
-		return ctx.api.v2Project.list.query({ organizationId });
+		const projects = await ctx.api.v2Project.list.query({ organizationId });
+		const hostId = resolveHostFilter({
+			host: options.host ?? undefined,
+			local: options.local ?? undefined,
</file context>

@Kitenite Kitenite merged commit ca7ad95 into superset-sh:main May 17, 2026
2 checks passed
@Kitenite
Copy link
Copy Markdown
Collaborator

Thanks for this @rifqi2320 adding a follow up PR with some handling on the settings page UI as well for multiple host

Kitenite added a commit that referenced this pull request May 17, 2026
)

* feat(desktop): polish v2 project settings to Linear-style layout

Restructures the v2 project settings page to match the canonical
SettingsRow pattern used in OrganizationSettings: flat list of rows
with a uniform w-96 control column, no inner borders or card chrome.

- Move project icon thumbnail into the page header beside the title;
  clicking the thumbnail opens a dropdown menu (Upload / Use GitHub
  icon / Remove) instead of inline buttons.
- Host scope chip rendered inline in the header (single-host hidden).
- Repository and Location each render a single w-96 field with a
  ghost icon button absolutely positioned inside it: FaGithub +
  tooltip "Open in GitHub" for Repository, LuFolderOpen + tooltip
  "Change location" for Location.
- Location path display uses overflow-x-auto whitespace-nowrap so
  long paths scroll horizontally inside the field instead of breaking
  mid-word; ClickablePath gains an opt-in truncate prop (kept for v1
  callers).
- Scripts editor uses underline-style tabs (no pill chrome, no gap,
  px-3 per trigger, hover transition), a skeleton-shaped loading
  state matching the rendered layout, and a tucked-in "Import" button
  inside the textarea corner.
- All inputs normalized to text-sm; mono fields keep font-mono.
- Delete project row aligned to py-2.5 / gap-8 rhythm without a
  separator above.

* fix: address review feedback on PR #4665

- cli/projects list: gracefully degrade when the host service can't
  be reached and the user did not explicitly pass --host/--local.
  Falls back to showing organization projects with setUp="?" and
  path="-" instead of throwing, restoring the previously API-only
  listing behavior. Still throws when --host or --local was requested
  explicitly, so the user gets a clear error in that case. (P1 flagged
  by greptile-apps and cubic-dev-ai.)
- cli/projects setup: reject "Project ID specified twice" whenever
  both --project and the positional argument are passed, even when
  the values match. (Flagged by coderabbitai.)
- v2 project settings: add `select-text cursor-text` to both
  AlertDialogDescription blocks in ProjectLocationSection so users
  can copy the conflict message and the From/To paths into bug
  reports. Aligns with the renderer-wide "error text must be
  selectable" rule in apps/desktop/AGENTS.md. (Flagged by
  coderabbitai.)

* refactor(desktop): tighten v2 Location empty state UI

The remote empty state previously rendered three side-by-side blocks
(a decorative "Not set up on X" input chrome, plus two stacked
input+button rows for Import and Clone) — busy and repeated the host
name three times.

Replace with a single inline form: mode Select (Clone / Import) +
path input + "Set up" button. Mode defaults to Clone when a GitHub
remote is linked, otherwise Import. The Clone option in the dropdown
disables and shows a tooltip when no repo is linked.

Local empty state drops the decorative left container too and just
shows the two outline buttons that trigger the native folder picker.

No behavior change: handleImport / handleClone still drive the same
setup logic and conflict precheck.

* feat(desktop): move v2 project setup form into a modal

Replace the inline empty-state setup form (mode select + path input +
button) with a single "Set up project…" button that opens a new
SetupProjectModal. The empty Location row now reads:

  Not set up on {host}.  [Set up project…]

The modal has Clone / Import existing tabs, a Repository readout on
the Clone tab, and a path input. For local-host setup the input is
paired with a browse button (native folder picker); for remote-host
setup the input is text-only with a hostName-qualified placeholder.

Conflict precheck is preserved: on import, if the path is already
linked to another project, the modal closes and the existing
"Repository already linked" AlertDialog opens via the parent.

ProjectLocationSection drops the now-unused remoteImportPath /
remoteCloneParentDir / remoteMode state and the inline submit
handlers; runSetup / runClone live in the modal. The Change… flow
and the Relocate confirmation dialog are untouched.

* feat(desktop): add RemotePathPicker for browsing host filesystem

When setting up a project on a remote host you couldn't previously
pick a directory — only type the absolute path blind. Add a reusable
folder browser that talks to the host service over tRPC.

Backend:
- New filesystem.browseHost protected query on the host-service
  router. Takes an optional absolute or ~-prefixed path (defaults to
  homedir()), normalizes it, and returns { path, parentPath, homePath,
  entries[] } with entries sorted dotfiles-last and folders-first.
  Hidden files filtered by default; pass includeHidden:true to see
  them. Unlike the existing listDirectory endpoint, this is not
  scoped to a workspace — used for setup flows where no workspace
  exists yet on the host. Path must be absolute or start with ~ for
  safety; relative paths are rejected.

Frontend (renderer/components/RemotePathPicker):
- Reusable component that opens a Dialog with a path input
  (~-aware), Up / Home / Refresh icon buttons, and a scrollable list
  of subfolders. Single-click highlights a folder in the path input;
  double-click descends into it. "Use this folder" picks the current
  path and closes. Reusable across any future flow that needs to
  pick a path on a host (workspace settings, script paths, etc.).

Integration:
- SetupProjectModal: the browse button now opens RemotePathPicker
  for remote hosts and the existing native Electron picker for local
  hosts, behind the same LuFolderOpen icon. Picked path fills the
  Clone parent-directory or Import existing-repo input.

* refactor(desktop): redesign RemotePathPicker with Linear design

Replace the four-button toolbar + editable path input with a clean
breadcrumb-driven path picker:

- Breadcrumb at top doubles as path display and navigation. Clicking
  any earlier segment jumps to that level. Last segment is bold. If
  the path lives under $HOME it starts with a "Home" segment; long
  paths collapse middle segments with BreadcrumbEllipsis.
- Folders below in a borderless scroll area. Single click on a folder
  descends into it (replaces the earlier double-click pattern, which
  was easy to miss). Hover state on each row, no outer border.
- Refresh moves into a quiet icon button next to the breadcrumb.
- Symlink indicator: small LuExternalLink at the row end instead of a
  text "link" badge.
- Empty state shows a muted folder glyph plus "Empty folder" / "No
  subfolders" message.
- Loading state renders skeleton rows that match the rendered row
  layout (icon + label).
- Borders only where they carry weight: under the breadcrumb row and
  above the footer. The dialog itself drops outer padding and gains
  per-section padding so the borders span the full dialog width.
- Drops the Up / Home / Edit-path toolbar buttons; up-navigation
  happens via breadcrumb segments and home-navigation via the
  first "Home" segment. The current path is always visible in the
  breadcrumb, so no separate read-only path readout is needed.

* fix(desktop): address review feedback on PR #4675

Functional fixes:
- ProjectLocationSection: the "Change location" pencil button used to
  open the local native folder picker even when the project was set
  up on a remote host, which would have produced an invalid
  relocation path. Now: on local targets it still opens the native
  picker; on remote targets it opens the RemotePathPicker against
  the remote host's filesystem. The relocate flow (conflict
  precheck + relocate confirm dialog) is unchanged.
- V2ScriptsEditor/ScriptField: add `pb-8 pr-20` to the textarea so
  the absolute-positioned Import button at the bottom-right can no
  longer overlap typed content.
- ClickablePath: the truncate span needs `min-w-0` when its parent
  is a flex container, otherwise the ellipsis never kicks in.

Structural fixes (one-component-per-file rule from AGENTS.md):
- Extract `SettingsRow` from V2ProjectSettings.tsx into its own
  SettingsRow/ folder with an index re-export. V2ProjectSettings.tsx
  imports it.
- Extract `ScriptField` from V2ScriptsEditor.tsx into a co-located
  components/ScriptField/ folder. V2ScriptsEditor.tsx imports it.
  (Co-located under V2ScriptsEditor since it's only used by that
  editor.)
sazabi Bot pushed a commit that referenced this pull request May 20, 2026
sazabi Bot pushed a commit that referenced this pull request May 20, 2026
)

* feat(desktop): polish v2 project settings to Linear-style layout

Restructures the v2 project settings page to match the canonical
SettingsRow pattern used in OrganizationSettings: flat list of rows
with a uniform w-96 control column, no inner borders or card chrome.

- Move project icon thumbnail into the page header beside the title;
  clicking the thumbnail opens a dropdown menu (Upload / Use GitHub
  icon / Remove) instead of inline buttons.
- Host scope chip rendered inline in the header (single-host hidden).
- Repository and Location each render a single w-96 field with a
  ghost icon button absolutely positioned inside it: FaGithub +
  tooltip "Open in GitHub" for Repository, LuFolderOpen + tooltip
  "Change location" for Location.
- Location path display uses overflow-x-auto whitespace-nowrap so
  long paths scroll horizontally inside the field instead of breaking
  mid-word; ClickablePath gains an opt-in truncate prop (kept for v1
  callers).
- Scripts editor uses underline-style tabs (no pill chrome, no gap,
  px-3 per trigger, hover transition), a skeleton-shaped loading
  state matching the rendered layout, and a tucked-in "Import" button
  inside the textarea corner.
- All inputs normalized to text-sm; mono fields keep font-mono.
- Delete project row aligned to py-2.5 / gap-8 rhythm without a
  separator above.

* fix: address review feedback on PR #4665

- cli/projects list: gracefully degrade when the host service can't
  be reached and the user did not explicitly pass --host/--local.
  Falls back to showing organization projects with setUp="?" and
  path="-" instead of throwing, restoring the previously API-only
  listing behavior. Still throws when --host or --local was requested
  explicitly, so the user gets a clear error in that case. (P1 flagged
  by greptile-apps and cubic-dev-ai.)
- cli/projects setup: reject "Project ID specified twice" whenever
  both --project and the positional argument are passed, even when
  the values match. (Flagged by coderabbitai.)
- v2 project settings: add `select-text cursor-text` to both
  AlertDialogDescription blocks in ProjectLocationSection so users
  can copy the conflict message and the From/To paths into bug
  reports. Aligns with the renderer-wide "error text must be
  selectable" rule in apps/desktop/AGENTS.md. (Flagged by
  coderabbitai.)

* refactor(desktop): tighten v2 Location empty state UI

The remote empty state previously rendered three side-by-side blocks
(a decorative "Not set up on X" input chrome, plus two stacked
input+button rows for Import and Clone) — busy and repeated the host
name three times.

Replace with a single inline form: mode Select (Clone / Import) +
path input + "Set up" button. Mode defaults to Clone when a GitHub
remote is linked, otherwise Import. The Clone option in the dropdown
disables and shows a tooltip when no repo is linked.

Local empty state drops the decorative left container too and just
shows the two outline buttons that trigger the native folder picker.

No behavior change: handleImport / handleClone still drive the same
setup logic and conflict precheck.

* feat(desktop): move v2 project setup form into a modal

Replace the inline empty-state setup form (mode select + path input +
button) with a single "Set up project…" button that opens a new
SetupProjectModal. The empty Location row now reads:

  Not set up on {host}.  [Set up project…]

The modal has Clone / Import existing tabs, a Repository readout on
the Clone tab, and a path input. For local-host setup the input is
paired with a browse button (native folder picker); for remote-host
setup the input is text-only with a hostName-qualified placeholder.

Conflict precheck is preserved: on import, if the path is already
linked to another project, the modal closes and the existing
"Repository already linked" AlertDialog opens via the parent.

ProjectLocationSection drops the now-unused remoteImportPath /
remoteCloneParentDir / remoteMode state and the inline submit
handlers; runSetup / runClone live in the modal. The Change… flow
and the Relocate confirmation dialog are untouched.

* feat(desktop): add RemotePathPicker for browsing host filesystem

When setting up a project on a remote host you couldn't previously
pick a directory — only type the absolute path blind. Add a reusable
folder browser that talks to the host service over tRPC.

Backend:
- New filesystem.browseHost protected query on the host-service
  router. Takes an optional absolute or ~-prefixed path (defaults to
  homedir()), normalizes it, and returns { path, parentPath, homePath,
  entries[] } with entries sorted dotfiles-last and folders-first.
  Hidden files filtered by default; pass includeHidden:true to see
  them. Unlike the existing listDirectory endpoint, this is not
  scoped to a workspace — used for setup flows where no workspace
  exists yet on the host. Path must be absolute or start with ~ for
  safety; relative paths are rejected.

Frontend (renderer/components/RemotePathPicker):
- Reusable component that opens a Dialog with a path input
  (~-aware), Up / Home / Refresh icon buttons, and a scrollable list
  of subfolders. Single-click highlights a folder in the path input;
  double-click descends into it. "Use this folder" picks the current
  path and closes. Reusable across any future flow that needs to
  pick a path on a host (workspace settings, script paths, etc.).

Integration:
- SetupProjectModal: the browse button now opens RemotePathPicker
  for remote hosts and the existing native Electron picker for local
  hosts, behind the same LuFolderOpen icon. Picked path fills the
  Clone parent-directory or Import existing-repo input.

* refactor(desktop): redesign RemotePathPicker with Linear design

Replace the four-button toolbar + editable path input with a clean
breadcrumb-driven path picker:

- Breadcrumb at top doubles as path display and navigation. Clicking
  any earlier segment jumps to that level. Last segment is bold. If
  the path lives under $HOME it starts with a "Home" segment; long
  paths collapse middle segments with BreadcrumbEllipsis.
- Folders below in a borderless scroll area. Single click on a folder
  descends into it (replaces the earlier double-click pattern, which
  was easy to miss). Hover state on each row, no outer border.
- Refresh moves into a quiet icon button next to the breadcrumb.
- Symlink indicator: small LuExternalLink at the row end instead of a
  text "link" badge.
- Empty state shows a muted folder glyph plus "Empty folder" / "No
  subfolders" message.
- Loading state renders skeleton rows that match the rendered row
  layout (icon + label).
- Borders only where they carry weight: under the breadcrumb row and
  above the footer. The dialog itself drops outer padding and gains
  per-section padding so the borders span the full dialog width.
- Drops the Up / Home / Edit-path toolbar buttons; up-navigation
  happens via breadcrumb segments and home-navigation via the
  first "Home" segment. The current path is always visible in the
  breadcrumb, so no separate read-only path readout is needed.

* fix(desktop): address review feedback on PR #4675

Functional fixes:
- ProjectLocationSection: the "Change location" pencil button used to
  open the local native folder picker even when the project was set
  up on a remote host, which would have produced an invalid
  relocation path. Now: on local targets it still opens the native
  picker; on remote targets it opens the RemotePathPicker against
  the remote host's filesystem. The relocate flow (conflict
  precheck + relocate confirm dialog) is unchanged.
- V2ScriptsEditor/ScriptField: add `pb-8 pr-20` to the textarea so
  the absolute-positioned Import button at the bottom-right can no
  longer overlap typed content.
- ClickablePath: the truncate span needs `min-w-0` when its parent
  is a flex container, otherwise the ellipsis never kicks in.

Structural fixes (one-component-per-file rule from AGENTS.md):
- Extract `SettingsRow` from V2ProjectSettings.tsx into its own
  SettingsRow/ folder with an index re-export. V2ProjectSettings.tsx
  imports it.
- Extract `ScriptField` from V2ScriptsEditor.tsx into a co-located
  components/ScriptField/ folder. V2ScriptsEditor.tsx imports it.
  (Co-located under V2ScriptsEditor since it's only used by that
  editor.)
@saddlepaddle saddlepaddle mentioned this pull request May 22, 2026
3 tasks
MocA-Love added a commit to MocA-Love/superset that referenced this pull request May 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants