Expire vendor risk assement
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
@@ -94,6 +94,13 @@ const vendorViewQuery = graphql`
|
||||
organization: node(id: $organizationId) {
|
||||
...PeopleSelector_organization
|
||||
}
|
||||
viewer {
|
||||
user {
|
||||
people(organizationId: $organizationId) {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -675,6 +682,13 @@ function RiskAssessmentsTable({
|
||||
});
|
||||
};
|
||||
|
||||
// Check if assessment is expired
|
||||
const isExpired = (expiresAt: string) => {
|
||||
console.log(new Date(expiresAt) < new Date());
|
||||
|
||||
return new Date(expiresAt) < new Date();
|
||||
};
|
||||
|
||||
// Get severity label based on data sensitivity and business impact
|
||||
const getSeverityLabel = (dataSensitivity: string, businessImpact: string) => {
|
||||
// Simple logic to determine severity - can be adjusted based on requirements
|
||||
@@ -731,35 +745,67 @@ function RiskAssessmentsTable({
|
||||
<tbody>
|
||||
{assessments.map((assessment) => {
|
||||
const severity = getSeverityLabel(assessment.dataSensitivity, assessment.businessImpact);
|
||||
const expired = isExpired(assessment.expiresAt);
|
||||
return (
|
||||
<tr key={assessment.id} className="border-b border-[rgba(2,42,2,0.08)]">
|
||||
<tr
|
||||
key={assessment.id}
|
||||
className={cn(
|
||||
"border-b border-[rgba(2,42,2,0.08)]",
|
||||
expired && "bg-[#F7F7F7] text-[#A0A5A0]"
|
||||
)}
|
||||
>
|
||||
<td className="px-4 py-3">
|
||||
<span className="text-sm font-normal text-[#141E12]">
|
||||
<span className={cn(
|
||||
"text-sm font-normal",
|
||||
expired ? "text-[#A0A5A0]" : "text-[#141E12]"
|
||||
)}>
|
||||
{formatDate(assessment.assessedAt)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<span className="text-sm font-normal text-[#141E12]">
|
||||
{formatDate(assessment.expiresAt)}
|
||||
</span>
|
||||
<div className="flex items-center">
|
||||
<span className={cn(
|
||||
"text-sm font-normal",
|
||||
expired ? "text-[#A0A5A0]" : "text-[#141E12]"
|
||||
)}>
|
||||
{formatDate(assessment.expiresAt)}
|
||||
</span>
|
||||
{expired && (
|
||||
<span className="ml-2 text-xs py-0.5 px-1.5 bg-[#F0F0F0] text-[#818780] rounded">
|
||||
Expired
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<span className="text-sm font-normal text-[#141E12]">
|
||||
<span className={cn(
|
||||
"text-sm font-normal",
|
||||
expired ? "text-[#A0A5A0]" : "text-[#141E12]"
|
||||
)}>
|
||||
{assessment.dataSensitivity.charAt(0) + assessment.dataSensitivity.slice(1).toLowerCase()}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<span className="text-sm font-normal text-[#141E12]">
|
||||
<span className={cn(
|
||||
"text-sm font-normal",
|
||||
expired ? "text-[#A0A5A0]" : "text-[#141E12]"
|
||||
)}>
|
||||
{assessment.businessImpact.charAt(0) + assessment.businessImpact.slice(1).toLowerCase()}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<span className={`text-sm font-normal px-2 py-1 rounded-full ${severity.color}`}>
|
||||
<span className={cn(
|
||||
"text-sm font-normal px-2 py-1 rounded-full",
|
||||
expired ? "bg-[#F0F0F0] text-[#818780]" : severity.color
|
||||
)}>
|
||||
{severity.label}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<span className="text-sm font-normal text-[#141E12]">
|
||||
<span className={cn(
|
||||
"text-sm font-normal",
|
||||
expired ? "text-[#A0A5A0]" : "text-[#141E12]"
|
||||
)}>
|
||||
{assessment.assessedBy?.fullName || 'N/A'}
|
||||
</span>
|
||||
</td>
|
||||
@@ -770,9 +816,9 @@ function RiskAssessmentsTable({
|
||||
onClick={() => setShowDropdown(showDropdown === assessment.id ? null : assessment.id)}
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 9.5C8.82843 9.5 9.5 8.82843 9.5 8C9.5 7.17157 8.82843 6.5 8 6.5C7.17157 6.5 6.5 7.17157 6.5 8C6.5 8.82843 7.17157 9.5 8 9.5Z" fill="#141E12"/>
|
||||
<path d="M3 9.5C3.82843 9.5 4.5 8.82843 4.5 8C4.5 7.17157 3.82843 6.5 3 6.5C2.17157 6.5 1.5 7.17157 1.5 8C1.5 8.82843 2.17157 9.5 3 9.5Z" fill="#141E12"/>
|
||||
<path d="M13 9.5C13.8284 9.5 14.5 8.82843 14.5 8C14.5 7.17157 13.8284 6.5 13 6.5C12.1716 6.5 11.5 7.17157 11.5 8C11.5 8.82843 12.1716 9.5 13 9.5Z" fill="#141E12"/>
|
||||
<path d="M8 9.5C8.82843 9.5 9.5 8.82843 9.5 8C9.5 7.17157 8.82843 6.5 8 6.5C7.17157 6.5 6.5 7.17157 6.5 8C6.5 8.82843 7.17157 9.5 8 9.5Z" fill={expired ? "#A0A5A0" : "#141E12"}/>
|
||||
<path d="M3 9.5C3.82843 9.5 4.5 8.82843 4.5 8C4.5 7.17157 3.82843 6.5 3 6.5C2.17157 6.5 1.5 7.17157 1.5 8C1.5 8.82843 2.17157 9.5 3 9.5Z" fill={expired ? "#A0A5A0" : "#141E12"}/>
|
||||
<path d="M13 9.5C13.8284 9.5 14.5 8.82843 14.5 8C14.5 7.17157 13.8284 6.5 13 6.5C12.1716 6.5 11.5 7.17157 11.5 8C11.5 8.82843 12.1716 9.5 13 9.5Z" fill={expired ? "#A0A5A0" : "#141E12"}/>
|
||||
</svg>
|
||||
</button>
|
||||
{showDropdown === assessment.id && (
|
||||
@@ -1270,27 +1316,9 @@ function VendorViewContent({
|
||||
businessImpact: BusinessImpact;
|
||||
notes: string;
|
||||
}) => {
|
||||
// Close the modal
|
||||
setShowRiskAssessmentModal(false);
|
||||
|
||||
// Current date for assessedAt, and 1 year later for expiresAt
|
||||
const today = new Date();
|
||||
const nextYear = new Date(today);
|
||||
const nextYear = new Date();
|
||||
nextYear.setFullYear(nextYear.getFullYear() + 1);
|
||||
|
||||
// Check if there's a business owner assigned
|
||||
const businessOwnerId = data.node.businessOwner?.id;
|
||||
if (!businessOwnerId) {
|
||||
// This check is now redundant as it's handled in the modal
|
||||
// but keeping it as a safeguard
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "Please assign a Business Owner to the vendor before creating a risk assessment",
|
||||
variant: "destructive",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
createRiskAssessment({
|
||||
variables: {
|
||||
connections: [
|
||||
@@ -1301,12 +1329,11 @@ function VendorViewContent({
|
||||
],
|
||||
input: {
|
||||
vendorId: data.node.id!,
|
||||
assessedBy: businessOwnerId,
|
||||
assessedBy: data.viewer.user.people?.id!,
|
||||
expiresAt: nextYear.toISOString(),
|
||||
dataSensitivity: formValues.dataSensitivity,
|
||||
businessImpact: formValues.businessImpact,
|
||||
notes: formValues.notes || "Risk assessment",
|
||||
attachments: []
|
||||
},
|
||||
},
|
||||
onCompleted: () => {
|
||||
@@ -1315,6 +1342,7 @@ function VendorViewContent({
|
||||
description: "Risk assessment created successfully",
|
||||
variant: "default",
|
||||
});
|
||||
setShowRiskAssessmentModal(false);
|
||||
loadQuery({
|
||||
vendorId: data.node.id!,
|
||||
organizationId: organizationId!,
|
||||
@@ -1328,7 +1356,7 @@ function VendorViewContent({
|
||||
});
|
||||
},
|
||||
});
|
||||
}, [createRiskAssessment, data.node.id, data.node.businessOwner?.id, loadQuery, toast, organizationId]);
|
||||
}, [createRiskAssessment, data.node.id, data.viewer.user.people?.id, loadQuery, toast, organizationId]);
|
||||
|
||||
const formatDate = (dateStr: string | null | undefined) => {
|
||||
if (!dateStr) return "N/A";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<8372d50934049d43afb678c894f40dbd>>
|
||||
* @generated SignedSource<<08de2d8758474132b472d63f413b59a5>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -13,7 +13,6 @@ export type BusinessImpact = "CRITICAL" | "HIGH" | "LOW" | "MEDIUM";
|
||||
export type DataSensitivity = "CRITICAL" | "HIGH" | "LOW" | "MEDIUM" | "NONE";
|
||||
export type CreateVendorRiskAssessmentInput = {
|
||||
assessedBy: string;
|
||||
attachments?: ReadonlyArray<string> | null | undefined;
|
||||
businessImpact: BusinessImpact;
|
||||
dataSensitivity: DataSensitivity;
|
||||
expiresAt: string;
|
||||
|
||||
101
apps/console/src/pages/organizations/vendors/__generated__/VendorViewQuery.graphql.ts
generated
vendored
101
apps/console/src/pages/organizations/vendors/__generated__/VendorViewQuery.graphql.ts
generated
vendored
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<bbfa9d7b4ab300f8ab96380582d2d9b7>>
|
||||
* @generated SignedSource<<c189e0079d6d90c845d93a6a108a0b76>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -78,6 +78,13 @@ export type VendorViewQuery$data = {
|
||||
readonly organization: {
|
||||
readonly " $fragmentSpreads": FragmentRefs<"PeopleSelector_organization">;
|
||||
};
|
||||
readonly viewer: {
|
||||
readonly user: {
|
||||
readonly people: {
|
||||
readonly id: string;
|
||||
} | null | undefined;
|
||||
};
|
||||
};
|
||||
};
|
||||
export type VendorViewQuery = {
|
||||
response: VendorViewQuery$data;
|
||||
@@ -444,15 +451,33 @@ v30 = [
|
||||
}
|
||||
],
|
||||
v31 = {
|
||||
"alias": null,
|
||||
"args": [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "organizationId",
|
||||
"variableName": "organizationId"
|
||||
}
|
||||
],
|
||||
"concreteType": "People",
|
||||
"kind": "LinkedField",
|
||||
"name": "people",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v3/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
v32 = {
|
||||
"kind": "Literal",
|
||||
"name": "first",
|
||||
"value": 100
|
||||
},
|
||||
v32 = [
|
||||
(v31/*: any*/)
|
||||
],
|
||||
v33 = [
|
||||
(v31/*: any*/),
|
||||
(v32/*: any*/)
|
||||
],
|
||||
v34 = [
|
||||
(v32/*: any*/),
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "orderBy",
|
||||
@@ -545,6 +570,29 @@ return {
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Viewer",
|
||||
"kind": "LinkedField",
|
||||
"name": "viewer",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "User",
|
||||
"kind": "LinkedField",
|
||||
"name": "user",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v31/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Query",
|
||||
@@ -593,7 +641,7 @@ return {
|
||||
(v24/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v32/*: any*/),
|
||||
"args": (v33/*: any*/),
|
||||
"concreteType": "VendorComplianceReportConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "complianceReports",
|
||||
@@ -603,7 +651,7 @@ return {
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v32/*: any*/),
|
||||
"args": (v33/*: any*/),
|
||||
"filters": null,
|
||||
"handle": "connection",
|
||||
"key": "VendorView_complianceReports",
|
||||
@@ -612,7 +660,7 @@ return {
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v32/*: any*/),
|
||||
"args": (v33/*: any*/),
|
||||
"concreteType": "VendorRiskAssessmentConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "riskAssessments",
|
||||
@@ -622,7 +670,7 @@ return {
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v32/*: any*/),
|
||||
"args": (v33/*: any*/),
|
||||
"filters": null,
|
||||
"handle": "connection",
|
||||
"key": "VendorView_riskAssessments",
|
||||
@@ -651,7 +699,7 @@ return {
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v33/*: any*/),
|
||||
"args": (v34/*: any*/),
|
||||
"concreteType": "PeopleConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "peoples",
|
||||
@@ -696,7 +744,7 @@ return {
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v33/*: any*/),
|
||||
"args": (v34/*: any*/),
|
||||
"filters": [
|
||||
"orderBy"
|
||||
],
|
||||
@@ -711,11 +759,36 @@ return {
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Viewer",
|
||||
"kind": "LinkedField",
|
||||
"name": "viewer",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "User",
|
||||
"kind": "LinkedField",
|
||||
"name": "user",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v31/*: any*/),
|
||||
(v3/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v3/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "5df12f781d305bd4bd6b6c0ccb4d947e",
|
||||
"cacheID": "9b2a625a96210e0168dceed7e4b98ed0",
|
||||
"id": null,
|
||||
"metadata": {
|
||||
"connection": [
|
||||
@@ -741,11 +814,11 @@ return {
|
||||
},
|
||||
"name": "VendorViewQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query VendorViewQuery(\n $vendorId: ID!\n $organizationId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n name\n description\n serviceStartAt\n serviceTerminationAt\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n securityPageUrl\n trustPageUrl\n certifications\n headquarterAddress\n legalName\n websiteUrl\n businessOwner {\n id\n fullName\n }\n securityOwner {\n id\n fullName\n }\n createdAt\n updatedAt\n complianceReports(first: 100) {\n edges {\n node {\n id\n reportName\n reportDate\n validUntil\n fileUrl\n fileSize\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n riskAssessments(first: 100) {\n edges {\n node {\n id\n assessedAt\n expiresAt\n dataSensitivity\n businessImpact\n notes\n assessedBy {\n id\n fullName\n }\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n organization: node(id: $organizationId) {\n __typename\n ...PeopleSelector_organization\n id\n }\n}\n\nfragment PeopleSelector_organization on Organization {\n id\n peoples(first: 100, orderBy: {direction: ASC, field: FULL_NAME}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n"
|
||||
"text": "query VendorViewQuery(\n $vendorId: ID!\n $organizationId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n name\n description\n serviceStartAt\n serviceTerminationAt\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n securityPageUrl\n trustPageUrl\n certifications\n headquarterAddress\n legalName\n websiteUrl\n businessOwner {\n id\n fullName\n }\n securityOwner {\n id\n fullName\n }\n createdAt\n updatedAt\n complianceReports(first: 100) {\n edges {\n node {\n id\n reportName\n reportDate\n validUntil\n fileUrl\n fileSize\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n riskAssessments(first: 100) {\n edges {\n node {\n id\n assessedAt\n expiresAt\n dataSensitivity\n businessImpact\n notes\n assessedBy {\n id\n fullName\n }\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n organization: node(id: $organizationId) {\n __typename\n ...PeopleSelector_organization\n id\n }\n viewer {\n user {\n people(organizationId: $organizationId) {\n id\n }\n id\n }\n id\n }\n}\n\nfragment PeopleSelector_organization on Organization {\n id\n peoples(first: 100, orderBy: {direction: ASC, field: FULL_NAME}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "2b856ea721d1bfb6b853fc281ee1aac6";
|
||||
(node as any).hash = "7f9a178bd20cefd76440ea8d71c3b2fa";
|
||||
|
||||
export default node;
|
||||
|
||||
Reference in New Issue
Block a user