Create ElementApply Workflow Changes

Create Element

Apply Workflow Changes

Learn how to apply element changes within the workflow.


Apply Workflow Changes

We'll now create the function that receives the new element's change object and returns the updated workflow by creating the following file:

// src/shared/kits/workflow/mvc/model/apply-workflow-change/element-type/parallel/index.ts

import { zet } from "@/shared/lib/zet";

import type { Workflow } from "@/shared/kits/workflow/mvc/model/workflow";
import type { ParallelChange } from "@/shared/kits/workflow/mvc/model/workflow-change";

import { select } from "./select";
import { selectCreateBranch } from "./select-create-branch";
import { selectBranch } from "./select-branch";
import { selectAddBranch } from "./select-add-branch";
import { createBranch } from "./create-branch";
import { deleteBranch } from "./delete-branch";
import { branchInfo } from "./branch-info";
import { addBranch } from "./add-branch";
import { enterBranchDropArea } from "./enter-branch-drop-area";
import { leaveBranchDropArea } from "./leave-branch-drop-area";

interface Zet {
  object: ParallelChange;
  nested: [];
  filter: ["change"];
  params: [Workflow];
  return: {
    workflow: Workflow;
    memory: boolean;
    center: string | null;
  };
}

const dispatch = zet<Zet>([], ["change"], {
  select: select,
  selectCreateBranch: selectCreateBranch,
  selectBranch: selectBranch,
  selectAddBranch: selectAddBranch,
  createBranch: createBranch,
  deleteBranch: deleteBranch,
  branchInfo: branchInfo,
  addBranch: addBranch,
  enterBranchDropArea: enterBranchDropArea,
  leaveBranchDropArea: leaveBranchDropArea,
});

export function applyParallelChange(
  change: ParallelChange,
  workflow: Workflow,
): {
  workflow: Workflow;
  memory: boolean;
  center: string | null;
} {
  return dispatch(change, workflow);
}

We'll also need to create the following functions that are imported.

The select function:

// src/shared/kits/workflow/mvc/model/apply-workflow-change/element-type/parallel/select.ts

import type {
  Workflow,
  ParallelFlow,
} from "@/shared/kits/workflow/mvc/model/workflow";
import type { ParallelSelectChange } from "@/shared/kits/workflow/mvc/model/workflow-change";

import { WorkflowUtils } from "../../../utils";

export function select(
  change: ParallelSelectChange,
  workflow: Workflow,
): {
  workflow: Workflow;
  memory: boolean;
  center: string | null;
} {
  const element = WorkflowUtils.get(workflow, change.id) as ParallelFlow;
  return {
    workflow: {
      ...workflow,
      widget: null,
      active: `${element.id}/flow/block`,
    },
    memory: false,
    center: null,
  };
}

The selectCreateBranch function:

// src/shared/kits/workflow/mvc/model/apply-workflow-change/element-type/parallel/select-create-branch.ts

import type {
  Workflow,
  ParallelFlow,
} from "@/shared/kits/workflow/mvc/model/workflow";
import type { ParallelSelectCreateBranchChange } from "@/shared/kits/workflow/mvc/model/workflow-change";

import { WorkflowUtils } from "../../../utils";

export function selectCreateBranch(
  change: ParallelSelectCreateBranchChange,
  workflow: Workflow,
): {
  workflow: Workflow;
  memory: boolean;
  center: string | null;
} {
  const element = WorkflowUtils.get(workflow, change.id) as ParallelFlow;
  return {
    workflow: {
      ...workflow,
      widget: {
        type: "elementType",
        elementType: "parallel",
        widget: "createBranch",
        element,
      },
      active: `${element.id}/flow/createBranch`,
    },
    memory: false,
    center: null,
  };
}

The selectBranch function:

// src/shared/kits/workflow/mvc/model/apply-workflow-change/element-type/parallel/select-branch.ts

import type {
  Workflow,
  ParallelFlow,
} from "@/shared/kits/workflow/mvc/model/workflow";
import type { ParallelSelectBranchChange } from "@/shared/kits/workflow/mvc/model/workflow-change";

import { WorkflowUtils } from "../../../utils";

export function selectBranch(
  change: ParallelSelectBranchChange,
  workflow: Workflow,
): {
  workflow: Workflow;
  memory: boolean;
  center: string | null;
} {
  const element = WorkflowUtils.get(workflow, change.id) as ParallelFlow;
  return {
    workflow: {
      ...workflow,
      widget: {
        type: "elementType",
        elementType: "parallel",
        widget: "branchInfo",
        element,
        branch: change.branch,
      },
      active: `${element.id}/flow/blockBranch/${change.branch}`,
    },
    memory: false,
    center: null,
  };
}

