Watch
0
0
Fork
You've already forked hyperhive
0

swarm-ui: give the new-flow draft a route no flow id can take, and drop the dead hit-count rule

/notifications/new could be a saved flow's own page, so the draft now opens at
/notifications/draft/new, which has a segment more than any flow's route. The
placeholder id no longer needs reserving. The .notify-node-hits rule styled the
removed tree rows; nothing renders it.
This commit is contained in:
iris 2026-10-25 01:33:29 +02:00 • committed by mara
commit 6e7b5f84e9
7 changed files with 21 additions and 28 deletions

View file

@ -356,16 +356,15 @@ export function duplicateFlow(
});
}
// The id of a flow nobody has saved yet. It is the editor's route for one, so
// no saved flow may take it.
// The editor's route for a flow nobody has saved yet. It has a segment more
// than a flow's own route, so no flow's id can reach it.
export const NEW_FLOW_PATH = "/notifications/draft/new";
// The id a draft carries until it is saved (see `savedAs`).
export const NEW_FLOW_ID = "new";
function savedIds(view: FlowsView): string[] {
return [
NEW_FLOW_ID,
...view.builtins.map((f) => f.id),
...view.flows.map((f) => f.id),
];
return [...view.builtins.map((f) => f.id), ...view.flows.map((f) => f.id)];
}
// The draft the editor opens for a flow not saved yet: an empty one, or a copy

View file

@ -3,7 +3,7 @@
// document back at the revision it was read. Edits stay in a draft until
// then, so a half-built flow never reaches the router.
//
// The same page makes a flow: `/notifications/new` is an empty draft, and
// The same page makes a flow: `NEW_FLOW_PATH` is an empty draft, and
// `?from=<id>` a copy of a flow to start from. Nothing exists until Save, which
// gives the flow an id made of its name.
//
@ -33,7 +33,6 @@ import {
isDirty,
limitsOf,
moveAmongSiblings,
NEW_FLOW_ID,
paletteKinds,
removeNode,
reparent,
@ -59,9 +58,12 @@ function rootOf(flow: Flow): string | null {
export function FlowEditorPage({
params,
}: RouteComponentProps<{ flowId: string }>) {
isNew = false,
}: RouteComponentProps<{ flowId: string }> & {
// The page for a flow not saved yet, which has no flow id.
isNew?: boolean;
}) {
const flowId = decodeURIComponent(params.flowId);
const isNew = flowId === NEW_FLOW_ID;
const from = new URLSearchParams(useSearch()).get("from");
const [, navigate] = useLocation();
const [view, setView] = useState<FlowsView | null>(null);

View file

@ -272,14 +272,7 @@
flex: 0 1 24em;
}
/* The dry run's counts beside each node, and the router's "not available". */
.notify-node-hits {
margin-left: auto;
flex: none;
color: var(--muted);
font-variant-numeric: tabular-nums;
}
/* The dry run's header line, and the router's "not available". */
.notify-dry-run {
margin: 0;
color: var(--muted);

View file

@ -20,7 +20,7 @@ import {
} from "../../ui/refresh-interval/RefreshInterval.js";
import { fetchJson, usePolled } from "../../ui/polled/usePolled.js";
import { Deliveries } from "./Deliveries.js";
import { NEW_FLOW_ID } from "./FlowDraft.js";
import { NEW_FLOW_PATH } from "./FlowDraft.js";
import { FlowGraph } from "./FlowGraph.js";
import { withBuiltin, type FlowsView } from "./FlowTypes.js";
import {
@ -91,8 +91,8 @@ export function NotificationsPage() {
const draftFrom = (from?: string) =>
navigate(
from === undefined
? `/notifications/${NEW_FLOW_ID}`
: `/notifications/${NEW_FLOW_ID}?from=${encodeURIComponent(from)}`,
? NEW_FLOW_PATH
: `${NEW_FLOW_PATH}?from=${encodeURIComponent(from)}`,
);
return (