diff --git a/apps/console/src/components/__generated__/SnapshotBannerQuery.graphql.ts b/apps/console/src/components/__generated__/SnapshotBannerQuery.graphql.ts index b7dc37aa3..af2ccc87e 100644 --- a/apps/console/src/components/__generated__/SnapshotBannerQuery.graphql.ts +++ b/apps/console/src/components/__generated__/SnapshotBannerQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<849144f476ae613437242fe09259fc68>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; -export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "RISKS" | "VENDORS"; +export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "PROCESSING_ACTIVITY_REGISTRIES" | "RISKS" | "VENDORS"; export type SnapshotBannerQuery$variables = { snapshotId: string; }; diff --git a/apps/console/src/components/snapshots/__generated__/LinkedSnapshotsCardFragment.graphql.ts b/apps/console/src/components/snapshots/__generated__/LinkedSnapshotsCardFragment.graphql.ts index edd19d312..b242bf7bd 100644 --- a/apps/console/src/components/snapshots/__generated__/LinkedSnapshotsCardFragment.graphql.ts +++ b/apps/console/src/components/snapshots/__generated__/LinkedSnapshotsCardFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<4856a36194f867773166e9420b403d0b>> + * @generated SignedSource<<449a3fe1cc57900bccd7085aa6c4eae8>> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ReaderFragment } from 'relay-runtime'; -export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "RISKS" | "VENDORS"; +export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "PROCESSING_ACTIVITY_REGISTRIES" | "RISKS" | "VENDORS"; import { FragmentRefs } from "relay-runtime"; export type LinkedSnapshotsCardFragment$data = { readonly createdAt: any; diff --git a/apps/console/src/components/snapshots/__generated__/LinkedSnapshotsDialogFragment.graphql.ts b/apps/console/src/components/snapshots/__generated__/LinkedSnapshotsDialogFragment.graphql.ts index 61b3217f2..390ec60d4 100644 --- a/apps/console/src/components/snapshots/__generated__/LinkedSnapshotsDialogFragment.graphql.ts +++ b/apps/console/src/components/snapshots/__generated__/LinkedSnapshotsDialogFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<1348b159bfe8d53aa1b080efc63bd1b4>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ReaderFragment } from 'relay-runtime'; -export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "RISKS" | "VENDORS"; +export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "PROCESSING_ACTIVITY_REGISTRIES" | "RISKS" | "VENDORS"; import { FragmentRefs } from "relay-runtime"; export type LinkedSnapshotsDialogFragment$data = { readonly id: string; diff --git a/apps/console/src/hooks/graph/ProcessingActivityRegistryGraph.ts b/apps/console/src/hooks/graph/ProcessingActivityRegistryGraph.ts index 9bf9efbfd..4e6b0555d 100644 --- a/apps/console/src/hooks/graph/ProcessingActivityRegistryGraph.ts +++ b/apps/console/src/hooks/graph/ProcessingActivityRegistryGraph.ts @@ -8,10 +8,10 @@ import { useMutationWithToasts } from "../useMutationWithToasts"; export const ProcessingActivityRegistriesConnectionKey = "ProcessingActivityRegistriesPage_processingActivityRegistries"; export const processingActivityRegistriesQuery = graphql` - query ProcessingActivityRegistryGraphListQuery($organizationId: ID!) { + query ProcessingActivityRegistryGraphListQuery($organizationId: ID!, $snapshotId: ID) { node(id: $organizationId) { ... on Organization { - ...ProcessingActivityRegistriesPageFragment + ...ProcessingActivityRegistriesPageFragment @arguments(snapshotId: $snapshotId) } } } @@ -22,6 +22,7 @@ export const processingActivityRegistryNodeQuery = graphql` node(id: $processingActivityRegistryId) { ... on ProcessingActivityRegistry { id + snapshotId name purpose dataSubjectCategory diff --git a/apps/console/src/hooks/graph/__generated__/ProcessingActivityRegistryGraphListQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/ProcessingActivityRegistryGraphListQuery.graphql.ts index eb82dc2ef..daa5f6c09 100644 --- a/apps/console/src/hooks/graph/__generated__/ProcessingActivityRegistryGraphListQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/ProcessingActivityRegistryGraphListQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<8f505e33f8bc537835367f0f54547998>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -12,6 +12,7 @@ import { ConcreteRequest } from 'relay-runtime'; import { FragmentRefs } from "relay-runtime"; export type ProcessingActivityRegistryGraphListQuery$variables = { organizationId: string; + snapshotId?: string | null | undefined; }; export type ProcessingActivityRegistryGraphListQuery$data = { readonly node: { @@ -29,6 +30,11 @@ var v0 = [ "defaultValue": null, "kind": "LocalArgument", "name": "organizationId" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "snapshotId" } ], v1 = [ @@ -38,21 +44,33 @@ v1 = [ "variableName": "organizationId" } ], -v2 = { +v2 = [ + { + "kind": "Variable", + "name": "snapshotId", + "variableName": "snapshotId" + } +], +v3 = { "alias": null, "args": null, "kind": "ScalarField", "name": "__typename", "storageKey": null }, -v3 = { +v4 = { "alias": null, "args": null, "kind": "ScalarField", "name": "id", "storageKey": null }, -v4 = [ +v5 = [ + { + "fields": (v2/*: any*/), + "kind": "ObjectValue", + "name": "filter" + }, { "kind": "Literal", "name": "first", @@ -78,7 +96,7 @@ return { "kind": "InlineFragment", "selections": [ { - "args": null, + "args": (v2/*: any*/), "kind": "FragmentSpread", "name": "ProcessingActivityRegistriesPageFragment" } @@ -107,14 +125,14 @@ return { "name": "node", "plural": false, "selections": [ - (v2/*: any*/), (v3/*: any*/), + (v4/*: any*/), { "kind": "InlineFragment", "selections": [ { "alias": null, - "args": (v4/*: any*/), + "args": (v5/*: any*/), "concreteType": "ProcessingActivityRegistryConnection", "kind": "LinkedField", "name": "processingActivityRegistries", @@ -143,7 +161,21 @@ return { "name": "node", "plural": false, "selections": [ - (v3/*: any*/), + (v4/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "snapshotId", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "sourceId", + "storageKey": null + }, { "alias": null, "args": null, @@ -207,7 +239,7 @@ return { "name": "updatedAt", "storageKey": null }, - (v2/*: any*/) + (v3/*: any*/) ], "storageKey": null }, @@ -259,12 +291,14 @@ return { ] } ], - "storageKey": "processingActivityRegistries(first:10)" + "storageKey": null }, { "alias": null, - "args": (v4/*: any*/), - "filters": null, + "args": (v5/*: any*/), + "filters": [ + "filter" + ], "handle": "connection", "key": "ProcessingActivityRegistriesPage_processingActivityRegistries", "kind": "LinkedHandle", @@ -280,16 +314,16 @@ return { ] }, "params": { - "cacheID": "720254aa19136fdf96cc29e26f980533", + "cacheID": "47f8a2cccc6749482bf09e1a1a57271d", "id": null, "metadata": {}, "name": "ProcessingActivityRegistryGraphListQuery", "operationKind": "query", - "text": "query ProcessingActivityRegistryGraphListQuery(\n $organizationId: ID!\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ProcessingActivityRegistriesPageFragment\n }\n id\n }\n}\n\nfragment ProcessingActivityRegistriesPageFragment on Organization {\n id\n processingActivityRegistries(first: 10) {\n totalCount\n edges {\n node {\n id\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 ProcessingActivityRegistryGraphListQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ProcessingActivityRegistriesPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ProcessingActivityRegistriesPageFragment_3iomuz on Organization {\n id\n processingActivityRegistries(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" } }; })(); -(node as any).hash = "c4a1ee426fd64c8605134d80ee873b62"; +(node as any).hash = "5b5316031782bbd4db8109a18b307430"; export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ProcessingActivityRegistryGraphNodeQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/ProcessingActivityRegistryGraphNodeQuery.graphql.ts index 6bb359792..84871b775 100644 --- a/apps/console/src/hooks/graph/__generated__/ProcessingActivityRegistryGraphNodeQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/ProcessingActivityRegistryGraphNodeQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<4453e7e28a9c546de765219f287f129a>> * @lightSyntaxTransform * @nogrep */ @@ -37,6 +37,8 @@ export type ProcessingActivityRegistryGraphNodeQuery$data = { readonly recipients?: string | null | undefined; readonly retentionPeriod?: string | null | undefined; readonly securityMeasures?: string | null | undefined; + readonly snapshotId?: string | null | undefined; + readonly sourceId?: string | null | undefined; readonly specialOrCriminalData?: ProcessingActivityRegistrySpecialOrCriminalData; readonly transferImpactAssessment?: ProcessingActivityRegistryTransferImpactAssessment; readonly transferSafeguards?: ProcessingActivityRegistryTransferSafeguards | null | undefined; @@ -74,108 +76,122 @@ v3 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "name", + "name": "snapshotId", "storageKey": null }, v4 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "purpose", + "name": "sourceId", "storageKey": null }, v5 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "dataSubjectCategory", + "name": "name", "storageKey": null }, v6 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "personalDataCategory", + "name": "purpose", "storageKey": null }, v7 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "specialOrCriminalData", + "name": "dataSubjectCategory", "storageKey": null }, v8 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "consentEvidenceLink", + "name": "personalDataCategory", "storageKey": null }, v9 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "lawfulBasis", + "name": "specialOrCriminalData", "storageKey": null }, v10 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "recipients", + "name": "consentEvidenceLink", "storageKey": null }, v11 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "location", + "name": "lawfulBasis", "storageKey": null }, v12 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "internationalTransfers", + "name": "recipients", "storageKey": null }, v13 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "transferSafeguards", + "name": "location", "storageKey": null }, v14 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "retentionPeriod", + "name": "internationalTransfers", "storageKey": null }, v15 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "securityMeasures", + "name": "transferSafeguards", "storageKey": null }, v16 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "dataProtectionImpactAssessment", + "name": "retentionPeriod", "storageKey": null }, v17 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "transferImpactAssessment", + "name": "securityMeasures", "storageKey": null }, v18 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "dataProtectionImpactAssessment", + "storageKey": null +}, +v19 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "transferImpactAssessment", + "storageKey": null +}, +v20 = { "alias": null, "args": null, "concreteType": "Organization", @@ -184,18 +200,18 @@ v18 = { "plural": false, "selections": [ (v2/*: any*/), - (v3/*: any*/) + (v5/*: any*/) ], "storageKey": null }, -v19 = { +v21 = { "alias": null, "args": null, "kind": "ScalarField", "name": "createdAt", "storageKey": null }, -v20 = { +v22 = { "alias": null, "args": null, "kind": "ScalarField", @@ -238,7 +254,9 @@ return { (v17/*: any*/), (v18/*: any*/), (v19/*: any*/), - (v20/*: any*/) + (v20/*: any*/), + (v21/*: any*/), + (v22/*: any*/) ], "type": "ProcessingActivityRegistry", "abstractKey": null @@ -292,7 +310,9 @@ return { (v17/*: any*/), (v18/*: any*/), (v19/*: any*/), - (v20/*: any*/) + (v20/*: any*/), + (v21/*: any*/), + (v22/*: any*/) ], "type": "ProcessingActivityRegistry", "abstractKey": null @@ -303,16 +323,16 @@ return { ] }, "params": { - "cacheID": "4a2a061717de77346b788a94d5c6b4ef", + "cacheID": "b8a3edd61ea5d94cc3594f40f181d27f", "id": null, "metadata": {}, "name": "ProcessingActivityRegistryGraphNodeQuery", "operationKind": "query", - "text": "query ProcessingActivityRegistryGraphNodeQuery(\n $processingActivityRegistryId: ID!\n) {\n node(id: $processingActivityRegistryId) {\n __typename\n ... on ProcessingActivityRegistry {\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 organization {\n id\n name\n }\n createdAt\n updatedAt\n }\n id\n }\n}\n" + "text": "query ProcessingActivityRegistryGraphNodeQuery(\n $processingActivityRegistryId: ID!\n) {\n node(id: $processingActivityRegistryId) {\n __typename\n ... on ProcessingActivityRegistry {\n id\n snapshotId\n sourceId\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 organization {\n id\n name\n }\n createdAt\n updatedAt\n }\n id\n }\n}\n" } }; })(); -(node as any).hash = "80aa43b56a3258a77b0d1c6c0c9b950d"; +(node as any).hash = "6714c1965f54321530f73a5b7ef86fa6"; export default node; diff --git a/apps/console/src/hooks/graph/__generated__/SnapshotGraphCreateMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/SnapshotGraphCreateMutation.graphql.ts index 8129f2ad6..f9ffe8885 100644 --- a/apps/console/src/hooks/graph/__generated__/SnapshotGraphCreateMutation.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/SnapshotGraphCreateMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<0b691997398fc5779891f6ce551192ae>> + * @generated SignedSource<<8b949b0eacdf3d9aa1bbd71cbe6af5b0>> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; -export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "RISKS" | "VENDORS"; +export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "PROCESSING_ACTIVITY_REGISTRIES" | "RISKS" | "VENDORS"; export type CreateSnapshotInput = { description?: string | null | undefined; name: string; diff --git a/apps/console/src/hooks/graph/__generated__/SnapshotGraphNodeQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/SnapshotGraphNodeQuery.graphql.ts index d7367d6db..29acc0b6e 100644 --- a/apps/console/src/hooks/graph/__generated__/SnapshotGraphNodeQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/SnapshotGraphNodeQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<202fa0acc16dc4343e193fb3f6784f3c>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; -export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "RISKS" | "VENDORS"; +export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "PROCESSING_ACTIVITY_REGISTRIES" | "RISKS" | "VENDORS"; export type SnapshotGraphNodeQuery$variables = { snapshotId: string; }; diff --git a/apps/console/src/pages/organizations/processingActivityRegistries/ProcessingActivityRegistriesPage.tsx b/apps/console/src/pages/organizations/processingActivityRegistries/ProcessingActivityRegistriesPage.tsx index ff0588247..b6c32ebe3 100644 --- a/apps/console/src/pages/organizations/processingActivityRegistries/ProcessingActivityRegistriesPage.tsx +++ b/apps/console/src/pages/organizations/processingActivityRegistries/ProcessingActivityRegistriesPage.tsx @@ -27,9 +27,11 @@ import { type PreloadedQuery, } from "react-relay"; import { useOrganizationId } from "/hooks/useOrganizationId"; +import { useParams } from "react-router"; import { CreateProcessingActivityRegistryDialog } from "./dialogs/CreateProcessingActivityRegistryDialog"; import { deleteProcessingActivityRegistryMutation, ProcessingActivityRegistriesConnectionKey } from "../../../hooks/graph/ProcessingActivityRegistryGraph"; import { sprintf, promisifyMutation } from "@probo/helpers"; +import { SnapshotBanner } from "/components/SnapshotBanner"; import type { NodeOf } from "/types"; import type { ProcessingActivityRegistriesPageQuery } from "./__generated__/ProcessingActivityRegistriesPageQuery.graphql"; import type { @@ -47,15 +49,22 @@ const processingActivityRegistriesPageFragment = graphql` @argumentDefinitions( first: { type: "Int", defaultValue: 10 } after: { type: "CursorKey" } + snapshotId: { type: "ID", defaultValue: null } ) { id - processingActivityRegistries(first: $first, after: $after) - @connection(key: "ProcessingActivityRegistriesPage_processingActivityRegistries") { + processingActivityRegistries( + first: $first + after: $after + filter: { snapshotId: $snapshotId } + ) + @connection(key: "ProcessingActivityRegistriesPage_processingActivityRegistries", filters: ["filter"]) { __id totalCount edges { node { id + snapshotId + sourceId name purpose dataSubjectCategory @@ -78,15 +87,18 @@ const processingActivityRegistriesPageFragment = graphql` export default function ProcessingActivityRegistriesPage({ queryRef }: ProcessingActivityRegistriesPageProps) { const { __ } = useTranslate(); const organizationId = useOrganizationId(); + const { snapshotId } = useParams<{ snapshotId?: string }>(); + const isSnapshotMode = Boolean(snapshotId); + usePageTitle(__("Processing Activity Registries")); const organization = usePreloadedQuery( graphql` - query ProcessingActivityRegistriesPageQuery($organizationId: ID!) { + query ProcessingActivityRegistriesPageQuery($organizationId: ID!, $snapshotId: ID) { node(id: $organizationId) { ... on Organization { - ...ProcessingActivityRegistriesPageFragment + ...ProcessingActivityRegistriesPageFragment @arguments(snapshotId: $snapshotId) } } } @@ -109,21 +121,27 @@ export default function ProcessingActivityRegistriesPage({ queryRef }: Processin const connectionId = ConnectionHandler.getConnectionID( organizationId, - ProcessingActivityRegistriesConnectionKey + ProcessingActivityRegistriesConnectionKey, + { filter: { snapshotId: snapshotId || null } } ); const registries = data?.processingActivityRegistries?.edges?.map((edge) => edge.node) ?? []; return (
+ {isSnapshotMode && snapshotId && ( + + )} - - - + {!isSnapshotMode && ( + + + + )} {registries.length > 0 ? ( @@ -137,7 +155,7 @@ export default function ProcessingActivityRegistriesPage({ queryRef }: Processin {__("Lawful Basis")} {__("Location")} {__("International Transfers")} - {__("Actions")} + {!isSnapshotMode && {__("Actions")}} @@ -188,6 +206,8 @@ function RegistryRow({ }) { const organizationId = useOrganizationId(); const { __ } = useTranslate(); + const { snapshotId } = useParams<{ snapshotId?: string }>(); + const isSnapshotMode = Boolean(snapshotId); const [deleteRegistry] = useMutation(deleteProcessingActivityRegistryMutation); const confirm = useConfirm(); @@ -213,8 +233,12 @@ function RegistryRow({ ); }; + const registryUrl = isSnapshotMode && snapshotId + ? `/organizations/${organizationId}/snapshots/${snapshotId}/processing-activity-registries/${registry.id}` + : `/organizations/${organizationId}/processing-activity-registries/${registry.id}`; + return ( - + {registry.name} @@ -231,17 +255,19 @@ function RegistryRow({ {registry.internationalTransfers ? __("Yes") : __("No")} - - - - {__("Delete")} - - - + {!isSnapshotMode && ( + + + + {__("Delete")} + + + + )} ); } diff --git a/apps/console/src/pages/organizations/processingActivityRegistries/ProcessingActivityRegistryDetailsPage.tsx b/apps/console/src/pages/organizations/processingActivityRegistries/ProcessingActivityRegistryDetailsPage.tsx index ed088c3bd..5b9179f92 100644 --- a/apps/console/src/pages/organizations/processingActivityRegistries/ProcessingActivityRegistryDetailsPage.tsx +++ b/apps/console/src/pages/organizations/processingActivityRegistries/ProcessingActivityRegistryDetailsPage.tsx @@ -24,9 +24,12 @@ import { } 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 z from "zod"; +import { validateSnapshotConsistency } from "@probo/helpers"; +import { SnapshotBanner } from "/components/SnapshotBanner"; import { SpecialOrCriminalDataOptions, LawfulBasisOptions, @@ -65,16 +68,21 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) { const { __ } = useTranslate(); const { toast } = useToast(); const organizationId = useOrganizationId(); + const { snapshotId } = useParams<{ snapshotId?: string }>(); + const isSnapshotMode = Boolean(snapshotId); if (!registry) { return
{__("Processing activity registry entry not found")}
; } + validateSnapshotConsistency(registry, snapshotId); + const updateRegistry = useUpdateProcessingActivityRegistry(); const connectionId = ConnectionHandler.getConnectionID( organizationId, - ProcessingActivityRegistriesConnectionKey + ProcessingActivityRegistriesConnectionKey, + { filter: { snapshotId: snapshotId || null } } ); const deleteRegistry = useDeleteProcessingActivityRegistry({ id: registry.id!, name: registry.name! }, connectionId); @@ -137,20 +145,29 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) { } }); + const breadcrumbRegistriesUrl = isSnapshotMode && snapshotId + ? `/organizations/${organizationId}/snapshots/${snapshotId}/processing-activity-registries` + : `/organizations/${organizationId}/processing-activity-registries`; + return (
+ {isSnapshotMode && snapshotId && ( + + )}
- - - {__("Delete")} - - + {!isSnapshotMode && ( + + + {__("Delete")} + + + )}
@@ -169,6 +186,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) { {...register("name")} error={formState.errors.name?.message} required + disabled={isSnapshotMode} />
@@ -177,6 +195,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) { {...register("purpose")} placeholder={__("Describe the purpose of processing")} rows={3} + disabled={isSnapshotMode} />
@@ -184,12 +203,14 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) { label={__("Data Subject Category")} {...register("dataSubjectCategory")} placeholder={__("e.g., employees, customers, prospects")} + disabled={isSnapshotMode} />
@@ -204,6 +225,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) { onValueChange={field.onChange} value={field.value} className="w-full" + disabled={isSnapshotMode} > @@ -218,6 +240,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) { label={__("Consent Evidence Link")} {...register("consentEvidenceLink")} placeholder={__("Link to consent evidence if applicable")} + disabled={isSnapshotMode} />
@@ -232,6 +255,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) { onValueChange={field.onChange} value={field.value} className="w-full" + disabled={isSnapshotMode} > @@ -248,28 +272,31 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) { label={__("Recipients")} {...register("recipients")} placeholder={__("Who receives the data")} + disabled={isSnapshotMode} /> ( -
- -
- - {__("Data is transferred internationally")} -
-
+
+ +
+ + {__("Data is transferred internationally")} +
+
)} /> @@ -285,6 +312,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) { onValueChange={field.onChange} value={field.value} className="w-full" + disabled={isSnapshotMode} > @@ -299,6 +327,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) { label={__("Retention Period")} {...register("retentionPeriod")} placeholder={__("How long is data retained")} + disabled={isSnapshotMode} />
@@ -307,6 +336,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) { {...register("securityMeasures")} placeholder={__("Technical and organizational measures")} rows={3} + disabled={isSnapshotMode} />
@@ -322,6 +352,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) { onValueChange={field.onChange} value={field.value} className="w-full" + disabled={isSnapshotMode} > @@ -344,6 +375,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) { onValueChange={field.onChange} value={field.value} className="w-full" + disabled={isSnapshotMode} > @@ -356,15 +388,17 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
-
- -
+ {!isSnapshotMode && ( +
+ +
+ )}
diff --git a/apps/console/src/pages/organizations/processingActivityRegistries/__generated__/ProcessingActivityRegistriesPageFragment.graphql.ts b/apps/console/src/pages/organizations/processingActivityRegistries/__generated__/ProcessingActivityRegistriesPageFragment.graphql.ts index 60d2689b9..afd586d7b 100644 --- a/apps/console/src/pages/organizations/processingActivityRegistries/__generated__/ProcessingActivityRegistriesPageFragment.graphql.ts +++ b/apps/console/src/pages/organizations/processingActivityRegistries/__generated__/ProcessingActivityRegistriesPageFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<138a897eea1aa78073db58d717fe2947>> * @lightSyntaxTransform * @nogrep */ @@ -26,6 +26,8 @@ export type ProcessingActivityRegistriesPageFragment$data = { readonly name: string; readonly personalDataCategory: string | null | undefined; readonly purpose: string | null | undefined; + readonly snapshotId: string | null | undefined; + readonly sourceId: string | null | undefined; readonly updatedAt: any; }; }>; @@ -66,6 +68,11 @@ return { "defaultValue": 10, "kind": "LocalArgument", "name": "first" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "snapshotId" } ], "kind": "Fragment", @@ -102,7 +109,19 @@ return { (v1/*: any*/), { "alias": "processingActivityRegistries", - "args": null, + "args": [ + { + "fields": [ + { + "kind": "Variable", + "name": "snapshotId", + "variableName": "snapshotId" + } + ], + "kind": "ObjectValue", + "name": "filter" + } + ], "concreteType": "ProcessingActivityRegistryConnection", "kind": "LinkedField", "name": "__ProcessingActivityRegistriesPage_processingActivityRegistries_connection", @@ -132,6 +151,20 @@ return { "plural": false, "selections": [ (v1/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "snapshotId", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "sourceId", + "storageKey": null + }, { "alias": null, "args": null, @@ -261,6 +294,6 @@ return { }; })(); -(node as any).hash = "25222b5244115092f96c424d8a52a5db"; +(node as any).hash = "a31cad7de09ddd436e7fa9068d53e05e"; export default node; diff --git a/apps/console/src/pages/organizations/processingActivityRegistries/__generated__/ProcessingActivityRegistriesPageQuery.graphql.ts b/apps/console/src/pages/organizations/processingActivityRegistries/__generated__/ProcessingActivityRegistriesPageQuery.graphql.ts index 03af5e6d4..6c5f6fff5 100644 --- a/apps/console/src/pages/organizations/processingActivityRegistries/__generated__/ProcessingActivityRegistriesPageQuery.graphql.ts +++ b/apps/console/src/pages/organizations/processingActivityRegistries/__generated__/ProcessingActivityRegistriesPageQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<71dfd7c0d78070061957215363022475>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -12,6 +12,7 @@ import { ConcreteRequest } from 'relay-runtime'; import { FragmentRefs } from "relay-runtime"; export type ProcessingActivityRegistriesPageQuery$variables = { organizationId: string; + snapshotId?: string | null | undefined; }; export type ProcessingActivityRegistriesPageQuery$data = { readonly node: { @@ -29,6 +30,11 @@ var v0 = [ "defaultValue": null, "kind": "LocalArgument", "name": "organizationId" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "snapshotId" } ], v1 = [ @@ -38,21 +44,33 @@ v1 = [ "variableName": "organizationId" } ], -v2 = { +v2 = [ + { + "kind": "Variable", + "name": "snapshotId", + "variableName": "snapshotId" + } +], +v3 = { "alias": null, "args": null, "kind": "ScalarField", "name": "__typename", "storageKey": null }, -v3 = { +v4 = { "alias": null, "args": null, "kind": "ScalarField", "name": "id", "storageKey": null }, -v4 = [ +v5 = [ + { + "fields": (v2/*: any*/), + "kind": "ObjectValue", + "name": "filter" + }, { "kind": "Literal", "name": "first", @@ -78,7 +96,7 @@ return { "kind": "InlineFragment", "selections": [ { - "args": null, + "args": (v2/*: any*/), "kind": "FragmentSpread", "name": "ProcessingActivityRegistriesPageFragment" } @@ -107,14 +125,14 @@ return { "name": "node", "plural": false, "selections": [ - (v2/*: any*/), (v3/*: any*/), + (v4/*: any*/), { "kind": "InlineFragment", "selections": [ { "alias": null, - "args": (v4/*: any*/), + "args": (v5/*: any*/), "concreteType": "ProcessingActivityRegistryConnection", "kind": "LinkedField", "name": "processingActivityRegistries", @@ -143,7 +161,21 @@ return { "name": "node", "plural": false, "selections": [ - (v3/*: any*/), + (v4/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "snapshotId", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "sourceId", + "storageKey": null + }, { "alias": null, "args": null, @@ -207,7 +239,7 @@ return { "name": "updatedAt", "storageKey": null }, - (v2/*: any*/) + (v3/*: any*/) ], "storageKey": null }, @@ -259,12 +291,14 @@ return { ] } ], - "storageKey": "processingActivityRegistries(first:10)" + "storageKey": null }, { "alias": null, - "args": (v4/*: any*/), - "filters": null, + "args": (v5/*: any*/), + "filters": [ + "filter" + ], "handle": "connection", "key": "ProcessingActivityRegistriesPage_processingActivityRegistries", "kind": "LinkedHandle", @@ -280,16 +314,16 @@ return { ] }, "params": { - "cacheID": "331d1a749711d7a519fbdc5a721d2cec", + "cacheID": "2b5cf834c7b4f34bb4a8e74705d1e530", "id": null, "metadata": {}, "name": "ProcessingActivityRegistriesPageQuery", "operationKind": "query", - "text": "query ProcessingActivityRegistriesPageQuery(\n $organizationId: ID!\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ProcessingActivityRegistriesPageFragment\n }\n id\n }\n}\n\nfragment ProcessingActivityRegistriesPageFragment on Organization {\n id\n processingActivityRegistries(first: 10) {\n totalCount\n edges {\n node {\n id\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 ProcessingActivityRegistriesPageQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ProcessingActivityRegistriesPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ProcessingActivityRegistriesPageFragment_3iomuz on Organization {\n id\n processingActivityRegistries(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" } }; })(); -(node as any).hash = "2d99b77d24e6583cb93580fdbf47ffb3"; +(node as any).hash = "a4030e6ab7ce0351b431ce90d0440135"; export default node; diff --git a/apps/console/src/pages/organizations/processingActivityRegistries/__generated__/ProcessingActivityRegistriesPageRefetchQuery.graphql.ts b/apps/console/src/pages/organizations/processingActivityRegistries/__generated__/ProcessingActivityRegistriesPageRefetchQuery.graphql.ts index c8b5763f7..a6dea900b 100644 --- a/apps/console/src/pages/organizations/processingActivityRegistries/__generated__/ProcessingActivityRegistriesPageRefetchQuery.graphql.ts +++ b/apps/console/src/pages/organizations/processingActivityRegistries/__generated__/ProcessingActivityRegistriesPageRefetchQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<3ad73dde5a41f4370035f6156fc1f38b>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -14,6 +14,7 @@ export type ProcessingActivityRegistriesPageRefetchQuery$variables = { after?: any | null | undefined; first?: number | null | undefined; id: string; + snapshotId?: string | null | undefined; }; export type ProcessingActivityRegistriesPageRefetchQuery$data = { readonly node: { @@ -26,73 +27,99 @@ export type ProcessingActivityRegistriesPageRefetchQuery = { }; const node: ConcreteRequest = (function(){ -var v0 = [ - { - "defaultValue": null, - "kind": "LocalArgument", - "name": "after" - }, - { - "defaultValue": 10, - "kind": "LocalArgument", - "name": "first" - }, - { - "defaultValue": null, - "kind": "LocalArgument", - "name": "id" - } -], -v1 = [ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "after" +}, +v1 = { + "defaultValue": 10, + "kind": "LocalArgument", + "name": "first" +}, +v2 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" +}, +v3 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "snapshotId" +}, +v4 = [ { "kind": "Variable", "name": "id", "variableName": "id" } ], -v2 = [ - { - "kind": "Variable", - "name": "after", - "variableName": "after" - }, - { - "kind": "Variable", - "name": "first", - "variableName": "first" - } -], -v3 = { +v5 = { + "kind": "Variable", + "name": "after", + "variableName": "after" +}, +v6 = { + "kind": "Variable", + "name": "first", + "variableName": "first" +}, +v7 = { + "kind": "Variable", + "name": "snapshotId", + "variableName": "snapshotId" +}, +v8 = { "alias": null, "args": null, "kind": "ScalarField", "name": "__typename", "storageKey": null }, -v4 = { +v9 = { "alias": null, "args": null, "kind": "ScalarField", "name": "id", "storageKey": null -}; +}, +v10 = [ + (v5/*: any*/), + { + "fields": [ + (v7/*: any*/) + ], + "kind": "ObjectValue", + "name": "filter" + }, + (v6/*: any*/) +]; return { "fragment": { - "argumentDefinitions": (v0/*: any*/), + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/), + (v2/*: any*/), + (v3/*: any*/) + ], "kind": "Fragment", "metadata": null, "name": "ProcessingActivityRegistriesPageRefetchQuery", "selections": [ { "alias": null, - "args": (v1/*: any*/), + "args": (v4/*: any*/), "concreteType": null, "kind": "LinkedField", "name": "node", "plural": false, "selections": [ { - "args": (v2/*: any*/), + "args": [ + (v5/*: any*/), + (v6/*: any*/), + (v7/*: any*/) + ], "kind": "FragmentSpread", "name": "ProcessingActivityRegistriesPageFragment" } @@ -105,26 +132,31 @@ return { }, "kind": "Request", "operation": { - "argumentDefinitions": (v0/*: any*/), + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/), + (v3/*: any*/), + (v2/*: any*/) + ], "kind": "Operation", "name": "ProcessingActivityRegistriesPageRefetchQuery", "selections": [ { "alias": null, - "args": (v1/*: any*/), + "args": (v4/*: any*/), "concreteType": null, "kind": "LinkedField", "name": "node", "plural": false, "selections": [ - (v3/*: any*/), - (v4/*: any*/), + (v8/*: any*/), + (v9/*: any*/), { "kind": "InlineFragment", "selections": [ { "alias": null, - "args": (v2/*: any*/), + "args": (v10/*: any*/), "concreteType": "ProcessingActivityRegistryConnection", "kind": "LinkedField", "name": "processingActivityRegistries", @@ -153,7 +185,21 @@ return { "name": "node", "plural": false, "selections": [ - (v4/*: any*/), + (v9/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "snapshotId", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "sourceId", + "storageKey": null + }, { "alias": null, "args": null, @@ -217,7 +263,7 @@ return { "name": "updatedAt", "storageKey": null }, - (v3/*: any*/) + (v8/*: any*/) ], "storageKey": null }, @@ -273,8 +319,10 @@ return { }, { "alias": null, - "args": (v2/*: any*/), - "filters": null, + "args": (v10/*: any*/), + "filters": [ + "filter" + ], "handle": "connection", "key": "ProcessingActivityRegistriesPage_processingActivityRegistries", "kind": "LinkedHandle", @@ -290,16 +338,16 @@ return { ] }, "params": { - "cacheID": "1d359fcdec190d343db1cef8c01c7672", + "cacheID": "f6f29dda67221647df6a500c124091a2", "id": null, "metadata": {}, "name": "ProcessingActivityRegistriesPageRefetchQuery", "operationKind": "query", - "text": "query ProcessingActivityRegistriesPageRefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ProcessingActivityRegistriesPageFragment_2HEEH6\n id\n }\n}\n\nfragment ProcessingActivityRegistriesPageFragment_2HEEH6 on Organization {\n id\n processingActivityRegistries(first: $first, after: $after) {\n totalCount\n edges {\n node {\n id\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 ProcessingActivityRegistriesPageRefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ProcessingActivityRegistriesPageFragment_35e0S5\n id\n }\n}\n\nfragment ProcessingActivityRegistriesPageFragment_35e0S5 on Organization {\n id\n processingActivityRegistries(first: $first, after: $after, 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" } }; })(); -(node as any).hash = "25222b5244115092f96c424d8a52a5db"; +(node as any).hash = "a31cad7de09ddd436e7fa9068d53e05e"; export default node; diff --git a/apps/console/src/pages/organizations/snapshots/__generated__/SnapshotsPageFragment.graphql.ts b/apps/console/src/pages/organizations/snapshots/__generated__/SnapshotsPageFragment.graphql.ts index 73ceab525..527f9e8f7 100644 --- a/apps/console/src/pages/organizations/snapshots/__generated__/SnapshotsPageFragment.graphql.ts +++ b/apps/console/src/pages/organizations/snapshots/__generated__/SnapshotsPageFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ReaderFragment } from 'relay-runtime'; -export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "RISKS" | "VENDORS"; +export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "PROCESSING_ACTIVITY_REGISTRIES" | "RISKS" | "VENDORS"; import { FragmentRefs } from "relay-runtime"; export type SnapshotsPageFragment$data = { readonly snapshots: { diff --git a/apps/console/src/pages/organizations/snapshots/dialog/__generated__/SnapshotFormDialogCreateMutation.graphql.ts b/apps/console/src/pages/organizations/snapshots/dialog/__generated__/SnapshotFormDialogCreateMutation.graphql.ts index 55f67a407..d7b953c7a 100644 --- a/apps/console/src/pages/organizations/snapshots/dialog/__generated__/SnapshotFormDialogCreateMutation.graphql.ts +++ b/apps/console/src/pages/organizations/snapshots/dialog/__generated__/SnapshotFormDialogCreateMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<8e3f14794ab1cbd6c2e67ab4eb8ac373>> + * @generated SignedSource<<50dda5d856ca750f1e85a8c1d2935c9c>> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; -export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "RISKS" | "VENDORS"; +export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "PROCESSING_ACTIVITY_REGISTRIES" | "RISKS" | "VENDORS"; export type CreateSnapshotInput = { description?: string | null | undefined; name: string; diff --git a/apps/console/src/routes/processingActivityRegistryRoutes.ts b/apps/console/src/routes/processingActivityRegistryRoutes.ts index a31f5717b..6b95d4b74 100644 --- a/apps/console/src/routes/processingActivityRegistryRoutes.ts +++ b/apps/console/src/routes/processingActivityRegistryRoutes.ts @@ -9,8 +9,23 @@ export const processingActivityRegistryRoutes = [ { path: "processing-activity-registries", fallback: PageSkeleton, - queryLoader: ({ organizationId }: { organizationId: string }) => - loadQuery(relayEnvironment, processingActivityRegistriesQuery, { organizationId }), + queryLoader: (params: Record) => + loadQuery(relayEnvironment, processingActivityRegistriesQuery, { + organizationId: params.organizationId, + snapshotId: null + }), + Component: lazy( + () => import("/pages/organizations/processingActivityRegistries/ProcessingActivityRegistriesPage") + ), + }, + { + path: "snapshots/:snapshotId/processing-activity-registries", + fallback: PageSkeleton, + queryLoader: (params: Record) => + loadQuery(relayEnvironment, processingActivityRegistriesQuery, { + organizationId: params.organizationId, + snapshotId: params.snapshotId + }), Component: lazy( () => import("/pages/organizations/processingActivityRegistries/ProcessingActivityRegistriesPage") ), @@ -26,4 +41,15 @@ export const processingActivityRegistryRoutes = [ () => import("/pages/organizations/processingActivityRegistries/ProcessingActivityRegistryDetailsPage") ), }, + { + path: "snapshots/:snapshotId/processing-activity-registries/:registryId", + fallback: PageSkeleton, + queryLoader: (params: Record) => + loadQuery(relayEnvironment, processingActivityRegistryNodeQuery, { + processingActivityRegistryId: params.registryId + }), + Component: lazy( + () => import("/pages/organizations/processingActivityRegistries/ProcessingActivityRegistryDetailsPage") + ), + }, ] satisfies AppRoute[]; diff --git a/packages/helpers/src/snapshots.ts b/packages/helpers/src/snapshots.ts index a42b3e429..8571c0a05 100644 --- a/packages/helpers/src/snapshots.ts +++ b/packages/helpers/src/snapshots.ts @@ -5,6 +5,7 @@ export const snapshotTypes = [ "NONCONFORMITY_REGISTRIES", "COMPLIANCE_REGISTRIES", "CONTINUAL_IMPROVEMENT_REGISTRIES", + "PROCESSING_ACTIVITY_REGISTRIES", ] as const; export function getSnapshotTypeLabel(__: Translator, type: string | null | undefined) { @@ -27,6 +28,8 @@ export function getSnapshotTypeLabel(__: Translator, type: string | null | undef return __("Compliance Registries"); case "CONTINUAL_IMPROVEMENT_REGISTRIES": return __("Continual Improvement Registries"); + case "PROCESSING_ACTIVITY_REGISTRIES": + return __("Processing Activity Registries"); default: return __("Unknown"); } @@ -42,6 +45,8 @@ export function getSnapshotTypeUrlPath(type?: string): string { return "/compliance-registries"; case "CONTINUAL_IMPROVEMENT_REGISTRIES": return "/continual-improvement-registries"; + case "PROCESSING_ACTIVITY_REGISTRIES": + return "/processing-activity-registries"; default: return ""; } diff --git a/packages/ui/src/Atoms/Checkbox/Checkbox.tsx b/packages/ui/src/Atoms/Checkbox/Checkbox.tsx index cd62314d4..f60db0f3f 100644 --- a/packages/ui/src/Atoms/Checkbox/Checkbox.tsx +++ b/packages/ui/src/Atoms/Checkbox/Checkbox.tsx @@ -5,6 +5,7 @@ import { IconCheckmark1 } from "../Icons"; type Props = { checked: boolean; onChange: (checked: boolean) => void; + disabled?: boolean; }; const checkbox = tv({ @@ -16,19 +17,23 @@ const checkbox = tv({ checked: { true: "bg-accent text-invert", }, + disabled: { + true: "opacity-50 cursor-not-allowed", + }, }, }); -export function Checkbox({ checked, onChange }: Props) { +export function Checkbox({ checked, onChange, disabled = false }: Props) { const [isFocused, setFocus] = useState(false); return ( -
+
onChange(e.target.checked)} - onFocus={() => setFocus(true)} + disabled={disabled} + onChange={(e) => !disabled && onChange(e.target.checked)} + onFocus={() => !disabled && setFocus(true)} onBlur={() => setFocus(false)} /> {checked && } diff --git a/pkg/coredata/migrations/20250829T141003Z.sql b/pkg/coredata/migrations/20250829T141003Z.sql new file mode 100644 index 000000000..f77d16202 --- /dev/null +++ b/pkg/coredata/migrations/20250829T141003Z.sql @@ -0,0 +1,13 @@ +ALTER TYPE snapshots_type ADD VALUE 'PROCESSING_ACTIVITY_REGISTRIES'; + +ALTER TABLE processing_activity_registries ADD COLUMN snapshot_id TEXT; +ALTER TABLE processing_activity_registries ADD COLUMN source_id TEXT; + +ALTER TABLE processing_activity_registries ADD CONSTRAINT processing_activity_registries_snapshot_id_fkey + FOREIGN KEY (snapshot_id) + REFERENCES snapshots(id) + ON UPDATE CASCADE + ON DELETE CASCADE; + +ALTER TABLE processing_activity_registries ADD CONSTRAINT processing_activity_registries_source_id_snapshot_id_key + UNIQUE (source_id, snapshot_id); diff --git a/pkg/coredata/processing_activity_registries.go b/pkg/coredata/processing_activity_registries.go index 650f2da19..2a8342aba 100644 --- a/pkg/coredata/processing_activity_registries.go +++ b/pkg/coredata/processing_activity_registries.go @@ -29,6 +29,8 @@ import ( type ( ProcessingActivityRegistry struct { ID gid.GID `db:"id"` + SnapshotID *gid.GID `db:"snapshot_id"` + SourceID *gid.GID `db:"source_id"` OrganizationID gid.GID `db:"organization_id"` Name string `db:"name"` Purpose *string `db:"purpose"` @@ -72,6 +74,8 @@ func (p *ProcessingActivityRegistry) LoadByID( q := ` SELECT id, + snapshot_id, + source_id, organization_id, name, purpose, @@ -123,6 +127,7 @@ func (p *ProcessingActivityRegistries) CountByOrganizationID( conn pg.Conn, scope Scoper, organizationID gid.GID, + filter *ProcessingActivityRegistryFilter, ) (int, error) { q := ` SELECT @@ -132,12 +137,14 @@ FROM WHERE %s AND organization_id = @organization_id + AND %s ` - q = fmt.Sprintf(q, scope.SQLFragment()) + q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment()) args := pgx.StrictNamedArgs{"organization_id": organizationID} maps.Copy(args, scope.SQLArguments()) + maps.Copy(args, filter.SQLArguments()) row := conn.QueryRow(ctx, q, args) @@ -156,10 +163,13 @@ func (p *ProcessingActivityRegistries) LoadByOrganizationID( scope Scoper, organizationID gid.GID, cursor *page.Cursor[ProcessingActivityRegistryOrderField], + filter *ProcessingActivityRegistryFilter, ) error { q := ` SELECT id, + snapshot_id, + source_id, organization_id, name, purpose, @@ -184,12 +194,14 @@ WHERE %s AND organization_id = @organization_id AND %s + AND %s ` - q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment()) + q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment(), cursor.SQLFragment()) args := pgx.StrictNamedArgs{"organization_id": organizationID} maps.Copy(args, scope.SQLArguments()) + maps.Copy(args, filter.SQLArguments()) maps.Copy(args, cursor.SQLArguments()) rows, err := conn.Query(ctx, q, args) @@ -216,6 +228,8 @@ func (p *ProcessingActivityRegistry) Insert( INSERT INTO processing_activity_registries ( id, tenant_id, + snapshot_id, + source_id, organization_id, name, purpose, @@ -237,6 +251,8 @@ INSERT INTO processing_activity_registries ( ) VALUES ( @id, @tenant_id, + @snapshot_id, + @source_id, @organization_id, @name, @purpose, @@ -261,6 +277,8 @@ INSERT INTO processing_activity_registries ( args := pgx.StrictNamedArgs{ "id": p.ID, "tenant_id": scope.GetTenantID(), + "snapshot_id": p.SnapshotID, + "source_id": p.SourceID, "organization_id": p.OrganizationID, "name": p.Name, "purpose": p.Purpose, @@ -316,6 +334,7 @@ SET WHERE %s AND id = @id + AND snapshot_id IS NULL ` q = fmt.Sprintf(q, scope.SQLFragment()) @@ -359,6 +378,7 @@ DELETE FROM processing_activity_registries WHERE %s AND id = @id + AND snapshot_id IS NULL ` q = fmt.Sprintf(q, scope.SQLFragment()) @@ -373,3 +393,74 @@ WHERE return nil } + +func (pars ProcessingActivityRegistries) Snapshot(ctx context.Context, conn pg.Conn, scope Scoper, organizationID, snapshotID gid.GID) error { + query := ` +INSERT INTO processing_activity_registries ( + id, + tenant_id, + snapshot_id, + source_id, + organization_id, + name, + purpose, + data_subject_category, + personal_data_category, + special_or_criminal_data, + consent_evidence_link, + lawful_basis, + recipients, + location, + international_transfers, + transfer_safeguards, + retention_period, + security_measures, + data_protection_impact_assessment, + transfer_impact_assessment, + created_at, + updated_at +) +SELECT + generate_gid(decode_base64_unpadded(@tenant_id), @processing_activity_registry_entity_type), + @tenant_id, + @snapshot_id, + par.id, + par.organization_id, + par.name, + par.purpose, + par.data_subject_category, + par.personal_data_category, + par.special_or_criminal_data, + par.consent_evidence_link, + par.lawful_basis, + par.recipients, + par.location, + par.international_transfers, + par.transfer_safeguards, + par.retention_period, + par.security_measures, + par.data_protection_impact_assessment, + par.transfer_impact_assessment, + par.created_at, + par.updated_at +FROM processing_activity_registries par +WHERE %s AND par.organization_id = @organization_id AND par.snapshot_id IS NULL + ` + + query = fmt.Sprintf(query, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{ + "tenant_id": scope.GetTenantID(), + "snapshot_id": snapshotID, + "organization_id": organizationID, + "processing_activity_registry_entity_type": ProcessingActivityRegistryEntityType, + } + maps.Copy(args, scope.SQLArguments()) + + _, err := conn.Exec(ctx, query, args) + if err != nil { + return fmt.Errorf("cannot insert processing activity registry snapshots: %w", err) + } + + return nil +} diff --git a/pkg/coredata/processing_activity_registry_filter.go b/pkg/coredata/processing_activity_registry_filter.go new file mode 100644 index 000000000..861757c10 --- /dev/null +++ b/pkg/coredata/processing_activity_registry_filter.go @@ -0,0 +1,54 @@ +// Copyright (c) 2025 Probo Inc . +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +package coredata + +import ( + "github.com/getprobo/probo/pkg/gid" + "github.com/jackc/pgx/v5" +) + +type ( + ProcessingActivityRegistryFilter struct { + snapshotID **gid.GID + } +) + +func NewProcessingActivityRegistryFilter(snapshotID **gid.GID) *ProcessingActivityRegistryFilter { + return &ProcessingActivityRegistryFilter{ + snapshotID: snapshotID, + } +} + +func (f *ProcessingActivityRegistryFilter) SQLArguments() pgx.NamedArgs { + args := pgx.NamedArgs{} + + if f.snapshotID != nil && *f.snapshotID != nil { + args["filter_snapshot_id"] = **f.snapshotID + } + + return args +} + +func (f *ProcessingActivityRegistryFilter) SQLFragment() string { + if f.snapshotID == nil { + return "TRUE" + } + + if *f.snapshotID == nil { + return "snapshot_id IS NULL" + } else { + return "snapshot_id = @filter_snapshot_id" + } +} diff --git a/pkg/coredata/snapshots_type.go b/pkg/coredata/snapshots_type.go index 84c61d67d..ca3b87fa4 100644 --- a/pkg/coredata/snapshots_type.go +++ b/pkg/coredata/snapshots_type.go @@ -31,6 +31,7 @@ const ( SnapshotsTypeNonConformityRegistries SnapshotsType = "NONCONFORMITY_REGISTRIES" SnapshotsTypeComplianceRegistries SnapshotsType = "COMPLIANCE_REGISTRIES" SnapshotsTypeContinualImprovementRegistries SnapshotsType = "CONTINUAL_IMPROVEMENT_REGISTRIES" + SnapshotsTypeProcessingActivityRegistries SnapshotsType = "PROCESSING_ACTIVITY_REGISTRIES" ) func (st SnapshotsType) String() string { @@ -63,6 +64,8 @@ func (st *SnapshotsType) Scan(value any) error { *st = SnapshotsTypeComplianceRegistries case SnapshotsTypeContinualImprovementRegistries.String(): *st = SnapshotsTypeContinualImprovementRegistries + case SnapshotsTypeProcessingActivityRegistries.String(): + *st = SnapshotsTypeProcessingActivityRegistries default: return fmt.Errorf("invalid SnapshotsType value: %q", s) } diff --git a/pkg/coredata/snapshottable.go b/pkg/coredata/snapshottable.go index 517e68a35..ce98b3273 100644 --- a/pkg/coredata/snapshottable.go +++ b/pkg/coredata/snapshottable.go @@ -36,6 +36,8 @@ func GetSnapshottable(snapshotType SnapshotsType) (Snapshottable, error) { return ComplianceRegistries{}, nil case SnapshotsTypeContinualImprovementRegistries: return ContinualImprovementRegistries{}, nil + case SnapshotsTypeProcessingActivityRegistries: + return ProcessingActivityRegistries{}, nil default: return nil, fmt.Errorf("unsupported snapshot type: %s", snapshotType) } diff --git a/pkg/probo/processing_activity_registry_service.go b/pkg/probo/processing_activity_registry_service.go index d28ef4803..ccadf7635 100644 --- a/pkg/probo/processing_activity_registry_service.go +++ b/pkg/probo/processing_activity_registry_service.go @@ -237,13 +237,14 @@ func (s ProcessingActivityRegistryService) ListForOrganizationID( ctx context.Context, organizationID gid.GID, cursor *page.Cursor[coredata.ProcessingActivityRegistryOrderField], + filter *coredata.ProcessingActivityRegistryFilter, ) (*page.Page[*coredata.ProcessingActivityRegistry, coredata.ProcessingActivityRegistryOrderField], error) { var processingActivityRegistries coredata.ProcessingActivityRegistries err := s.svc.pg.WithConn( ctx, func(conn pg.Conn) error { - err := processingActivityRegistries.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor) + err := processingActivityRegistries.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor, filter) if err != nil { return fmt.Errorf("cannot load processing activity registries: %w", err) } @@ -262,6 +263,7 @@ func (s ProcessingActivityRegistryService) ListForOrganizationID( func (s ProcessingActivityRegistryService) CountForOrganizationID( ctx context.Context, organizationID gid.GID, + filter *coredata.ProcessingActivityRegistryFilter, ) (int, error) { var count int @@ -269,7 +271,7 @@ func (s ProcessingActivityRegistryService) CountForOrganizationID( ctx, func(conn pg.Conn) (err error) { processingActivityRegistries := coredata.ProcessingActivityRegistries{} - count, err = processingActivityRegistries.CountByOrganizationID(ctx, conn, s.svc.scope, organizationID) + count, err = processingActivityRegistries.CountByOrganizationID(ctx, conn, s.svc.scope, organizationID, filter) if err != nil { return fmt.Errorf("cannot count processing activity registries: %w", err) } diff --git a/pkg/server/api/console/v1/schema.graphql b/pkg/server/api/console/v1/schema.graphql index 01983568b..13ad4bee2 100644 --- a/pkg/server/api/console/v1/schema.graphql +++ b/pkg/server/api/console/v1/schema.graphql @@ -880,6 +880,10 @@ enum SnapshotsType @goEnum( value: "github.com/getprobo/probo/pkg/coredata.SnapshotsTypeContinualImprovementRegistries" ) + PROCESSING_ACTIVITY_REGISTRIES + @goEnum( + value: "github.com/getprobo/probo/pkg/coredata.SnapshotsTypeProcessingActivityRegistries" + ) } enum SnapshotOrderField @@ -1122,6 +1126,10 @@ input ContinualImprovementRegistryFilter { snapshotId: ID } +input ProcessingActivityRegistryFilter { + snapshotId: ID +} + # Core Types type TrustCenter implements Node { id: ID! @@ -1288,6 +1296,7 @@ type Organization implements Node { last: Int before: CursorKey orderBy: ProcessingActivityRegistryOrder + filter: ProcessingActivityRegistryFilter ): ProcessingActivityRegistryConnection! @goField(forceResolver: true) snapshots( @@ -1770,6 +1779,8 @@ type ContinualImprovementRegistry implements Node { type ProcessingActivityRegistry implements Node { id: ID! + snapshotId: ID + sourceId: ID organization: Organization! @goField(forceResolver: true) name: String! purpose: String diff --git a/pkg/server/api/console/v1/schema/schema.go b/pkg/server/api/console/v1/schema/schema.go index af50be9ed..0956bc3fc 100644 --- a/pkg/server/api/console/v1/schema/schema.go +++ b/pkg/server/api/console/v1/schema/schema.go @@ -889,7 +889,7 @@ type ComplexityRoot struct { Name func(childComplexity int) int NonconformityRegistries func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.NonconformityRegistryOrderBy, filter *types.NonconformityRegistryFilter) int Peoples func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PeopleOrderBy, filter *types.PeopleFilter) int - ProcessingActivityRegistries func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityRegistryOrderBy) int + ProcessingActivityRegistries func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityRegistryOrderBy, filter *types.ProcessingActivityRegistryFilter) int Risks func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RiskOrderBy, filter *types.RiskFilter) int Snapshots func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SnapshotOrderBy) int Tasks func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TaskOrderBy) int @@ -956,6 +956,8 @@ type ComplexityRoot struct { Recipients func(childComplexity int) int RetentionPeriod func(childComplexity int) int SecurityMeasures func(childComplexity int) int + SnapshotID func(childComplexity int) int + SourceID func(childComplexity int) int SpecialOrCriminalData func(childComplexity int) int TransferImpactAssessment func(childComplexity int) int TransferSafeguards func(childComplexity int) int @@ -1675,7 +1677,7 @@ type OrganizationResolver interface { NonconformityRegistries(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.NonconformityRegistryOrderBy, filter *types.NonconformityRegistryFilter) (*types.NonconformityRegistryConnection, error) ComplianceRegistries(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ComplianceRegistryOrderBy, filter *types.ComplianceRegistryFilter) (*types.ComplianceRegistryConnection, error) ContinualImprovementRegistries(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ContinualImprovementRegistriesOrderBy, filter *types.ContinualImprovementRegistryFilter) (*types.ContinualImprovementRegistryConnection, error) - ProcessingActivityRegistries(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityRegistryOrderBy) (*types.ProcessingActivityRegistryConnection, error) + ProcessingActivityRegistries(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityRegistryOrderBy, filter *types.ProcessingActivityRegistryFilter) (*types.ProcessingActivityRegistryConnection, error) Snapshots(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SnapshotOrderBy) (*types.SnapshotConnection, error) TrustCenter(ctx context.Context, obj *types.Organization) (*types.TrustCenter, error) } @@ -5550,7 +5552,7 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return 0, false } - return e.complexity.Organization.ProcessingActivityRegistries(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.ProcessingActivityRegistryOrderBy)), true + return e.complexity.Organization.ProcessingActivityRegistries(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.ProcessingActivityRegistryOrderBy), args["filter"].(*types.ProcessingActivityRegistryFilter)), true case "Organization.risks": if e.complexity.Organization.Risks == nil { @@ -5892,6 +5894,20 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.ProcessingActivityRegistry.SecurityMeasures(childComplexity), true + case "ProcessingActivityRegistry.snapshotId": + if e.complexity.ProcessingActivityRegistry.SnapshotID == nil { + break + } + + return e.complexity.ProcessingActivityRegistry.SnapshotID(childComplexity), true + + case "ProcessingActivityRegistry.sourceId": + if e.complexity.ProcessingActivityRegistry.SourceID == nil { + break + } + + return e.complexity.ProcessingActivityRegistry.SourceID(childComplexity), true + case "ProcessingActivityRegistry.specialOrCriminalData": if e.complexity.ProcessingActivityRegistry.SpecialOrCriminalData == nil { break @@ -7780,6 +7796,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputOrganizationOrder, ec.unmarshalInputPeopleFilter, ec.unmarshalInputPeopleOrder, + ec.unmarshalInputProcessingActivityRegistryFilter, ec.unmarshalInputProcessingActivityRegistryOrder, ec.unmarshalInputPublishDocumentVersionInput, ec.unmarshalInputRemoveUserInput, @@ -8806,6 +8823,10 @@ enum SnapshotsType @goEnum( value: "github.com/getprobo/probo/pkg/coredata.SnapshotsTypeContinualImprovementRegistries" ) + PROCESSING_ACTIVITY_REGISTRIES + @goEnum( + value: "github.com/getprobo/probo/pkg/coredata.SnapshotsTypeProcessingActivityRegistries" + ) } enum SnapshotOrderField @@ -9048,6 +9069,10 @@ input ContinualImprovementRegistryFilter { snapshotId: ID } +input ProcessingActivityRegistryFilter { + snapshotId: ID +} + # Core Types type TrustCenter implements Node { id: ID! @@ -9214,6 +9239,7 @@ type Organization implements Node { last: Int before: CursorKey orderBy: ProcessingActivityRegistryOrder + filter: ProcessingActivityRegistryFilter ): ProcessingActivityRegistryConnection! @goField(forceResolver: true) snapshots( @@ -9696,6 +9722,8 @@ type ContinualImprovementRegistry implements Node { type ProcessingActivityRegistry implements Node { id: ID! + snapshotId: ID + sourceId: ID organization: Organization! @goField(forceResolver: true) name: String! purpose: String @@ -17139,6 +17167,11 @@ func (ec *executionContext) field_Organization_processingActivityRegistries_args return nil, err } args["orderBy"] = arg4 + arg5, err := ec.field_Organization_processingActivityRegistries_argsFilter(ctx, rawArgs) + if err != nil { + return nil, err + } + args["filter"] = arg5 return args, nil } func (ec *executionContext) field_Organization_processingActivityRegistries_argsFirst( @@ -17206,6 +17239,19 @@ func (ec *executionContext) field_Organization_processingActivityRegistries_args return zeroVal, nil } +func (ec *executionContext) field_Organization_processingActivityRegistries_argsFilter( + ctx context.Context, + rawArgs map[string]any, +) (*types.ProcessingActivityRegistryFilter, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("filter")) + if tmp, ok := rawArgs["filter"]; ok { + return ec.unmarshalOProcessingActivityRegistryFilter2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐProcessingActivityRegistryFilter(ctx, tmp) + } + + var zeroVal *types.ProcessingActivityRegistryFilter + return zeroVal, nil +} + func (ec *executionContext) field_Organization_risks_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -42331,7 +42377,7 @@ func (ec *executionContext) _Organization_processingActivityRegistries(ctx conte }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Organization().ProcessingActivityRegistries(rctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.ProcessingActivityRegistryOrderBy)) + return ec.resolvers.Organization().ProcessingActivityRegistries(rctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.ProcessingActivityRegistryOrderBy), fc.Args["filter"].(*types.ProcessingActivityRegistryFilter)) }) if err != nil { ec.Error(ctx, err) @@ -43733,6 +43779,88 @@ func (ec *executionContext) fieldContext_ProcessingActivityRegistry_id(_ context return fc, nil } +func (ec *executionContext) _ProcessingActivityRegistry_snapshotId(ctx context.Context, field graphql.CollectedField, obj *types.ProcessingActivityRegistry) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ProcessingActivityRegistry_snapshotId(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.SnapshotID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*gid.GID) + fc.Result = res + return ec.marshalOID2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ProcessingActivityRegistry_snapshotId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ProcessingActivityRegistry", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ProcessingActivityRegistry_sourceId(ctx context.Context, field graphql.CollectedField, obj *types.ProcessingActivityRegistry) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ProcessingActivityRegistry_sourceId(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.SourceID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*gid.GID) + fc.Result = res + return ec.marshalOID2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ProcessingActivityRegistry_sourceId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ProcessingActivityRegistry", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _ProcessingActivityRegistry_organization(ctx context.Context, field graphql.CollectedField, obj *types.ProcessingActivityRegistry) (ret graphql.Marshaler) { fc, err := ec.fieldContext_ProcessingActivityRegistry_organization(ctx, field) if err != nil { @@ -44781,6 +44909,10 @@ func (ec *executionContext) fieldContext_ProcessingActivityRegistryEdge_node(_ c switch field.Name { case "id": return ec.fieldContext_ProcessingActivityRegistry_id(ctx, field) + case "snapshotId": + return ec.fieldContext_ProcessingActivityRegistry_snapshotId(ctx, field) + case "sourceId": + return ec.fieldContext_ProcessingActivityRegistry_sourceId(ctx, field) case "organization": return ec.fieldContext_ProcessingActivityRegistry_organization(ctx, field) case "name": @@ -50682,6 +50814,10 @@ func (ec *executionContext) fieldContext_UpdateProcessingActivityRegistryPayload switch field.Name { case "id": return ec.fieldContext_ProcessingActivityRegistry_id(ctx, field) + case "snapshotId": + return ec.fieldContext_ProcessingActivityRegistry_snapshotId(ctx, field) + case "sourceId": + return ec.fieldContext_ProcessingActivityRegistry_sourceId(ctx, field) case "organization": return ec.fieldContext_ProcessingActivityRegistry_organization(ctx, field) case "name": @@ -63407,6 +63543,33 @@ func (ec *executionContext) unmarshalInputPeopleOrder(ctx context.Context, obj a return it, nil } +func (ec *executionContext) unmarshalInputProcessingActivityRegistryFilter(ctx context.Context, obj any) (types.ProcessingActivityRegistryFilter, error) { + var it types.ProcessingActivityRegistryFilter + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"snapshotId"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "snapshotId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("snapshotId")) + data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v) + if err != nil { + return it, err + } + it.SnapshotID = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputProcessingActivityRegistryOrder(ctx context.Context, obj any) (types.ProcessingActivityRegistryOrderBy, error) { var it types.ProcessingActivityRegistryOrderBy asMap := map[string]any{} @@ -75118,6 +75281,10 @@ func (ec *executionContext) _ProcessingActivityRegistry(ctx context.Context, sel if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } + case "snapshotId": + out.Values[i] = ec._ProcessingActivityRegistry_snapshotId(ctx, field, obj) + case "sourceId": + out.Values[i] = ec._ProcessingActivityRegistry_sourceId(ctx, field, obj) case "organization": field := field @@ -84978,6 +85145,7 @@ var ( "NONCONFORMITY_REGISTRIES": coredata.SnapshotsTypeNonConformityRegistries, "COMPLIANCE_REGISTRIES": coredata.SnapshotsTypeComplianceRegistries, "CONTINUAL_IMPROVEMENT_REGISTRIES": coredata.SnapshotsTypeContinualImprovementRegistries, + "PROCESSING_ACTIVITY_REGISTRIES": coredata.SnapshotsTypeProcessingActivityRegistries, } marshalNSnapshotsType2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐSnapshotsType = map[coredata.SnapshotsType]string{ coredata.SnapshotsTypeRisks: "RISKS", @@ -84987,6 +85155,7 @@ var ( coredata.SnapshotsTypeNonConformityRegistries: "NONCONFORMITY_REGISTRIES", coredata.SnapshotsTypeComplianceRegistries: "COMPLIANCE_REGISTRIES", coredata.SnapshotsTypeContinualImprovementRegistries: "CONTINUAL_IMPROVEMENT_REGISTRIES", + coredata.SnapshotsTypeProcessingActivityRegistries: "PROCESSING_ACTIVITY_REGISTRIES", } ) @@ -87738,6 +87907,14 @@ var ( } ) +func (ec *executionContext) unmarshalOProcessingActivityRegistryFilter2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐProcessingActivityRegistryFilter(ctx context.Context, v any) (*types.ProcessingActivityRegistryFilter, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputProcessingActivityRegistryFilter(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalOProcessingActivityRegistryLawfulBasis2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐProcessingActivityRegistryLawfulBasis(ctx context.Context, v any) (*coredata.ProcessingActivityRegistryLawfulBasis, error) { if v == nil { return nil, nil diff --git a/pkg/server/api/console/v1/types/processing_activity_registry.go b/pkg/server/api/console/v1/types/processing_activity_registry.go index 29c27981c..89d411615 100644 --- a/pkg/server/api/console/v1/types/processing_activity_registry.go +++ b/pkg/server/api/console/v1/types/processing_activity_registry.go @@ -30,6 +30,7 @@ type ( Resolver any ParentID gid.GID + Filter *ProcessingActivityRegistryFilter } ) @@ -37,6 +38,7 @@ func NewProcessingActivityRegistryConnection( p *page.Page[*coredata.ProcessingActivityRegistry, coredata.ProcessingActivityRegistryOrderField], parentType any, parentID gid.GID, + filter *ProcessingActivityRegistryFilter, ) *ProcessingActivityRegistryConnection { edges := make([]*ProcessingActivityRegistryEdge, len(p.Data)) for i, registry := range p.Data { @@ -49,12 +51,14 @@ func NewProcessingActivityRegistryConnection( Resolver: parentType, ParentID: parentID, + Filter: filter, } } func NewProcessingActivityRegistry(par *coredata.ProcessingActivityRegistry) *ProcessingActivityRegistry { return &ProcessingActivityRegistry{ ID: par.ID, + SnapshotID: par.SnapshotID, Name: par.Name, Purpose: par.Purpose, DataSubjectCategory: par.DataSubjectCategory, diff --git a/pkg/server/api/console/v1/types/types.go b/pkg/server/api/console/v1/types/types.go index a2a4eea5e..c8af3e47c 100644 --- a/pkg/server/api/console/v1/types/types.go +++ b/pkg/server/api/console/v1/types/types.go @@ -1239,6 +1239,8 @@ type PeopleFilter struct { type ProcessingActivityRegistry struct { ID gid.GID `json:"id"` + SnapshotID *gid.GID `json:"snapshotId,omitempty"` + SourceID *gid.GID `json:"sourceId,omitempty"` Organization *Organization `json:"organization"` Name string `json:"name"` Purpose *string `json:"purpose,omitempty"` @@ -1267,6 +1269,10 @@ type ProcessingActivityRegistryEdge struct { Node *ProcessingActivityRegistry `json:"node"` } +type ProcessingActivityRegistryFilter struct { + SnapshotID *gid.GID `json:"snapshotId,omitempty"` +} + type PublishDocumentVersionInput struct { DocumentID gid.GID `json:"documentId"` Changelog *string `json:"changelog,omitempty"` diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go index 20510ef01..cb623811d 100644 --- a/pkg/server/api/console/v1/v1_resolver.go +++ b/pkg/server/api/console/v1/v1_resolver.go @@ -3797,7 +3797,7 @@ func (r *organizationResolver) ContinualImprovementRegistries(ctx context.Contex } // ProcessingActivityRegistries is the resolver for the processingActivityRegistries field. -func (r *organizationResolver) ProcessingActivityRegistries(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityRegistryOrderBy) (*types.ProcessingActivityRegistryConnection, error) { +func (r *organizationResolver) ProcessingActivityRegistries(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityRegistryOrderBy, filter *types.ProcessingActivityRegistryFilter) (*types.ProcessingActivityRegistryConnection, error) { prb := r.ProboService(ctx, obj.ID.TenantID()) pageOrderBy := page.OrderBy[coredata.ProcessingActivityRegistryOrderField]{ @@ -3814,12 +3814,17 @@ func (r *organizationResolver) ProcessingActivityRegistries(ctx context.Context, cursor := types.NewCursor(first, after, last, before, pageOrderBy) - page, err := prb.ProcessingActivityRegistries.ListForOrganizationID(ctx, obj.ID, cursor) + processingActivityRegistryFilter := coredata.NewProcessingActivityRegistryFilter(nil) + if filter != nil { + processingActivityRegistryFilter = coredata.NewProcessingActivityRegistryFilter(&filter.SnapshotID) + } + + page, err := prb.ProcessingActivityRegistries.ListForOrganizationID(ctx, obj.ID, cursor, processingActivityRegistryFilter) if err != nil { panic(fmt.Errorf("cannot list organization processing activity registries: %w", err)) } - return types.NewProcessingActivityRegistryConnection(page, r, obj.ID), nil + return types.NewProcessingActivityRegistryConnection(page, r, obj.ID, filter), nil } // Snapshots is the resolver for the snapshots field. @@ -3898,7 +3903,12 @@ func (r *processingActivityRegistryConnectionResolver) TotalCount(ctx context.Co switch obj.Resolver.(type) { case *organizationResolver: - count, err := prb.ProcessingActivityRegistries.CountForOrganizationID(ctx, obj.ParentID) + processingActivityRegistryFilter := coredata.NewProcessingActivityRegistryFilter(nil) + if obj.Filter != nil { + processingActivityRegistryFilter = coredata.NewProcessingActivityRegistryFilter(&obj.Filter.SnapshotID) + } + + count, err := prb.ProcessingActivityRegistries.CountForOrganizationID(ctx, obj.ParentID, processingActivityRegistryFilter) if err != nil { panic(fmt.Errorf("cannot count organization processing activity registries: %w", err)) }