The selectAddBranch function:

// src/shared/kits/workflow/mvc/model/apply-workflow-change/element-type/parallel/select-add-branch.ts

import type {
  Workflow,
  ParallelFlow,
} from "@/shared/kits/workflow/mvc/model/workflow";
import type { ParallelSelectAddBranchChange } from "@/shared/kits/workflow/mvc/model/workflow-change";

import { WorkflowUtils } from "../../../utils";

export function selectAddBranch(
  change: ParallelSelectAddBranchChange,
  workflow: Workflow,
): {
  workflow: Workflow;
  memory: boolean;
  center: string | null;
} {
  const element = WorkflowUtils.get(workflow, change.id) as ParallelFlow;
  return {
    workflow: {
      ...workflow,
      widget: {
        type: "elementType",
        elementType: "parallel",
        widget: "addBranch",
        element,
        branch: change.branch,
      },
      active: `${element.id}/flow/addBranch/${change.branch}`,
    },
    memory: false,
    center: null,
  };
}

The createBranch function:

// src/shared/kits/workflow/mvc/model/apply-workflow-change/element-type/parallel/create-branch.ts

import type {
  Workflow,
  ParallelFlow,
} from "@/shared/kits/workflow/mvc/model/workflow";
import type { ParallelCreateBranchChange } from "@/shared/kits/workflow/mvc/model/workflow-change";

import { WorkflowUtils, ParallelUtils } from "../../../utils";

export function createBranch(
  change: ParallelCreateBranchChange,
  workflow: Workflow,
): {
  workflow: Workflow;
  memory: boolean;
  center: string | null;
} {
  const parallelElement = WorkflowUtils.get(
    workflow,
    change.id,
  ) as ParallelFlow;
  return {
    workflow: {
      ...WorkflowUtils.modify(workflow, change.id, (element) => {
        const parallelElement = element as ParallelFlow;
        return ParallelUtils.createBranch(parallelElement, change.label);
      }),
      widget: null,
      active: null,
      failure: null,
    },
    memory: true,
    center: `${change.id}/flow/blockBranch/${parallelElement.branches.length}`,
  };
}

The deleteBranch function:

// src/shared/kits/workflow/mvc/model/apply-workflow-change/element-type/parallel/delete-branch.ts

import type {
  Workflow,
  ParallelFlow,
} from "@/shared/kits/workflow/mvc/model/workflow";
import type { ParallelDeleteBranchChange } from "@/shared/kits/workflow/mvc/model/workflow-change";

import { WorkflowUtils, ParallelUtils } from "../../../utils";

export function deleteBranch(
  change: ParallelDeleteBranchChange,
  workflow: Workflow,
): {
  workflow: Workflow;
  memory: boolean;
  center: string | null;
} {
  return {
    workflow: {
      ...WorkflowUtils.modify(workflow, change.id, (element) => {
        const parallelElement = element as ParallelFlow;
        return ParallelUtils.deleteBranch(parallelElement, change.branch);
      }),
      widget: null,
      active: null,
      failure: null,
    },
    memory: true,
    center: null,
  };
}

The branchInfo function:

// src/shared/kits/workflow/mvc/model/apply-workflow-change/element-type/parallel/branch-info.ts

import type {
  Workflow,
  ParallelFlow,
} from "@/shared/kits/workflow/mvc/model/workflow";
import type { ParallelBranchInfoChange } from "@/shared/kits/workflow/mvc/model/workflow-change";

import { WorkflowUtils, ParallelUtils } from "../../../utils";

export function branchInfo(
  change: ParallelBranchInfoChange,
  workflow: Workflow,
): {
  workflow: Workflow;
  memory: boolean;
  center: string | null;
} {
  return {
    workflow: {
      ...WorkflowUtils.modify(workflow, change.id, (element) => {
        const parallelElement = element as ParallelFlow;
        return ParallelUtils.setBranchInfo(
          parallelElement,
          change.branch,
          change.label,
        );
      }),
      widget: null,
      active: null,
      failure: null,
    },
    memory: true,
    center: null,
  };
}

The addBranch function:

// src/shared/kits/workflow/mvc/model/apply-workflow-change/element-type/parallel/add-branch.ts

import type {
  Workflow,
  ParallelFlow,
} from "@/shared/kits/workflow/mvc/model/workflow";
import type { ParallelAddBranchChange } from "@/shared/kits/workflow/mvc/model/workflow-change";

