diff --git a/apps/console/src/components/form/ProcessingActivityEnumOptions.tsx b/apps/console/src/components/form/ProcessingActivityEnumOptions.tsx index fb74dded7..29acb27c8 100644 --- a/apps/console/src/components/form/ProcessingActivityEnumOptions.tsx +++ b/apps/console/src/components/form/ProcessingActivityEnumOptions.tsx @@ -74,6 +74,21 @@ export function getLawfulBasisLabel( return labels[value] || value; } +export function getResidualRiskLabel( + value: "LOW" | "MEDIUM" | "HIGH" | null | undefined, + __: (key: string) => string +): string { + if (!value) return "-"; + + const labels = { + LOW: __("Low"), + MEDIUM: __("Medium"), + HIGH: __("High"), + }; + + return labels[value] || value; +} + export function TransferSafeguardsOptions() { const { __ } = useTranslate(); @@ -150,3 +165,25 @@ export function TransferImpactAssessmentOptions() { ); } + +export function RoleOptions() { + const { __ } = useTranslate(); + + const options: Array<{ + value: "CONTROLLER" | "PROCESSOR"; + label: string; + }> = [ + { value: "CONTROLLER", label: __("Controller") }, + { value: "PROCESSOR", label: __("Processor") }, + ]; + + return ( + <> + {options.map((option) => ( + + ))} + + ); +} diff --git a/apps/console/src/hooks/graph/ProcessingActivityGraph.ts b/apps/console/src/hooks/graph/ProcessingActivityGraph.ts index 34ecb6de8..b4ca02733 100644 --- a/apps/console/src/hooks/graph/ProcessingActivityGraph.ts +++ b/apps/console/src/hooks/graph/ProcessingActivityGraph.ts @@ -6,12 +6,15 @@ import { promisifyMutation, sprintf } from "@probo/helpers"; import { useMutationWithToasts } from "../useMutationWithToasts"; export const ProcessingActivitiesConnectionKey = "ProcessingActivitiesPage_processingActivities"; +export type ProcessingActivityDPIAResidualRisk = "LOW" | "MEDIUM" | "HIGH"; export const processingActivitiesQuery = graphql` query ProcessingActivityGraphListQuery($organizationId: ID!, $snapshotId: ID) { node(id: $organizationId) { ... on Organization { ...ProcessingActivitiesPageFragment @arguments(snapshotId: $snapshotId) + ...ProcessingActivitiesPageDPIAFragment + ...ProcessingActivitiesPageTIAFragment } } } @@ -38,6 +41,13 @@ export const processingActivityNodeQuery = graphql` securityMeasures dataProtectionImpactAssessment transferImpactAssessment + lastReviewDate + nextReviewDate + role + dataProtectionOfficer { + id + fullName + } vendors(first: 50) { edges { node { @@ -48,6 +58,26 @@ export const processingActivityNodeQuery = graphql` } } } + dpia { + id + description + necessityAndProportionality + potentialRisk + mitigations + residualRisk + createdAt + updatedAt + } + tia { + id + dataSubjects + legalMechanism + transfer + localLawRisk + supplementaryMeasures + createdAt + updatedAt + } organization { id name @@ -83,6 +113,13 @@ export const createProcessingActivityMutation = graphql` securityMeasures dataProtectionImpactAssessment transferImpactAssessment + lastReviewDate + nextReviewDate + role + dataProtectionOfficer { + id + fullName + } vendors(first: 50) { edges { node { @@ -119,6 +156,13 @@ export const updateProcessingActivityMutation = graphql` securityMeasures dataProtectionImpactAssessment transferImpactAssessment + lastReviewDate + nextReviewDate + role + dataProtectionOfficer { + id + fullName + } vendors(first: 50) { edges { node { @@ -200,6 +244,10 @@ export const useCreateProcessingActivity = (connectionId?: string) => { securityMeasures?: string; dataProtectionImpactAssessment?: string; transferImpactAssessment?: string; + lastReviewDate?: string; + nextReviewDate?: string; + role: string; + dataProtectionOfficerId?: string; vendorIds?: string[]; }) => { if (!input.organizationId) { @@ -228,6 +276,10 @@ export const useCreateProcessingActivity = (connectionId?: string) => { securityMeasures: input.securityMeasures, dataProtectionImpactAssessment: input.dataProtectionImpactAssessment, transferImpactAssessment: input.transferImpactAssessment, + lastReviewDate: input.lastReviewDate, + nextReviewDate: input.nextReviewDate, + role: input.role, + dataProtectionOfficerId: input.dataProtectionOfficerId, vendorIds: input.vendorIds, }, connections: connectionId ? [connectionId] : [], @@ -257,6 +309,10 @@ export const useUpdateProcessingActivity = () => { securityMeasures?: string; dataProtectionImpactAssessment?: string; transferImpactAssessment?: string; + lastReviewDate?: string | null; + nextReviewDate?: string | null; + role?: string; + dataProtectionOfficerId?: string | null; vendorIds?: string[]; }) => { if (!input.id) { @@ -270,3 +326,257 @@ export const useUpdateProcessingActivity = () => { }); }; }; + +export const createProcessingActivityDPIAMutation = graphql` + mutation ProcessingActivityGraphCreateDPIAMutation( + $input: CreateProcessingActivityDPIAInput! + ) { + createProcessingActivityDPIA(input: $input) { + processingActivityDpia { + id + description + necessityAndProportionality + potentialRisk + mitigations + residualRisk + createdAt + updatedAt + } + } + } +`; + +export const updateProcessingActivityDPIAMutation = graphql` + mutation ProcessingActivityGraphUpdateDPIAMutation( + $input: UpdateProcessingActivityDPIAInput! + ) { + updateProcessingActivityDPIA(input: $input) { + processingActivityDpia { + id + description + necessityAndProportionality + potentialRisk + mitigations + residualRisk + createdAt + updatedAt + } + } + } +`; + +export const deleteProcessingActivityDPIAMutation = graphql` + mutation ProcessingActivityGraphDeleteDPIAMutation( + $input: DeleteProcessingActivityDPIAInput! + ) { + deleteProcessingActivityDPIA(input: $input) { + deletedProcessingActivityDpiaId + } + } +`; + +export const useCreateProcessingActivityDPIA = () => { + const [mutate] = useMutation(createProcessingActivityDPIAMutation); + const { __ } = useTranslate(); + + return (input: { + processingActivityId: string; + description?: string; + necessityAndProportionality?: string; + potentialRisk?: string; + mitigations?: string; + residualRisk?: ProcessingActivityDPIAResidualRisk; + }) => { + if (!input.processingActivityId) { + return alert(__("Failed to create DPIA: Processing Activity ID is required")); + } + + return promisifyMutation(mutate)({ + variables: { + input, + }, + }); + }; +}; + +export const useUpdateProcessingActivityDPIA = () => { + const [mutate] = useMutation(updateProcessingActivityDPIAMutation); + const { __ } = useTranslate(); + + return (input: { + id: string; + description?: string; + necessityAndProportionality?: string; + potentialRisk?: string; + mitigations?: string; + residualRisk?: ProcessingActivityDPIAResidualRisk; + }) => { + if (!input.id) { + return alert(__("Failed to update DPIA: ID is required")); + } + + return promisifyMutation(mutate)({ + variables: { + input, + }, + }); + }; +}; + +export const useDeleteProcessingActivityDPIA = ( + dpia: { id: string }, + options?: { onSuccess?: () => void } +) => { + const { __ } = useTranslate(); + const [mutate] = useMutationWithToasts(deleteProcessingActivityDPIAMutation, { + successMessage: __("DPIA deleted successfully"), + errorMessage: __("Failed to delete DPIA"), + }); + const confirm = useConfirm(); + + return () => { + confirm( + () => + mutate({ + variables: { + input: { + processingActivityDpiaId: dpia.id, + }, + }, + onSuccess: options?.onSuccess, + }), + { + message: __( + "This will permanently delete this Data Protection Impact Assessment. This action cannot be undone." + ), + } + ); + }; +}; + +export const createProcessingActivityTIAMutation = graphql` + mutation ProcessingActivityGraphCreateTIAMutation( + $input: CreateProcessingActivityTIAInput! + ) { + createProcessingActivityTIA(input: $input) { + processingActivityTia { + id + dataSubjects + legalMechanism + transfer + localLawRisk + supplementaryMeasures + createdAt + updatedAt + } + } + } +`; + +export const updateProcessingActivityTIAMutation = graphql` + mutation ProcessingActivityGraphUpdateTIAMutation( + $input: UpdateProcessingActivityTIAInput! + ) { + updateProcessingActivityTIA(input: $input) { + processingActivityTia { + id + dataSubjects + legalMechanism + transfer + localLawRisk + supplementaryMeasures + createdAt + updatedAt + } + } + } +`; + +export const deleteProcessingActivityTIAMutation = graphql` + mutation ProcessingActivityGraphDeleteTIAMutation( + $input: DeleteProcessingActivityTIAInput! + ) { + deleteProcessingActivityTIA(input: $input) { + deletedProcessingActivityTiaId + } + } +`; + +export const useCreateProcessingActivityTIA = () => { + const [mutate] = useMutation(createProcessingActivityTIAMutation); + const { __ } = useTranslate(); + + return (input: { + processingActivityId: string; + dataSubjects?: string; + legalMechanism?: string; + transfer?: string; + localLawRisk?: string; + supplementaryMeasures?: string; + }) => { + if (!input.processingActivityId) { + return alert(__("Failed to create TIA: Processing Activity ID is required")); + } + + return promisifyMutation(mutate)({ + variables: { + input, + }, + }); + }; +}; + +export const useUpdateProcessingActivityTIA = () => { + const [mutate] = useMutation(updateProcessingActivityTIAMutation); + const { __ } = useTranslate(); + + return (input: { + id: string; + dataSubjects?: string; + legalMechanism?: string; + transfer?: string; + localLawRisk?: string; + supplementaryMeasures?: string; + }) => { + if (!input.id) { + return alert(__("Failed to update TIA: ID is required")); + } + + return promisifyMutation(mutate)({ + variables: { + input, + }, + }); + }; +}; + +export const useDeleteProcessingActivityTIA = ( + tia: { id: string }, + options?: { onSuccess?: () => void } +) => { + const { __ } = useTranslate(); + const [mutate] = useMutationWithToasts(deleteProcessingActivityTIAMutation, { + successMessage: __("TIA deleted successfully"), + errorMessage: __("Failed to delete TIA"), + }); + const confirm = useConfirm(); + + return () => { + confirm( + () => + mutate({ + variables: { + input: { + processingActivityTiaId: tia.id, + }, + }, + onSuccess: options?.onSuccess, + }), + { + message: __( + "This will permanently delete this Transfer Impact Assessment. This action cannot be undone." + ), + } + ); + }; +}; diff --git a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphCreateDPIAMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphCreateDPIAMutation.graphql.ts new file mode 100644 index 000000000..3834d3231 --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphCreateDPIAMutation.graphql.ts @@ -0,0 +1,167 @@ +/** + * @generated SignedSource<> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type ProcessingActivityDPIAResidualRisk = "HIGH" | "LOW" | "MEDIUM"; +export type CreateProcessingActivityDPIAInput = { + description?: string | null | undefined; + mitigations?: string | null | undefined; + necessityAndProportionality?: string | null | undefined; + potentialRisk?: string | null | undefined; + processingActivityId: string; + residualRisk?: ProcessingActivityDPIAResidualRisk | null | undefined; +}; +export type ProcessingActivityGraphCreateDPIAMutation$variables = { + input: CreateProcessingActivityDPIAInput; +}; +export type ProcessingActivityGraphCreateDPIAMutation$data = { + readonly createProcessingActivityDPIA: { + readonly processingActivityDpia: { + readonly createdAt: any; + readonly description: string | null | undefined; + readonly id: string; + readonly mitigations: string | null | undefined; + readonly necessityAndProportionality: string | null | undefined; + readonly potentialRisk: string | null | undefined; + readonly residualRisk: ProcessingActivityDPIAResidualRisk | null | undefined; + readonly updatedAt: any; + }; + }; +}; +export type ProcessingActivityGraphCreateDPIAMutation = { + response: ProcessingActivityGraphCreateDPIAMutation$data; + variables: ProcessingActivityGraphCreateDPIAMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "CreateProcessingActivityDPIAPayload", + "kind": "LinkedField", + "name": "createProcessingActivityDPIA", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ProcessingActivityDPIA", + "kind": "LinkedField", + "name": "processingActivityDpia", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "necessityAndProportionality", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "potentialRisk", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "mitigations", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "residualRisk", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ProcessingActivityGraphCreateDPIAMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ProcessingActivityGraphCreateDPIAMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "5bdea885aa22aedfe71b19bf6781be61", + "id": null, + "metadata": {}, + "name": "ProcessingActivityGraphCreateDPIAMutation", + "operationKind": "mutation", + "text": "mutation ProcessingActivityGraphCreateDPIAMutation(\n $input: CreateProcessingActivityDPIAInput!\n) {\n createProcessingActivityDPIA(input: $input) {\n processingActivityDpia {\n id\n description\n necessityAndProportionality\n potentialRisk\n mitigations\n residualRisk\n createdAt\n updatedAt\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "2b7346936fb433d268f816e687ddc2a6"; + +export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphCreateMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphCreateMutation.graphql.ts index 8b7df08d2..a3edd97fa 100644 --- a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphCreateMutation.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphCreateMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<8ff0215134a49d15ba4b9153461f2fd8>> * @lightSyntaxTransform * @nogrep */ @@ -11,22 +11,27 @@ import { ConcreteRequest } from 'relay-runtime'; export type ProcessingActivityDataProtectionImpactAssessment = "NEEDED" | "NOT_NEEDED"; export type ProcessingActivityLawfulBasis = "CONSENT" | "CONTRACTUAL_NECESSITY" | "LEGAL_OBLIGATION" | "LEGITIMATE_INTEREST" | "PUBLIC_TASK" | "VITAL_INTERESTS"; +export type ProcessingActivityRole = "CONTROLLER" | "PROCESSOR"; export type ProcessingActivitySpecialOrCriminalDatum = "NO" | "POSSIBLE" | "YES"; export type ProcessingActivityTransferImpactAssessment = "NEEDED" | "NOT_NEEDED"; export type ProcessingActivityTransferSafeguard = "ADEQUACY_DECISION" | "BINDING_CORPORATE_RULES" | "CERTIFICATION_MECHANISMS" | "CODES_OF_CONDUCT" | "DEROGATIONS" | "STANDARD_CONTRACTUAL_CLAUSES"; export type CreateProcessingActivityInput = { consentEvidenceLink?: string | null | undefined; dataProtectionImpactAssessment: ProcessingActivityDataProtectionImpactAssessment; + dataProtectionOfficerId?: string | null | undefined; dataSubjectCategory?: string | null | undefined; internationalTransfers: boolean; + lastReviewDate?: any | null | undefined; lawfulBasis: ProcessingActivityLawfulBasis; location?: string | null | undefined; name: string; + nextReviewDate?: any | null | undefined; organizationId: string; personalDataCategory?: string | null | undefined; purpose?: string | null | undefined; recipients?: string | null | undefined; retentionPeriod?: string | null | undefined; + role: ProcessingActivityRole; securityMeasures?: string | null | undefined; specialOrCriminalData: ProcessingActivitySpecialOrCriminalDatum; transferImpactAssessment: ProcessingActivityTransferImpactAssessment; @@ -44,16 +49,23 @@ export type ProcessingActivityGraphCreateMutation$data = { readonly consentEvidenceLink: string | null | undefined; readonly createdAt: any; readonly dataProtectionImpactAssessment: ProcessingActivityDataProtectionImpactAssessment; + readonly dataProtectionOfficer: { + readonly fullName: string; + readonly id: string; + } | null | undefined; readonly dataSubjectCategory: string | null | undefined; readonly id: string; readonly internationalTransfers: boolean; + readonly lastReviewDate: any | null | undefined; readonly lawfulBasis: ProcessingActivityLawfulBasis; readonly location: string | null | undefined; readonly name: string; + readonly nextReviewDate: any | null | undefined; readonly personalDataCategory: string | null | undefined; readonly purpose: string | null | undefined; readonly recipients: string | null | undefined; readonly retentionPeriod: string | null | undefined; + readonly role: ProcessingActivityRole; readonly securityMeasures: string | null | undefined; readonly specialOrCriminalData: ProcessingActivitySpecialOrCriminalDatum; readonly transferImpactAssessment: ProcessingActivityTransferImpactAssessment; @@ -224,6 +236,46 @@ v5 = { "name": "transferImpactAssessment", "storageKey": null }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "lastReviewDate", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "nextReviewDate", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "role", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "People", + "kind": "LinkedField", + "name": "dataProtectionOfficer", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + } + ], + "storageKey": null + }, { "alias": null, "args": [ @@ -351,16 +403,16 @@ return { ] }, "params": { - "cacheID": "4992c543938b28bc08d2316602d7bd1e", + "cacheID": "dbc6953ae60bda370ed5d730e3499eec", "id": null, "metadata": {}, "name": "ProcessingActivityGraphCreateMutation", "operationKind": "mutation", - "text": "mutation ProcessingActivityGraphCreateMutation(\n $input: CreateProcessingActivityInput!\n) {\n createProcessingActivity(input: $input) {\n processingActivityEdge {\n node {\n id\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n specialOrCriminalData\n consentEvidenceLink\n lawfulBasis\n recipients\n location\n internationalTransfers\n transferSafeguards\n retentionPeriod\n securityMeasures\n dataProtectionImpactAssessment\n transferImpactAssessment\n vendors(first: 50) {\n edges {\n node {\n id\n name\n websiteUrl\n }\n }\n }\n createdAt\n }\n }\n }\n}\n" + "text": "mutation ProcessingActivityGraphCreateMutation(\n $input: CreateProcessingActivityInput!\n) {\n createProcessingActivity(input: $input) {\n processingActivityEdge {\n node {\n id\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n specialOrCriminalData\n consentEvidenceLink\n lawfulBasis\n recipients\n location\n internationalTransfers\n transferSafeguards\n retentionPeriod\n securityMeasures\n dataProtectionImpactAssessment\n transferImpactAssessment\n lastReviewDate\n nextReviewDate\n role\n dataProtectionOfficer {\n id\n fullName\n }\n vendors(first: 50) {\n edges {\n node {\n id\n name\n websiteUrl\n }\n }\n }\n createdAt\n }\n }\n }\n}\n" } }; })(); -(node as any).hash = "2150e01b5dfb4ebf1553817b7cb39f08"; +(node as any).hash = "5bfa8b212d24257297f668a19c230d56"; export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphCreateTIAMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphCreateTIAMutation.graphql.ts new file mode 100644 index 000000000..b16d83b2d --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphCreateTIAMutation.graphql.ts @@ -0,0 +1,166 @@ +/** + * @generated SignedSource<<3da7aca4f891de8057947eda276a017f>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type CreateProcessingActivityTIAInput = { + dataSubjects?: string | null | undefined; + legalMechanism?: string | null | undefined; + localLawRisk?: string | null | undefined; + processingActivityId: string; + supplementaryMeasures?: string | null | undefined; + transfer?: string | null | undefined; +}; +export type ProcessingActivityGraphCreateTIAMutation$variables = { + input: CreateProcessingActivityTIAInput; +}; +export type ProcessingActivityGraphCreateTIAMutation$data = { + readonly createProcessingActivityTIA: { + readonly processingActivityTia: { + readonly createdAt: any; + readonly dataSubjects: string | null | undefined; + readonly id: string; + readonly legalMechanism: string | null | undefined; + readonly localLawRisk: string | null | undefined; + readonly supplementaryMeasures: string | null | undefined; + readonly transfer: string | null | undefined; + readonly updatedAt: any; + }; + }; +}; +export type ProcessingActivityGraphCreateTIAMutation = { + response: ProcessingActivityGraphCreateTIAMutation$data; + variables: ProcessingActivityGraphCreateTIAMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "CreateProcessingActivityTIAPayload", + "kind": "LinkedField", + "name": "createProcessingActivityTIA", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ProcessingActivityTIA", + "kind": "LinkedField", + "name": "processingActivityTia", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "dataSubjects", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "legalMechanism", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "transfer", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "localLawRisk", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "supplementaryMeasures", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ProcessingActivityGraphCreateTIAMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ProcessingActivityGraphCreateTIAMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "f04e4606a7ac8b57f6155cf5e2fa3eaa", + "id": null, + "metadata": {}, + "name": "ProcessingActivityGraphCreateTIAMutation", + "operationKind": "mutation", + "text": "mutation ProcessingActivityGraphCreateTIAMutation(\n $input: CreateProcessingActivityTIAInput!\n) {\n createProcessingActivityTIA(input: $input) {\n processingActivityTia {\n id\n dataSubjects\n legalMechanism\n transfer\n localLawRisk\n supplementaryMeasures\n createdAt\n updatedAt\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "e6315a3ae7db66c15850cfdae5927c03"; + +export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphDeleteDPIAMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphDeleteDPIAMutation.graphql.ts new file mode 100644 index 000000000..1046e667e --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphDeleteDPIAMutation.graphql.ts @@ -0,0 +1,92 @@ +/** + * @generated SignedSource<> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type DeleteProcessingActivityDPIAInput = { + processingActivityDpiaId: string; +}; +export type ProcessingActivityGraphDeleteDPIAMutation$variables = { + input: DeleteProcessingActivityDPIAInput; +}; +export type ProcessingActivityGraphDeleteDPIAMutation$data = { + readonly deleteProcessingActivityDPIA: { + readonly deletedProcessingActivityDpiaId: string; + }; +}; +export type ProcessingActivityGraphDeleteDPIAMutation = { + response: ProcessingActivityGraphDeleteDPIAMutation$data; + variables: ProcessingActivityGraphDeleteDPIAMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "DeleteProcessingActivityDPIAPayload", + "kind": "LinkedField", + "name": "deleteProcessingActivityDPIA", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "deletedProcessingActivityDpiaId", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ProcessingActivityGraphDeleteDPIAMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ProcessingActivityGraphDeleteDPIAMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "0c27b0098614053d1a252f87e75f8a24", + "id": null, + "metadata": {}, + "name": "ProcessingActivityGraphDeleteDPIAMutation", + "operationKind": "mutation", + "text": "mutation ProcessingActivityGraphDeleteDPIAMutation(\n $input: DeleteProcessingActivityDPIAInput!\n) {\n deleteProcessingActivityDPIA(input: $input) {\n deletedProcessingActivityDpiaId\n }\n}\n" + } +}; +})(); + +(node as any).hash = "9fc639df8d4ca6c8856acd9326c92997"; + +export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphDeleteTIAMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphDeleteTIAMutation.graphql.ts new file mode 100644 index 000000000..cab2d5f53 --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphDeleteTIAMutation.graphql.ts @@ -0,0 +1,92 @@ +/** + * @generated SignedSource<<0fa59581ecefda2fad4570e8e8c2f667>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type DeleteProcessingActivityTIAInput = { + processingActivityTiaId: string; +}; +export type ProcessingActivityGraphDeleteTIAMutation$variables = { + input: DeleteProcessingActivityTIAInput; +}; +export type ProcessingActivityGraphDeleteTIAMutation$data = { + readonly deleteProcessingActivityTIA: { + readonly deletedProcessingActivityTiaId: string; + }; +}; +export type ProcessingActivityGraphDeleteTIAMutation = { + response: ProcessingActivityGraphDeleteTIAMutation$data; + variables: ProcessingActivityGraphDeleteTIAMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "DeleteProcessingActivityTIAPayload", + "kind": "LinkedField", + "name": "deleteProcessingActivityTIA", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "deletedProcessingActivityTiaId", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ProcessingActivityGraphDeleteTIAMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ProcessingActivityGraphDeleteTIAMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "59c2e5775439e71d1c3546f094810389", + "id": null, + "metadata": {}, + "name": "ProcessingActivityGraphDeleteTIAMutation", + "operationKind": "mutation", + "text": "mutation ProcessingActivityGraphDeleteTIAMutation(\n $input: DeleteProcessingActivityTIAInput!\n) {\n deleteProcessingActivityTIA(input: $input) {\n deletedProcessingActivityTiaId\n }\n}\n" + } +}; +})(); + +(node as any).hash = "358c23b60d25478b3a217ae16938caed"; + +export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphListQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphListQuery.graphql.ts index f3458cbc8..ebe4f44f7 100644 --- a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphListQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphListQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -16,7 +16,7 @@ export type ProcessingActivityGraphListQuery$variables = { }; export type ProcessingActivityGraphListQuery$data = { readonly node: { - readonly " $fragmentSpreads": FragmentRefs<"ProcessingActivitiesPageFragment">; + readonly " $fragmentSpreads": FragmentRefs<"ProcessingActivitiesPageDPIAFragment" | "ProcessingActivitiesPageFragment" | "ProcessingActivitiesPageTIAFragment">; }; }; export type ProcessingActivityGraphListQuery = { @@ -65,18 +65,107 @@ v4 = { "name": "id", "storageKey": null }, -v5 = [ +v5 = { + "kind": "Literal", + "name": "first", + "value": 10 +}, +v6 = [ { "fields": (v2/*: any*/), "kind": "ObjectValue", "name": "filter" }, - { - "kind": "Literal", - "name": "first", - "value": 10 - } -]; + (v5/*: any*/) +], +v7 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "totalCount", + "storageKey": null +}, +v8 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v9 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null +}, +v10 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null +}, +v11 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null +}, +v12 = { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + } + ], + "storageKey": null +}, +v13 = { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__id", + "storageKey": null + } + ] +}, +v14 = [ + (v5/*: any*/) +], +v15 = { + "alias": null, + "args": null, + "concreteType": "ProcessingActivity", + "kind": "LinkedField", + "name": "processingActivity", + "plural": false, + "selections": [ + (v4/*: any*/), + (v8/*: any*/) + ], + "storageKey": null +}; return { "fragment": { "argumentDefinitions": (v0/*: any*/), @@ -99,6 +188,16 @@ return { "args": (v2/*: any*/), "kind": "FragmentSpread", "name": "ProcessingActivitiesPageFragment" + }, + { + "args": null, + "kind": "FragmentSpread", + "name": "ProcessingActivitiesPageDPIAFragment" + }, + { + "args": null, + "kind": "FragmentSpread", + "name": "ProcessingActivitiesPageTIAFragment" } ], "type": "Organization", @@ -132,19 +231,13 @@ return { "selections": [ { "alias": null, - "args": (v5/*: any*/), + "args": (v6/*: any*/), "concreteType": "ProcessingActivityConnection", "kind": "LinkedField", "name": "processingActivities", "plural": false, "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "totalCount", - "storageKey": null - }, + (v7/*: any*/), { "alias": null, "args": null, @@ -176,13 +269,7 @@ return { "name": "sourceId", "storageKey": null }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "name", - "storageKey": null - }, + (v8/*: any*/), { "alias": null, "args": null, @@ -225,77 +312,24 @@ return { "name": "internationalTransfers", "storageKey": null }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "createdAt", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "updatedAt", - "storageKey": null - }, + (v9/*: any*/), + (v10/*: any*/), (v3/*: any*/) ], "storageKey": null }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "cursor", - "storageKey": null - } + (v11/*: any*/) ], "storageKey": null }, - { - "alias": null, - "args": null, - "concreteType": "PageInfo", - "kind": "LinkedField", - "name": "pageInfo", - "plural": false, - "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "hasNextPage", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "endCursor", - "storageKey": null - } - ], - "storageKey": null - }, - { - "kind": "ClientExtension", - "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__id", - "storageKey": null - } - ] - } + (v12/*: any*/), + (v13/*: any*/) ], "storageKey": null }, { "alias": null, - "args": (v5/*: any*/), + "args": (v6/*: any*/), "filters": [ "filter" ], @@ -303,6 +337,150 @@ return { "key": "ProcessingActivitiesPage_processingActivities", "kind": "LinkedHandle", "name": "processingActivities" + }, + { + "alias": null, + "args": (v14/*: any*/), + "concreteType": "ProcessingActivityDPIAConnection", + "kind": "LinkedField", + "name": "dataProtectionImpactAssessments", + "plural": false, + "selections": [ + (v7/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "ProcessingActivityDPIAEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ProcessingActivityDPIA", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v4/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "potentialRisk", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "residualRisk", + "storageKey": null + }, + (v15/*: any*/), + (v9/*: any*/), + (v10/*: any*/), + (v3/*: any*/) + ], + "storageKey": null + }, + (v11/*: any*/) + ], + "storageKey": null + }, + (v12/*: any*/), + (v13/*: any*/) + ], + "storageKey": "dataProtectionImpactAssessments(first:10)" + }, + { + "alias": null, + "args": (v14/*: any*/), + "filters": null, + "handle": "connection", + "key": "ProcessingActivitiesPage_dataProtectionImpactAssessments", + "kind": "LinkedHandle", + "name": "dataProtectionImpactAssessments" + }, + { + "alias": null, + "args": (v14/*: any*/), + "concreteType": "ProcessingActivityTIAConnection", + "kind": "LinkedField", + "name": "transferImpactAssessments", + "plural": false, + "selections": [ + (v7/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "ProcessingActivityTIAEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ProcessingActivityTIA", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v4/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "dataSubjects", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "transfer", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "localLawRisk", + "storageKey": null + }, + (v15/*: any*/), + (v9/*: any*/), + (v10/*: any*/), + (v3/*: any*/) + ], + "storageKey": null + }, + (v11/*: any*/) + ], + "storageKey": null + }, + (v12/*: any*/), + (v13/*: any*/) + ], + "storageKey": "transferImpactAssessments(first:10)" + }, + { + "alias": null, + "args": (v14/*: any*/), + "filters": null, + "handle": "connection", + "key": "ProcessingActivitiesPage_transferImpactAssessments", + "kind": "LinkedHandle", + "name": "transferImpactAssessments" } ], "type": "Organization", @@ -314,16 +492,16 @@ return { ] }, "params": { - "cacheID": "5b9b9ab3b28fe10be6f1e57f3756187a", + "cacheID": "e518b4737308d2e7528a2f68e26d0e32", "id": null, "metadata": {}, "name": "ProcessingActivityGraphListQuery", "operationKind": "query", - "text": "query ProcessingActivityGraphListQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ProcessingActivitiesPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ProcessingActivitiesPageFragment_3iomuz on Organization {\n id\n processingActivities(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n lawfulBasis\n location\n internationalTransfers\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" + "text": "query ProcessingActivityGraphListQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ProcessingActivitiesPageFragment_3iomuz\n ...ProcessingActivitiesPageDPIAFragment\n ...ProcessingActivitiesPageTIAFragment\n }\n id\n }\n}\n\nfragment ProcessingActivitiesPageDPIAFragment on Organization {\n id\n dataProtectionImpactAssessments(first: 10) {\n totalCount\n edges {\n node {\n id\n description\n potentialRisk\n residualRisk\n processingActivity {\n id\n name\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n\nfragment ProcessingActivitiesPageFragment_3iomuz on Organization {\n id\n processingActivities(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n lawfulBasis\n location\n internationalTransfers\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n\nfragment ProcessingActivitiesPageTIAFragment on Organization {\n id\n transferImpactAssessments(first: 10) {\n totalCount\n edges {\n node {\n id\n dataSubjects\n transfer\n localLawRisk\n processingActivity {\n id\n name\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" } }; })(); -(node as any).hash = "4daedd61c0ba271c6d37811cef029da8"; +(node as any).hash = "bbd2c1907bd9e4607a0beb1bb12d0f11"; export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphNodeQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphNodeQuery.graphql.ts index 5d626c6a4..536ff7a06 100644 --- a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphNodeQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphNodeQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<736925258373b1116c286fc16d19ad7d>> + * @generated SignedSource<<65e5159bb6afd503a3dc92a2a87845ea>> * @lightSyntaxTransform * @nogrep */ @@ -9,8 +9,10 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; +export type ProcessingActivityDPIAResidualRisk = "HIGH" | "LOW" | "MEDIUM"; export type ProcessingActivityDataProtectionImpactAssessment = "NEEDED" | "NOT_NEEDED"; export type ProcessingActivityLawfulBasis = "CONSENT" | "CONTRACTUAL_NECESSITY" | "LEGAL_OBLIGATION" | "LEGITIMATE_INTEREST" | "PUBLIC_TASK" | "VITAL_INTERESTS"; +export type ProcessingActivityRole = "CONTROLLER" | "PROCESSOR"; export type ProcessingActivitySpecialOrCriminalDatum = "NO" | "POSSIBLE" | "YES"; export type ProcessingActivityTransferImpactAssessment = "NEEDED" | "NOT_NEEDED"; export type ProcessingActivityTransferSafeguard = "ADEQUACY_DECISION" | "BINDING_CORPORATE_RULES" | "CERTIFICATION_MECHANISMS" | "CODES_OF_CONDUCT" | "DEROGATIONS" | "STANDARD_CONTRACTUAL_CLAUSES"; @@ -23,12 +25,28 @@ export type ProcessingActivityGraphNodeQuery$data = { readonly consentEvidenceLink?: string | null | undefined; readonly createdAt?: any; readonly dataProtectionImpactAssessment?: ProcessingActivityDataProtectionImpactAssessment; + readonly dataProtectionOfficer?: { + readonly fullName: string; + readonly id: string; + } | null | undefined; readonly dataSubjectCategory?: string | null | undefined; + readonly dpia?: { + readonly createdAt: any; + readonly description: string | null | undefined; + readonly id: string; + readonly mitigations: string | null | undefined; + readonly necessityAndProportionality: string | null | undefined; + readonly potentialRisk: string | null | undefined; + readonly residualRisk: ProcessingActivityDPIAResidualRisk | null | undefined; + readonly updatedAt: any; + } | null | undefined; readonly id?: string; readonly internationalTransfers?: boolean; + readonly lastReviewDate?: any | null | undefined; readonly lawfulBasis?: ProcessingActivityLawfulBasis; readonly location?: string | null | undefined; readonly name?: string; + readonly nextReviewDate?: any | null | undefined; readonly organization?: { readonly id: string; readonly name: string; @@ -37,9 +55,20 @@ export type ProcessingActivityGraphNodeQuery$data = { readonly purpose?: string | null | undefined; readonly recipients?: string | null | undefined; readonly retentionPeriod?: string | null | undefined; + readonly role?: ProcessingActivityRole; readonly securityMeasures?: string | null | undefined; readonly snapshotId?: string | null | undefined; readonly specialOrCriminalData?: ProcessingActivitySpecialOrCriminalDatum; + readonly tia?: { + readonly createdAt: any; + readonly dataSubjects: string | null | undefined; + readonly id: string; + readonly legalMechanism: string | null | undefined; + readonly localLawRisk: string | null | undefined; + readonly supplementaryMeasures: string | null | undefined; + readonly transfer: string | null | undefined; + readonly updatedAt: any; + } | null | undefined; readonly transferImpactAssessment?: ProcessingActivityTransferImpactAssessment; readonly transferSafeguards?: ProcessingActivityTransferSafeguard | null | undefined; readonly updatedAt?: any; @@ -195,6 +224,46 @@ v18 = { "storageKey": null }, v19 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "lastReviewDate", + "storageKey": null +}, +v20 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "nextReviewDate", + "storageKey": null +}, +v21 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "role", + "storageKey": null +}, +v22 = { + "alias": null, + "args": null, + "concreteType": "People", + "kind": "LinkedField", + "name": "dataProtectionOfficer", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + } + ], + "storageKey": null +}, +v23 = { "alias": null, "args": [ { @@ -249,7 +318,119 @@ v19 = { ], "storageKey": "vendors(first:50)" }, -v20 = { +v24 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null +}, +v25 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null +}, +v26 = { + "alias": null, + "args": null, + "concreteType": "ProcessingActivityDPIA", + "kind": "LinkedField", + "name": "dpia", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "necessityAndProportionality", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "potentialRisk", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "mitigations", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "residualRisk", + "storageKey": null + }, + (v24/*: any*/), + (v25/*: any*/) + ], + "storageKey": null +}, +v27 = { + "alias": null, + "args": null, + "concreteType": "ProcessingActivityTIA", + "kind": "LinkedField", + "name": "tia", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "dataSubjects", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "legalMechanism", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "transfer", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "localLawRisk", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "supplementaryMeasures", + "storageKey": null + }, + (v24/*: any*/), + (v25/*: any*/) + ], + "storageKey": null +}, +v28 = { "alias": null, "args": null, "concreteType": "Organization", @@ -261,20 +442,6 @@ v20 = { (v4/*: any*/) ], "storageKey": null -}, -v21 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "createdAt", - "storageKey": null -}, -v22 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "updatedAt", - "storageKey": null }; return { "fragment": { @@ -314,7 +481,13 @@ return { (v19/*: any*/), (v20/*: any*/), (v21/*: any*/), - (v22/*: any*/) + (v22/*: any*/), + (v23/*: any*/), + (v26/*: any*/), + (v27/*: any*/), + (v28/*: any*/), + (v24/*: any*/), + (v25/*: any*/) ], "type": "ProcessingActivity", "abstractKey": null @@ -370,7 +543,13 @@ return { (v19/*: any*/), (v20/*: any*/), (v21/*: any*/), - (v22/*: any*/) + (v22/*: any*/), + (v23/*: any*/), + (v26/*: any*/), + (v27/*: any*/), + (v28/*: any*/), + (v24/*: any*/), + (v25/*: any*/) ], "type": "ProcessingActivity", "abstractKey": null @@ -381,16 +560,16 @@ return { ] }, "params": { - "cacheID": "9e9d13d95bf99c04488b8bdd313e8f33", + "cacheID": "8584062347b5ee761ed590f6019926be", "id": null, "metadata": {}, "name": "ProcessingActivityGraphNodeQuery", "operationKind": "query", - "text": "query ProcessingActivityGraphNodeQuery(\n $processingActivityId: ID!\n) {\n node(id: $processingActivityId) {\n __typename\n ... on ProcessingActivity {\n id\n snapshotId\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n specialOrCriminalData\n consentEvidenceLink\n lawfulBasis\n recipients\n location\n internationalTransfers\n transferSafeguards\n retentionPeriod\n securityMeasures\n dataProtectionImpactAssessment\n transferImpactAssessment\n vendors(first: 50) {\n edges {\n node {\n id\n name\n websiteUrl\n category\n }\n }\n }\n organization {\n id\n name\n }\n createdAt\n updatedAt\n }\n id\n }\n}\n" + "text": "query ProcessingActivityGraphNodeQuery(\n $processingActivityId: ID!\n) {\n node(id: $processingActivityId) {\n __typename\n ... on ProcessingActivity {\n id\n snapshotId\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n specialOrCriminalData\n consentEvidenceLink\n lawfulBasis\n recipients\n location\n internationalTransfers\n transferSafeguards\n retentionPeriod\n securityMeasures\n dataProtectionImpactAssessment\n transferImpactAssessment\n lastReviewDate\n nextReviewDate\n role\n dataProtectionOfficer {\n id\n fullName\n }\n vendors(first: 50) {\n edges {\n node {\n id\n name\n websiteUrl\n category\n }\n }\n }\n dpia {\n id\n description\n necessityAndProportionality\n potentialRisk\n mitigations\n residualRisk\n createdAt\n updatedAt\n }\n tia {\n id\n dataSubjects\n legalMechanism\n transfer\n localLawRisk\n supplementaryMeasures\n createdAt\n updatedAt\n }\n organization {\n id\n name\n }\n createdAt\n updatedAt\n }\n id\n }\n}\n" } }; })(); -(node as any).hash = "0112adb4f323533e0ce7a0922c5866d2"; +(node as any).hash = "317a9dae11ec982599b6efd6ef6e3187"; export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphUpdateDPIAMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphUpdateDPIAMutation.graphql.ts new file mode 100644 index 000000000..4a6055d3d --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphUpdateDPIAMutation.graphql.ts @@ -0,0 +1,167 @@ +/** + * @generated SignedSource<<17c0715666a53d67a24e1c5c860c182d>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type ProcessingActivityDPIAResidualRisk = "HIGH" | "LOW" | "MEDIUM"; +export type UpdateProcessingActivityDPIAInput = { + description?: string | null | undefined; + id: string; + mitigations?: string | null | undefined; + necessityAndProportionality?: string | null | undefined; + potentialRisk?: string | null | undefined; + residualRisk?: ProcessingActivityDPIAResidualRisk | null | undefined; +}; +export type ProcessingActivityGraphUpdateDPIAMutation$variables = { + input: UpdateProcessingActivityDPIAInput; +}; +export type ProcessingActivityGraphUpdateDPIAMutation$data = { + readonly updateProcessingActivityDPIA: { + readonly processingActivityDpia: { + readonly createdAt: any; + readonly description: string | null | undefined; + readonly id: string; + readonly mitigations: string | null | undefined; + readonly necessityAndProportionality: string | null | undefined; + readonly potentialRisk: string | null | undefined; + readonly residualRisk: ProcessingActivityDPIAResidualRisk | null | undefined; + readonly updatedAt: any; + }; + }; +}; +export type ProcessingActivityGraphUpdateDPIAMutation = { + response: ProcessingActivityGraphUpdateDPIAMutation$data; + variables: ProcessingActivityGraphUpdateDPIAMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "UpdateProcessingActivityDPIAPayload", + "kind": "LinkedField", + "name": "updateProcessingActivityDPIA", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ProcessingActivityDPIA", + "kind": "LinkedField", + "name": "processingActivityDpia", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "necessityAndProportionality", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "potentialRisk", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "mitigations", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "residualRisk", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ProcessingActivityGraphUpdateDPIAMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ProcessingActivityGraphUpdateDPIAMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "7b73761c8025d6f30a2fe6b9fdafff49", + "id": null, + "metadata": {}, + "name": "ProcessingActivityGraphUpdateDPIAMutation", + "operationKind": "mutation", + "text": "mutation ProcessingActivityGraphUpdateDPIAMutation(\n $input: UpdateProcessingActivityDPIAInput!\n) {\n updateProcessingActivityDPIA(input: $input) {\n processingActivityDpia {\n id\n description\n necessityAndProportionality\n potentialRisk\n mitigations\n residualRisk\n createdAt\n updatedAt\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "2a4a592df6f98848a7191288ceec2f18"; + +export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphUpdateMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphUpdateMutation.graphql.ts index de1b6dffc..f32f045a1 100644 --- a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphUpdateMutation.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphUpdateMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<7004a9f42c1d7e16eadf8adbdb613b2a>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -11,22 +11,27 @@ import { ConcreteRequest } from 'relay-runtime'; export type ProcessingActivityDataProtectionImpactAssessment = "NEEDED" | "NOT_NEEDED"; export type ProcessingActivityLawfulBasis = "CONSENT" | "CONTRACTUAL_NECESSITY" | "LEGAL_OBLIGATION" | "LEGITIMATE_INTEREST" | "PUBLIC_TASK" | "VITAL_INTERESTS"; +export type ProcessingActivityRole = "CONTROLLER" | "PROCESSOR"; export type ProcessingActivitySpecialOrCriminalDatum = "NO" | "POSSIBLE" | "YES"; export type ProcessingActivityTransferImpactAssessment = "NEEDED" | "NOT_NEEDED"; export type ProcessingActivityTransferSafeguard = "ADEQUACY_DECISION" | "BINDING_CORPORATE_RULES" | "CERTIFICATION_MECHANISMS" | "CODES_OF_CONDUCT" | "DEROGATIONS" | "STANDARD_CONTRACTUAL_CLAUSES"; export type UpdateProcessingActivityInput = { consentEvidenceLink?: string | null | undefined; dataProtectionImpactAssessment?: ProcessingActivityDataProtectionImpactAssessment | null | undefined; + dataProtectionOfficerId?: string | null | undefined; dataSubjectCategory?: string | null | undefined; id: string; internationalTransfers?: boolean | null | undefined; + lastReviewDate?: any | null | undefined; lawfulBasis?: ProcessingActivityLawfulBasis | null | undefined; location?: string | null | undefined; name?: string | null | undefined; + nextReviewDate?: any | null | undefined; personalDataCategory?: string | null | undefined; purpose?: string | null | undefined; recipients?: string | null | undefined; retentionPeriod?: string | null | undefined; + role?: ProcessingActivityRole | null | undefined; securityMeasures?: string | null | undefined; specialOrCriminalData?: ProcessingActivitySpecialOrCriminalDatum | null | undefined; transferImpactAssessment?: ProcessingActivityTransferImpactAssessment | null | undefined; @@ -41,16 +46,23 @@ export type ProcessingActivityGraphUpdateMutation$data = { readonly processingActivity: { readonly consentEvidenceLink: string | null | undefined; readonly dataProtectionImpactAssessment: ProcessingActivityDataProtectionImpactAssessment; + readonly dataProtectionOfficer: { + readonly fullName: string; + readonly id: string; + } | null | undefined; readonly dataSubjectCategory: string | null | undefined; readonly id: string; readonly internationalTransfers: boolean; + readonly lastReviewDate: any | null | undefined; readonly lawfulBasis: ProcessingActivityLawfulBasis; readonly location: string | null | undefined; readonly name: string; + readonly nextReviewDate: any | null | undefined; readonly personalDataCategory: string | null | undefined; readonly purpose: string | null | undefined; readonly recipients: string | null | undefined; readonly retentionPeriod: string | null | undefined; + readonly role: ProcessingActivityRole; readonly securityMeasures: string | null | undefined; readonly specialOrCriminalData: ProcessingActivitySpecialOrCriminalDatum; readonly transferImpactAssessment: ProcessingActivityTransferImpactAssessment; @@ -218,6 +230,46 @@ v3 = [ "name": "transferImpactAssessment", "storageKey": null }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "lastReviewDate", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "nextReviewDate", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "role", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "People", + "kind": "LinkedField", + "name": "dataProtectionOfficer", + "plural": false, + "selections": [ + (v1/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + } + ], + "storageKey": null + }, { "alias": null, "args": [ @@ -298,16 +350,16 @@ return { "selections": (v3/*: any*/) }, "params": { - "cacheID": "8050213c76270c28b5543a629a956d47", + "cacheID": "c67a2cee083821566c9379f74360c489", "id": null, "metadata": {}, "name": "ProcessingActivityGraphUpdateMutation", "operationKind": "mutation", - "text": "mutation ProcessingActivityGraphUpdateMutation(\n $input: UpdateProcessingActivityInput!\n) {\n updateProcessingActivity(input: $input) {\n processingActivity {\n id\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n specialOrCriminalData\n consentEvidenceLink\n lawfulBasis\n recipients\n location\n internationalTransfers\n transferSafeguards\n retentionPeriod\n securityMeasures\n dataProtectionImpactAssessment\n transferImpactAssessment\n vendors(first: 50) {\n edges {\n node {\n id\n name\n websiteUrl\n }\n }\n }\n updatedAt\n }\n }\n}\n" + "text": "mutation ProcessingActivityGraphUpdateMutation(\n $input: UpdateProcessingActivityInput!\n) {\n updateProcessingActivity(input: $input) {\n processingActivity {\n id\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n specialOrCriminalData\n consentEvidenceLink\n lawfulBasis\n recipients\n location\n internationalTransfers\n transferSafeguards\n retentionPeriod\n securityMeasures\n dataProtectionImpactAssessment\n transferImpactAssessment\n lastReviewDate\n nextReviewDate\n role\n dataProtectionOfficer {\n id\n fullName\n }\n vendors(first: 50) {\n edges {\n node {\n id\n name\n websiteUrl\n }\n }\n }\n updatedAt\n }\n }\n}\n" } }; })(); -(node as any).hash = "cb14a2c41f4690c0079a185c8caad3f4"; +(node as any).hash = "31dcb6c411d7ffd7a63eb9941f4f2609"; export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphUpdateTIAMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphUpdateTIAMutation.graphql.ts new file mode 100644 index 000000000..e2cd21f18 --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphUpdateTIAMutation.graphql.ts @@ -0,0 +1,166 @@ +/** + * @generated SignedSource<> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type UpdateProcessingActivityTIAInput = { + dataSubjects?: string | null | undefined; + id: string; + legalMechanism?: string | null | undefined; + localLawRisk?: string | null | undefined; + supplementaryMeasures?: string | null | undefined; + transfer?: string | null | undefined; +}; +export type ProcessingActivityGraphUpdateTIAMutation$variables = { + input: UpdateProcessingActivityTIAInput; +}; +export type ProcessingActivityGraphUpdateTIAMutation$data = { + readonly updateProcessingActivityTIA: { + readonly processingActivityTia: { + readonly createdAt: any; + readonly dataSubjects: string | null | undefined; + readonly id: string; + readonly legalMechanism: string | null | undefined; + readonly localLawRisk: string | null | undefined; + readonly supplementaryMeasures: string | null | undefined; + readonly transfer: string | null | undefined; + readonly updatedAt: any; + }; + }; +}; +export type ProcessingActivityGraphUpdateTIAMutation = { + response: ProcessingActivityGraphUpdateTIAMutation$data; + variables: ProcessingActivityGraphUpdateTIAMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "UpdateProcessingActivityTIAPayload", + "kind": "LinkedField", + "name": "updateProcessingActivityTIA", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ProcessingActivityTIA", + "kind": "LinkedField", + "name": "processingActivityTia", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "dataSubjects", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "legalMechanism", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "transfer", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "localLawRisk", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "supplementaryMeasures", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ProcessingActivityGraphUpdateTIAMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ProcessingActivityGraphUpdateTIAMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "d596534ba9782fe47b15cd56e008db42", + "id": null, + "metadata": {}, + "name": "ProcessingActivityGraphUpdateTIAMutation", + "operationKind": "mutation", + "text": "mutation ProcessingActivityGraphUpdateTIAMutation(\n $input: UpdateProcessingActivityTIAInput!\n) {\n updateProcessingActivityTIA(input: $input) {\n processingActivityTia {\n id\n dataSubjects\n legalMechanism\n transfer\n localLawRisk\n supplementaryMeasures\n createdAt\n updatedAt\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "a669ab652dd3687dff4069814b3ea0e8"; + +export default node; diff --git a/apps/console/src/pages/organizations/processingActivities/ProcessingActivitiesPage.tsx b/apps/console/src/pages/organizations/processingActivities/ProcessingActivitiesPage.tsx index 9c59472ad..c22ac2d00 100644 --- a/apps/console/src/pages/organizations/processingActivities/ProcessingActivitiesPage.tsx +++ b/apps/console/src/pages/organizations/processingActivities/ProcessingActivitiesPage.tsx @@ -14,10 +14,12 @@ import { IconTrashCan, Table, useConfirm, + Tabs, + TabItem, } from "@probo/ui"; import { useTranslate } from "@probo/i18n"; import { usePageTitle } from "@probo/hooks"; -import { getLawfulBasisLabel } from "../../../components/form/ProcessingActivityEnumOptions"; +import { getLawfulBasisLabel, getResidualRiskLabel } from "../../../components/form/ProcessingActivityEnumOptions"; import { ConnectionHandler, graphql, @@ -37,8 +39,16 @@ import type { ProcessingActivitiesPageFragment$key, ProcessingActivitiesPageFragment$data, } from "./__generated__/ProcessingActivitiesPageFragment.graphql"; +import type { + ProcessingActivitiesPageDPIAFragment$key, + ProcessingActivitiesPageDPIAFragment$data, +} from "./__generated__/ProcessingActivitiesPageDPIAFragment.graphql"; +import type { + ProcessingActivitiesPageTIAFragment$key, + ProcessingActivitiesPageTIAFragment$data, +} from "./__generated__/ProcessingActivitiesPageTIAFragment.graphql"; import { PermissionsContext } from "/providers/PermissionsContext"; -import { use } from "react"; +import { use, useState } from "react"; import type { ProcessingActivityGraphListQuery } from "/hooks/graph/__generated__/ProcessingActivityGraphListQuery.graphql"; interface ProcessingActivitiesPageProps { @@ -86,12 +96,87 @@ const processingActivitiesPageFragment = graphql` } `; +const dpiaListPageFragment = graphql` + fragment ProcessingActivitiesPageDPIAFragment on Organization + @refetchable(queryName: "ProcessingActivitiesPageDPIARefetchQuery") + @argumentDefinitions( + first: { type: "Int", defaultValue: 10 } + after: { type: "CursorKey" } + ) { + id + dataProtectionImpactAssessments( + first: $first + after: $after + ) + @connection(key: "ProcessingActivitiesPage_dataProtectionImpactAssessments") { + __id + totalCount + edges { + node { + id + description + potentialRisk + residualRisk + processingActivity { + id + name + } + createdAt + updatedAt + } + } + pageInfo { + hasNextPage + endCursor + } + } + } +`; + +const tiaListPageFragment = graphql` + fragment ProcessingActivitiesPageTIAFragment on Organization + @refetchable(queryName: "ProcessingActivitiesPageTIARefetchQuery") + @argumentDefinitions( + first: { type: "Int", defaultValue: 10 } + after: { type: "CursorKey" } + ) { + id + transferImpactAssessments( + first: $first + after: $after + ) + @connection(key: "ProcessingActivitiesPage_transferImpactAssessments") { + __id + totalCount + edges { + node { + id + dataSubjects + transfer + localLawRisk + processingActivity { + id + name + } + createdAt + updatedAt + } + } + pageInfo { + hasNextPage + endCursor + } + } + } +`; + export default function ProcessingActivitiesPage({ queryRef }: ProcessingActivitiesPageProps) { const { __ } = useTranslate(); const organizationId = useOrganizationId(); const { snapshotId } = useParams<{ snapshotId?: string }>(); const isSnapshotMode = Boolean(snapshotId); const { isAuthorized } = use(PermissionsContext); + const [activeTab, setActiveTab] = useState<"activities" | "dpia" | "tia">("activities"); usePageTitle(__("Processing Activities")); @@ -101,21 +186,43 @@ export default function ProcessingActivitiesPage({ queryRef }: ProcessingActivit ); const { - data, - loadNext, - hasNext, - isLoadingNext, + data: activitiesData, + loadNext: loadNextActivities, + hasNext: hasNextActivities, + isLoadingNext: isLoadingNextActivities, } = usePaginationFragment< ProcessingActivityGraphListQuery, ProcessingActivitiesPageFragment$key >(processingActivitiesPageFragment, organization.node); + const { + data: dpiaData, + loadNext: loadNextDPIAs, + hasNext: hasNextDPIAs, + isLoadingNext: isLoadingNextDPIAs, + } = usePaginationFragment< + ProcessingActivityGraphListQuery, + ProcessingActivitiesPageDPIAFragment$key + >(dpiaListPageFragment, organization.node); + + const { + data: tiaData, + loadNext: loadNextTIAs, + hasNext: hasNextTIAs, + isLoadingNext: isLoadingNextTIAs, + } = usePaginationFragment< + ProcessingActivityGraphListQuery, + ProcessingActivitiesPageTIAFragment$key + >(tiaListPageFragment, organization.node); + const connectionId = ConnectionHandler.getConnectionID( organizationId, ProcessingActivitiesConnectionKey, { filter: { snapshotId: snapshotId || null } } ); - const activities = data?.processingActivities?.edges?.map((edge) => edge.node) ?? []; + const activities = activitiesData?.processingActivities?.edges?.map((edge) => edge.node) ?? []; + const dpias = dpiaData?.dataProtectionImpactAssessments?.edges?.map((edge) => edge.node) ?? []; + const tias = tiaData?.transferImpactAssessments?.edges?.map((edge) => edge.node) ?? []; const hasAnyAction = !isSnapshotMode && ( isAuthorized("ProcessingActivity", "updateProcessingActivity") || @@ -128,7 +235,7 @@ export default function ProcessingActivitiesPage({ queryRef }: ProcessingActivit )} - {!isSnapshotMode && ( + {!isSnapshotMode && activeTab === "activities" && ( isAuthorized("Organization", "createProcessingActivity") && ( - {activities.length > 0 ? ( - - - - - - - - - - - {hasAnyAction && } - - - - {activities.map((activity) => ( - - ))} - -
{__("Name")}{__("Purpose")}{__("Data Subject")}{__("Lawful Basis")}{__("Location")}{__("International Transfers")}{__("Actions")}
+ + setActiveTab("activities")}> + {__("Processing Activities")} + + setActiveTab("dpia")}> + {__("Data Protection Impact Assessments")} + + setActiveTab("tia")}> + {__("Transfer Impact Assessments")} + + - {hasNext && ( -
- -
+ {activeTab === "activities" && ( + <> + {activities.length > 0 ? ( + + + + + + + + + + + {hasAnyAction && } + + + + {activities.map((activity) => ( + + ))} + +
{__("Name")}{__("Purpose")}{__("Data Subject")}{__("Lawful Basis")}{__("Location")}{__("International Transfers")}{__("Actions")}
+ + {hasNextActivities && ( +
+ +
+ )} +
+ ) : ( + +
+

+ {__("No processing activities yet")} +

+

+ {__("Create your first processing activity to get started with GDPR compliance.")} +

+
+
)} -
- ) : ( - -
-

- {__("No processing activities yet")} -

-

- {__("Create your first processing activity to get started with GDPR compliance.")} -

-
-
+ + )} + + {activeTab === "dpia" && ( + <> + {dpias.length > 0 ? ( + + + + + + + + + + + + {dpias.map((dpia) => ( + + ))} + +
{__("Processing Activity")}{__("Description")}{__("Potential Risk")}{__("Residual Risk")}
+ + {hasNextDPIAs && ( +
+ +
+ )} +
+ ) : ( + +
+

+ {__("No Data Protection Impact Assessments yet")} +

+

+ {__("DPIAs are created from within individual processing activities.")} +

+
+
+ )} + + )} + + {activeTab === "tia" && ( + <> + {tias.length > 0 ? ( + + + + + + + + + + + + {tias.map((tia) => ( + + ))} + +
{__("Processing Activity")}{__("Data Subjects")}{__("Transfer")}{__("Local Law Risk")}
+ + {hasNextTIAs && ( +
+ +
+ )} +
+ ) : ( + +
+

+ {__("No Transfer Impact Assessments yet")} +

+

+ {__("TIAs are created from within individual processing activities.")} +

+
+
+ )} + )} ); @@ -275,3 +492,80 @@ function ActivityRow({ ); } + +function DPIARow({ + dpia, +}: { + dpia: NodeOf>; +}) { + const organizationId = useOrganizationId(); + const { __ } = useTranslate(); + const { snapshotId } = useParams<{ snapshotId?: string }>(); + const isSnapshotMode = Boolean(snapshotId); + + const activityUrl = isSnapshotMode && snapshotId + ? `/organizations/${organizationId}/snapshots/${snapshotId}/processing-activities/${dpia.processingActivity.id}#dpia` + : `/organizations/${organizationId}/processing-activities/${dpia.processingActivity.id}#dpia`; + + return ( + + + {dpia.processingActivity.name} + + + + {dpia.description || "-"} + + + + + {dpia.potentialRisk || "-"} + + + + {dpia.residualRisk ? ( + + {getResidualRiskLabel(dpia.residualRisk, __)} + + ) : "-"} + + + ); +} + +function TIARow({ + tia, +}: { + tia: NodeOf>; +}) { + const organizationId = useOrganizationId(); + const { snapshotId } = useParams<{ snapshotId?: string }>(); + const isSnapshotMode = Boolean(snapshotId); + + const activityUrl = isSnapshotMode && snapshotId + ? `/organizations/${organizationId}/snapshots/${snapshotId}/processing-activities/${tia.processingActivity.id}#tia` + : `/organizations/${organizationId}/processing-activities/${tia.processingActivity.id}#tia`; + + return ( + + + {tia.processingActivity.name} + + + + {tia.dataSubjects || "-"} + + + + + {tia.transfer || "-"} + + + + + {tia.localLawRisk || "-"} + + + + ); +} diff --git a/apps/console/src/pages/organizations/processingActivities/ProcessingActivityDetailsPage.tsx b/apps/console/src/pages/organizations/processingActivities/ProcessingActivityDetailsPage.tsx index de666bf9d..9b64903d3 100644 --- a/apps/console/src/pages/organizations/processingActivities/ProcessingActivityDetailsPage.tsx +++ b/apps/console/src/pages/organizations/processingActivities/ProcessingActivityDetailsPage.tsx @@ -7,7 +7,14 @@ import { processingActivityNodeQuery, useDeleteProcessingActivity, useUpdateProcessingActivity, + useCreateProcessingActivityDPIA, + useUpdateProcessingActivityDPIA, + useDeleteProcessingActivityDPIA, + useCreateProcessingActivityTIA, + useUpdateProcessingActivityTIA, + useDeleteProcessingActivityTIA, ProcessingActivitiesConnectionKey, + type ProcessingActivityDPIAResidualRisk, } from "../../../hooks/graph/ProcessingActivityGraph"; import { ActionDropdown, @@ -21,27 +28,33 @@ import { Label, Checkbox, Select, + Input, + Option, + Tabs, + TabItem, } from "@probo/ui"; import { useTranslate } from "@probo/i18n"; import { useOrganizationId } from "/hooks/useOrganizationId"; import { useParams } from "react-router"; import { useFormWithSchema } from "/hooks/useFormWithSchema"; -import { Controller } from "react-hook-form"; +import { Controller, useForm } from "react-hook-form"; import { formatError, type GraphQLError } from "@probo/helpers"; import z from "zod"; -import { validateSnapshotConsistency } from "@probo/helpers"; +import { validateSnapshotConsistency, formatDatetime, toDateInput } from "@probo/helpers"; import { SnapshotBanner } from "/components/SnapshotBanner"; import { VendorsMultiSelectField } from "/components/form/VendorsMultiSelectField"; +import { PeopleSelectField } from "/components/form/PeopleSelectField"; import { SpecialOrCriminalDataOptions, LawfulBasisOptions, TransferSafeguardsOptions, DataProtectionImpactAssessmentOptions, TransferImpactAssessmentOptions, + RoleOptions, } from "../../../components/form/ProcessingActivityEnumOptions"; import type { ProcessingActivityGraphNodeQuery } from "/hooks/graph/__generated__/ProcessingActivityGraphNodeQuery.graphql"; -import { use } from "react"; +import { use, useState, useEffect } from "react"; import { PermissionsContext } from "/providers/PermissionsContext"; const updateProcessingActivitySchema = z.object({ @@ -60,6 +73,10 @@ const updateProcessingActivitySchema = z.object({ securityMeasures: z.string().optional(), dataProtectionImpactAssessment: z.enum(["NEEDED", "NOT_NEEDED"] as const), transferImpactAssessment: z.enum(["NEEDED", "NOT_NEEDED"] as const), + lastReviewDate: z.string().optional(), + nextReviewDate: z.string().optional(), + role: z.enum(["CONTROLLER", "PROCESSOR"] as const), + dataProtectionOfficerId: z.string().optional(), vendorIds: z.array(z.string()).optional(), }); @@ -77,9 +94,65 @@ export default function ProcessingActivityDetailsPage(props: Props) { const isSnapshotMode = Boolean(snapshotId); const { isAuthorized } = use(PermissionsContext); + // Get initial tab from URL hash + const getInitialTab = (): "overview" | "dpia" | "tia" => { + const hash = window.location.hash.slice(1); + if (hash === "dpia" || hash === "tia") return hash; + return "overview"; + }; + + const [activeTab, setActiveTab] = useState<"overview" | "dpia" | "tia">(getInitialTab); + const [dpiaSubmitting, setDpiaSubmitting] = useState(false); + const [tiaSubmitting, setTiaSubmitting] = useState(false); + const [showDpiaForm, setShowDpiaForm] = useState(Boolean(activity?.dpia?.id)); + const [showTiaForm, setShowTiaForm] = useState(Boolean(activity?.tia?.id)); + const [dpiaDeleted, setDpiaDeleted] = useState(false); + const [tiaDeleted, setTiaDeleted] = useState(false); + + // Update URL hash when tab changes + useEffect(() => { + window.location.hash = activeTab === "overview" ? "" : activeTab; + }, [activeTab]); + validateSnapshotConsistency(activity, snapshotId); const updateActivity = useUpdateProcessingActivity(); + const createDPIA = useCreateProcessingActivityDPIA(); + const updateDPIA = useUpdateProcessingActivityDPIA(); + const deleteDPIA = useDeleteProcessingActivityDPIA( + { id: activity?.dpia?.id || "" }, + { + onSuccess: () => { + setDpiaDeleted(true); + setShowDpiaForm(false); + dpiaForm.reset({ + description: "", + necessityAndProportionality: "", + potentialRisk: "", + mitigations: "", + residualRisk: "", + }); + }, + } + ); + const createTIA = useCreateProcessingActivityTIA(); + const updateTIA = useUpdateProcessingActivityTIA(); + const deleteTIA = useDeleteProcessingActivityTIA( + { id: activity?.tia?.id || "" }, + { + onSuccess: () => { + setTiaDeleted(true); + setShowTiaForm(false); + tiaForm.reset({ + dataSubjects: "", + legalMechanism: "", + transfer: "", + localLawRisk: "", + supplementaryMeasures: "", + }); + }, + } + ); const connectionId = ConnectionHandler.getConnectionID( organizationId, @@ -111,11 +184,35 @@ export default function ProcessingActivityDetailsPage(props: Props) { securityMeasures: activity.securityMeasures || "", dataProtectionImpactAssessment: activity.dataProtectionImpactAssessment || "NOT_NEEDED" as const, transferImpactAssessment: activity.transferImpactAssessment || "NOT_NEEDED" as const, + lastReviewDate: toDateInput(activity.lastReviewDate), + nextReviewDate: toDateInput(activity.nextReviewDate), + role: activity.role || "CONTROLLER" as const, + dataProtectionOfficerId: activity.dataProtectionOfficer?.id || "", vendorIds: vendorIds, }, } ); + const dpiaForm = useForm({ + defaultValues: { + description: activity?.dpia?.description || "", + necessityAndProportionality: activity?.dpia?.necessityAndProportionality || "", + potentialRisk: activity?.dpia?.potentialRisk || "", + mitigations: activity?.dpia?.mitigations || "", + residualRisk: (activity?.dpia?.residualRisk || "") as ProcessingActivityDPIAResidualRisk | "", + }, + }); + + const tiaForm = useForm({ + defaultValues: { + dataSubjects: activity?.tia?.dataSubjects || "", + legalMechanism: activity?.tia?.legalMechanism || "", + transfer: activity?.tia?.transfer || "", + localLawRisk: activity?.tia?.localLawRisk || "", + supplementaryMeasures: activity?.tia?.supplementaryMeasures || "", + }, + }); + const onSubmit = handleSubmit(async (formData) => { try { await updateActivity({ @@ -135,6 +232,10 @@ export default function ProcessingActivityDetailsPage(props: Props) { securityMeasures: formData.securityMeasures || undefined, dataProtectionImpactAssessment: formData.dataProtectionImpactAssessment || undefined, transferImpactAssessment: formData.transferImpactAssessment || undefined, + lastReviewDate: formatDatetime(formData.lastReviewDate) ?? null, + nextReviewDate: formatDatetime(formData.nextReviewDate) ?? null, + role: formData.role, + dataProtectionOfficerId: formData.dataProtectionOfficerId || null, vendorIds: formData.vendorIds, }); @@ -152,6 +253,100 @@ export default function ProcessingActivityDetailsPage(props: Props) { } }); + const onDPIASubmit = dpiaForm.handleSubmit(async (formData) => { + setDpiaSubmitting(true); + try { + const isCreating = !activity?.dpia?.id || dpiaDeleted; + if (!isCreating) { + // Update existing DPIA + await updateDPIA({ + id: activity.dpia!.id, + description: formData.description || undefined, + necessityAndProportionality: formData.necessityAndProportionality || undefined, + potentialRisk: formData.potentialRisk || undefined, + mitigations: formData.mitigations || undefined, + residualRisk: formData.residualRisk as ProcessingActivityDPIAResidualRisk || undefined, + }); + toast({ + title: __("Success"), + description: __("DPIA updated successfully"), + variant: "success", + }); + } else { + // Create new DPIA + await createDPIA({ + processingActivityId: activity.id!, + description: formData.description || undefined, + necessityAndProportionality: formData.necessityAndProportionality || undefined, + potentialRisk: formData.potentialRisk || undefined, + mitigations: formData.mitigations || undefined, + residualRisk: formData.residualRisk as ProcessingActivityDPIAResidualRisk || undefined, + }); + setDpiaDeleted(false); + toast({ + title: __("Success"), + description: __("DPIA created successfully"), + variant: "success", + }); + } + } catch (error) { + toast({ + title: __("Error"), + description: formatError(__("Failed to save DPIA"), error as GraphQLError), + variant: "error", + }); + } finally { + setDpiaSubmitting(false); + } + }); + + const onTIASubmit = tiaForm.handleSubmit(async (formData) => { + setTiaSubmitting(true); + try { + const isCreating = !activity?.tia?.id || tiaDeleted; + if (!isCreating) { + // Update existing TIA + await updateTIA({ + id: activity.tia!.id, + dataSubjects: formData.dataSubjects || undefined, + legalMechanism: formData.legalMechanism || undefined, + transfer: formData.transfer || undefined, + localLawRisk: formData.localLawRisk || undefined, + supplementaryMeasures: formData.supplementaryMeasures || undefined, + }); + toast({ + title: __("Success"), + description: __("TIA updated successfully"), + variant: "success", + }); + } else { + // Create new TIA + await createTIA({ + processingActivityId: activity.id!, + dataSubjects: formData.dataSubjects || undefined, + legalMechanism: formData.legalMechanism || undefined, + transfer: formData.transfer || undefined, + localLawRisk: formData.localLawRisk || undefined, + supplementaryMeasures: formData.supplementaryMeasures || undefined, + }); + setTiaDeleted(false); + toast({ + title: __("Success"), + description: __("TIA created successfully"), + variant: "success", + }); + } + } catch (error) { + toast({ + title: __("Error"), + description: formatError(__("Failed to save TIA"), error as GraphQLError), + variant: "error", + }); + } finally { + setTiaSubmitting(false); + } + }); + const breadcrumbProcessingActivitiesUrl = isSnapshotMode && snapshotId ? `/organizations/${organizationId}/snapshots/${snapshotId}/processing-activities` : `/organizations/${organizationId}/processing-activities`; @@ -179,249 +374,563 @@ export default function ProcessingActivityDetailsPage(props: Props) { )} - -
-
-
-

{activity.name}

-
-
+
+

{activity.name}

+
-
-
-
- + + setActiveTab("overview")}> + {__("Overview")} + + setActiveTab("dpia")}> + {__("Data Protection Impact Assessment")} + + setActiveTab("tia")}> + {__("Transfer Impact Assessment")} + + -
- -