Create ElementController

Create Element

Controller

Learn how to map node changes to element changes in the controller.


Controller

With the view layer updated, we can now move on to the controller layer. We'll convert the node changes that occur within the element into their corresponding element changes. To do this, we'll update the following file to include the function for the new element:

// src/shared/kits/workflow/mvc/controller/controller/element-type/index.ts

import { zet, type Refine } from "@/shared/lib/zet";

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

import type { TypedFlows } from "@/shared/kits/workflow/mvc/view/types/flows";

import type { ElementTypeChange } from "..";

import { actionChangeToWorkflowChanges } from "./action";
import { conditionChangeToWorkflowChanges } from "./condition";
import { switchChangeToWorkflowChanges } from "./switch";
import { loopChangeToWorkflowChanges } from "./loop";
import { parallelChangeToWorkflowChanges } from "./parallel";

interface Zet {
  object: ElementTypeChange;
  nested: ["node", "entity"];
  filter: ["meta", "elementType"];
  params: [Workflow, TypedFlows];
  return: WorkflowChange[];
}

const dispatch = zet<Zet>(["node", "entity"], ["meta", "elementType"], {
  action: actionChangeToWorkflowChanges,
  condition: conditionChangeToWorkflowChanges,
  switch: switchChangeToWorkflowChanges,
  loop: loopChangeToWorkflowChanges,
  parallel: parallelChangeToWorkflowChanges,
});

export function elementTypeChangeToWorkflowChanges(
  change: ElementTypeChange,
  workflow: Workflow,
  flows: TypedFlows,
): WorkflowChange[] {
  return dispatch(change, workflow, flows);
}

export type ActionChange = Refine<{
  object: ElementTypeChange;
  nested: ["node", "entity"];
  filter: ["meta", "elementType"];
  narrow: "action";
}>;

export type ConditionChange = Refine<{
  object: ElementTypeChange;
  nested: ["node", "entity"];
  filter: ["meta", "elementType"];
  narrow: "condition";
}>;

export type SwitchChange = Refine<{
  object: ElementTypeChange;
  nested: ["node", "entity"];
  filter: ["meta", "elementType"];
  narrow: "switch";
}>;

export type LoopChange = Refine<{
  object: ElementTypeChange;
  nested: ["node", "entity"];
  filter: ["meta", "elementType"];
  narrow: "loop";
}>;

export type ParallelChange = Refine<{
  object: ElementTypeChange;
  nested: ["node", "entity"];
  filter: ["meta", "elementType"];
  narrow: "parallel";
}>;

We'll create this newly imported function by adding the files shown below.

The parallel/index.ts file:

// src/shared/kits/workflow/mvc/controller/controller/element-type/parallel/index.ts

import { zet, type Refine } from "@/shared/lib/zet";

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

import type { TypedFlows } from "@/shared/kits/workflow/mvc/view/types/flows";

import type { ParallelChange } from "..";

import { flowChangeToWorkflowChanges } from "./flow";

interface Zet {
  object: ParallelChange;
  nested: ["node", "entity"];
  filter: ["meta", "mode"];
  params: [Workflow, TypedFlows];
  return: WorkflowChange[];
}

const dispatch = zet<Zet>(["node", "entity"], ["meta", "mode"], {
  flow: flowChangeToWorkflowChanges,
  drag: () => [],
});

export function parallelChangeToWorkflowChanges(
  change: ParallelChange,
  workflow: Workflow,
  flows: TypedFlows,
): WorkflowChange[] {
  return dispatch(change, workflow, flows);
}

export type FlowChange = Refine<{
  object: ParallelChange;
  nested: ["node", "entity"];
  filter: ["meta", "mode"];
  narrow: "flow";
}>;

The parallel/flow/index.ts file:

// src/shared/kits/workflow/mvc/controller/controller/element-type/parallel/flow/index.ts

import { zet, type Refine } from "@/shared/lib/zet";

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

import type { TypedFlows } from "@/shared/kits/workflow/mvc/view/types/flows";

import type { FlowChange } from "..";

