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:
parent
d0a55502a8
commit
6e7b5f84e9
7 changed files with 21 additions and 28 deletions
|
|
@ -9,6 +9,7 @@ import { AlertsPage } from "./pages/AlertsPage.js";
|
|||
import { BuildsPage } from "./pages/builds/BuildsPage.js";
|
||||
import { BroadcastPage } from "./pages/broadcast/BroadcastPage.js";
|
||||
import { MessagesPage } from "./pages/messages/MessagesPage.js";
|
||||
import { NEW_FLOW_PATH } from "./pages/notifications/FlowDraft.js";
|
||||
import { FlowEditorPage } from "./pages/notifications/FlowEditorPage.js";
|
||||
import { NotificationsPage } from "./pages/notifications/NotificationsPage.js";
|
||||
import { ComponentsPage } from "./pages/ComponentsPage.js";
|
||||
|
|
@ -48,6 +49,9 @@ export function App() {
|
|||
<Route path="/broadcast" component={BroadcastPage} />
|
||||
<Route path="/messages" component={MessagesPage} />
|
||||
<Route path="/notifications" component={NotificationsPage} />
|
||||
<Route path={NEW_FLOW_PATH}>
|
||||
<FlowEditorPage params={{ flowId: "" }} isNew />
|
||||
</Route>
|
||||
<Route path="/notifications/:flowId" component={FlowEditorPage} />
|
||||
<Route path="/issues" component={IssueReportPage} />
|
||||
<Route path="/review" component={ReviewPage} />
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -388,9 +388,4 @@ test("savedAs takes the id from the name, clear of every saved id", () => {
|
|||
assert.equal(savedAs(view, { ...draft, name: "Closed" }).id, "closed");
|
||||
assert.equal(savedAs(view, { ...draft, name: "Assigned" }).id, "assigned-2");
|
||||
assert.equal(savedAs(view, { ...draft, name: "mine" }).id, "mine-2");
|
||||
assert.equal(
|
||||
savedAs(view, { ...draft, name: "New" }).id,
|
||||
"new-2",
|
||||
"no flow takes the id of the new-flow route",
|
||||
);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue