@@ -39,6 +39,7 @@ const FrameworkOverviewPageQuery = graphql`
|
|||||||
name
|
name
|
||||||
description
|
description
|
||||||
state
|
state
|
||||||
|
category
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,49 +57,22 @@ function FrameworkOverviewPageContent({
|
|||||||
const framework = data.node;
|
const framework = data.node;
|
||||||
const controls = framework.controls?.edges.map((edge) => edge?.node) ?? [];
|
const controls = framework.controls?.edges.map((edge) => edge?.node) ?? [];
|
||||||
|
|
||||||
const controlsByCategory = {
|
// Group controls by their category
|
||||||
office: controls.filter((c) => c?.name.toLowerCase().includes("office")),
|
const controlsByCategory = controls.reduce((acc, control) => {
|
||||||
computer: controls.filter((c) =>
|
if (!control?.category) return acc;
|
||||||
c?.name.toLowerCase().includes("computer"),
|
if (!acc[control.category]) {
|
||||||
),
|
acc[control.category] = [];
|
||||||
employees: controls.filter((c) =>
|
}
|
||||||
c?.name.toLowerCase().includes("employee"),
|
acc[control.category].push(control);
|
||||||
),
|
return acc;
|
||||||
email: controls.filter((c) => c?.name.toLowerCase().includes("email")),
|
}, {} as Record<string, typeof controls>);
|
||||||
code: controls.filter((c) => c?.name.toLowerCase().includes("code")),
|
|
||||||
infrastructure: controls.filter((c) =>
|
|
||||||
c?.name.toLowerCase().includes("infrastructure"),
|
|
||||||
),
|
|
||||||
network: controls.filter((c) => c?.name.toLowerCase().includes("network")),
|
|
||||||
data: controls.filter((c) => c?.name.toLowerCase().includes("data")),
|
|
||||||
logging: controls.filter((c) => c?.name.toLowerCase().includes("log")),
|
|
||||||
incidents: controls.filter((c) =>
|
|
||||||
c?.name.toLowerCase().includes("incident"),
|
|
||||||
),
|
|
||||||
vendors: controls.filter((c) => c?.name.toLowerCase().includes("vendor")),
|
|
||||||
sharing: controls.filter((c) => c?.name.toLowerCase().includes("share")),
|
|
||||||
};
|
|
||||||
|
|
||||||
const controlCards = [
|
const controlCards = Object.entries(controlsByCategory).map(([category, controls]) => ({
|
||||||
{
|
title: category,
|
||||||
icon: <Building2 className="w-4 h-4" />,
|
controls,
|
||||||
title: "Secure your offices and internet access",
|
completed: controls.filter((c) => c?.state === "IMPLEMENTED").length,
|
||||||
controls: controlsByCategory.office,
|
total: controls.length,
|
||||||
completed: controlsByCategory.office.filter(
|
}));
|
||||||
(c) => c?.state === "IMPLEMENTED",
|
|
||||||
).length,
|
|
||||||
total: controlsByCategory.office.length,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <Computer className="w-4 h-4" />,
|
|
||||||
title: "Manage your computers",
|
|
||||||
controls: controlsByCategory.computer,
|
|
||||||
completed: controlsByCategory.computer.filter(
|
|
||||||
(c) => c?.state === "IMPLEMENTED",
|
|
||||||
).length,
|
|
||||||
total: controlsByCategory.computer.length,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const totalImplemented = controls.filter(
|
const totalImplemented = controls.filter(
|
||||||
(c) => c?.state === "IMPLEMENTED",
|
(c) => c?.state === "IMPLEMENTED",
|
||||||
@@ -106,7 +80,6 @@ function FrameworkOverviewPageContent({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-background p-6">
|
<div className="min-h-screen bg-background p-6">
|
||||||
{/* Header */}
|
|
||||||
<div className="space-y-4 mb-8">
|
<div className="space-y-4 mb-8">
|
||||||
<h1 className="text-2xl font-semibold">{framework.name}</h1>
|
<h1 className="text-2xl font-semibold">{framework.name}</h1>
|
||||||
<p className="text-muted-foreground max-w-3xl">
|
<p className="text-muted-foreground max-w-3xl">
|
||||||
@@ -114,7 +87,6 @@ function FrameworkOverviewPageContent({
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Timeline */}
|
|
||||||
<div className="mb-8 space-y-4">
|
<div className="mb-8 space-y-4">
|
||||||
<div className="flex items-center gap-2 text-sm">
|
<div className="flex items-center gap-2 text-sm">
|
||||||
<div className="bg-primary/10 text-primary px-3 py-1 rounded-md flex items-center gap-2">
|
<div className="bg-primary/10 text-primary px-3 py-1 rounded-md flex items-center gap-2">
|
||||||
@@ -150,7 +122,7 @@ function FrameworkOverviewPageContent({
|
|||||||
<Card key={index}>
|
<Card key={index}>
|
||||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
||||||
{card.icon}
|
<Shield className="w-4 h-4" />
|
||||||
{card.title}
|
{card.title}
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<Avatar className="h-6 w-6">
|
<Avatar className="h-6 w-6">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<f9715593419cda898b34a0056729d77c>>
|
* @generated SignedSource<<27e925c9f55d555878de5cbe0c131d44>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -18,6 +18,7 @@ export type FrameworkOverviewPageQuery$data = {
|
|||||||
readonly controls?: {
|
readonly controls?: {
|
||||||
readonly edges: ReadonlyArray<{
|
readonly edges: ReadonlyArray<{
|
||||||
readonly node: {
|
readonly node: {
|
||||||
|
readonly category: string;
|
||||||
readonly description: string;
|
readonly description: string;
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
@@ -109,6 +110,13 @@ v5 = {
|
|||||||
"kind": "ScalarField",
|
"kind": "ScalarField",
|
||||||
"name": "state",
|
"name": "state",
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "category",
|
||||||
|
"storageKey": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
@@ -176,16 +184,16 @@ return {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
"cacheID": "4190ee685492e95820ecb106f2dc7e3c",
|
"cacheID": "c02ad61a9b6ce13a83576ad58aa0a7f4",
|
||||||
"id": null,
|
"id": null,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"name": "FrameworkOverviewPageQuery",
|
"name": "FrameworkOverviewPageQuery",
|
||||||
"operationKind": "query",
|
"operationKind": "query",
|
||||||
"text": "query FrameworkOverviewPageQuery(\n $frameworkId: ID!\n) {\n node(id: $frameworkId) {\n __typename\n id\n ... on Framework {\n name\n description\n controls {\n edges {\n node {\n id\n name\n description\n state\n }\n }\n }\n }\n }\n}\n"
|
"text": "query FrameworkOverviewPageQuery(\n $frameworkId: ID!\n) {\n node(id: $frameworkId) {\n __typename\n id\n ... on Framework {\n name\n description\n controls {\n edges {\n node {\n id\n name\n description\n state\n category\n }\n }\n }\n }\n }\n}\n"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
(node as any).hash = "25fb6b72c598d19767825ac648654fcf";
|
(node as any).hash = "3103fb6eba6ddf2625aa5b50bcdb43f6";
|
||||||
|
|
||||||
export default node;
|
export default node;
|
||||||
|
|||||||
Reference in New Issue
Block a user