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
2 changes: 1 addition & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@
"os-locale": "^6.0.2",
"pidtree": "^0.6.0",
"posthog-js": "1.310.1",
"posthog-node": "^5.18.0",
"posthog-node": "^5.24.7",
"react": "19.1.0",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export function useCreateWorkspace(options?: UseCreateWorkspaceOptions) {
await utils.workspaces.invalidate();

if (!options?.skipNavigation) {
navigateToWorkspace(data.workspace.id, navigate);
navigateToWorkspace(data.workspace.id, navigate, { replace: true });
}

await options?.onSuccess?.(data, ...rest);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Spinner } from "@superset/ui/spinner";
import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { useEffect } from "react";
import { electronTrpc } from "renderer/lib/electron-trpc";
import { StartView } from "renderer/screens/main/components/StartView";

export const Route = createFileRoute("/_authenticated/_dashboard/workspace/")({
component: WorkspaceIndexPage,
Expand All @@ -26,7 +25,12 @@ function WorkspaceIndexPage() {

useEffect(() => {
if (isLoading || !workspaces) return;
if (allWorkspaces.length === 0) return; // Show StartView instead

if (allWorkspaces.length === 0) {
// Redirect to clean onboarding screen (no sidebar/topbar)
navigate({ to: "/welcome", replace: true });
return;
}

// Try to restore last viewed workspace
const lastViewedId = localStorage.getItem("lastViewedWorkspaceId");
Expand All @@ -43,7 +47,7 @@ function WorkspaceIndexPage() {
}, [workspaces, isLoading, navigate, allWorkspaces]);

if (hasNoWorkspaces) {
return <StartView />;
return <LoadingSpinner />;
}

return <LoadingSpinner />;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { createFileRoute, Outlet } from "@tanstack/react-router";
import { electronTrpc } from "renderer/lib/electron-trpc";

export const Route = createFileRoute("/_authenticated/_onboarding")({
component: OnboardingLayout,
});

function OnboardingLayout() {
const { data: platform } = electronTrpc.window.getPlatform.useQuery();
const isMac = platform === undefined || platform === "darwin";

return (
<div className="flex flex-col h-full w-full bg-background">
{/* Drag region for window dragging (macOS traffic lights / Windows title bar) */}
<div
className="drag h-12 w-full shrink-0"
style={{
paddingLeft: isMac ? "88px" : "16px",
}}
/>
<Outlet />
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { createFileRoute } from "@tanstack/react-router";
import { StartView } from "renderer/screens/main/components/StartView";

export const Route = createFileRoute("/_authenticated/_onboarding/welcome/")({
component: WelcomePage,
});

function WelcomePage() {
return <StartView />;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
import { Button } from "@superset/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@superset/ui/dialog";
import { Input } from "@superset/ui/input";
import { useState } from "react";
import { electronTrpc } from "renderer/lib/electron-trpc";
import { useCreateWorkspace } from "renderer/react-query/workspaces";
Expand All @@ -18,6 +28,8 @@ export function CloneRepoDialog({
const cloneRepo = electronTrpc.projects.cloneRepo.useMutation();
const createWorkspace = useCreateWorkspace();

const isLoading = cloneRepo.isPending || createWorkspace.isPending;

const handleClone = async () => {
if (!url.trim()) {
onError("Please enter a repository URL");
Expand All @@ -28,19 +40,16 @@ export function CloneRepoDialog({
{ url: url.trim() },
{
onSuccess: (result) => {
// User canceled the directory picker - silent no-op
if (result.canceled) {
return;
}

if (result.success && result.project) {
// Invalidate recents so the new/updated project appears
utils.projects.getRecents.invalidate();
createWorkspace.mutate({ projectId: result.project.id });
onClose();
setUrl("");
} else if (!result.success) {
// Show user-friendly error message
onError(result.error ?? "Failed to clone repository");
}
},
Expand All @@ -51,61 +60,47 @@ export function CloneRepoDialog({
);
};

if (!isOpen) return null;

const isLoading = cloneRepo.isPending || createWorkspace.isPending;

return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-sm">
<div className="bg-card border border-border rounded-lg p-8 w-full max-w-md shadow-2xl">
<h2 className="text-xl font-normal text-foreground mb-6">
Clone Repository
</h2>

<div className="space-y-6">
<div>
<label
htmlFor="repo-url"
className="block text-xs font-normal text-muted-foreground mb-2"
>
Repository URL
</label>
<input
id="repo-url"
type="text"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder="https://github.com/user/repo.git"
className="w-full px-3 py-2.5 bg-background border border-border rounded-md text-foreground placeholder:text-muted-foreground/50 focus:outline-none focus:border-ring transition-colors"
disabled={isLoading}
onKeyDown={(e) => {
if (e.key === "Enter" && !isLoading) {
handleClone();
}
}}
/>
</div>
<Dialog open={isOpen} onOpenChange={(open) => !open && onClose()}>
<DialogContent>
<DialogHeader>
<DialogTitle>Clone Repository</DialogTitle>
<DialogDescription>
Enter a repository URL to clone it locally.
</DialogDescription>
</DialogHeader>

<div className="flex gap-3 justify-end pt-2">
<button
type="button"
onClick={onClose}
disabled={isLoading}
className="px-4 py-2 rounded-md border border-border text-foreground hover:bg-accent transition-colors disabled:opacity-50 disabled:cursor-not-allowed text-sm"
>
Cancel
</button>
<button
type="button"
onClick={handleClone}
disabled={isLoading}
className="px-4 py-2 rounded-md bg-foreground text-background hover:bg-foreground/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed text-sm font-medium"
>
{isLoading ? "Cloning..." : "Clone"}
</button>
</div>
<div>
<label
htmlFor="repo-url"
className="block text-sm font-medium text-foreground mb-2"
>
Repository URL
</label>
<Input
id="repo-url"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder="https://github.com/user/repo.git"
disabled={isLoading}
onKeyDown={(e) => {
if (e.key === "Enter" && !isLoading) {
handleClone();
}
}}
autoFocus
/>
</div>
</div>
</div>

<DialogFooter>
<Button variant="outline" onClick={onClose} disabled={isLoading}>
Cancel
</Button>
<Button onClick={handleClone} disabled={isLoading}>
{isLoading ? "Cloning..." : "Clone"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Button } from "@superset/ui/button";
import { cn } from "@superset/ui/utils";
import { useNavigate } from "@tanstack/react-router";
import { useCallback, useEffect, useState } from "react";
Expand Down Expand Up @@ -66,6 +67,7 @@ export function StartView() {
navigate({
to: "/project/$projectId",
params: { projectId: result.project.id },
replace: true,
});
}
},
Expand Down Expand Up @@ -154,6 +156,7 @@ export function StartView() {
navigate({
to: "/project/$projectId",
params: { projectId: result.project.id },
replace: true,
});
}
},
Expand All @@ -179,89 +182,81 @@ export function StartView() {
onDragLeave={handleDragLeave}
onDrop={handleDrop}
>
<div className="flex flex-col items-center w-full max-w-xs px-4">
<div className="flex flex-col items-center w-full max-w-md px-6">
<SupersetLogo
className={cn(
"h-8 w-auto mb-6 transition-opacity duration-200",
"h-10 w-auto mb-10 transition-opacity duration-200",
isDragOver && "opacity-0",
)}
/>

<div className="w-full flex flex-col gap-2">
<div className="w-full flex flex-col gap-3">
<div>
<button
type="button"
onClick={handleOpenProject}
disabled={isLoading}
className={cn(
"w-full rounded border border-dashed transition-colors",
"w-full rounded-lg border border-dashed transition-colors",
"focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
"disabled:opacity-50 disabled:pointer-events-none",
isDragOver
? "border-foreground/40 bg-accent/50 py-16"
: "border-border bg-card px-4 py-7 hover:bg-accent",
? "border-foreground/40 bg-accent/50 py-32"
: "border-border bg-card px-6 py-20 hover:bg-accent",
)}
>
{isDragOver ? (
<div className="flex flex-col items-center gap-1">
<LuFolderGit className="w-5 h-5 text-foreground" />
<span className="text-sm text-foreground">
<div className="flex flex-col items-center gap-2">
<LuFolderGit className="w-7 h-7 text-foreground" />
<span className="text-base text-foreground">
Drop git project
</span>
</div>
) : (
<div className="flex-1 text-left">
<LuFolderOpen className="w-4 h-4 text-muted-foreground" />
<div className="text-sm pt-1 text-foreground">
<LuFolderOpen className="w-5 h-5 text-muted-foreground" />
<div className="text-base pt-2 text-foreground">
Open Project
</div>
<div className="text-xs pt-0.5 text-muted-foreground">
Drag git folder or click to browse
<div className="text-sm pt-1 text-muted-foreground">
Drag any folder with a .git here or click to browse
</div>
</div>
)}
</button>
<p
className={cn(
"mt-1.5 text-xs text-muted-foreground/60 text-center transition-opacity",
isDragOver && "opacity-0",
)}
>
Any folder with a .git directory
</p>
</div>

<button
type="button"
onClick={() => setIsCloneDialogOpen(true)}
disabled={isLoading || isDragOver}
<div
className={cn(
"w-full rounded border border-border bg-transparent px-3 py-2",
"transition-colors hover:bg-accent",
"focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
"disabled:opacity-50 disabled:pointer-events-none",
"flex items-center gap-1 transition-opacity",
isDragOver && "opacity-0",
)}
>
<div className="flex items-center gap-3">
<LuFolderGit className="w-4 h-4 text-muted-foreground" />
<span className="text-sm text-muted-foreground">
Clone Repository
</span>
</div>
</button>
<span className="text-sm text-muted-foreground/60">
Don't have a local repo?
</span>
<Button
variant="link"
size="sm"
onClick={() => setIsCloneDialogOpen(true)}
disabled={isLoading}
className="text-sm text-foreground"
>
Clone Repository
</Button>
</div>
</div>

{error && !isDragOver && (
<div className="mt-4 w-full flex items-start gap-2 rounded-md px-3 py-2 bg-destructive/10 border border-destructive/20">
<span className="flex-1 text-xs text-destructive">{error}</span>
<div className="mt-5 w-full flex items-start gap-2 rounded-md px-4 py-3 bg-destructive/10 border border-destructive/20">
<span className="flex-1 text-sm text-destructive">{error}</span>
<button
type="button"
onClick={() => setError(null)}
className="shrink-0 rounded p-0.5 text-destructive/70 hover:text-destructive transition-colors"
aria-label="Dismiss error"
>
<LuX className="h-3 w-3" />
<LuX className="h-3.5 w-3.5" />
</button>
</div>
)}
Expand Down
Loading