import { blockChangeToWorkflowChanges } from "./block";
import { addNextChangeToWorkflowChanges } from "./add-next";
import { blockBranchChangeToWorkflowChanges } from "./block-branch";
import { createBranchChangeToWorkflowChanges } from "./create-branch";
import { addBranchChangeToWorkflowChanges } from "./add-branch";

interface Zet {
  object: FlowChange;
  nested: ["node", "entity"];
  filter: ["meta", "item"];
  params: [Workflow, TypedFlows];
  return: WorkflowChange[];
}

const dispatch = zet<Zet>(["node", "entity"], ["meta", "item"], {
  block: blockChangeToWorkflowChanges,
  addNext: addNextChangeToWorkflowChanges,
  blockBranch: blockBranchChangeToWorkflowChanges,
  createBranch: createBranchChangeToWorkflowChanges,
  addBranch: addBranchChangeToWorkflowChanges,
  container: () => [],
});

export function flowChangeToWorkflowChanges(
  change: FlowChange,
  workflow: Workflow,
  flows: TypedFlows,
): WorkflowChange[] {
  return dispatch(change, workflow, flows);
}

export type BlockChange = Refine<{
  object: FlowChange;
  nested: ["node", "entity"];
  filter: ["meta", "item"];
  narrow: "block";
}>;

export type AddNextChange = Refine<{
  object: FlowChange;
  nested: ["node", "entity"];
  filter: ["meta", "item"];
  narrow: "addNext";
}>;

export type BlockBranchChange = Refine<{
  object: FlowChange;
  nested: ["node", "entity"];
  filter: ["meta", "item"];
  narrow: "blockBranch";
}>;

export type CreateBranchChange = Refine<{
  object: FlowChange;
  nested: ["node", "entity"];
  filter: ["meta", "item"];
  narrow: "createBranch";
}>;

export type AddBranch = Refine<{
  object: FlowChange;
  nested: ["node", "entity"];
  filter: ["meta", "item"];
  narrow: "addBranch";
}>;

The parallel/flow/block/index.ts file:

// src/shared/kits/workflow/mvc/controller/controller/element-type/parallel/flow/block/index.ts

import { zet, type Refine } from "@/shared/lib/zet";

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

import type { TypedFlows } from "@/shared/kits/workflow/mvc/view/types/flows";

import type { BlockChange } from "..";

import { selectChangeToWorkflowChanges } from "./select";
import { dragChangeToWorkflowChanges } from "./drag";
import { dropChangeToWorkflowChanges } from "./drop";

interface Zet {
  object: BlockChange;
  nested: [];
  filter: ["type"];
  params: [Workflow, TypedFlows];
  return: WorkflowChange[];
}

const dispatch = zet<Zet>([], ["type"], {
  select: selectChangeToWorkflowChanges,
  drag: dragChangeToWorkflowChanges,
  drop: dropChangeToWorkflowChanges,
});

export function blockChangeToWorkflowChanges(
  change: BlockChange,
  workflow: Workflow,
  flows: TypedFlows,
): WorkflowChange[] {
  return dispatch(change, workflow, flows);
}

export type SelectChange = Refine<{
  object: BlockChange;
  nested: [];
  filter: ["type"];
  narrow: "select";
}>;

export type DragChange = Refine<{
  object: BlockChange;
  nested: [];
  filter: ["type"];
  narrow: "drag";
}>;

export type DropChange = Refine<{
  object: BlockChange;
  nested: [];
  filter: ["type"];
  narrow: "drop";
}>;

The parallel/flow/block/select.ts file:

// src/shared/kits/workflow/mvc/controller/controller/element-type/parallel/flow/block/select.ts

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

import type { SelectChange } from ".";

export function selectChangeToWorkflowChanges(
  change: SelectChange,
): WorkflowChange[] {
  if (change.selected) {
    const workflowChange: ParallelSelectChange = {
      type: "elementType",
      elementType: "parallel",
      change: "select",
      id: change.node.entity.meta.id,
    };
    return [workflowChange];
  }
  return [];
}

The parallel/flow/block/drag.ts file:

// src/shared/kits/workflow/mvc/controller/controller/element-type/parallel/flow/block/drag.ts

