Skip to content

Commit b1bc072

Browse files
Merge pull request #1865 from bluewave-labs/hp-july-31-add-risks-to-EU
Attach risks to EU AI Act
2 parents 5bd1886 + fca5c7e commit b1bc072

File tree

21 files changed

+704
-32
lines changed

21 files changed

+704
-32
lines changed

Clients/src/domain/interfaces/iWidget.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export interface DropDownsProps {
7373
isControl?: boolean;
7474
projectId?: number;
7575
readOnly?: boolean;
76+
setAuditedStatusModalOpen?: (open: boolean) => void;
7677
}
7778

7879
export interface FieldProps {

Clients/src/domain/types/Control.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ export type Control = {
1616
numberOfSubcontrols?: number;
1717
numberOfDoneSubcontrols?: number;
1818
subControls?: Subcontrol[];
19+
risks: number[];
1920
};

Clients/src/domain/types/ProjectRisk.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export type ProjectRiskMitigation = {
77
sub_id: number;
88
title: string;
99
parent_id: number;
10-
type: "subclause" | "annexcategory";
10+
type: "subclause" | "annexcategory" | "assessment" | "control";
1111
}
1212

1313
export type ProjectRisk = {
@@ -84,5 +84,7 @@ export type ProjectRisk = {
8484
date_of_assessment: Date;
8585
annexCategories?: ProjectRiskMitigation[];
8686
subClauses?: ProjectRiskMitigation[];
87+
assessments?: ProjectRiskMitigation[];
88+
controls?: ProjectRiskMitigation[];
8789
recommendations?: string;
8890
};

Clients/src/domain/types/Question.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ export type Question = {
1616
subtopic_id: number;
1717
status: string;
1818
answer_id: number;
19+
risks: number[];
1920
};

Clients/src/presentation/components/Inputs/Dropdowns/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const DropDowns: React.FC<DropDownsProps> = ({
1717
setState,
1818
projectId,
1919
readOnly = false,
20+
setAuditedStatusModalOpen
2021
}) => {
2122
const [status, setStatus] = useState("");
2223
const [approver, setApprover] = useState("");
@@ -109,6 +110,9 @@ const DropDowns: React.FC<DropDownsProps> = ({
109110
) => {
110111
const stringValue = e.target.value.toString();
111112
setter(stringValue);
113+
if (field === "status" && stringValue === "Done") {
114+
setAuditedStatusModalOpen?.(true);
115+
}
112116
if (setState) {
113117
setState({ ...state, [field]: e.target.value });
114118
}

Clients/src/presentation/components/Modals/Controlpane/NewControlPane.tsx

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
Box,
33
Button,
4+
Dialog,
45
Divider,
56
Modal,
67
Stack,
@@ -11,7 +12,7 @@ import {
1112
} from "@mui/material";
1213
import { ReactComponent as CloseIcon } from "../../../assets/icons/close.svg";
1314
import DropDowns from "../../Inputs/Dropdowns";
14-
import { useState, useContext } from "react";
15+
import { useState, useContext, Suspense } from "react";
1516
import AuditorFeedback from "../ComplianceFeedback/ComplianceFeedback";
1617
import { updateEntityById } from "../../../../application/repository/entity.repository";
1718
import { Subcontrol } from "../../../../domain/types/Subcontrol";
@@ -29,6 +30,8 @@ import {
2930
import { handleAlert } from "../../../../application/tools/alertUtils";
3031
import { AlertProps } from "../../../../domain/interfaces/iAlert";
3132
import allowedRoles from "../../../../application/constants/permissions";
33+
import LinkedRisksPopup from "../../LinkedRisks";
34+
import AuditRiskPopup from "../../RiskPopup/AuditRiskPopup";
3235

3336
const tabStyle = {
3437
textTransform: "none",
@@ -73,6 +76,10 @@ const NewControlPane = ({
7376
feedback: FileData[];
7477
};
7578
}>({});
79+
const [isLinkedRisksModalOpen, setIsLinkedRisksModalOpen] = useState<boolean>(false);
80+
const [selectedRisks, setSelectedRisks] = useState<number[]>([]);
81+
const [deletedRisks, setDeletedRisks] = useState<number[]>([]);
82+
const [auditedStatusModalOpen, setAuditedStatusModalOpen] = useState<boolean>(false);
7683
const context = useContext(VerifyWiseContext);
7784
const userRoleName = context?.userRoleName;
7885
const isEditingDisabled =
@@ -122,8 +129,8 @@ const NewControlPane = ({
122129
implementation_details: data.implementation_details,
123130
due_date: data.due_date,
124131
control_category_id: data.control_category_id, // Added missing property
125-
126132
subControls: initialSubControlState || [],
133+
risks: data.risks || [],
127134
}));
128135

129136
const handleSelectedTab = (_: React.SyntheticEvent, newValue: number) => {
@@ -304,6 +311,9 @@ const NewControlPane = ({
304311
// Add delete array if needed (you might want to track deleted files)
305312
formData.append("delete", JSON.stringify(deletedFilesIds));
306313

314+
formData.append("risksDelete", JSON.stringify(deletedRisks));
315+
formData.append("risksMitigated", JSON.stringify(selectedRisks));
316+
307317
const response = await updateEntityById({
308318
routeUrl: `/eu-ai-act/saveControls/${state.id}`,
309319
body: formData,
@@ -446,7 +456,80 @@ const NewControlPane = ({
446456
}))
447457
}
448458
readOnly={isEditingDisabled}
459+
setAuditedStatusModalOpen={setAuditedStatusModalOpen}
449460
/>
461+
<Stack direction="row" spacing={2}>
462+
<Button
463+
variant="contained"
464+
sx={{
465+
mt: 2,
466+
borderRadius: 2,
467+
width: 155,
468+
height: 25,
469+
fontSize: 11,
470+
border: "1px solid #D0D5DD",
471+
backgroundColor: "white",
472+
color: "#344054",
473+
}}
474+
disableRipple
475+
onClick={() => setIsLinkedRisksModalOpen(true)}
476+
disabled={isEditingDisabled}
477+
>
478+
Add/Remove risks
479+
</Button>
480+
<Stack direction="row" spacing={10}>
481+
<Typography
482+
sx={{
483+
fontSize: 11,
484+
color: "#344054",
485+
display: "flex",
486+
justifyContent: "center",
487+
alignItems: "center",
488+
textAlign: "center",
489+
margin: "auto",
490+
textWrap: "wrap",
491+
}}
492+
>
493+
{`${state.risks.length || 0} risks linked`}
494+
</Typography>
495+
{selectedRisks.length > 0 && (
496+
<Typography
497+
sx={{
498+
fontSize: 11,
499+
color: "#344054",
500+
display: "flex",
501+
justifyContent: "center",
502+
alignItems: "center",
503+
textAlign: "center",
504+
margin: "auto",
505+
textWrap: "wrap",
506+
}}
507+
>
508+
{`${selectedRisks.length} ${
509+
selectedRisks.length === 1 ? "risk" : "risks"
510+
} pending upload`}
511+
</Typography>
512+
)}
513+
{deletedRisks.length > 0 && (
514+
<Typography
515+
sx={{
516+
fontSize: 11,
517+
color: "#344054",
518+
display: "flex",
519+
justifyContent: "center",
520+
alignItems: "center",
521+
textAlign: "center",
522+
margin: "auto",
523+
textWrap: "wrap",
524+
}}
525+
>
526+
{`${deletedRisks.length} ${
527+
deletedRisks.length === 1 ? "risk" : "risks"
528+
} pending delete`}
529+
</Typography>
530+
)}
531+
</Stack>
532+
</Stack>
450533

451534
{/* this is working fine */}
452535
<Divider sx={{ borderColor: "#C2C2C2", mt: theme.spacing(3) }} />
@@ -639,6 +722,34 @@ const NewControlPane = ({
639722
</Stack>
640723
</Stack>
641724
</Modal>
725+
<Dialog
726+
open={isLinkedRisksModalOpen}
727+
onClose={() => setIsLinkedRisksModalOpen(false)}
728+
>
729+
<Suspense fallback={"loading..."}>
730+
<LinkedRisksPopup
731+
onClose={() => setIsLinkedRisksModalOpen(false)}
732+
currentRisks={state.risks.concat(selectedRisks).filter(risk => !deletedRisks.includes(risk))}
733+
setSelectecRisks={setSelectedRisks}
734+
_setDeletedRisks={setDeletedRisks}
735+
/>
736+
</Suspense>
737+
</Dialog>
738+
<Dialog
739+
open={auditedStatusModalOpen}
740+
onClose={() => setAuditedStatusModalOpen(false)}
741+
>
742+
<Suspense fallback={"loading..."}>
743+
<AuditRiskPopup
744+
onClose={() => setAuditedStatusModalOpen(false)}
745+
risks={state.risks.concat(selectedRisks)}
746+
_deletedRisks={deletedRisks}
747+
_setDeletedRisks={setDeletedRisks}
748+
_selectedRisks={selectedRisks}
749+
_setSelectedRisks={setSelectedRisks}
750+
/>
751+
</Suspense>
752+
</Dialog>
642753
</>
643754
);
644755
};

Clients/src/presentation/components/ProjectRiskMitigation/ProjectRiskMitigation.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@ interface ProjectRiskMitigationProps {
77
onClose: () => void;
88
annexCategories: ProjectRiskMitigationType[];
99
subClauses: ProjectRiskMitigationType[];
10+
assessments: ProjectRiskMitigationType[];
11+
controls: ProjectRiskMitigationType[];
1012
}
1113

1214
export const ProjectRiskMitigation: React.FC<ProjectRiskMitigationProps> = ({
1315
onClose,
1416
annexCategories,
1517
subClauses,
18+
assessments,
19+
controls
1620
}) => {
1721
return (
1822
<Stack sx={{
@@ -44,7 +48,7 @@ export const ProjectRiskMitigation: React.FC<ProjectRiskMitigationProps> = ({
4448
</Stack>
4549
<Stack>
4650
<ProjectRiskMitigationTable
47-
rows={[...subClauses, ...annexCategories]}
51+
rows={[...subClauses, ...annexCategories, ...assessments, ...controls]}
4852
/>
4953
</Stack>
5054
</Stack>

Clients/src/presentation/components/Table/ProjectRiskMitigationTable/ProjectRiskMitigationTableBody.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,15 @@ export const ProjectRiskMitigationTableBody: React.FC<ProjectRiskMitigationTable
4848
navigteToNewTab(`/project-view?projectId=${searchParams.get("projectId")}&tab=frameworks&framework=iso-42001&annexId=${riskData.parent_id}&annexCategoryId=${riskData.meta_id}`);
4949
} else if (riskData.type === "subclause") {
5050
navigteToNewTab(`/project-view?projectId=${searchParams.get("projectId")}&tab=frameworks&framework=iso-42001&clauseId=${riskData.parent_id}&subClauseId=${riskData.meta_id}`);
51+
} else if (riskData.type === "control") {
52+
navigteToNewTab(`/project-view?projectId=${searchParams.get("projectId")}&tab=frameworks&framework=eu-ai-act&controlId=${riskData.meta_id}`);
53+
} else if (riskData.type === "assessment") {
54+
navigteToNewTab(`/project-view?projectId=${searchParams.get("projectId")}&tab=frameworks&framework=eu-ai-act&topicId=${riskData.sup_id}&questionId=${riskData.meta_id}`);
5155
}
5256
}
5357

5458
}
59+
console.log("Rows in ProjectRiskMitigationTableBody:", rows);
5560

5661
return (
5762
<>
@@ -64,16 +69,17 @@ export const ProjectRiskMitigationTableBody: React.FC<ProjectRiskMitigationTable
6469
<TableCell sx={cellStyle}>
6570
{
6671
(() => {
67-
const title = `${row.type === "annexcategory" ? "A.": ""}${row.sup_id}.${row.sub_id} ${row.title}`
68-
console.log(title.length);
69-
return title.length > 30
70-
? `${title.slice(0, 30)}...`
72+
const title = `${row.type === "annexcategory" ? `A.${row.sup_id}.${row.sub_id} `:
73+
row.type === "assessment" ? "" : `${row.sup_id}.${row.sub_id} `
74+
}${row.title}`
75+
return title.length > 50
76+
? `${title.slice(0, 50)}...`
7177
: title
7278
})()
7379
}
7480
</TableCell>
7581
<TableCell sx={cellStyle}>
76-
{row.type === "annexcategory" ? "ISO42001: Annex Category" : row.type === "subclause" ? "ISO42001: Sub-Clause" : "ISO42001: Clause"}
82+
{row.type === "annexcategory" ? "ISO42001: Annex Category" : row.type === "subclause" ? "ISO42001: Sub-Clause" : row.type === "assessment" ? "EU-AI-Act: Assessment" : "EU-AI-Act: Control"}
7783
</TableCell>
7884
<TableCell>
7985
<CustomizableButton

0 commit comments

Comments
 (0)