fix(ui): project dialog improvements, onboarding cleanup, scroll-area fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dotta
2026-03-02 16:09:07 -06:00
parent f12bef2f77
commit 7642743e62
4 changed files with 23 additions and 52 deletions

View File

@@ -31,6 +31,7 @@ import { PROJECT_COLORS } from "@paperclip/shared";
import { cn } from "../lib/utils"; import { cn } from "../lib/utils";
import { MarkdownEditor, type MarkdownEditorRef } from "./MarkdownEditor"; import { MarkdownEditor, type MarkdownEditorRef } from "./MarkdownEditor";
import { StatusBadge } from "./StatusBadge"; import { StatusBadge } from "./StatusBadge";
import { ChoosePathButton } from "./PathInstructionsModal";
const projectStatuses = [ const projectStatuses = [
{ value: "backlog", label: "Backlog" }, { value: "backlog", label: "Backlog" },
@@ -333,12 +334,15 @@ export function NewProjectDialog() {
{(workspaceSetup === "local" || workspaceSetup === "both") && ( {(workspaceSetup === "local" || workspaceSetup === "both") && (
<div className="rounded-md border border-border p-2"> <div className="rounded-md border border-border p-2">
<label className="mb-1 block text-xs text-muted-foreground">Local folder (full path)</label> <label className="mb-1 block text-xs text-muted-foreground">Local folder (full path)</label>
<input <div className="flex items-center gap-2">
className="w-full rounded border border-border bg-transparent px-2 py-1 text-xs font-mono outline-none" <input
value={workspaceLocalPath} className="w-full rounded border border-border bg-transparent px-2 py-1 text-xs font-mono outline-none"
onChange={(e) => setWorkspaceLocalPath(e.target.value)} value={workspaceLocalPath}
placeholder="/absolute/path/to/workspace" onChange={(e) => setWorkspaceLocalPath(e.target.value)}
/> placeholder="/absolute/path/to/workspace"
/>
<ChoosePathButton />
</div>
</div> </div>
)} )}
{(workspaceSetup === "repo" || workspaceSetup === "both") && ( {(workspaceSetup === "repo" || workspaceSetup === "both") && (

View File

@@ -19,6 +19,7 @@ import { cn } from "../lib/utils";
import { getUIAdapter } from "../adapters"; import { getUIAdapter } from "../adapters";
import { defaultCreateValues } from "./agent-config-defaults"; import { defaultCreateValues } from "./agent-config-defaults";
import { AsciiArtAnimation } from "./AsciiArtAnimation"; import { AsciiArtAnimation } from "./AsciiArtAnimation";
import { ChoosePathButton } from "./PathInstructionsModal";
import { import {
Building2, Building2,
Bot, Bot,
@@ -63,7 +64,6 @@ export function OnboardingWizard() {
const [command, setCommand] = useState(""); const [command, setCommand] = useState("");
const [args, setArgs] = useState(""); const [args, setArgs] = useState("");
const [url, setUrl] = useState(""); const [url, setUrl] = useState("");
const [cwdPickerNotice, setCwdPickerNotice] = useState<string | null>(null);
// Step 3 // Step 3
const [taskTitle, setTaskTitle] = useState("Create your CEO HEARTBEAT.md"); const [taskTitle, setTaskTitle] = useState("Create your CEO HEARTBEAT.md");
@@ -94,7 +94,6 @@ export function OnboardingWizard() {
setCommand(""); setCommand("");
setArgs(""); setArgs("");
setUrl(""); setUrl("");
setCwdPickerNotice(null);
setTaskTitle("Create your CEO HEARTBEAT.md"); setTaskTitle("Create your CEO HEARTBEAT.md");
setTaskDescription("You're the CEO of the company, make sure you have a file agents/ceo/HEARTBEAT.md that tells you your core loop. You MUST use the Paperclip SKILL."); setTaskDescription("You're the CEO of the company, make sure you have a file agents/ceo/HEARTBEAT.md that tells you your core loop. You MUST use the Paperclip SKILL.");
setCreatedCompanyId(null); setCreatedCompanyId(null);
@@ -415,44 +414,8 @@ export function OnboardingWizard() {
value={cwd} value={cwd}
onChange={(e) => setCwd(e.target.value)} onChange={(e) => setCwd(e.target.value)}
/> />
<button <ChoosePathButton />
type="button"
className="inline-flex items-center rounded-md border border-border px-2 py-0.5 text-xs text-muted-foreground hover:bg-accent/50 transition-colors shrink-0"
onClick={async () => {
try {
setCwdPickerNotice(null);
// @ts-expect-error -- showDirectoryPicker is not in all TS lib defs yet
const handle = await window.showDirectoryPicker({ mode: "read" });
const pickedPath =
typeof handle === "object" &&
handle !== null &&
typeof (handle as { path?: unknown }).path === "string"
? String((handle as { path: string }).path)
: "";
if (pickedPath) {
setCwd(pickedPath);
return;
}
const selectedName =
typeof handle === "object" &&
handle !== null &&
typeof (handle as { name?: unknown }).name === "string"
? String((handle as { name: string }).name)
: "selected folder";
setCwdPickerNotice(
`Directory picker only exposed "${selectedName}". Paste the absolute path manually.`,
);
} catch {
// user cancelled or API unsupported
}
}}
>
Choose
</button>
</div> </div>
{cwdPickerNotice && (
<p className="mt-1 text-xs text-amber-400">{cwdPickerNotice}</p>
)}
</div> </div>
<div> <div>
<label className="text-xs text-muted-foreground mb-1 block"> <label className="text-xs text-muted-foreground mb-1 block">

View File

@@ -13,6 +13,7 @@ import { Button } from "@/components/ui/button";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { ExternalLink, Github, Plus, Trash2, X } from "lucide-react"; import { ExternalLink, Github, Plus, Trash2, X } from "lucide-react";
import { ChoosePathButton } from "./PathInstructionsModal";
interface ProjectPropertiesProps { interface ProjectPropertiesProps {
project: Project; project: Project;
@@ -384,12 +385,15 @@ export function ProjectProperties({ project, onUpdate }: ProjectPropertiesProps)
</div> </div>
{workspaceMode === "local" && ( {workspaceMode === "local" && (
<div className="space-y-1.5 rounded-md border border-border p-2"> <div className="space-y-1.5 rounded-md border border-border p-2">
<input <div className="flex items-center gap-2">
className="w-full rounded border border-border bg-transparent px-2 py-1 text-xs font-mono outline-none" <input
value={workspaceCwd} className="w-full rounded border border-border bg-transparent px-2 py-1 text-xs font-mono outline-none"
onChange={(e) => setWorkspaceCwd(e.target.value)} value={workspaceCwd}
placeholder="/absolute/path/to/workspace" onChange={(e) => setWorkspaceCwd(e.target.value)}
/> placeholder="/absolute/path/to/workspace"
/>
<ChoosePathButton />
</div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button <Button
variant="outline" variant="outline"

View File

@@ -11,7 +11,7 @@ function ScrollArea({
return ( return (
<ScrollAreaPrimitive.Root <ScrollAreaPrimitive.Root
data-slot="scroll-area" data-slot="scroll-area"
className={cn("relative flex flex-col", className)} className={cn("relative flex flex-col overflow-hidden", className)}
{...props} {...props}
> >
<ScrollAreaPrimitive.Viewport <ScrollAreaPrimitive.Viewport