import type { Workflow } from "@/shared/kits/workflow/mvc/model/workflow";
import type { TypedFlows } from "@/shared/kits/workflow/mvc/view/types/flows";

import type {
  WorkflowChange,
  ElementDragChange,
} from "@/shared/kits/workflow/mvc/model/workflow-change";

import { createDropAreaChanges } from "@/shared/kits/workflow/mvc/controller/utils";

import type { DragChange } from ".";

export function dragChangeToWorkflowChanges(
  change: DragChange,
  workflow: Workflow,
  flows: TypedFlows,
): WorkflowChange[] {
  const workflowChange: ElementDragChange = {
    type: "element",
    change: "drag",
    id: change.node.entity.meta.id,
    position: change.positionAbsolute,
  };
  return [
    workflowChange,
    ...createDropAreaChanges(
      change.node,
      change.positionAbsolute,
      workflow,
      flows,
    ),
  ];
}

The parallel/flow/block/drop.ts file:

// src/shared/kits/workflow/mvc/controller/controller/element-type/parallel/flow/block/drop.ts

import type {
  WorkflowChange,
  ElementDropChange,
} from "@/shared/kits/workflow/mvc/model/workflow-change";

import type { DropChange } from ".";

export function dropChangeToWorkflowChanges(
  change: DropChange,
): WorkflowChange[] {
  const workflowChange: ElementDropChange = {
    type: "element",
    change: "drop",
    id: change.node.entity.meta.id,
  };
  return [workflowChange];
}

The parallel/flow/add-next/index.ts file:

// src/shared/kits/workflow/mvc/controller/controller/element-type/parallel/flow/add-next/index.ts

import { zet, type Refine } from "@/shared/lib/zet";

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

import type { TypedFlows } from "@/shared/kits/workflow/mvc/view/types/flows";

import type { AddNextChange } from "..";

import { selectChangeToWorkflowChanges } from "./select";

interface Zet {
  object: AddNextChange;
  nested: [];
  filter: ["type"];
  params: [Workflow, TypedFlows];
  return: WorkflowChange[];
}

const dispatch = zet<Zet>([], ["type"], {
  select: selectChangeToWorkflowChanges,
  drag: () => [],
  drop: () => [],
});

export function addNextChangeToWorkflowChanges(
  change: AddNextChange,
  workflow: Workflow,
  flows: TypedFlows,
): WorkflowChange[] {
  return dispatch(change, workflow, flows);
}

export type SelectChange = Refine<{
  object: AddNextChange;
  nested: [];
  filter: ["type"];
  narrow: "select";
}>;

The parallel/flow/add-next/select.ts file:

// src/shared/kits/workflow/mvc/controller/controller/element-type/parallel/flow/add-next/select.ts

import type {
  WorkflowChange,
  ElementSelectAddNextChange,
} from "@/shared/kits/workflow/mvc/model/workflow-change";

import type { SelectChange } from ".";

export function selectChangeToWorkflowChanges(
  change: SelectChange,
): WorkflowChange[] {
  if (change.selected) {
    const workflowChange: ElementSelectAddNextChange = {
      type: "element",
      change: "selectAddNext",
      id: change.node.entity.meta.id,
    };
    return [workflowChange];
  }
  return [];
}

The parallel/flow/block-branch/index.ts file:

// src/shared/kits/workflow/mvc/controller/controller/element-type/parallel/flow/block-branch/index.ts

import { zet, type Refine } from "@/shared/lib/zet";

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

import type { TypedFlows } from "@/shared/kits/workflow/mvc/view/types/flows";

import type { BlockBranchChange } from "..";

import { selectChangeToWorkflowChanges } from "./select";

interface Zet {
  object: BlockBranchChange;
  nested: [];
  filter: ["type"];
  params: [Workflow, TypedFlows];
  return: WorkflowChange[];
}

const dispatch = zet<Zet>([], ["type"], {
  select: selectChangeToWorkflowChanges,
  drag: () => [],
  drop: () => [],
});

export function blockBranchChangeToWorkflowChanges(
  change: BlockBranchChange,
  workflow: Workflow,
  flows: TypedFlows,
): WorkflowChange[] {
  return dispatch(change, workflow, flows);
}

