swarm-ui: a todo switched from clear to upsert drops its prefix flag
This commit is contained in:
parent
06f3e76329
commit
fb8aa23e66
5 changed files with 34 additions and 12 deletions
|
|
@ -258,9 +258,12 @@ Edits stay in a draft until **save**, which sends the whole flows document with
|
||||||
the revision the editor read. **discard edits** goes back to the saved flow and
|
the revision the editor read. **discard edits** goes back to the saved flow and
|
||||||
**delete flow** removes it, after a confirmation. If someone changed the flows
|
**delete flow** removes it, after a confirmation. If someone changed the flows
|
||||||
elsewhere in the meantime, the controller turns the save down as stale, and the
|
elsewhere in the meantime, the controller turns the save down as stale, and the
|
||||||
editor offers to reload and drop your edits, or to keep them on top of the
|
editor offers to reload and drop your edits, or to keep them and replace this
|
||||||
latest. For any other refusal the editor shows the controller's own message.
|
flow's latest version with them. For any other refusal the editor shows the
|
||||||
The router runs a saved flow from its next event.
|
controller's own message. The router runs a saved flow from its next event.
|
||||||
|
|
||||||
|
Closing or reloading the tab with unsaved edits asks first. Leaving through a
|
||||||
|
link in the app, or the browser's back button, drops the draft without asking.
|
||||||
|
|
||||||
### Sending a message to an agent
|
### Sending a message to an agent
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,20 @@ export function reparent(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A todo with its op switched. A clear carries no text, and only a clear may
|
||||||
|
// be a prefix, so each is reset where the new op has no place for it.
|
||||||
|
export function withOp(
|
||||||
|
node: Extract<FlowNode, { kind: "todo" }>,
|
||||||
|
op: "upsert" | "clear",
|
||||||
|
): Extract<FlowNode, { kind: "todo" }> {
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
op,
|
||||||
|
text: op === "clear" ? "" : node.text,
|
||||||
|
prefix: op === "clear" ? node.prefix : false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// The node with `next.id` swapped for `next`. A node keeps its place and its
|
// The node with `next.id` swapped for `next`. A node keeps its place and its
|
||||||
// kind-class: the source stays the source, and nothing with children becomes
|
// kind-class: the source stays the source, and nothing with children becomes
|
||||||
// a todo.
|
// a todo.
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ export function FlowEditorPage({
|
||||||
reload and drop my edits
|
reload and drop my edits
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => void load(true)}>
|
<Button onClick={() => void load(true)}>
|
||||||
keep my edits on top of the latest
|
keep my edits (replaces this flow's latest version)
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import {
|
||||||
replaceNode,
|
replaceNode,
|
||||||
type Edit,
|
type Edit,
|
||||||
type Limits,
|
type Limits,
|
||||||
|
withOp,
|
||||||
} from "./FlowDraft.js";
|
} from "./FlowDraft.js";
|
||||||
import {
|
import {
|
||||||
kindValues,
|
kindValues,
|
||||||
|
|
@ -237,14 +238,7 @@ function TodoFields({
|
||||||
label="op"
|
label="op"
|
||||||
value={node.op}
|
value={node.op}
|
||||||
options={opList}
|
options={opList}
|
||||||
onChange={(op) =>
|
onChange={(op) => onChange(withOp(node, op as TodoNode["op"]))}
|
||||||
onChange({
|
|
||||||
...node,
|
|
||||||
op: op as TodoNode["op"],
|
|
||||||
// A clear carries no text.
|
|
||||||
text: op === "clear" ? "" : node.text,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<SelectField
|
<SelectField
|
||||||
id={`${keyPrefix}-to-kind`}
|
id={`${keyPrefix}-to-kind`}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import {
|
||||||
subtreeIds,
|
subtreeIds,
|
||||||
withFlow,
|
withFlow,
|
||||||
withoutFlow,
|
withoutFlow,
|
||||||
|
withOp,
|
||||||
} from "../src/pages/notifications/FlowDraft.ts";
|
} from "../src/pages/notifications/FlowDraft.ts";
|
||||||
|
|
||||||
const todo = (id) => ({
|
const todo = (id) => ({
|
||||||
|
|
@ -156,6 +157,16 @@ test("replaceNode keeps the place and the kind class", () => {
|
||||||
assert.equal(replaceNode(f, todo("nope")).ok, false);
|
assert.equal(replaceNode(f, todo("nope")).ok, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("withOp drops what the new op has no place for", () => {
|
||||||
|
const clearing = { ...todo("t"), op: "clear", prefix: true, text: "" };
|
||||||
|
const up = withOp(clearing, "upsert");
|
||||||
|
assert.equal(up.op, "upsert");
|
||||||
|
assert.equal(up.prefix, false, "only a clear may be a prefix");
|
||||||
|
const back = withOp({ ...todo("t"), prefix: false }, "clear");
|
||||||
|
assert.equal(back.text, "", "a clear carries no text");
|
||||||
|
assert.equal(withOp(clearing, "clear").prefix, true, "kept on a clear");
|
||||||
|
});
|
||||||
|
|
||||||
test("new ids do not collide", () => {
|
test("new ids do not collide", () => {
|
||||||
const f = flow();
|
const f = flow();
|
||||||
assert.equal(newNodeId(f, "match"), "match1");
|
assert.equal(newNodeId(f, "match"), "match1");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue