From d4280b1111e3b70e6e3f6caea0118464bc60dd41 Mon Sep 17 00:00:00 2001 From: gearnode Date: Thu, 13 Mar 2025 08:46:51 +0100 Subject: [PATCH] Add control importance Signed-off-by: gearnode --- .../console/src/pages/ControlOverviewPage.tsx | 96 ++- .../src/pages/FrameworkOverviewPage.tsx | 6 +- apps/console/src/pages/UpdateControlPage.tsx | 54 +- .../ControlOverviewPageQuery.graphql.ts | 77 +- .../FrameworkOverviewPageQuery.graphql.ts | 17 +- .../UpdateControlPageQuery.graphql.ts | 25 +- ...ontrolPageUpdateControlMutation.graphql.ts | 16 +- pkg/coredata/control.go | 46 +- pkg/coredata/control_importance.go | 100 +++ pkg/coredata/migrations/20250312T180800Z.sql | 8 + pkg/probo/control_service.go | 4 + pkg/server/api/console/v1/schema.graphql | 51 +- pkg/server/api/console/v1/schema/schema.go | 786 ++++++++++++++++-- pkg/server/api/console/v1/types/control.go | 1 + pkg/server/api/console/v1/types/types.go | 60 +- pkg/server/api/console/v1/v1_resolver.go | 1 + 16 files changed, 1162 insertions(+), 186 deletions(-) create mode 100644 pkg/coredata/control_importance.go create mode 100644 pkg/coredata/migrations/20250312T180800Z.sql diff --git a/apps/console/src/pages/ControlOverviewPage.tsx b/apps/console/src/pages/ControlOverviewPage.tsx index 7ff43867c..870fcb02b 100644 --- a/apps/console/src/pages/ControlOverviewPage.tsx +++ b/apps/console/src/pages/ControlOverviewPage.tsx @@ -64,6 +64,7 @@ const controlOverviewPageQuery = graphql` name description state + importance category tasks(first: 100) @connection(key: "ControlOverviewPage_tasks") { __id @@ -195,6 +196,60 @@ function ControlOverviewPageContent({ const { organizationId, frameworkId, controlId } = useParams(); const navigate = useNavigate(); const environment = useRelayEnvironment(); + + const formatImportance = (importance: string | undefined): string => { + if (!importance) return ""; + + const upperImportance = importance.toUpperCase(); + + if (upperImportance === "MANDATORY") return "Mandatory"; + if (upperImportance === "PREFERRED") return "Preferred"; + if (upperImportance === "ADVANCED") return "Advanced"; + + const formatted = importance.toLowerCase(); + return formatted.charAt(0).toUpperCase() + formatted.slice(1); + }; + + const formatState = (state: string | undefined): string => { + if (!state) return ""; + + const upperState = state.toUpperCase(); + + if (upperState === "NOT_STARTED") return "Not Started"; + if (upperState === "IN_PROGRESS") return "In Progress"; + if (upperState === "NOT_APPLICABLE") return "Not Applicable"; + if (upperState === "IMPLEMENTED") return "Implemented"; + + // Fallback for any other states + const formatted = state.toLowerCase(); + return formatted.charAt(0).toUpperCase() + formatted.slice(1); + }; + + const getStateColor = (state: string | undefined): string => { + if (!state) return "bg-gray-100 text-gray-800"; + + const upperState = state.toUpperCase(); + + if (upperState === "NOT_STARTED") return "bg-gray-100 text-gray-800"; + if (upperState === "IN_PROGRESS") return "bg-blue-100 text-blue-800"; + if (upperState === "NOT_APPLICABLE") return "bg-purple-100 text-purple-800"; + if (upperState === "IMPLEMENTED") return "bg-green-100 text-green-800"; + + return "bg-gray-100 text-gray-800"; + }; + + const getImportanceColor = (importance: string | undefined): string => { + if (!importance) return "bg-gray-100 text-gray-800"; + + const upperImportance = importance.toUpperCase(); + + if (upperImportance === "MANDATORY") return "bg-red-100 text-red-800"; + if (upperImportance === "PREFERRED") return "bg-orange-100 text-orange-800"; + if (upperImportance === "ADVANCED") return "bg-blue-100 text-blue-800"; + + return "bg-gray-100 text-gray-800"; + }; + const [updateTask] = useMutation( updateTaskStateMutation @@ -542,7 +597,6 @@ function ControlOverviewPageContent({ }); }; - // Function to format file size const formatFileSize = (bytes: number) => { if (bytes === 0) return "0 Bytes"; const k = 1024; @@ -551,7 +605,6 @@ function ControlOverviewPageContent({ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]; }; - // Function to format date const formatDate = (dateString: string) => { const date = new Date(dateString); return date.toLocaleDateString("en-US", { @@ -681,40 +734,25 @@ function ControlOverviewPageContent({ -
- 30 min +
+ {formatState(data.control.state)}
-
- Mandatory +
+ {formatImportance(data.control.importance)}

{data.control.description}

- - -
-
-
-
- - {data.control.state === "IMPLEMENTED" - ? "Validated" - : "Not validated"} - -
- - -

Tasks

diff --git a/apps/console/src/pages/FrameworkOverviewPage.tsx b/apps/console/src/pages/FrameworkOverviewPage.tsx index 439239c10..c6069b02b 100644 --- a/apps/console/src/pages/FrameworkOverviewPage.tsx +++ b/apps/console/src/pages/FrameworkOverviewPage.tsx @@ -28,6 +28,7 @@ const FrameworkOverviewPageQuery = graphql` description state category + importance } } } @@ -209,7 +210,10 @@ function FrameworkOverviewPageContent({ 30 min
- Mandatory + { + controlCards[hoveredCard]?.controls[hoveredControl] + ?.importance + }
diff --git a/apps/console/src/pages/UpdateControlPage.tsx b/apps/console/src/pages/UpdateControlPage.tsx index b6d5520f7..4e5bdac3d 100644 --- a/apps/console/src/pages/UpdateControlPage.tsx +++ b/apps/console/src/pages/UpdateControlPage.tsx @@ -23,10 +23,11 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; - -// Type imports will be available after Relay compiler runs -// import type { UpdateControlPageQuery as UpdateControlPageQueryType } from "./__generated__/UpdateControlPageQuery.graphql"; -// import type { UpdateControlPageUpdateControlMutation as UpdateControlPageUpdateControlMutationType } from "./__generated__/UpdateControlPageUpdateControlMutation.graphql"; +import type { UpdateControlPageUpdateControlMutation as UpdateControlPageUpdateControlMutationType } from "./__generated__/UpdateControlPageUpdateControlMutation.graphql"; +import type { + ControlState, + ControlImportance, +} from "./__generated__/UpdateControlPageUpdateControlMutation.graphql"; const updateControlMutation = graphql` mutation UpdateControlPageUpdateControlMutation($input: UpdateControlInput!) { @@ -36,6 +37,7 @@ const updateControlMutation = graphql` name description category + importance state version } @@ -51,6 +53,7 @@ const updateControlQuery = graphql` name description category + importance state version } @@ -98,7 +101,7 @@ function EditableField({ } className={cn( "w-full resize-none", - required && !value && "border-red-500", + required && !value && "border-red-500" )} placeholder={`Enter ${label.toLowerCase()}`} rows={4} @@ -135,6 +138,7 @@ function UpdateControlPageContent({ description: "", category: "", state: "", + importance: "", }); useEffect(() => { @@ -144,12 +148,15 @@ function UpdateControlPageContent({ description: data.node.description || "", category: data.node.category || "", state: data.node.state || "", + importance: data.node.importance || "", }); } }, [data.node]); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const [commit, isInFlight] = useMutation(updateControlMutation); + const [commit, isInFlight] = + useMutation( + updateControlMutation + ); const handleFieldChange = (field: keyof typeof formData, value: string) => { setFormData((prev) => ({ @@ -161,7 +168,7 @@ function UpdateControlPageContent({ const handleCancel = () => { navigate( - `/organizations/${organizationId}/frameworks/${frameworkId}/controls/${controlId}`, + `/organizations/${organizationId}/frameworks/${frameworkId}/controls/${controlId}` ); }; @@ -185,7 +192,8 @@ function UpdateControlPageContent({ name?: string; description?: string; category?: string; - state?: string; + state?: ControlState; + importance?: ControlImportance; } = { id: controlId!, expectedVersion: data.node.version, @@ -201,7 +209,10 @@ function UpdateControlPageContent({ input.category = formData.category; } if (editedFields.has("state")) { - input.state = formData.state; + input.state = formData.state as ControlState; + } + if (editedFields.has("importance")) { + input.importance = formData.importance as ControlImportance; } commit({ @@ -224,7 +235,7 @@ function UpdateControlPageContent({ }); navigate( - `/organizations/${organizationId}/frameworks/${frameworkId}/controls/${controlId}`, + `/organizations/${organizationId}/frameworks/${frameworkId}/controls/${controlId}` ); }, onError(error) { @@ -273,6 +284,27 @@ function UpdateControlPageContent({ required /> +
+ + +
+