export type SelectChange = Refine<{
  object: BlockBranchChange;
  nested: [];
  filter: ["type"];
  narrow: "select";
}>;

The parallel/flow/block-branch/select.ts file:

// src/shared/kits/workflow/mvc/controller/controller/element-type/parallel/flow/block-branch/select.ts

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

import type { SelectChange } from ".";

export function selectChangeToWorkflowChanges(
  change: SelectChange,
): WorkflowChange[] {
  if (change.selected) {
    const workflowChange: ParallelSelectBranchChange = {
      type: "elementType",
      elementType: "parallel",
      change: "selectBranch",
      id: change.node.entity.meta.id,
      branch: change.node.entity.meta.branch,
    };
    return [workflowChange];
  }
  return [];
}

The parallel/flow/create-branch/index.ts file:

// src/shared/kits/workflow/mvc/controller/controller/element-type/parallel/flow/create-branch/index.ts

import { zet, type Refine } from "@/shared/lib/zet";

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

import type { TypedFlows } from "@/shared/kits/workflow/mvc/view/types/flows";

import type { CreateBranchChange } from "..";

import { selectChangeToWorkflowChanges } from "./select";

interface Zet {
  object: CreateBranchChange;
  nested: [];
  filter: ["type"];
  params: [Workflow, TypedFlows];
  return: WorkflowChange[];
}

const dispatch = zet<Zet>([], ["type"], {
  select: selectChangeToWorkflowChanges,
  drag: () => [],
  drop: () => [],
});

export function createBranchChangeToWorkflowChanges(
  change: CreateBranchChange,
  workflow: Workflow,
  flows: TypedFlows,
): WorkflowChange[] {
  return dispatch(change, workflow, flows);
}

export type SelectChange = Refine<{
  object: CreateBranchChange;
  nested: [];
  filter: ["type"];
  narrow: "select";
}>;

The parallel/flow/create-branch/select.ts file:

// src/shared/kits/workflow/mvc/controller/controller/element-type/parallel/flow/create-branch/select.ts

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

import type { SelectChange } from ".";

export function selectChangeToWorkflowChanges(
  change: SelectChange,
): WorkflowChange[] {
  if (change.selected) {
    const workflowChange: ParallelSelectCreateBranchChange = {
      type: "elementType",
      elementType: "parallel",
      change: "selectCreateBranch",
      id: change.node.entity.meta.id,
    };
    return [workflowChange];
  }
  return [];
}

The parallel/flow/add-branch/index.ts file:

// src/shared/kits/workflow/mvc/controller/controller/element-type/parallel/flow/add-branch/index.ts

import { zet, type Refine } from "@/shared/lib/zet";

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

import type { TypedFlows } from "@/shared/kits/workflow/mvc/view/types/flows";

import type { AddBranch } from "..";

import { selectChangeToWorkflowChanges } from "./select";

interface Zet {
  object: AddBranch;
  nested: [];
  filter: ["type"];
  params: [Workflow, TypedFlows];
  return: WorkflowChange[];
}

const dispatch = zet<Zet>([], ["type"], {
  select: selectChangeToWorkflowChanges,
  drag: () => [],
  drop: () => [],
});

export function addBranchChangeToWorkflowChanges(
  change: AddBranch,
  workflow: Workflow,
  flows: TypedFlows,
): WorkflowChange[] {
  return dispatch(change, workflow, flows);
}

export type SelectChange = Refine<{
  object: AddBranch;
  nested: [];
  filter: ["type"];
  narrow: "select";
}>;

The parallel/flow/add-branch/select.ts file:

// src/shared/kits/workflow/mvc/controller/controller/element-type/parallel/flow/add-branch/select.ts

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

import type { SelectChange } from ".";

export function selectChangeToWorkflowChanges(
  change: SelectChange,
): WorkflowChange[] {
  if (change.selected) {
    const workflowChange: ParallelSelectAddBranchChange = {
      type: "elementType",
      elementType: "parallel",
      change: "selectAddBranch",
      branch: change.node.entity.meta.branch,
      id: change.node.entity.meta.id,
    };
    return [workflowChange];
  }
  return [];
}