From 949fc0bf7ed7f9a6dcb4b87f8b7cda6f59a92e46 Mon Sep 17 00:00:00 2001 From: stroblme Date: Sun, 16 Aug 2026 19:08:22 +0200 Subject: [PATCH] Ask for the name in a dialog instead of a field that is always there Create in both overviews now opens a dialog, so the toolbar is a search box and one button. The specs and the capture script open it first. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01H7LwYgJfpkbLCTeiAf8U4A --- frontend/scripts/capture-screenshots.mjs | 2 + .../src/routes/_layout/dashboards/index.tsx | 78 +++++++++++++------ frontend/src/routes/_layout/flows/index.tsx | 78 +++++++++++++------ frontend/tests/drafts.spec.ts | 1 + frontend/tests/flows.spec.ts | 1 + 5 files changed, 110 insertions(+), 50 deletions(-) diff --git a/frontend/scripts/capture-screenshots.mjs b/frontend/scripts/capture-screenshots.mjs index a012607..99f2991 100644 --- a/frontend/scripts/capture-screenshots.mjs +++ b/frontend/scripts/capture-screenshots.mjs @@ -86,6 +86,7 @@ async function captureDashboards(page, dir) { await page.goto(`${APP_URL}/dashboards`, { waitUntil: "networkidle" }) if (!(await page.getByTestId("dashboard-card").count())) { + await page.getByTestId("new-dashboard").click() await page.getByTestId("new-dashboard-name").fill("panel") await page.getByTestId("create-dashboard").click() await page.waitForURL(/\/dashboards\/.+/, { timeout: 15000 }) @@ -113,6 +114,7 @@ async function captureFlows(page, dir) { if (await page.getByTestId("flow-card").count()) { await page.getByTestId("flow-card").first().click() } else { + await page.getByTestId("new-flow").click() await page.getByTestId("new-flow-name").fill("first_flow") await page.getByTestId("create-flow").click() } diff --git a/frontend/src/routes/_layout/dashboards/index.tsx b/frontend/src/routes/_layout/dashboards/index.tsx index 8ed58bd..de7ff0b 100644 --- a/frontend/src/routes/_layout/dashboards/index.tsx +++ b/frontend/src/routes/_layout/dashboards/index.tsx @@ -9,6 +9,15 @@ import { dashboardsQueryOptions, } from "@/components/Dashboard/queries" import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" import { Input } from "@/components/ui/input" import useCustomToast from "@/hooks/useCustomToast" import { handleError } from "@/utils" @@ -24,12 +33,14 @@ function Dashboards() { const { showErrorToast } = useCustomToast() const [name, setName] = useState("") const [search, setSearch] = useState("") + const [dialogOpen, setDialogOpen] = useState(false) const create = useMutation({ mutationFn: (dashboard: string) => DashboardsService.createDashboard({ name: dashboard }), onSuccess: (created) => { queryClient.invalidateQueries({ queryKey: dashboardKeys.all }) + setDialogOpen(false) navigate({ to: "/dashboards/$name", params: { name: created.name }, @@ -67,37 +78,54 @@ function Dashboards() { data-testid="search-dashboards" onChange={(event) => setSearch(event.target.value)} /> -
{ - event.preventDefault() - if (slug) create.mutate(slug) - }} - > - setName(event.target.value)} - /> - -
+ + + + + +
{ + event.preventDefault() + if (slug) create.mutate(slug) + }} + > + + New dashboard + + Name it after the panel it will hang on, or what it shows. + + + setName(event.target.value)} + /> + + + +
+
+
{dashboards.length === 0 ? (

{needle ? "No dashboard matches that." - : "No dashboards yet. Name one above to start."} + : "No dashboards yet. Create one to start."}

) : (
diff --git a/frontend/src/routes/_layout/flows/index.tsx b/frontend/src/routes/_layout/flows/index.tsx index d8bdae5..ae89e0a 100644 --- a/frontend/src/routes/_layout/flows/index.tsx +++ b/frontend/src/routes/_layout/flows/index.tsx @@ -6,6 +6,15 @@ import { useState } from "react" import { FlowsService } from "@/client" import { flowKeys, flowsQueryOptions } from "@/components/Flow/queries" import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" import { Input } from "@/components/ui/input" import useCustomToast from "@/hooks/useCustomToast" import { handleError } from "@/utils" @@ -25,6 +34,7 @@ function Flows() { const { showErrorToast } = useCustomToast() const [name, setName] = useState("") const [search, setSearch] = useState("") + const [dialogOpen, setDialogOpen] = useState(false) const create = useMutation({ mutationFn: (flow: string) => @@ -34,6 +44,7 @@ function Flows() { }), onSuccess: (_saved, flow) => { queryClient.invalidateQueries({ queryKey: flowKeys.all }) + setDialogOpen(false) navigate({ to: "/flows/$flowName", params: { flowName: flow } }) }, onError: handleError.bind(showErrorToast), @@ -67,37 +78,54 @@ function Flows() { data-testid="search-flows" onChange={(event) => setSearch(event.target.value)} /> -
{ - event.preventDefault() - if (NAME.test(slug)) create.mutate(slug) - }} - > - setName(event.target.value)} - /> - -
+ + + + + +
{ + event.preventDefault() + if (NAME.test(slug)) create.mutate(slug) + }} + > + + New flow + + Flows are small on purpose. Name this one after what it does. + + + setName(event.target.value)} + /> + + + +
+
+
{flows.length === 0 ? (

{needle ? "No flow matches that." - : "No flows yet. Name one above to start."} + : "No flows yet. Create one to start."}

) : (
diff --git a/frontend/tests/drafts.spec.ts b/frontend/tests/drafts.spec.ts index c47399c..69de4c6 100644 --- a/frontend/tests/drafts.spec.ts +++ b/frontend/tests/drafts.spec.ts @@ -19,6 +19,7 @@ test.afterAll(async ({ browser }) => { test("a draft stays off the engine until it is published", async ({ page }) => { await page.goto("/flows") + await page.getByTestId("new-flow").click() await page.getByTestId("new-flow-name").fill(flowName) await page.getByTestId("create-flow").click() await page.waitForURL(`/flows/${flowName}`) diff --git a/frontend/tests/flows.spec.ts b/frontend/tests/flows.spec.ts index 2557298..214df4e 100644 --- a/frontend/tests/flows.spec.ts +++ b/frontend/tests/flows.spec.ts @@ -73,6 +73,7 @@ test("a flow can be created, wired up, and comes back after a reload", async ({ await page.goto("/flows") // Create a flow of our own so the test does not lean on existing data. + await page.getByTestId("new-flow").click() await page.getByTestId("new-flow-name").fill(flowName) await page.getByTestId("create-flow").click() await page.waitForURL(`/flows/${flowName}`)