Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,51 +9,88 @@ import {
import { toast } from "@superset/ui/sonner";
import { Tabs, TabsList, TabsTrigger } from "@superset/ui/tabs";
import { useNavigate } from "@tanstack/react-router";
import { useEffect, useState } from "react";
import { useEffect } from "react";
import { electronTrpc } from "renderer/lib/electron-trpc";
import { useOpenProject } from "renderer/react-query/projects";
import {
type NewWorkspaceModalTab,
useCloseNewWorkspaceModal,
useNewWorkspaceModalActiveTab,
useNewWorkspaceModalBranchesQuery,
useNewWorkspaceModalIssuesQuery,
useNewWorkspaceModalOpen,
usePreSelectedProjectId,
useNewWorkspaceModalPullRequestsQuery,
useSelectedNewWorkspaceModalProjectId,
useSetNewWorkspaceModalActiveTab,
useSetNewWorkspaceModalBranchesQuery,
useSetNewWorkspaceModalIssuesQuery,
useSetNewWorkspaceModalPullRequestsQuery,
useSetSelectedNewWorkspaceModalProjectId,
} from "renderer/stores/new-workspace-modal";
import { BranchesGroup } from "./components/BranchesGroup";
import { IssuesGroup } from "./components/IssuesGroup";
import { ProjectSelector } from "./components/ProjectSelector";
import { PromptGroup } from "./components/PromptGroup";
import { PullRequestsGroup } from "./components/PullRequestsGroup";

type Tab = "prompt" | "issues" | "pull-requests" | "branches";
const COMMAND_CLASS_NAME =
"[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5 flex h-full w-full flex-1 flex-col overflow-hidden rounded-none";

export function NewWorkspaceModal() {
const isOpen = useNewWorkspaceModalOpen();
const closeModal = useCloseNewWorkspaceModal();
const preSelectedProjectId = usePreSelectedProjectId();
const [activeTab, setActiveTab] = useState<Tab>("prompt");
const [selectedProjectId, setSelectedProjectId] = useState<string | null>(
null,
);
const activeTab = useNewWorkspaceModalActiveTab();
const setActiveTab = useSetNewWorkspaceModalActiveTab();
const selectedProjectId = useSelectedNewWorkspaceModalProjectId();
const setSelectedProjectId = useSetSelectedNewWorkspaceModalProjectId();
const issuesQuery = useNewWorkspaceModalIssuesQuery();
const setIssuesQuery = useSetNewWorkspaceModalIssuesQuery();
const pullRequestsQuery = useNewWorkspaceModalPullRequestsQuery();
const setPullRequestsQuery = useSetNewWorkspaceModalPullRequestsQuery();
const branchesQuery = useNewWorkspaceModalBranchesQuery();
const setBranchesQuery = useSetNewWorkspaceModalBranchesQuery();
const navigate = useNavigate();
const { openNew } = useOpenProject();

const { data: recentProjects = [] } =
electronTrpc.projects.getRecents.useQuery();

// Sync pre-selected project when modal opens
// biome-ignore lint/correctness/useExhaustiveDependencies: reset on modal open
useEffect(() => {
if (!isOpen) return;
if (preSelectedProjectId) {
setSelectedProjectId(preSelectedProjectId);
} else if (recentProjects.length > 0 && !selectedProjectId) {
setSelectedProjectId(recentProjects[0].id);
const hasSelectedProject = recentProjects.some(
(project) => project.id === selectedProjectId,
);
if (!hasSelectedProject) {
setSelectedProjectId(recentProjects[0]?.id ?? null);
}
Comment on lines +63 to 65
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Mar 7, 2026

Choose a reason for hiding this comment

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

P2: This condition resets the selected project while recents are still loading (empty array), which can wipe the persisted project selection on reopen.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx, line 63:

<comment>This condition resets the selected project while recents are still loading (empty array), which can wipe the persisted project selection on reopen.</comment>

<file context>
@@ -57,8 +57,11 @@ export function NewWorkspaceModal() {
+		const hasSelectedProject = recentProjects.some(
+			(project) => project.id === selectedProjectId,
+		);
+		if (!hasSelectedProject) {
+			setSelectedProjectId(recentProjects[0]?.id ?? null);
 		}
</file context>
Suggested change
if (!hasSelectedProject) {
setSelectedProjectId(recentProjects[0]?.id ?? null);
}
if (recentProjects.length > 0 && !hasSelectedProject) {
setSelectedProjectId(recentProjects[0]?.id ?? null);
}
Fix with Cubic

}, [isOpen]);
}, [isOpen, recentProjects, selectedProjectId, setSelectedProjectId]);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const selectedProject = recentProjects.find(
(p) => p.id === selectedProjectId,
(project) => project.id === selectedProjectId,
);
const isListTab = activeTab !== "prompt";
const listQuery =
activeTab === "issues"
? issuesQuery
: activeTab === "branches"
? branchesQuery
: pullRequestsQuery;

const handleListQueryChange = (value: string) => {
switch (activeTab) {
case "issues":
setIssuesQuery(value);
return;
case "branches":
setBranchesQuery(value);
return;
case "pull-requests":
setPullRequestsQuery(value);
return;
default:
return;
}
};

const handleImportRepo = async () => {
closeModal();
Expand Down Expand Up @@ -87,7 +124,9 @@ export function NewWorkspaceModal() {
<div className="flex items-center justify-between border-b px-3 py-2">
<Tabs
value={activeTab}
onValueChange={(value) => setActiveTab(value as Tab)}
onValueChange={(value) =>
setActiveTab(value as NewWorkspaceModalTab)
}
>
<TabsList>
<TabsTrigger value="prompt">Prompt</TabsTrigger>
Expand All @@ -99,16 +138,20 @@ export function NewWorkspaceModal() {
<ProjectSelector
selectedProjectId={selectedProjectId}
selectedProjectName={selectedProject?.name ?? null}
recentProjects={recentProjects.filter((p) => Boolean(p.id))}
recentProjects={recentProjects.filter((project) =>
Boolean(project.id),
)}
onSelectProject={setSelectedProjectId}
onImportRepo={handleImportRepo}
onNewProject={handleNewProject}
/>
</div>

{isListTab ? (
<Command className="[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5 flex h-full w-full flex-1 flex-col overflow-hidden rounded-none">
<Command className={COMMAND_CLASS_NAME}>
<CommandInput
value={listQuery}
onValueChange={handleListQueryChange}
placeholder={
activeTab === "issues"
? "Search by slug, title, or description"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import { electronTrpc } from "renderer/lib/electron-trpc";
import { useCreateBranchWorkspace } from "renderer/react-query/workspaces";
import { navigateToWorkspace } from "renderer/routes/_authenticated/_dashboard/utils/workspace-navigation";
import { useHotkeysStore } from "renderer/stores/hotkeys/store";
import {
useClearNewWorkspaceModalInputs,
useClearNewWorkspaceModalInputsIfDraftVersion,
useNewWorkspaceModalDraftVersion,
} from "renderer/stores/new-workspace-modal";

interface BranchesGroupProps {
projectId: string | null;
Expand All @@ -19,6 +24,10 @@ export function BranchesGroup({ projectId, onClose }: BranchesGroupProps) {
const modKey = platform === "darwin" ? "⌘" : "Ctrl";
const navigate = useNavigate();
const createBranchWorkspace = useCreateBranchWorkspace();
const clearInputs = useClearNewWorkspaceModalInputs();
const clearInputsIfDraftVersion =
useClearNewWorkspaceModalInputsIfDraftVersion();
const draftVersion = useNewWorkspaceModalDraftVersion();

const { data, isLoading } = electronTrpc.projects.getBranches.useQuery(
{ projectId: projectId ?? "" },
Expand Down Expand Up @@ -52,29 +61,40 @@ export function BranchesGroup({ projectId, onClose }: BranchesGroupProps) {
const handleCreate = useCallback(
(branchName: string) => {
if (!projectId) return;
const submitDraftVersion = draftVersion;
const createWorkspacePromise = createBranchWorkspace.mutateAsync({
projectId,
branch: branchName,
});
onClose();
toast.promise(
createBranchWorkspace.mutateAsync({
projectId,
branch: branchName,
}),
{
loading: "Creating workspace from branch...",
success: "Workspace created",
error: (err) =>
err instanceof Error ? err.message : "Failed to create workspace",
},
);
toast.promise(createWorkspacePromise, {
loading: "Creating workspace from branch...",
success: "Workspace created",
error: (err) =>
err instanceof Error ? err.message : "Failed to create workspace",
});
void createWorkspacePromise
.then(() => {
clearInputsIfDraftVersion(submitDraftVersion);
})
.catch(() => undefined);
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Mar 7, 2026

Choose a reason for hiding this comment

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

P2: Avoid swallowing create-workspace errors in an empty catch; log the rejection context so failures remain observable.

(Based on your team's feedback about avoiding empty catch blocks that hide failures.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/components/NewWorkspaceModal/components/BranchesGroup/BranchesGroup.tsx, line 72:

<comment>Avoid swallowing create-workspace errors in an empty catch; log the rejection context so failures remain observable.

(Based on your team's feedback about avoiding empty catch blocks that hide failures.) </comment>

<file context>
@@ -52,29 +54,33 @@ export function BranchesGroup({ projectId, onClose }: BranchesGroupProps) {
+				.then(() => {
+					clearInputs();
+				})
+				.catch(() => undefined);
 		},
-		[projectId, onClose, createBranchWorkspace],
</file context>
Suggested change
.catch(() => undefined);
.catch((err) => {
console.warn("[BranchesGroup] failed to create workspace from branch", err);
return undefined;
});
Fix with Cubic

},
[projectId, onClose, createBranchWorkspace],
[
clearInputsIfDraftVersion,
createBranchWorkspace,
draftVersion,
onClose,
projectId,
],
);

const handleOpen = useCallback(
(workspaceId: string) => {
clearInputs();
onClose();
navigateToWorkspace(workspaceId, navigate);
},
[onClose, navigate],
[clearInputs, onClose, navigate],
);

if (!projectId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ import {
} from "renderer/routes/_authenticated/_dashboard/tasks/components/TasksView/components/shared/StatusIcon";
import { navigateToWorkspace } from "renderer/routes/_authenticated/_dashboard/utils/workspace-navigation";
import { useCollections } from "renderer/routes/_authenticated/providers/CollectionsProvider";
import {
useClearNewWorkspaceModalInputs,
useClearNewWorkspaceModalInputsIfDraftVersion,
useNewWorkspaceModalDraftVersion,
} from "renderer/stores/new-workspace-modal";

interface IssuesGroupProps {
projectId: string | null;
Expand All @@ -30,6 +35,10 @@ export function IssuesGroup({ projectId, onClose }: IssuesGroupProps) {
const navigate = useNavigate();
const { gateFeature } = usePaywall();
const createWorkspace = useCreateWorkspace();
const clearInputs = useClearNewWorkspaceModalInputs();
const clearInputsIfDraftVersion =
useClearNewWorkspaceModalInputsIfDraftVersion();
const draftVersion = useNewWorkspaceModalDraftVersion();

const { data: integrations } = useLiveQuery(
(q) =>
Expand Down Expand Up @@ -125,26 +134,31 @@ export function IssuesGroup({ projectId, onClose }: IssuesGroupProps) {
}
const existingId = workspaceByBranch.get(task.slug.toLowerCase());
if (existingId) {
clearInputs();
onClose();
navigateToWorkspace(existingId, navigate);
return;
}
const submitDraftVersion = draftVersion;
const createWorkspacePromise = createWorkspace.mutateAsync({
projectId,
name: task.title,
branchName: task.slug.toLowerCase(),
});
onClose();
toast.promise(
createWorkspace.mutateAsync({
projectId,
name: task.title,
branchName: task.slug.toLowerCase(),
}),
{
loading: "Creating workspace...",
success: "Workspace created",
error: (err) =>
err instanceof Error
? err.message
: "Failed to create workspace",
},
);
toast.promise(createWorkspacePromise, {
loading: "Creating workspace...",
success: "Workspace created",
error: (err) =>
err instanceof Error
? err.message
: "Failed to create workspace",
});
void createWorkspacePromise
.then(() => {
clearInputsIfDraftVersion(submitDraftVersion);
})
.catch(() => undefined);
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Mar 7, 2026

Choose a reason for hiding this comment

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

P3: Avoid using an empty catch here; log the rejected error so create-workspace failures are still diagnosable.

(Based on your team's feedback about avoiding empty catch blocks that hide failures.)

View Feedback: 1 2

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/components/NewWorkspaceModal/components/IssuesGroup/IssuesGroup.tsx, line 153:

<comment>Avoid using an empty catch here; log the rejected error so create-workspace failures are still diagnosable.

(Based on your team's feedback about avoiding empty catch blocks that hide failures.) </comment>

<file context>
@@ -125,26 +127,30 @@ export function IssuesGroup({ projectId, onClose }: IssuesGroupProps) {
+							.then(() => {
+								clearInputs();
+							})
+							.catch(() => undefined);
 					}}
 					className="group h-12"
</file context>
Suggested change
.catch(() => undefined);
.catch((err) => console.warn("[IssuesGroup] workspace creation failed", err));
Fix with Cubic

}}
className="group h-12"
>
Expand Down
Loading
Loading