import { WorkflowUtils, ParallelUtils } from "../../../utils";

import { getWidget } from "../../widget";

export function addBranch(
  change: ParallelAddBranchChange,
  workflow: Workflow,
): {
  workflow: Workflow;
  memory: boolean;
  center: string | null;
} {
  return {
    workflow: {
      ...WorkflowUtils.modify(workflow, change.id, (element) => {
        const parallelElement = element as ParallelFlow;
        return ParallelUtils.addBranch(
          parallelElement,
          change.branch,
          change.element,
        );
      }),
      widget: getWidget(change.element),
      active: `${change.element.id}/flow/block`,
      failure: null,
    },
    memory: true,
    center: `${change.element.id}/flow/block`,
  };
}

The enterBranchDropArea function:

// src/shared/kits/workflow/mvc/model/apply-workflow-change/element-type/parallel/enter-branch-drop-area.ts

import type {
  Workflow,
  ParallelFlow,
} from "@/shared/kits/workflow/mvc/model/workflow";
import type { ParallelEnterBranchDropAreaChange } from "@/shared/kits/workflow/mvc/model/workflow-change";

import { WorkflowUtils, ParallelUtils } from "../../../utils";

export function enterBranchDropArea(
  change: ParallelEnterBranchDropAreaChange,
  workflow: Workflow,
): {
  workflow: Workflow;
  memory: boolean;
  center: string | null;
} {
  return {
    workflow: WorkflowUtils.modify(workflow, change.id, (element) => {
      const parallelElement = element as ParallelFlow;
      return ParallelUtils.enterBranchDropArea(
        parallelElement,
        change.branch,
        change.enter,
      );
    }),
    memory: false,
    center: null,
  };
}

The leaveBranchDropArea function:

// src/shared/kits/workflow/mvc/model/apply-workflow-change/element-type/parallel/leave-branch-drop-area.ts

import type {
  Workflow,
  ParallelFlow,
} from "@/shared/kits/workflow/mvc/model/workflow";
import type { ParallelLeaveBranchDropAreaChange } from "@/shared/kits/workflow/mvc/model/workflow-change";

import { WorkflowUtils, ParallelUtils } from "../../../utils";

export function leaveBranchDropArea(
  change: ParallelLeaveBranchDropAreaChange,
  workflow: Workflow,
): {
  workflow: Workflow;
  memory: boolean;
  center: string | null;
} {
  return {
    workflow: WorkflowUtils.modify(workflow, change.id, (element) => {
      const parallelElement = element as ParallelFlow;
      return ParallelUtils.leaveBranchDropArea(
        parallelElement,
        change.branch,
        change.leave,
      );
    }),
    memory: false,
    center: null,
  };
}

Then, we'll update the following file to include the new function we created:

// src/shared/kits/workflow/mvc/model/apply-workflow-change/element-type/index.ts

import { zet } from "@/shared/lib/zet";

import type { Workflow } from "../../workflow";
import type { ElementTypeChange } from "../../workflow-change";

import { applyActionChange } from "./action";
import { applyConditionChange } from "./condition";
import { applySwitchChange } from "./switch";
import { applyLoopChange } from "./loop";
import { applyParallelChange } from "./parallel";

interface Zet {
  object: ElementTypeChange;
  nested: [];
  filter: ["elementType"];
  params: [Workflow];
  return: {
    workflow: Workflow;
    memory: boolean;
    center: string | null;
  };
}

const dispatch = zet<Zet>([], ["elementType"], {
  action: applyActionChange,
  condition: applyConditionChange,
  switch: applySwitchChange,
  loop: applyLoopChange,
  parallel: applyParallelChange,
});

export function applyElementTypeChange(
  change: ElementTypeChange,
  workflow: Workflow,
): {
  workflow: Workflow;
  memory: boolean;
  center: string | null;
} {
  return dispatch(change, workflow);
}

Finally, we'll update the following utility function to include the new element:

// src/shared/kits/workflow/mvc/model/apply-workflow-change/widget.ts

import type { ElementFlow, Widget } from "../workflow";

export function getWidget(element: ElementFlow): Widget | null {
  switch (element.type) {
    case "action": {
      return {
        type: "elementType",
        elementType: "action",
        widget: "info",
        element,
      };
    }
    case "condition": {
      return {
        type: "elementType",
        elementType: "condition",
        widget: "info",
        element,
      };
    }
    case "switch": {
      return null;
    }
    case "loop": {
      return {
        type: "elementType",
        elementType: "loop",
        widget: "info",
        element,
      };
    }
    case "parallel": {
      return null;
    }
  }
}