Fix mesure types

Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
gearnode
2025-04-14 11:25:04 -07:00
parent 021f6c0e06
commit e773ebc5b8
2 changed files with 96 additions and 89 deletions

View File

@@ -88,7 +88,10 @@ import { MesureViewAssignTaskMutation as MesureViewAssignTaskMutationType } from
import { MesureViewUnassignTaskMutation as MesureViewUnassignTaskMutationType } from "./__generated__/MesureViewUnassignTaskMutation.graphql"; import { MesureViewUnassignTaskMutation as MesureViewUnassignTaskMutationType } from "./__generated__/MesureViewUnassignTaskMutation.graphql";
import { MesureViewUpdateMesureStateMutation as MesureViewUpdateMesureStateMutationType } from "./__generated__/MesureViewUpdateMesureStateMutation.graphql"; import { MesureViewUpdateMesureStateMutation as MesureViewUpdateMesureStateMutationType } from "./__generated__/MesureViewUpdateMesureStateMutation.graphql";
import { MesureViewQuery as MesureViewQueryType } from "./__generated__/MesureViewQuery.graphql"; import { MesureViewQuery as MesureViewQueryType } from "./__generated__/MesureViewQuery.graphql";
import { MesureViewOrganizationQuery$data } from "./__generated__/MesureViewOrganizationQuery.graphql"; import {
MesureViewOrganizationQuery,
MesureViewOrganizationQuery$data,
} from "./__generated__/MesureViewOrganizationQuery.graphql";
import { import {
MesureViewFrameworksQuery, MesureViewFrameworksQuery,
MesureViewFrameworksQuery$data, MesureViewFrameworksQuery$data,
@@ -99,6 +102,10 @@ import {
} from "./__generated__/MesureViewLinkedControlsQuery.graphql"; } from "./__generated__/MesureViewLinkedControlsQuery.graphql";
import { MesureViewCreateEvidenceMutation as MesureViewCreateEvidenceMutationType } from "./__generated__/MesureViewCreateEvidenceMutation.graphql"; import { MesureViewCreateEvidenceMutation as MesureViewCreateEvidenceMutationType } from "./__generated__/MesureViewCreateEvidenceMutation.graphql";
import { MesureViewFulfillEvidenceMutation as MesureViewFulfillEvidenceMutationType } from "./__generated__/MesureViewFulfillEvidenceMutation.graphql"; import { MesureViewFulfillEvidenceMutation as MesureViewFulfillEvidenceMutationType } from "./__generated__/MesureViewFulfillEvidenceMutation.graphql";
import { MesureViewCreateControlMappingMutation } from "./__generated__/MesureViewCreateControlMappingMutation.graphql";
import { MesureViewDeleteControlMappingMutation } from "./__generated__/MesureViewDeleteControlMappingMutation.graphql";
import { MesureViewRisksQuery$data } from "./__generated__/MesureViewRisksQuery.graphql";
import { MesureViewRisksQuery } from "./__generated__/MesureViewRisksQuery.graphql";
// Function to format ISO8601 duration to human-readable format // Function to format ISO8601 duration to human-readable format
const formatDuration = (isoDuration: string): string => { const formatDuration = (isoDuration: string): string => {
@@ -448,6 +455,10 @@ const mesureRisksQuery = graphql`
description description
inherentLikelihood inherentLikelihood
inherentImpact inherentImpact
inherentSeverity
residualLikelihood
residualImpact
residualSeverity
createdAt createdAt
updatedAt updatedAt
} }
@@ -458,55 +469,6 @@ const mesureRisksQuery = graphql`
} }
`; `;
// Define type for framework structure
type FrameworkEdge = {
node: {
id: string;
name: string;
controls: {
edges: Array<{
node: {
id: string;
referenceId: string;
name: string;
description?: string;
};
}>;
};
};
};
type ControlNode = {
id: string;
referenceId: string;
name: string;
description?: string;
};
// Define Risk type
type RiskNode = {
id: string;
name: string;
description: string;
likelihood: number;
impact: number;
severity: number;
createdAt: string;
updatedAt: string;
};
// Define the risks data type
type MesureRisksData = {
mesure?: {
id: string;
risks?: {
edges: Array<{
node: RiskNode;
}>;
};
};
};
function MesureViewContent({ function MesureViewContent({
queryRef, queryRef,
}: { }: {
@@ -548,18 +510,22 @@ function MesureViewContent({
const [isUnlinkingControl, setIsUnlinkingControl] = useState(false); const [isUnlinkingControl, setIsUnlinkingControl] = useState(false);
// Create mutation hooks for control mapping // Create mutation hooks for control mapping
const [commitCreateControlMapping] = useMutation( const [commitCreateControlMapping] =
createControlMappingMutation useMutation<MesureViewCreateControlMappingMutation>(
); createControlMappingMutation
const [commitDeleteControlMapping] = useMutation( );
deleteControlMappingMutation const [commitDeleteControlMapping] =
); useMutation<MesureViewDeleteControlMappingMutation>(
deleteControlMappingMutation
);
useEffect(() => { useEffect(() => {
if (organizationId) { if (organizationId) {
fetchQuery(environment, organizationQuery, { organizationId }).subscribe({ fetchQuery<MesureViewOrganizationQuery>(environment, organizationQuery, {
next: (data: unknown) => { organizationId,
setOrganizationData(data as MesureViewOrganizationQuery$data); }).subscribe({
next: (data) => {
setOrganizationData(data);
}, },
error: (error: Error) => { error: (error: Error) => {
console.error("Error fetching organization:", error); console.error("Error fetching organization:", error);
@@ -571,9 +537,13 @@ function MesureViewContent({
// Load linked controls when component mounts // Load linked controls when component mounts
useEffect(() => { useEffect(() => {
if (mesureId) { if (mesureId) {
fetchQuery(environment, linkedControlsQuery, { mesureId }).subscribe({ fetchQuery<MesureViewLinkedControlsQuery>(
next: (data: unknown) => { environment,
setLinkedControlsData(data as MesureViewLinkedControlsQuery$data); linkedControlsQuery,
{ mesureId }
).subscribe({
next: (data) => {
setLinkedControlsData(data);
}, },
error: (error: Error) => { error: (error: Error) => {
console.error("Error fetching linked controls:", error); console.error("Error fetching linked controls:", error);
@@ -583,14 +553,18 @@ function MesureViewContent({
}, [environment, mesureId]); }, [environment, mesureId]);
// Add state for risks data // Add state for risks data
const [risksData, setRisksData] = useState<MesureRisksData | null>(null); const [risksData, setRisksData] = useState<MesureViewRisksQuery$data | null>(
null
);
// Load risks data when component mounts // Load risks data when component mounts
useEffect(() => { useEffect(() => {
if (mesureId) { if (mesureId) {
fetchQuery(environment, mesureRisksQuery, { mesureId }).subscribe({ fetchQuery<MesureViewRisksQuery>(environment, mesureRisksQuery, {
next: (data: unknown) => { mesureId,
setRisksData(data as MesureRisksData); }).subscribe({
next: (data) => {
setRisksData(data);
}, },
error: (error: Error) => { error: (error: Error) => {
console.error("Error fetching risks:", error); console.error("Error fetching risks:", error);
@@ -1626,11 +1600,15 @@ function MesureViewContent({
}, },
complete: () => { complete: () => {
// Fetch already linked controls for this mesure // Fetch already linked controls for this mesure
fetchQuery(environment, linkedControlsQuery, { fetchQuery<MesureViewLinkedControlsQuery>(
mesureId, environment,
}).subscribe({ linkedControlsQuery,
next: (data: unknown) => { {
setLinkedControlsData(data as MesureViewLinkedControlsQuery$data); mesureId,
}
).subscribe({
next: (data) => {
setLinkedControlsData(data);
setIsLoadingControls(false); setIsLoadingControls(false);
}, },
error: (error: Error) => { error: (error: Error) => {
@@ -1660,11 +1638,10 @@ function MesureViewContent({
if (!frameworksData?.organization?.frameworks?.edges) return []; if (!frameworksData?.organization?.frameworks?.edges) return [];
// Get controls from the selected framework // Get controls from the selected framework
const frameworks = frameworksData.organization.frameworks const frameworks = frameworksData.organization.frameworks.edges;
.edges as Array<FrameworkEdge>;
if (selectedFrameworkId) { if (selectedFrameworkId) {
const selectedFramework = frameworks.find( const selectedFramework = frameworks.find(
(edge: FrameworkEdge) => edge.node.id === selectedFrameworkId (edge) => edge.node.id === selectedFrameworkId
); );
if (selectedFramework?.node?.controls?.edges) { if (selectedFramework?.node?.controls?.edges) {
@@ -1673,7 +1650,7 @@ function MesureViewContent({
} }
// If no framework is selected or it doesn't have controls, return controls from all frameworks // If no framework is selected or it doesn't have controls, return controls from all frameworks
return frameworks.flatMap((framework: FrameworkEdge) => return frameworks.flatMap((framework) =>
framework.node.controls.edges.map((edge) => edge.node) framework.node.controls.edges.map((edge) => edge.node)
); );
}, [frameworksData, selectedFrameworkId]); }, [frameworksData, selectedFrameworkId]);
@@ -1688,9 +1665,7 @@ function MesureViewContent({
const isControlLinked = useCallback( const isControlLinked = useCallback(
(controlId: string) => { (controlId: string) => {
const linkedControls = getLinkedControls(); const linkedControls = getLinkedControls();
return linkedControls.some( return linkedControls.some((control) => control.id === controlId);
(control: ControlNode) => control.id === controlId
);
}, },
[getLinkedControls] [getLinkedControls]
); );
@@ -1824,7 +1799,7 @@ function MesureViewContent({
const lowerQuery = controlSearchQuery.toLowerCase(); const lowerQuery = controlSearchQuery.toLowerCase();
return controls.filter( return controls.filter(
(control: ControlNode) => (control) =>
control.referenceId.toLowerCase().includes(lowerQuery) || control.referenceId.toLowerCase().includes(lowerQuery) ||
control.name.toLowerCase().includes(lowerQuery) || control.name.toLowerCase().includes(lowerQuery) ||
(control.description && (control.description &&
@@ -1849,7 +1824,7 @@ function MesureViewContent({
}; };
// Format likelihood as text // Format likelihood as text
const formatlikelihood = (value: number): string => { const formatLikelihood = (value: number): string => {
if (value <= 0.1) return "Very Low"; if (value <= 0.1) return "Very Low";
if (value <= 0.3) return "Low"; if (value <= 0.3) return "Low";
if (value <= 0.5) return "Medium"; if (value <= 0.5) return "Medium";
@@ -2144,7 +2119,7 @@ function MesureViewContent({
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{getLinkedControls().map((control: ControlNode) => ( {getLinkedControls().map((control) => (
<tr <tr
key={control.id} key={control.id}
className="border-b hover:bg-invert-bg" className="border-b hover:bg-invert-bg"
@@ -2832,21 +2807,21 @@ function MesureViewContent({
</td> </td>
<td className="py-3 px-4"> <td className="py-3 px-4">
<div className="bg-blue-100 text-blue-800 px-2 py-0.5 rounded-full text-xs inline-block"> <div className="bg-blue-100 text-blue-800 px-2 py-0.5 rounded-full text-xs inline-block">
{formatlikelihood(node.likelihood)} {formatLikelihood(node.inherentLikelihood)}
</div> </div>
</td> </td>
<td className="py-3 px-4"> <td className="py-3 px-4">
<div className="bg-purple-100 text-purple-800 px-2 py-0.5 rounded-full text-xs inline-block"> <div className="bg-purple-100 text-purple-800 px-2 py-0.5 rounded-full text-xs inline-block">
{formatImpact(node.impact)} {formatImpact(node.inherentImpact)}
</div> </div>
</td> </td>
<td className="py-3 px-4"> <td className="py-3 px-4">
<div <div
className={`${getRiskSeverityColor( className={`${getRiskSeverityColor(
node.severity node.inherentSeverity
)} px-2 py-0.5 rounded-full text-xs inline-block`} )} px-2 py-0.5 rounded-full text-xs inline-block`}
> >
{getRiskSeverityText(node.severity)} {getRiskSeverityText(node.inherentSeverity)}
</div> </div>
</td> </td>
</tr> </tr>

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<a6bd25e3b378dcc7ac26ba611a054fbe>> * @generated SignedSource<<016c2795072dd550f7353660e6f36afe>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -23,7 +23,11 @@ export type MesureViewRisksQuery$data = {
readonly id: string; readonly id: string;
readonly inherentImpact: number; readonly inherentImpact: number;
readonly inherentLikelihood: number; readonly inherentLikelihood: number;
readonly inherentSeverity: number;
readonly name: string; readonly name: string;
readonly residualImpact: number;
readonly residualLikelihood: number;
readonly residualSeverity: number;
readonly updatedAt: string; readonly updatedAt: string;
}; };
}>; }>;
@@ -110,6 +114,34 @@ v4 = [
"name": "inherentImpact", "name": "inherentImpact",
"storageKey": null "storageKey": null
}, },
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "inherentSeverity",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "residualLikelihood",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "residualImpact",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "residualSeverity",
"storageKey": null
},
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -259,7 +291,7 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "b8095743d31791d2084177fde0203ed4", "cacheID": "d61a109844cdf35d2e6ffe92a2c9b629",
"id": null, "id": null,
"metadata": { "metadata": {
"connection": [ "connection": [
@@ -276,11 +308,11 @@ return {
}, },
"name": "MesureViewRisksQuery", "name": "MesureViewRisksQuery",
"operationKind": "query", "operationKind": "query",
"text": "query MesureViewRisksQuery(\n $mesureId: ID!\n) {\n mesure: node(id: $mesureId) {\n __typename\n id\n ... on Mesure {\n risks(first: 100) {\n edges {\n node {\n id\n name\n description\n inherentLikelihood\n inherentImpact\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n" "text": "query MesureViewRisksQuery(\n $mesureId: ID!\n) {\n mesure: node(id: $mesureId) {\n __typename\n id\n ... on Mesure {\n risks(first: 100) {\n edges {\n node {\n id\n name\n description\n inherentLikelihood\n inherentImpact\n inherentSeverity\n residualLikelihood\n residualImpact\n residualSeverity\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
} }
}; };
})(); })();
(node as any).hash = "0609b3e58837ae65fb4df484b967060a"; (node as any).hash = "9f8d865c3f979dc21ec52526f283bf4a";
export default node; export default node;