feat: control selected-step dataflow mutations
This commit is contained in:
@@ -70,6 +70,9 @@ const controller = {
|
||||
resetGeneration: 0,
|
||||
addCapability: vi.fn(),
|
||||
updateCapability: vi.fn(),
|
||||
setStepInputs: vi.fn(),
|
||||
setStepOutputs: vi.fn(),
|
||||
updateSetup: vi.fn(),
|
||||
setRoute: vi.fn(),
|
||||
validate: vi.fn(),
|
||||
reload: vi.fn(),
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { act, renderHook } from "@testing-library/react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { useConsoleWorkspace } from "../context.js";
|
||||
import type { DraftWorkspace } from "../domain/draft-workspace-models.js";
|
||||
import type {
|
||||
DraftWorkspace,
|
||||
InputBinding,
|
||||
OutputBinding,
|
||||
} from "../domain/draft-workspace-models.js";
|
||||
import type { DraftAuthoringClient } from "../domain/draft-authoring-client.js";
|
||||
import type { DraftWorkspaceClient } from "../domain/draft-workspace-client.js";
|
||||
import type { ConsoleReadExecutor } from "../domain/read-executor.js";
|
||||
@@ -10,6 +14,7 @@ import type { OperationName } from "../../connection/contracts.js";
|
||||
import type { WorkbenchSelection } from "./authoring-graph.js";
|
||||
import { createDraftAuthoringClient } from "../domain/draft-authoring-client.js";
|
||||
import { createDraftWorkspaceClient } from "../domain/draft-workspace-client.js";
|
||||
import type { CapabilitySetupPatch } from "./selected-step-dataflow.js";
|
||||
import { useDraftAuthoring } from "./useDraftAuthoring.js";
|
||||
|
||||
vi.mock("../context.js", () => ({ useConsoleWorkspace: vi.fn() }));
|
||||
@@ -459,4 +464,221 @@ describe("useDraftAuthoring", () => {
|
||||
expect(result.current.draft).toBe(initial);
|
||||
expect(result.current.dirty).toBe(true);
|
||||
});
|
||||
|
||||
it("submits selected-step inputs against the selected node and current revision", async () => {
|
||||
const initial = workspace({ revision: 7 });
|
||||
const canonical = workspace({ revision: 8 });
|
||||
const bindings = [
|
||||
{ path: "input.title", target: "title" },
|
||||
{ target: "separator", value: null },
|
||||
] satisfies ReadonlyArray<InputBinding>;
|
||||
setStepInputBindings.mockResolvedValue(canonical);
|
||||
const { result } = renderHook(() => useDraftAuthoring({
|
||||
draft: initial,
|
||||
initialSelection: { kind: "node", nodeId: "render" },
|
||||
}));
|
||||
|
||||
await act(async () => result.current.setStepInputs(bindings));
|
||||
|
||||
expect(setStepInputBindings).toHaveBeenCalledWith({
|
||||
workspaceId: "draft-report",
|
||||
revision: 7,
|
||||
stepId: "render",
|
||||
bindings,
|
||||
});
|
||||
expect(result.current.draft).toBe(canonical);
|
||||
});
|
||||
|
||||
it("submits ordered output bindings and commits the returned draft", async () => {
|
||||
const initial = workspace({ revision: 4 });
|
||||
const canonical = workspace({ revision: 5 });
|
||||
const bindings = [
|
||||
{ source: "text", target: "state.report" },
|
||||
{ source: "text", target: "state.audit.latest" },
|
||||
] satisfies ReadonlyArray<OutputBinding>;
|
||||
setStepOutputBindings.mockResolvedValue(canonical);
|
||||
const { result } = renderHook(() => useDraftAuthoring({
|
||||
draft: initial,
|
||||
initialSelection: { kind: "node", nodeId: "render" },
|
||||
}));
|
||||
|
||||
await act(async () => result.current.setStepOutputs(bindings));
|
||||
|
||||
expect(setStepOutputBindings).toHaveBeenCalledWith({
|
||||
workspaceId: "draft-report",
|
||||
revision: 4,
|
||||
stepId: "render",
|
||||
bindings,
|
||||
});
|
||||
expect(result.current.draft).toBe(canonical);
|
||||
});
|
||||
|
||||
it("sends only present setup fields, including zero and explicit null", async () => {
|
||||
const initial = workspace({ revision: 7 });
|
||||
updateCapabilityStep
|
||||
.mockResolvedValueOnce(workspace({ revision: 8 }))
|
||||
.mockResolvedValueOnce(workspace({ revision: 9 }));
|
||||
const { result } = renderHook(() => useDraftAuthoring({
|
||||
draft: initial,
|
||||
initialSelection: { kind: "node", nodeId: "render" },
|
||||
}));
|
||||
|
||||
const retryPatch = { retry: 0 } satisfies CapabilitySetupPatch;
|
||||
await act(async () => result.current.updateSetup(retryPatch));
|
||||
await act(async () => result.current.updateSetup({ timeoutSeconds: null }));
|
||||
|
||||
expect(updateCapabilityStep).toHaveBeenNthCalledWith(1, {
|
||||
workspaceId: "draft-report",
|
||||
revision: 7,
|
||||
stepId: "render",
|
||||
update: { retry: 0 },
|
||||
});
|
||||
expect(updateCapabilityStep).toHaveBeenNthCalledWith(2, {
|
||||
workspaceId: "draft-report",
|
||||
revision: 8,
|
||||
stepId: "render",
|
||||
update: { timeoutSeconds: null },
|
||||
});
|
||||
});
|
||||
|
||||
it("coalesces duplicate selected-step mutations and rejects a different pending mutation", async () => {
|
||||
const initial = workspace({ revision: 6 });
|
||||
let resolveInputs: ((value: DraftWorkspace) => void) | undefined;
|
||||
setStepInputBindings.mockReturnValueOnce(
|
||||
new Promise<DraftWorkspace>((resolve) => { resolveInputs = resolve; }),
|
||||
);
|
||||
const { result } = renderHook(() => useDraftAuthoring({
|
||||
draft: initial,
|
||||
initialSelection: { kind: "node", nodeId: "render" },
|
||||
}));
|
||||
const bindings = [{ path: "input.title", target: "title" }] satisfies ReadonlyArray<InputBinding>;
|
||||
|
||||
let first: Promise<void> | undefined;
|
||||
let duplicate: Promise<void> | undefined;
|
||||
act(() => {
|
||||
first = result.current.setStepInputs(bindings);
|
||||
duplicate = result.current.setStepInputs(bindings);
|
||||
});
|
||||
const different = result.current.setStepOutputs([
|
||||
{ source: "text", target: "state.report" },
|
||||
] satisfies ReadonlyArray<OutputBinding>);
|
||||
|
||||
expect(first).toBe(duplicate);
|
||||
await expect(different).rejects.toThrow("Another draft authoring request is in progress.");
|
||||
expect(setStepInputBindings).toHaveBeenCalledTimes(1);
|
||||
expect(setStepOutputBindings).not.toHaveBeenCalled();
|
||||
|
||||
resolveInputs?.(workspace({ revision: 7 }));
|
||||
await act(async () => first);
|
||||
});
|
||||
|
||||
it("ignores a selected-step response after the selection target becomes stale", async () => {
|
||||
const initial = workspace({ revision: 7 });
|
||||
let resolveInputs: ((value: DraftWorkspace) => void) | undefined;
|
||||
setStepInputBindings.mockReturnValueOnce(
|
||||
new Promise<DraftWorkspace>((resolve) => { resolveInputs = resolve; }),
|
||||
);
|
||||
const { result } = renderHook(() => useDraftAuthoring({
|
||||
draft: initial,
|
||||
initialSelection: { kind: "node", nodeId: "render" },
|
||||
}));
|
||||
const request = result.current.setStepInputs([
|
||||
{ path: "input.title", target: "title" },
|
||||
]);
|
||||
|
||||
act(() => result.current.select({ kind: "node", nodeId: "publish" }));
|
||||
resolveInputs?.(workspace({ revision: 8 }));
|
||||
await act(async () => request);
|
||||
|
||||
expect(result.current.draft).toBe(initial);
|
||||
expect(result.current.selection).toEqual({ kind: "node", nodeId: "publish" });
|
||||
});
|
||||
|
||||
it("reapplies the exact input submission to its original step after reload", async () => {
|
||||
const initial = workspace({ revision: 7 });
|
||||
const conflict = workspace({ revision: 7, status: "conflict" });
|
||||
const reloaded = workspace({ revision: 8, status: "invalid" });
|
||||
const canonical = workspace({ revision: 9 });
|
||||
const bindings = [
|
||||
{ path: "input.items", target: "items" },
|
||||
{ target: "separator", value: null },
|
||||
{ path: "state.fallback", target: "fallback" },
|
||||
] satisfies ReadonlyArray<InputBinding>;
|
||||
setStepInputBindings.mockResolvedValueOnce(conflict).mockResolvedValueOnce(canonical);
|
||||
load.mockResolvedValue(reloaded);
|
||||
const { result } = renderHook(() => useDraftAuthoring({
|
||||
draft: initial,
|
||||
initialSelection: { kind: "node", nodeId: "render" },
|
||||
}));
|
||||
|
||||
await act(async () => result.current.setStepInputs(bindings));
|
||||
act(() => result.current.select({ kind: "node", nodeId: "publish" }));
|
||||
await act(async () => result.current.reload());
|
||||
await act(async () => result.current.reapply());
|
||||
|
||||
expect(setStepInputBindings).toHaveBeenLastCalledWith({
|
||||
workspaceId: "draft-report",
|
||||
revision: 8,
|
||||
stepId: "render",
|
||||
bindings,
|
||||
});
|
||||
expect(result.current.draft).toBe(canonical);
|
||||
});
|
||||
|
||||
it("reapplies the exact output submission to its original step after reload", async () => {
|
||||
const initial = workspace({ revision: 7 });
|
||||
const conflict = workspace({ revision: 7, status: "conflict" });
|
||||
const reloaded = workspace({ revision: 8, status: "invalid" });
|
||||
const canonical = workspace({ revision: 9 });
|
||||
const bindings = [
|
||||
{ source: "text", target: "state.report" },
|
||||
{ source: "text", target: "state.audit.latest" },
|
||||
] satisfies ReadonlyArray<OutputBinding>;
|
||||
setStepOutputBindings.mockResolvedValueOnce(conflict).mockResolvedValueOnce(canonical);
|
||||
load.mockResolvedValue(reloaded);
|
||||
const { result } = renderHook(() => useDraftAuthoring({
|
||||
draft: initial,
|
||||
initialSelection: { kind: "node", nodeId: "render" },
|
||||
}));
|
||||
|
||||
await act(async () => result.current.setStepOutputs(bindings));
|
||||
act(() => result.current.select({ kind: "node", nodeId: "publish" }));
|
||||
await act(async () => result.current.reload());
|
||||
await act(async () => result.current.reapply());
|
||||
|
||||
expect(setStepOutputBindings).toHaveBeenLastCalledWith({
|
||||
workspaceId: "draft-report",
|
||||
revision: 8,
|
||||
stepId: "render",
|
||||
bindings,
|
||||
});
|
||||
expect(result.current.draft).toBe(canonical);
|
||||
});
|
||||
|
||||
it("reapplies the exact setup patch to its original step after reload", async () => {
|
||||
const initial = workspace({ revision: 7 });
|
||||
const conflict = workspace({ revision: 7, status: "conflict" });
|
||||
const reloaded = workspace({ revision: 8, status: "invalid" });
|
||||
const canonical = workspace({ revision: 9 });
|
||||
updateCapabilityStep.mockResolvedValueOnce(conflict).mockResolvedValueOnce(canonical);
|
||||
load.mockResolvedValue(reloaded);
|
||||
const { result } = renderHook(() => useDraftAuthoring({
|
||||
draft: initial,
|
||||
initialSelection: { kind: "node", nodeId: "render" },
|
||||
}));
|
||||
const patch = { retry: 0 } satisfies CapabilitySetupPatch;
|
||||
|
||||
await act(async () => result.current.updateSetup(patch));
|
||||
act(() => result.current.select({ kind: "node", nodeId: "publish" }));
|
||||
await act(async () => result.current.reload());
|
||||
await act(async () => result.current.reapply());
|
||||
|
||||
expect(updateCapabilityStep).toHaveBeenLastCalledWith({
|
||||
workspaceId: "draft-report",
|
||||
revision: 8,
|
||||
stepId: "render",
|
||||
update: { retry: 0 },
|
||||
});
|
||||
expect(result.current.draft).toBe(canonical);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,7 +8,11 @@ import {
|
||||
createDraftWorkspaceClient,
|
||||
type DraftWorkspaceClient,
|
||||
} from "../domain/draft-workspace-client.js";
|
||||
import type { DraftWorkspace } from "../domain/draft-workspace-models.js";
|
||||
import type {
|
||||
DraftWorkspace,
|
||||
InputBinding,
|
||||
OutputBinding,
|
||||
} from "../domain/draft-workspace-models.js";
|
||||
import type { CapabilityNodeFormValue } from "./CapabilityNodeForm.js";
|
||||
import type { RouteFormValue } from "./RouteForm.js";
|
||||
import {
|
||||
@@ -16,6 +20,7 @@ import {
|
||||
type InsertionContext,
|
||||
type WorkbenchSelection,
|
||||
} from "./authoring-graph.js";
|
||||
import type { CapabilitySetupPatch } from "./selected-step-dataflow.js";
|
||||
|
||||
export type DraftAuthoringPhase = "idle" | "saving" | "conflict" | "error";
|
||||
|
||||
@@ -30,6 +35,9 @@ export interface DraftAuthoringController {
|
||||
readonly preservedCapabilityForm: PreservedCapabilityForm;
|
||||
readonly addCapability: (input: CapabilityNodeFormValue) => Promise<void>;
|
||||
readonly updateCapability: (input: CapabilityNodeFormValue) => Promise<void>;
|
||||
readonly setStepInputs: (bindings: ReadonlyArray<InputBinding>) => Promise<void>;
|
||||
readonly setStepOutputs: (bindings: ReadonlyArray<OutputBinding>) => Promise<void>;
|
||||
readonly updateSetup: (patch: CapabilitySetupPatch) => Promise<void>;
|
||||
readonly setRoute: (input: RouteFormValue) => Promise<void>;
|
||||
readonly validate: () => Promise<void>;
|
||||
readonly reload: () => Promise<void>;
|
||||
@@ -80,8 +88,30 @@ type LastSubmission =
|
||||
readonly input: CapabilityNodeFormValue;
|
||||
}
|
||||
| { readonly kind: "route"; readonly input: RouteFormValue }
|
||||
| {
|
||||
readonly kind: "setup";
|
||||
readonly targetStepId: string;
|
||||
readonly patch: CapabilitySetupPatch;
|
||||
}
|
||||
| {
|
||||
readonly kind: "inputs";
|
||||
readonly targetStepId: string;
|
||||
readonly bindings: ReadonlyArray<InputBinding>;
|
||||
}
|
||||
| {
|
||||
readonly kind: "outputs";
|
||||
readonly targetStepId: string;
|
||||
readonly bindings: ReadonlyArray<OutputBinding>;
|
||||
}
|
||||
| null;
|
||||
|
||||
type MutationOptions = {
|
||||
readonly nextSelection?: WorkbenchSelection;
|
||||
readonly targetStepId?: string;
|
||||
readonly allowTargetSelectionChange?: boolean;
|
||||
readonly submission?: Exclude<LastSubmission, null>;
|
||||
};
|
||||
|
||||
export type PreservedCapabilityForm =
|
||||
| { readonly kind: "add"; readonly input: CapabilityNodeFormValue }
|
||||
| { readonly kind: "update"; readonly input: CapabilityNodeFormValue }
|
||||
@@ -151,6 +181,9 @@ export const useDraftAuthoring = ({
|
||||
resetGeneration: 0,
|
||||
}));
|
||||
const pendingRef = useRef<PendingMutation | null>(null);
|
||||
// The draft is confirmed canonical state. Selected-step forms own active
|
||||
// tabs and unsaved rows; this ref stores only the exact mutation payload
|
||||
// needed for an explicit conflict reapply.
|
||||
const lastSubmissionRef = useRef<LastSubmission>(null);
|
||||
|
||||
const adoptsDraftInput =
|
||||
@@ -243,7 +276,7 @@ export const useDraftAuthoring = ({
|
||||
kind: string,
|
||||
input: unknown,
|
||||
operation: (client: DraftAuthoringClient, requestDraft: DraftWorkspace) => Promise<DraftWorkspace>,
|
||||
nextSelection?: WorkbenchSelection,
|
||||
options: MutationOptions = {},
|
||||
): Promise<void> => {
|
||||
const requestDraft = currentDraftRef.current;
|
||||
const key = mutationKey(kind, input, requestDraft.revision);
|
||||
@@ -270,6 +303,9 @@ export const useDraftAuthoring = ({
|
||||
});
|
||||
}
|
||||
|
||||
if (options.submission !== undefined) {
|
||||
lastSubmissionRef.current = options.submission;
|
||||
}
|
||||
const requestProvenance = currentProvenanceRef.current;
|
||||
setState((current) => ({
|
||||
...current,
|
||||
@@ -279,7 +315,14 @@ export const useDraftAuthoring = ({
|
||||
}));
|
||||
const promise = operation(authoringClient, requestDraft)
|
||||
.then((response) => {
|
||||
const committed = commitResponse(response, requestProvenance, nextSelection);
|
||||
const targetIsCurrent =
|
||||
options.targetStepId === undefined ||
|
||||
options.allowTargetSelectionChange === true ||
|
||||
(currentSelectionRef.current.kind === "node" &&
|
||||
currentSelectionRef.current.nodeId === options.targetStepId);
|
||||
const committed =
|
||||
targetIsCurrent &&
|
||||
commitResponse(response, requestProvenance, options.nextSelection);
|
||||
if (!committed && sameProvenance(requestProvenance, currentProvenanceRef.current)) {
|
||||
throw new Error("The authoring response did not match the requested workspace.");
|
||||
}
|
||||
@@ -304,7 +347,6 @@ export const useDraftAuthoring = ({
|
||||
|
||||
const addCapability = useCallback(
|
||||
(input: CapabilityNodeFormValue): Promise<void> => {
|
||||
lastSubmissionRef.current = { kind: "add", input };
|
||||
const insertion = currentInsertionContextRef.current;
|
||||
return runMutation(
|
||||
"add",
|
||||
@@ -329,7 +371,10 @@ export const useDraftAuthoring = ({
|
||||
retry: input.retry,
|
||||
timeoutSeconds: input.timeoutSeconds,
|
||||
}),
|
||||
{ kind: "node", nodeId: input.stepId },
|
||||
{
|
||||
nextSelection: { kind: "node", nodeId: input.stepId },
|
||||
submission: { kind: "add", input },
|
||||
},
|
||||
);
|
||||
},
|
||||
[runMutation],
|
||||
@@ -339,7 +384,6 @@ export const useDraftAuthoring = ({
|
||||
(targetStepId: string, input: CapabilityNodeFormValue): Promise<void> => {
|
||||
// Persist the immutable mutation target with the form. A conflict may
|
||||
// outlive the current graph selection before the operator reapplies it.
|
||||
lastSubmissionRef.current = { kind: "update", targetStepId, input };
|
||||
return runMutation(
|
||||
"update",
|
||||
{ targetStepId, input },
|
||||
@@ -355,6 +399,9 @@ export const useDraftAuthoring = ({
|
||||
timeoutSeconds: input.timeoutSeconds,
|
||||
},
|
||||
}),
|
||||
{
|
||||
submission: { kind: "update", targetStepId, input },
|
||||
},
|
||||
);
|
||||
},
|
||||
[runMutation],
|
||||
@@ -373,9 +420,135 @@ export const useDraftAuthoring = ({
|
||||
[submitCapabilityUpdate],
|
||||
);
|
||||
|
||||
const selectedStepId = useCallback((): string | null => {
|
||||
const selection = currentSelectionRef.current;
|
||||
return selection.kind === "node" ? selection.nodeId : null;
|
||||
}, []);
|
||||
|
||||
const missingSelectedStep = useCallback((): Promise<void> => {
|
||||
const error = new Error("Select a capability node before editing its dataflow.");
|
||||
setState((current) => ({
|
||||
...current,
|
||||
dirty: true,
|
||||
phase: "error",
|
||||
message: error.message,
|
||||
}));
|
||||
return Promise.reject(error);
|
||||
}, []);
|
||||
|
||||
const submitSetup = useCallback(
|
||||
(
|
||||
targetStepId: string,
|
||||
patch: CapabilitySetupPatch,
|
||||
allowTargetSelectionChange = false,
|
||||
): Promise<void> => {
|
||||
const update = {
|
||||
...(patch.description !== undefined ? { description: patch.description } : {}),
|
||||
...(patch.retry !== undefined ? { retry: patch.retry } : {}),
|
||||
...(patch.timeoutSeconds !== undefined ? { timeoutSeconds: patch.timeoutSeconds } : {}),
|
||||
};
|
||||
return runMutation(
|
||||
"setup",
|
||||
{ targetStepId, patch },
|
||||
(client, requestDraft) =>
|
||||
client.updateCapabilityStep({
|
||||
workspaceId: requestDraft.workspaceId,
|
||||
revision: requestDraft.revision,
|
||||
stepId: targetStepId,
|
||||
update,
|
||||
}),
|
||||
{
|
||||
targetStepId,
|
||||
allowTargetSelectionChange,
|
||||
submission: { kind: "setup", targetStepId, patch },
|
||||
},
|
||||
);
|
||||
},
|
||||
[runMutation],
|
||||
);
|
||||
|
||||
const submitStepInputs = useCallback(
|
||||
(
|
||||
targetStepId: string,
|
||||
bindings: ReadonlyArray<InputBinding>,
|
||||
allowTargetSelectionChange = false,
|
||||
): Promise<void> =>
|
||||
runMutation(
|
||||
"inputs",
|
||||
{ targetStepId, bindings },
|
||||
(client, requestDraft) =>
|
||||
client.setStepInputBindings({
|
||||
workspaceId: requestDraft.workspaceId,
|
||||
revision: requestDraft.revision,
|
||||
stepId: targetStepId,
|
||||
bindings,
|
||||
}),
|
||||
{
|
||||
targetStepId,
|
||||
allowTargetSelectionChange,
|
||||
submission: { kind: "inputs", targetStepId, bindings },
|
||||
},
|
||||
),
|
||||
[runMutation],
|
||||
);
|
||||
|
||||
const submitStepOutputs = useCallback(
|
||||
(
|
||||
targetStepId: string,
|
||||
bindings: ReadonlyArray<OutputBinding>,
|
||||
allowTargetSelectionChange = false,
|
||||
): Promise<void> =>
|
||||
runMutation(
|
||||
"outputs",
|
||||
{ targetStepId, bindings },
|
||||
(client, requestDraft) =>
|
||||
client.setStepOutputBindings({
|
||||
workspaceId: requestDraft.workspaceId,
|
||||
revision: requestDraft.revision,
|
||||
stepId: targetStepId,
|
||||
bindings,
|
||||
}),
|
||||
{
|
||||
targetStepId,
|
||||
allowTargetSelectionChange,
|
||||
submission: { kind: "outputs", targetStepId, bindings },
|
||||
},
|
||||
),
|
||||
[runMutation],
|
||||
);
|
||||
|
||||
const updateSetup = useCallback(
|
||||
(patch: CapabilitySetupPatch): Promise<void> => {
|
||||
const targetStepId = selectedStepId();
|
||||
return targetStepId === null
|
||||
? missingSelectedStep()
|
||||
: submitSetup(targetStepId, patch);
|
||||
},
|
||||
[missingSelectedStep, selectedStepId, submitSetup],
|
||||
);
|
||||
|
||||
const setStepInputs = useCallback(
|
||||
(bindings: ReadonlyArray<InputBinding>): Promise<void> => {
|
||||
const targetStepId = selectedStepId();
|
||||
return targetStepId === null
|
||||
? missingSelectedStep()
|
||||
: submitStepInputs(targetStepId, bindings);
|
||||
},
|
||||
[missingSelectedStep, selectedStepId, submitStepInputs],
|
||||
);
|
||||
|
||||
const setStepOutputs = useCallback(
|
||||
(bindings: ReadonlyArray<OutputBinding>): Promise<void> => {
|
||||
const targetStepId = selectedStepId();
|
||||
return targetStepId === null
|
||||
? missingSelectedStep()
|
||||
: submitStepOutputs(targetStepId, bindings);
|
||||
},
|
||||
[missingSelectedStep, selectedStepId, submitStepOutputs],
|
||||
);
|
||||
|
||||
const setRoute = useCallback(
|
||||
(input: RouteFormValue): Promise<void> => {
|
||||
lastSubmissionRef.current = { kind: "route", input };
|
||||
return runMutation(
|
||||
"route",
|
||||
input,
|
||||
@@ -387,6 +560,7 @@ export const useDraftAuthoring = ({
|
||||
outcome: input.outcome,
|
||||
target: input.target,
|
||||
}),
|
||||
{ submission: { kind: "route", input } },
|
||||
);
|
||||
},
|
||||
[runMutation],
|
||||
@@ -470,8 +644,18 @@ export const useDraftAuthoring = ({
|
||||
if (last === null) return Promise.resolve();
|
||||
if (last.kind === "add") return addCapability(last.input);
|
||||
if (last.kind === "update") return submitCapabilityUpdate(last.targetStepId, last.input);
|
||||
return setRoute(last.input);
|
||||
}, [addCapability, setRoute, submitCapabilityUpdate]);
|
||||
if (last.kind === "route") return setRoute(last.input);
|
||||
if (last.kind === "setup") return submitSetup(last.targetStepId, last.patch, true);
|
||||
if (last.kind === "inputs") return submitStepInputs(last.targetStepId, last.bindings, true);
|
||||
return submitStepOutputs(last.targetStepId, last.bindings, true);
|
||||
}, [
|
||||
addCapability,
|
||||
setRoute,
|
||||
submitCapabilityUpdate,
|
||||
submitSetup,
|
||||
submitStepInputs,
|
||||
submitStepOutputs,
|
||||
]);
|
||||
|
||||
const rememberCapabilityForm = useCallback(
|
||||
(kind: "add" | "update", input: CapabilityNodeFormValue): void => {
|
||||
@@ -505,6 +689,9 @@ export const useDraftAuthoring = ({
|
||||
resetGeneration,
|
||||
addCapability,
|
||||
updateCapability,
|
||||
setStepInputs,
|
||||
setStepOutputs,
|
||||
updateSetup,
|
||||
setRoute,
|
||||
validate,
|
||||
reload,
|
||||
|
||||
Reference in New Issue
Block a user