major change on how workflow builder works. It now fetches in edit mode all the currently configured workflows
This commit is contained in:
@@ -33,6 +33,7 @@ export default function WorkflowForm({ workflow, onWorkflowChange, entityApprove
|
||||
key: stepCounter,
|
||||
stepType: "approval-by",
|
||||
stepNumber: workflow.steps.length,
|
||||
completed: false,
|
||||
assignees: [null],
|
||||
firstStep: false,
|
||||
finalStep: false,
|
||||
|
||||
@@ -43,6 +43,10 @@ export interface EditableWorkflowStep {
|
||||
key: number,
|
||||
stepType: StepType,
|
||||
stepNumber: number,
|
||||
completed: boolean,
|
||||
rejected?: boolean,
|
||||
completedBy?: User["id"],
|
||||
completedDate?: number,
|
||||
assignees: (User["id"] | null | undefined)[]; // bit of an hack, but allowing null or undefined values allows us to match one to one the select input components with the assignees array. And since select inputs allow undefined or null values, it is allowed here too, but must validate required input before form submission
|
||||
firstStep: boolean,
|
||||
finalStep?: boolean,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { ApprovalWorkflow } from "@/interfaces/approval.workflow";
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import { requestUser } from "@/utils/api";
|
||||
import { createApprovalWorkflow } from "@/utils/approval.workflows.be";
|
||||
import { createConfiguredWorkflow } from "@/utils/approval.workflows.be";
|
||||
import { withIronSessionApiRoute } from "iron-session/next";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
@@ -23,5 +23,5 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
|
||||
const approvalWorkflow: ApprovalWorkflow = req.body;
|
||||
|
||||
if (approvalWorkflow)
|
||||
return res.status(201).json(await createApprovalWorkflow(approvalWorkflow));
|
||||
return res.status(201).json(await createConfiguredWorkflow(approvalWorkflow));
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { ApprovalWorkflow } from "@/interfaces/approval.workflow";
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import { requestUser } from "@/utils/api";
|
||||
import { updateApprovalWorkflow } from "@/utils/approval.workflows.be";
|
||||
import { updateConfiguredWorkflow } from "@/utils/approval.workflows.be";
|
||||
import { withIronSessionApiRoute } from "iron-session/next";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
@@ -24,7 +24,7 @@ async function put(req: NextApiRequest, res: NextApiResponse) {
|
||||
const approvalWorkflow: ApprovalWorkflow = req.body;
|
||||
|
||||
if (id && approvalWorkflow) {
|
||||
await updateApprovalWorkflow(id, approvalWorkflow);
|
||||
await updateConfiguredWorkflow(approvalWorkflow);
|
||||
return res.status(204).end();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { ApprovalWorkflow } from "@/interfaces/approval.workflow";
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import { requestUser } from "@/utils/api";
|
||||
import { deleteApprovalWorkflow, updateApprovalWorkflow } from "@/utils/approval.workflows.be";
|
||||
import { deleteConfiguredWorkflow, updateConfiguredWorkflow } from "@/utils/approval.workflows.be";
|
||||
import { withIronSessionApiRoute } from "iron-session/next";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
@@ -23,7 +23,7 @@ async function del(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
||||
const { id } = req.query as { id?: string };
|
||||
|
||||
if (id) return res.status(200).json(await deleteApprovalWorkflow(id));
|
||||
if (id) return res.status(200).json(await deleteConfiguredWorkflow(id));
|
||||
}
|
||||
|
||||
async function put(req: NextApiRequest, res: NextApiResponse) {
|
||||
@@ -38,7 +38,7 @@ async function put(req: NextApiRequest, res: NextApiResponse) {
|
||||
const workflow = req.body;
|
||||
|
||||
if (id && workflow) {
|
||||
await updateApprovalWorkflow(id, workflow);
|
||||
await updateConfiguredWorkflow(workflow);
|
||||
return res.status(204).end();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import { ApprovalWorkflow } from "@/interfaces/approval.workflow";
|
||||
import { Entity } from "@/interfaces/entity";
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import { requestUser } from "@/utils/api";
|
||||
import { createApprovalWorkflows } from "@/utils/approval.workflows.be";
|
||||
import { replaceConfiguredWorkflowsByEntities } from "@/utils/approval.workflows.be";
|
||||
import { withIronSessionApiRoute } from "iron-session/next";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
|
||||
interface ReplaceApprovalWorkflowsRequest {
|
||||
filteredWorkflows: ApprovalWorkflow[];
|
||||
userEntitiesWithLabel: Entity[];
|
||||
}
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (req.method === "POST") return await post(req, res);
|
||||
}
|
||||
@@ -20,9 +26,12 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
|
||||
return res.status(403).json({ ok: false });
|
||||
}
|
||||
|
||||
const approvalWorkflows: ApprovalWorkflow[] = req.body;
|
||||
const { filteredWorkflows, userEntitiesWithLabel } = req.body as ReplaceApprovalWorkflowsRequest;
|
||||
|
||||
await createApprovalWorkflows(approvalWorkflows);
|
||||
const configuredWorkflows: ApprovalWorkflow[] = filteredWorkflows;
|
||||
const entitiesIds: string[] = userEntitiesWithLabel.map((e) => e.id);
|
||||
|
||||
return res.status(201).json(approvalWorkflows);
|
||||
await replaceConfiguredWorkflowsByEntities(configuredWorkflows, entitiesIds);
|
||||
|
||||
return res.status(201).json({ ok: true });
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ import { useEffect, useState } from "react";
|
||||
import { BsChevronLeft } from "react-icons/bs";
|
||||
import { GrClearOption } from "react-icons/gr";
|
||||
import { toast, ToastContainer } from "react-toastify";
|
||||
import { getApprovalWorkflow } from "@/utils/approval.workflows.be";
|
||||
import { useRouter } from "next/router";
|
||||
import axios from "axios";
|
||||
import { getConfiguredWorkflow } from "@/utils/approval.workflows.be";
|
||||
|
||||
export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }) => {
|
||||
const user = await requestUser(req, res);
|
||||
@@ -35,7 +35,7 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }
|
||||
|
||||
const { id } = params as { id: string };
|
||||
|
||||
const workflow: ApprovalWorkflow | null = await getApprovalWorkflow(id);
|
||||
const workflow: ApprovalWorkflow | null = await getConfiguredWorkflow(id);
|
||||
|
||||
if (!workflow)
|
||||
return redirect("/approval-workflows")
|
||||
@@ -91,6 +91,7 @@ export default function Home({ user, workflow, userEntitiesWithLabel, userEntiti
|
||||
key: step.stepNumber + 999, // just making sure they are unique because new steps that users add will have key=3 key=4 etc
|
||||
stepType: step.stepType,
|
||||
stepNumber: step.stepNumber,
|
||||
completed: false,
|
||||
assignees: step.assignees.map(id => id),
|
||||
firstStep: step.firstStep || false,
|
||||
finalStep: step.finalStep || false,
|
||||
@@ -179,8 +180,8 @@ export default function Home({ user, workflow, userEntitiesWithLabel, userEntiti
|
||||
startDate: Date.now(),
|
||||
status: "pending",
|
||||
steps: [
|
||||
{ key: 9998, stepType: "form-intake", stepNumber: 1, firstStep: true, finalStep: false, assignees: [null] },
|
||||
{ key: 9999, stepType: "approval-by", stepNumber: 2, firstStep: false, finalStep: true, assignees: [null] },
|
||||
{ key: 9998, stepType: "form-intake", stepNumber: 1, completed: false, firstStep: true, finalStep: false, assignees: [null] },
|
||||
{ key: 9999, stepType: "approval-by", stepNumber: 2, completed: false, firstStep: false, finalStep: true, assignees: [null] },
|
||||
],
|
||||
};
|
||||
setCloneWorkflow(newWorkflow);
|
||||
|
||||
@@ -8,18 +8,18 @@ import { CorporateUser, DeveloperUser, MasterCorporateUser, TeacherUser, User }
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import { redirect, serialize } from "@/utils";
|
||||
import { requestUser } from "@/utils/api";
|
||||
import { getConfiguredWorkflow } from "@/utils/approval.workflows.be";
|
||||
import { shouldRedirectHome } from "@/utils/navigation.disabled";
|
||||
import { getEntityUsers } from "@/utils/users.be";
|
||||
import axios from "axios";
|
||||
import { motion } from "framer-motion";
|
||||
import { withIronSessionSsr } from "iron-session/next";
|
||||
import Head from "next/head";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { BsChevronLeft } from "react-icons/bs";
|
||||
import { toast, ToastContainer } from "react-toastify";
|
||||
import axios from "axios";
|
||||
import { getApprovalWorkflow } from "@/utils/approval.workflows.be";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }) => {
|
||||
const user = await requestUser(req, res);
|
||||
@@ -30,7 +30,7 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }
|
||||
|
||||
const { id } = params as { id: string };
|
||||
|
||||
const workflow: ApprovalWorkflow | null = await getApprovalWorkflow(id);
|
||||
const workflow: ApprovalWorkflow | null = await getConfiguredWorkflow(id);
|
||||
|
||||
if (!workflow)
|
||||
return redirect("/approval-workflows")
|
||||
@@ -62,6 +62,9 @@ export default function Home({ user, workflow, workflowEntityApprovers }: Props)
|
||||
key: step.stepNumber + 999, // just making sure they are unique because new steps that users add will have key=3 key=4 etc
|
||||
stepType: step.stepType,
|
||||
stepNumber: step.stepNumber,
|
||||
completed: step.completed,
|
||||
completedBy: step.completedBy || undefined,
|
||||
completedDate: step.completedDate || undefined,
|
||||
assignees: step.assignees.map(id => id),
|
||||
firstStep: step.firstStep || false,
|
||||
finalStep: step.finalStep || false,
|
||||
|
||||
@@ -11,7 +11,7 @@ import { User } from "@/interfaces/user";
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import { redirect, serialize } from "@/utils";
|
||||
import { requestUser } from "@/utils/api";
|
||||
import { getApprovalWorkflow } from "@/utils/approval.workflows.be";
|
||||
import { getConfiguredWorkflow } from "@/utils/approval.workflows.be";
|
||||
import { shouldRedirectHome } from "@/utils/navigation.disabled";
|
||||
import { getSpecificUsers, getUser } from "@/utils/users.be";
|
||||
import axios from "axios";
|
||||
@@ -23,12 +23,14 @@ import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import { BsChevronLeft } from "react-icons/bs";
|
||||
import { FaSpinner, FaWpforms } from "react-icons/fa6";
|
||||
import { FiSave } from "react-icons/fi";
|
||||
import { IoMdCheckmarkCircleOutline } from "react-icons/io";
|
||||
import { IoDocumentTextOutline } from "react-icons/io5";
|
||||
import { MdOutlineDoubleArrow } from "react-icons/md";
|
||||
import { RiThumbUpLine } from "react-icons/ri";
|
||||
import { toast, ToastContainer } from "react-toastify";
|
||||
import { IoMdCheckmarkCircleOutline } from "react-icons/io";
|
||||
import { FiSave } from "react-icons/fi";
|
||||
import { RxCrossCircled } from "react-icons/rx";
|
||||
import { TiEdit } from "react-icons/ti";
|
||||
import { toast, ToastContainer } from "react-toastify";
|
||||
|
||||
export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }) => {
|
||||
const user = await requestUser(req, res);
|
||||
@@ -39,7 +41,7 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }
|
||||
|
||||
const { id } = params as { id: string };
|
||||
|
||||
const workflow: ApprovalWorkflow | null = await getApprovalWorkflow(id);
|
||||
const workflow: ApprovalWorkflow | null = await getConfiguredWorkflow(id);
|
||||
|
||||
if (!workflow)
|
||||
return redirect("/approval-workflows")
|
||||
@@ -132,6 +134,7 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
|
||||
const updatedWorkflow: ApprovalWorkflow = {
|
||||
...workflow,
|
||||
status: selectedStepIndex === workflow.steps.length - 1 ? "approved" : "pending",
|
||||
steps: workflow.steps.map((step, index) =>
|
||||
index === selectedStepIndex ?
|
||||
{
|
||||
@@ -206,6 +209,14 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
})
|
||||
};
|
||||
|
||||
const handleViewExam = () => {
|
||||
|
||||
}
|
||||
|
||||
const handleEditExam = () => {
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
@@ -244,6 +255,29 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
status={workflow.status}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row gap-3">
|
||||
<Button
|
||||
color="purple"
|
||||
variant="solid"
|
||||
onClick={handleViewExam}
|
||||
padding="px-6 py-2"
|
||||
className="w-[240px] text-lg flex items-center justify-center gap-2 text-left"
|
||||
>
|
||||
<IoDocumentTextOutline />
|
||||
View Exam
|
||||
</Button>
|
||||
<Button
|
||||
color="purple"
|
||||
variant="solid"
|
||||
onClick={handleEditExam}
|
||||
padding="px-6 py-2"
|
||||
className="w-[240px] text-lg flex items-center justify-center gap-2 text-left"
|
||||
>
|
||||
<TiEdit size={20} />
|
||||
Edit Exam
|
||||
</Button>
|
||||
|
||||
</div>
|
||||
{steps.find((step) => !step.completed) === undefined &&
|
||||
<Tip text="All steps in this instance have been completed." />
|
||||
}
|
||||
@@ -271,7 +305,7 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
{/* Side panel */}
|
||||
<AnimatePresence mode="wait">
|
||||
<LayoutGroup key="sidePanel">
|
||||
<section className={`absolute inset-y-0 right-0 h-full bg-mti-purple-ultralight bg-opacity-50 shadow-xl shadow-mti-purple transition-all duration-300 overflow-hidden ${isPanelOpen ? 'w-2/5' : 'w-0'}`}>
|
||||
<section className={`absolute inset-y-0 right-0 h-full bg-mti-purple-ultralight bg-opacity-50 shadow-xl shadow-mti-purple transition-all duration-300 overflow-hidden ${isPanelOpen ? 'w-[500px]' : 'w-0'}`}>
|
||||
{isPanelOpen && selectedStep && (
|
||||
<motion.div
|
||||
className="p-6"
|
||||
@@ -412,7 +446,7 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
) : (
|
||||
<>
|
||||
<RxCrossCircled size={20} />
|
||||
Reject Step
|
||||
Reject
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { CorporateUser, DeveloperUser, MasterCorporateUser, TeacherUser, User }
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import { redirect, serialize } from "@/utils";
|
||||
import { requestUser } from "@/utils/api";
|
||||
import { getConfiguredWorkflowsByEntities } from "@/utils/approval.workflows.be";
|
||||
import { getEntities } from "@/utils/entities.be";
|
||||
import { shouldRedirectHome } from "@/utils/navigation.disabled";
|
||||
import { getEntitiesUsers } from "@/utils/users.be";
|
||||
@@ -34,9 +35,12 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
|
||||
|
||||
const userEntitiesWithLabel = await getEntities(user.entities.map(entity => entity.id));
|
||||
|
||||
const allConfiguredWorkflows = await getConfiguredWorkflowsByEntities(userEntitiesWithLabel.map(entity => entity.id));
|
||||
|
||||
return {
|
||||
props: serialize({
|
||||
user,
|
||||
allConfiguredWorkflows,
|
||||
userEntitiesWithLabel,
|
||||
userEntitiesApprovers: await getEntitiesUsers(userEntitiesWithLabel.map(entity => entity.id), { type: { $in: ["teacher", "corporate", "mastercorporate", "developer"] } }) as (TeacherUser | CorporateUser | MasterCorporateUser | DeveloperUser)[],
|
||||
}),
|
||||
@@ -45,12 +49,13 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
|
||||
|
||||
interface Props {
|
||||
user: User,
|
||||
allConfiguredWorkflows: EditableApprovalWorkflow[],
|
||||
userEntitiesWithLabel: Entity[],
|
||||
userEntitiesApprovers: (TeacherUser | CorporateUser | MasterCorporateUser | DeveloperUser)[],
|
||||
}
|
||||
|
||||
export default function Home({ user, userEntitiesWithLabel, userEntitiesApprovers }: Props) {
|
||||
const [workflows, setWorkflows] = useState<EditableApprovalWorkflow[]>([]);
|
||||
export default function Home({ user, allConfiguredWorkflows, userEntitiesWithLabel, userEntitiesApprovers }: Props) {
|
||||
const [workflows, setWorkflows] = useState<EditableApprovalWorkflow[]>(allConfiguredWorkflows);
|
||||
const [selectedWorkflowId, setSelectedWorkflowId] = useState<string | undefined>(undefined);
|
||||
const [entityId, setEntityId] = useState<string | null | undefined>(null);
|
||||
const [entityApprovers, setEntityApprovers] = useState<(TeacherUser | CorporateUser | MasterCorporateUser | DeveloperUser)[]>([]);
|
||||
@@ -93,13 +98,14 @@ export default function Home({ user, userEntitiesWithLabel, userEntitiesApprover
|
||||
...workflow,
|
||||
steps: workflow.steps.map(step => ({
|
||||
...step,
|
||||
completed: false,
|
||||
assignees: step.assignees.filter((assignee): assignee is string => assignee !== null && assignee !== undefined)
|
||||
}))
|
||||
}));
|
||||
|
||||
const requestData = {filteredWorkflows, userEntitiesWithLabel};
|
||||
|
||||
axios
|
||||
.post(`/api/approval-workflows/create`, filteredWorkflows)
|
||||
.post(`/api/approval-workflows/create`, requestData)
|
||||
.then(() => {
|
||||
toast.success("Approval Workflows created successfully.");
|
||||
setIsRedirecting(true);
|
||||
@@ -135,8 +141,8 @@ export default function Home({ user, userEntitiesWithLabel, userEntitiesApprover
|
||||
startDate: Date.now(),
|
||||
status: "pending",
|
||||
steps: [
|
||||
{ key: 9998, stepType: "form-intake", stepNumber: 1, firstStep: true, finalStep: false, assignees: [null] },
|
||||
{ key: 9999, stepType: "approval-by", stepNumber: 2, firstStep: false, finalStep: true, assignees: [null] },
|
||||
{ key: 9998, stepType: "form-intake", stepNumber: 1, completed: false, firstStep: true, finalStep: false, assignees: [null] },
|
||||
{ key: 9999, stepType: "approval-by", stepNumber: 2, completed: false, firstStep: false, finalStep: true, assignees: [null] },
|
||||
],
|
||||
};
|
||||
setWorkflows((prev) => [...prev, newWorkflow]);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Layout from "@/components/High/Layout";
|
||||
import Button from "@/components/Low/Button";
|
||||
import Input from "@/components/Low/Input";
|
||||
import Select from "@/components/Low/Select";
|
||||
import { Module, ModuleTypeLabels } from "@/interfaces";
|
||||
import { ApprovalWorkflow, ApprovalWorkflowStatus, ApprovalWorkflowStatusLabel, StepTypeLabel } from "@/interfaces/approval.workflow";
|
||||
@@ -8,6 +9,7 @@ import { User } from "@/interfaces/user";
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import { redirect, serialize } from "@/utils";
|
||||
import { requestUser } from "@/utils/api";
|
||||
import { getConfiguredWorkflows } from "@/utils/approval.workflows.be";
|
||||
import { getEntities } from "@/utils/entities.be";
|
||||
import { shouldRedirectHome } from "@/utils/navigation.disabled";
|
||||
import { getSpecificUsers } from "@/utils/users.be";
|
||||
@@ -17,18 +19,14 @@ import clsx from "clsx";
|
||||
import { withIronSessionSsr } from "iron-session/next";
|
||||
import Head from "next/head";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { BsTrash } from "react-icons/bs";
|
||||
import { FaRegEdit } from "react-icons/fa";
|
||||
import { FaRegClone } from "react-icons/fa6";
|
||||
import { IoIosAddCircleOutline } from "react-icons/io";
|
||||
import { toast, ToastContainer } from "react-toastify";
|
||||
|
||||
import Input from "@/components/Low/Input";
|
||||
import { FaRegClone } from "react-icons/fa6";
|
||||
import useApprovalWorkflows from "@/hooks/useApprovalWorkflows";
|
||||
import { getApprovalWorkflows } from "@/utils/approval.workflows.be";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
const columnHelper = createColumnHelper<ApprovalWorkflow>();
|
||||
|
||||
export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
|
||||
@@ -38,7 +36,7 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
|
||||
if (shouldRedirectHome(user) || !["admin", "developer", "teacher", "corporate", "mastercorporate"].includes(user.type))
|
||||
return redirect("/")
|
||||
|
||||
const workflows = await getApprovalWorkflows();
|
||||
const workflows = await getConfiguredWorkflows();
|
||||
|
||||
const allAssigneeIds: string[] = [
|
||||
...new Set(
|
||||
@@ -331,7 +329,7 @@ export default function ApprovalWorkflows({ user, workflows, workflowsAssignees,
|
||||
className="min-w-fit text-lg font-medium flex items-center gap-2 text-left"
|
||||
>
|
||||
<IoIosAddCircleOutline className="size-6" />
|
||||
Configure New Workflows
|
||||
Configure Workflows
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -1,36 +1,83 @@
|
||||
import { ObjectId } from "mongodb";
|
||||
import { ApprovalWorkflow } from "@/interfaces/approval.workflow";
|
||||
import client from "@/lib/mongodb";
|
||||
import { ObjectId } from "mongodb";
|
||||
|
||||
const db = client.db(process.env.MONGODB_DB);
|
||||
|
||||
export const getApprovalWorkflows = async (ids?: string[]) => {
|
||||
export const getConfiguredWorkflows = async (ids?: string[]) => {
|
||||
return await db
|
||||
.collection<ApprovalWorkflow>("approval-workflows")
|
||||
.collection<ApprovalWorkflow>("configured-workflows")
|
||||
.find(ids ? { _id: { $in: ids.map((id) => new ObjectId(id)) } } : {})
|
||||
.toArray();
|
||||
};
|
||||
|
||||
export const getApprovalWorkflow = async (id: string) => {
|
||||
return await db.collection<ApprovalWorkflow>("approval-workflows").findOne({ _id: new ObjectId(id) });
|
||||
export const getConfiguredWorkflow = async (id: string) => {
|
||||
return await db.collection<ApprovalWorkflow>("configured-workflows").findOne({ _id: new ObjectId(id) });
|
||||
};
|
||||
|
||||
export const createApprovalWorkflow = async (workflow: ApprovalWorkflow) => {
|
||||
export const getConfiguredWorkflowsByEntities = async (ids: string[]) => {
|
||||
return await db
|
||||
.collection<ApprovalWorkflow>("configured-workflows")
|
||||
.find({ entityId: { $in: ids } })
|
||||
.toArray();
|
||||
};
|
||||
|
||||
export const createConfiguredWorkflow = async (workflow: ApprovalWorkflow) => {
|
||||
const { _id, ...workflowWithoutId } = workflow as ApprovalWorkflow;
|
||||
return await db.collection("approval-workflows").insertOne(workflowWithoutId);
|
||||
return await db.collection("configured-workflows").insertOne(workflowWithoutId);
|
||||
};
|
||||
|
||||
export const createApprovalWorkflows = async (workflows: ApprovalWorkflow[]) => {
|
||||
export const createConfiguredWorkflows = async (workflows: ApprovalWorkflow[]) => {
|
||||
if (workflows.length === 0) return;
|
||||
const workflowsWithoutIds: ApprovalWorkflow[] = workflows.map(({_id, ...wfs}) => wfs)
|
||||
return await db.collection("approval-workflows").insertMany(workflowsWithoutIds);
|
||||
const workflowsWithoutIds: ApprovalWorkflow[] = workflows.map(({ _id, ...wfs }) => wfs);
|
||||
return await db.collection("configured-workflows").insertMany(workflowsWithoutIds);
|
||||
};
|
||||
|
||||
export const updateApprovalWorkflow = async (id: string, workflow: ApprovalWorkflow) => {
|
||||
export const updateConfiguredWorkflow = async (workflow: ApprovalWorkflow) => {
|
||||
const { _id, ...workflowWithoutId } = workflow as ApprovalWorkflow;
|
||||
return await db.collection("approval-workflows").replaceOne({ _id: new ObjectId(id) }, workflowWithoutId);
|
||||
return await db.collection("configured-workflows").replaceOne({ _id: new ObjectId(_id) }, workflowWithoutId);
|
||||
};
|
||||
|
||||
export const deleteApprovalWorkflow = async (id: string) => {
|
||||
return await db.collection("approval-workflows").deleteOne({ _id: new ObjectId(id) });
|
||||
export const updateConfiguredWorkflows = async (workflows: ApprovalWorkflow[]) => {
|
||||
const bulkOperations = workflows.map((workflow) => {
|
||||
const { _id, ...workflowWithoutId } = workflow;
|
||||
return {
|
||||
replaceOne: {
|
||||
filter: { _id: new ObjectId(_id) },
|
||||
replacement: workflowWithoutId,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return await db.collection("configured-workflows").bulkWrite(bulkOperations);
|
||||
};
|
||||
|
||||
export const deleteConfiguredWorkflow = async (id: string) => {
|
||||
return await db.collection("configured-workflows").deleteOne({ _id: new ObjectId(id) });
|
||||
};
|
||||
|
||||
export const replaceConfiguredWorkflowsByEntities = async (workflows: ApprovalWorkflow[], entityIds: string[]) => {
|
||||
// 1. Keep track of the _id values of all workflows we want to end up with
|
||||
const finalIds = new Set<string>();
|
||||
|
||||
// 2. Process incoming workflows
|
||||
for (const workflow of workflows) {
|
||||
if (workflow._id) {
|
||||
// Replace the existing ones
|
||||
await updateConfiguredWorkflow(workflow);
|
||||
finalIds.add(workflow._id.toString());
|
||||
} else {
|
||||
// Insert if no _id
|
||||
const insertResult = await createConfiguredWorkflow(workflow);
|
||||
finalIds.add(insertResult.insertedId.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Delete any existing workflow (within these entityIds) that wasn't in the final list
|
||||
await db.collection("configured-workflows").deleteMany({
|
||||
_id: {
|
||||
$nin: Array.from(finalIds).map((id) => new ObjectId(id)),
|
||||
},
|
||||
entityId: { $in: entityIds },
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user