- fix assignees bug after editing active workflow

- only allow corporate+ to configure workflows
- give admins and devs permissions to approve and reject steps even when they are not assigned to them.
- small fixes
This commit is contained in:
Joao Correia
2025-02-05 16:50:09 +00:00
parent 845a5aa9dc
commit f0849b9b42
6 changed files with 25 additions and 19 deletions

View File

@@ -215,12 +215,12 @@ const LevelSettings: React.FC = () => {
});
const requestBody = await (async () => {
const handledExam = await getExamById("writing", result.data.id);
const handledExam = await getExamById("level", result.data.id);
return {
examAuthor: handledExam?.createdBy ?? "Unknown Author",
examEntities: handledExam?.entities ?? [],
examId: handledExam?.id ?? "Unknown ID",
examModule: "writing"
examModule: "level"
};
})();
await axios

View File

@@ -153,12 +153,12 @@ const ListeningSettings: React.FC = () => {
toast.success(`Submitted Exam ID: ${result.data.id}`);
const requestBody = await (async () => {
const handledExam = await getExamById("writing", result.data.id);
const handledExam = await getExamById("listening", result.data.id);
return {
examAuthor: handledExam?.createdBy ?? "Unknown Author",
examEntities: handledExam?.entities ?? [],
examId: handledExam?.id ?? "Unknown ID",
examModule: "writing"
examModule: "listening"
};
})();
await axios

View File

@@ -197,12 +197,12 @@ const SpeakingSettings: React.FC = () => {
});
const requestBody = await (async () => {
const handledExam = await getExamById("writing", result.data.id);
const handledExam = await getExamById("speaking", result.data.id);
return {
examAuthor: handledExam?.createdBy ?? "Unknown Author",
examEntities: handledExam?.entities ?? [],
examId: handledExam?.id ?? "Unknown ID",
examModule: "writing"
examModule: "speaking"
};
})();
await axios

View File

@@ -334,7 +334,7 @@ export default function Home({ user, initialWorkflow, id, workflowAssignees, wor
variant="solid"
onClick={handleEditExam}
padding="px-6 py-2"
disabled={!currentWorkflow.steps[currentStepIndex].assignees.includes(user.id) || editExamIsLoading}
disabled={(!currentWorkflow.steps[currentStepIndex].assignees.includes(user.id) && user.type !== "admin" && user.type !== "developer") || editExamIsLoading}
className="w-[240px] text-lg flex items-center justify-center gap-2 text-left"
>
{editExamIsLoading ? (
@@ -475,7 +475,7 @@ export default function Home({ user, initialWorkflow, id, workflowAssignees, wor
type="submit"
color="purple"
variant="solid"
disabled={!selectedStep.assignees.includes(user.id) || isLoading}
disabled={(!selectedStep.assignees.includes(user.id) && user.type !== "admin" && user.type !== "developer") || isLoading}
onClick={handleApproveStep}
padding="px-6 py-2"
className="mb-3 w-full text-lg flex items-center justify-center gap-2 text-left"
@@ -496,7 +496,7 @@ export default function Home({ user, initialWorkflow, id, workflowAssignees, wor
type="submit"
color="red"
variant="solid"
disabled={!selectedStep.assignees.includes(user.id) || isLoading}
disabled={(!selectedStep.assignees.includes(user.id) && user.type !== "admin" && user.type !== "developer") || isLoading}
onClick={handleRejectStep}
padding="px-6 py-2"
className="mb-3 w-1/2 text-lg flex items-center justify-center gap-2 text-left"

View File

@@ -31,19 +31,27 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
const user = await requestUser(req, res)
if (!user) return redirect("/login")
if (shouldRedirectHome(user) || !["admin", "developer", "teacher", "corporate", "mastercorporate"].includes(user.type))
if (shouldRedirectHome(user) || !["admin", "developer", "corporate", "mastercorporate"].includes(user.type))
return redirect("/")
const userEntitiesWithLabel = await getEntities(user.entities.map(entity => entity.id));
const allConfiguredWorkflows = await getApprovalWorkflowsByEntities("configured-workflows", userEntitiesWithLabel.map(entity => entity.id));
const approverTypes = ["teacher", "corporate", "mastercorporate"];
if (user.type === "developer") {
approverTypes.push("developer");
}
const userEntitiesApprovers = await getEntitiesUsers(userEntitiesWithLabel.map(entity => entity.id), { type: { $in: approverTypes } }) as (TeacherUser | CorporateUser | MasterCorporateUser | DeveloperUser)[];
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)[],
userEntitiesApprovers,
}),
};
}, sessionOptions);
@@ -129,7 +137,7 @@ export default function Home({ user, allConfiguredWorkflows, userEntitiesWithLab
for (const step of workflow.steps) {
if (step.assignees.every(x => !x)) {
toast.warning("There are empty steps in at least one of the configured workflows.");
setIsLoading(false);
setIsLoading(false);
return;
}
}
@@ -211,9 +219,9 @@ export default function Home({ user, allConfiguredWorkflows, userEntitiesWithLab
const handleCloneWorkflow = (id: string) => {
const workflowToClone = workflows.find(wf => wf.id === id);
if (!workflowToClone) return;
const newId = uuidv4();
const clonedWorkflow: EditableApprovalWorkflow = {
...workflowToClone,
id: newId,
@@ -222,7 +230,7 @@ export default function Home({ user, allConfiguredWorkflows, userEntitiesWithLab
assignees: step.firstStep ? [null] : [...step.assignees], // we can't have more than one form intaker per teacher per entity
})),
};
setWorkflows(prev => {
const updatedWorkflows = [...prev, clonedWorkflow];
setSelectedWorkflowId(newId);
@@ -280,7 +288,7 @@ export default function Home({ user, allConfiguredWorkflows, userEntitiesWithLab
</div>
</section>
<Tip text="Setting a teacher as a Form Intaker means the configured workflow will be instantiated when said teacher publishes an exam. Only one Form Intake per teacher per entity is allowed."/>
<Tip text="Setting a teacher as a Form Intaker means the configured workflow will be instantiated when said teacher publishes an exam. Only one Form Intake per teacher per entity is allowed." />
<section className="flex flex-row gap-6">
<Button

View File

@@ -36,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("configured-workflows");
const workflows = await getApprovalWorkflows("active-workflows");
const allAssigneeIds: string[] = [
...new Set(
@@ -97,8 +97,6 @@ export default function ApprovalWorkflows({ user, initialWorkflows, workflowsAss
const {workflows, reload} = useApprovalWorkflows();
const currentWorkflows = workflows || initialWorkflows;
console.log(currentWorkflows);
const [filteredWorkflows, setFilteredWorkflows] = useState<ApprovalWorkflow[]>([]);
const [statusFilter, setStatusFilter] = useState<CustomStatus>(undefined);