mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-01 15:37:32 +08:00
fix cloned workflow steps keeping the source step's uuid
`CopyStepAction` deleted the cloned step's `id` so a fresh one would be assigned, but never did the same for `uuid`, so a cloned step kept its source's uuid verbatim and saving after cloning failed with "Duplicate step UUID '...' in request." The Options API `onClone` used to strip `uuid` at the call site, but that got dropped during the Composition API migration; moving the fix into `CopyStepAction` itself means any future caller of `copyStep` gets correct behavior automatically. Added a regression test in `Index.test.ts` that adds a step with a fixed uuid to the step store, emits `onClone` from the `WorkflowGraph` stub, and asserts the resulting clone has a different id, uuid, and label than the source step. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -363,6 +363,9 @@ export class CopyStepAction extends UndoRedoAction {
|
||||
this.stepLabel = `${step.id + 1}: ${step.label ?? step.name}`;
|
||||
this.step = cloneStepWithUniqueLabel(step, labelSet);
|
||||
delete this.step.id;
|
||||
// A cloned step must get its own uuid; keeping the source step's uuid
|
||||
// produces a "Duplicate step UUID" error when saving the workflow.
|
||||
delete this.step.uuid;
|
||||
}
|
||||
|
||||
get name() {
|
||||
|
||||
@@ -14,6 +14,7 @@ import { getWorkflowFull } from "@/components/Workflow/workflows.services";
|
||||
import { getAppRoot } from "@/onload/loadConfig";
|
||||
import { useDatatypesMapperStore } from "@/stores/datatypesMapperStore";
|
||||
import { useWorkflowStateStore } from "@/stores/workflowEditorStateStore";
|
||||
import { useWorkflowStepStore } from "@/stores/workflowStepStore";
|
||||
|
||||
import { getVersions, saveWorkflow } from "./modules/services";
|
||||
import { getStateUpgradeMessages } from "./modules/utilities";
|
||||
@@ -168,6 +169,36 @@ describe("Index", () => {
|
||||
expect(stateStore.hasChanges).toBeFalsy();
|
||||
});
|
||||
|
||||
it("assigns a fresh id and uuid when cloning a step", async () => {
|
||||
await flushPromises();
|
||||
|
||||
const stepStore = useWorkflowStepStore("workflow_id");
|
||||
const sourceStep = stepStore.addStep({
|
||||
type: "tool",
|
||||
label: "source label",
|
||||
name: "source step",
|
||||
content_id: "cat1",
|
||||
tool_id: "cat1",
|
||||
tool_state: {},
|
||||
input_connections: {},
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
position: { left: 0, top: 0 },
|
||||
uuid: "11111111-1111-1111-1111-111111111111",
|
||||
});
|
||||
|
||||
wrapper.find(SELECTORS.WORKFLOW_GRAPH).vm.$emit("onClone", String(sourceStep.id));
|
||||
await nextTick();
|
||||
|
||||
const clonedStepId = Object.keys(stepStore.steps).find((stepId) => stepId !== String(sourceStep.id))!;
|
||||
const clonedStep = stepStore.steps[clonedStepId]!;
|
||||
|
||||
// The clone must not keep the source step's uuid, otherwise saving
|
||||
// the workflow fails with "Duplicate step UUID ... in request."
|
||||
expect(clonedStep.uuid).not.toBe(sourceStep.uuid);
|
||||
expect(clonedStep.label).not.toBe(sourceStep.label);
|
||||
});
|
||||
|
||||
it("routes to download URL and respects Galaxy prefix", async () => {
|
||||
Object.defineProperty(window, "location", {
|
||||
value: { href: "original" },
|
||||
|
||||
Reference in New Issue
Block a user