Add processing activity registry snapshots

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-08-29 16:59:54 +02:00
parent 433101fce9
commit 612149afc8
29 changed files with 831 additions and 192 deletions

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<849144f476ae613437242fe09259fc68>>
* @generated SignedSource<<e5b5af0abe1d8af6f97da741084f1b16>>
* @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;
};

View File

@@ -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;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<1348b159bfe8d53aa1b080efc63bd1b4>>
* @generated SignedSource<<aaed837d3d9cdc303e3096ea7a467bd9>>
* @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;

View File

@@ -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

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<8f505e33f8bc537835367f0f54547998>>
* @generated SignedSource<<c9fc3a1c4c1b2b41057496949cfea3bb>>
* @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;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<e44cc513f256fbae2b03229efc8bd938>>
* @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;

View File

@@ -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;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<202fa0acc16dc4343e193fb3f6784f3c>>
* @generated SignedSource<<a8ffaeebdff333e49715088203906cdb>>
* @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;
};

View File

@@ -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 (
<div className="space-y-6">
{isSnapshotMode && snapshotId && (
<SnapshotBanner snapshotId={snapshotId} />
)}
<PageHeader title={__("Processing Activity Registries")} description={__("Manage your processing activity registry entries under GDPR")}>
<CreateProcessingActivityRegistryDialog
organizationId={organizationId}
connectionId={connectionId}
>
<Button icon={IconPlusLarge}>
{__("Add processing activity registry")}
</Button>
</CreateProcessingActivityRegistryDialog>
{!isSnapshotMode && (
<CreateProcessingActivityRegistryDialog
organizationId={organizationId}
connectionId={connectionId}
>
<Button icon={IconPlusLarge}>
{__("Add processing activity registry")}
</Button>
</CreateProcessingActivityRegistryDialog>
)}
</PageHeader>
{registries.length > 0 ? (
@@ -137,7 +155,7 @@ export default function ProcessingActivityRegistriesPage({ queryRef }: Processin
<Th>{__("Lawful Basis")}</Th>
<Th>{__("Location")}</Th>
<Th>{__("International Transfers")}</Th>
<Th>{__("Actions")}</Th>
{!isSnapshotMode && <Th>{__("Actions")}</Th>}
</Tr>
</Thead>
<Tbody>
@@ -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 (
<Tr to={`/organizations/${organizationId}/processing-activity-registries/${registry.id}`}>
<Tr to={registryUrl}>
<Td>
<span className="font-semibold">{registry.name}</span>
</Td>
@@ -231,17 +255,19 @@ function RegistryRow({
{registry.internationalTransfers ? __("Yes") : __("No")}
</Badge>
</Td>
<Td noLink width={50} className="text-end">
<ActionDropdown>
<DropdownItem
icon={IconTrashCan}
variant="danger"
onSelect={handleDelete}
>
{__("Delete")}
</DropdownItem>
</ActionDropdown>
</Td>
{!isSnapshotMode && (
<Td noLink width={50} className="text-end">
<ActionDropdown>
<DropdownItem
icon={IconTrashCan}
variant="danger"
onSelect={handleDelete}
>
{__("Delete")}
</DropdownItem>
</ActionDropdown>
</Td>
)}
</Tr>
);
}

View File

@@ -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 <div>{__("Processing activity registry entry not found")}</div>;
}
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 (
<div className="space-y-6">
{isSnapshotMode && snapshotId && (
<SnapshotBanner snapshotId={snapshotId} />
)}
<div className="flex items-center justify-between">
<Breadcrumb
items={[
{ label: __("Processing Activity Registries"), to: "../processing-activity-registries" },
{ label: __("Processing Activity Registries"), to: breadcrumbRegistriesUrl },
{ label: registry.name! },
]}
/>
<ActionDropdown>
<DropdownItem onClick={deleteRegistry} variant="danger">
{__("Delete")}
</DropdownItem>
</ActionDropdown>
{!isSnapshotMode && (
<ActionDropdown>
<DropdownItem onClick={deleteRegistry} variant="danger">
{__("Delete")}
</DropdownItem>
</ActionDropdown>
)}
</div>
<Card>
@@ -169,6 +186,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
{...register("name")}
error={formState.errors.name?.message}
required
disabled={isSnapshotMode}
/>
<div>
@@ -177,6 +195,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
{...register("purpose")}
placeholder={__("Describe the purpose of processing")}
rows={3}
disabled={isSnapshotMode}
/>
</div>
@@ -184,12 +203,14 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
label={__("Data Subject Category")}
{...register("dataSubjectCategory")}
placeholder={__("e.g., employees, customers, prospects")}
disabled={isSnapshotMode}
/>
<Field
label={__("Personal Data Category")}
{...register("personalDataCategory")}
placeholder={__("e.g., contact details, financial data")}
disabled={isSnapshotMode}
/>
<div>
@@ -204,6 +225,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
onValueChange={field.onChange}
value={field.value}
className="w-full"
disabled={isSnapshotMode}
>
<SpecialOrCriminalDataOptions />
</Select>
@@ -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}
/>
<div>
@@ -232,6 +255,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
onValueChange={field.onChange}
value={field.value}
className="w-full"
disabled={isSnapshotMode}
>
<LawfulBasisOptions />
</Select>
@@ -248,28 +272,31 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
label={__("Recipients")}
{...register("recipients")}
placeholder={__("Who receives the data")}
disabled={isSnapshotMode}
/>
<Field
label={__("Location")}
{...register("location")}
placeholder={__("Where is the data processed")}
disabled={isSnapshotMode}
/>
<Controller
control={control}
name="internationalTransfers"
render={({ field }) => (
<div>
<Label>{__("International Transfers")}</Label>
<div className="mt-2 flex items-center gap-2">
<Checkbox
checked={field.value}
onChange={field.onChange}
/>
<span>{__("Data is transferred internationally")}</span>
</div>
</div>
<div>
<Label>{__("International Transfers")}</Label>
<div className="mt-2 flex items-center gap-2">
<Checkbox
checked={field.value}
onChange={field.onChange}
disabled={isSnapshotMode}
/>
<span>{__("Data is transferred internationally")}</span>
</div>
</div>
)}
/>
@@ -285,6 +312,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
onValueChange={field.onChange}
value={field.value}
className="w-full"
disabled={isSnapshotMode}
>
<TransferSafeguardsOptions />
</Select>
@@ -299,6 +327,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
label={__("Retention Period")}
{...register("retentionPeriod")}
placeholder={__("How long is data retained")}
disabled={isSnapshotMode}
/>
<div>
@@ -307,6 +336,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
{...register("securityMeasures")}
placeholder={__("Technical and organizational measures")}
rows={3}
disabled={isSnapshotMode}
/>
</div>
@@ -322,6 +352,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
onValueChange={field.onChange}
value={field.value}
className="w-full"
disabled={isSnapshotMode}
>
<DataProtectionImpactAssessmentOptions />
</Select>
@@ -344,6 +375,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
onValueChange={field.onChange}
value={field.value}
className="w-full"
disabled={isSnapshotMode}
>
<TransferImpactAssessmentOptions />
</Select>
@@ -356,15 +388,17 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
</div>
</div>
<div className="flex justify-end pt-4">
<Button
type="submit"
variant="primary"
disabled={formState.isSubmitting}
>
{formState.isSubmitting ? __("Saving...") : __("Save Changes")}
</Button>
</div>
{!isSnapshotMode && (
<div className="flex justify-end pt-4">
<Button
type="submit"
variant="primary"
disabled={formState.isSubmitting}
>
{formState.isSubmitting ? __("Saving...") : __("Save Changes")}
</Button>
</div>
)}
</form>
</div>
</Card>

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<f2595590d945925932f5093a2c76dd1b>>
* @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;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<71dfd7c0d78070061957215363022475>>
* @generated SignedSource<<e77ebb6a609b6122e9c6927f4e00acc4>>
* @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;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<3ad73dde5a41f4370035f6156fc1f38b>>
* @generated SignedSource<<fc4bc917b12579179eb09cc4919b1b57>>
* @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;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<e89d235e5971b278e9826d421b4a680c>>
* @generated SignedSource<<dc710d55da977c21a12e3e21f29fbe94>>
* @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: {

View File

@@ -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;

View File

@@ -9,8 +9,23 @@ export const processingActivityRegistryRoutes = [
{
path: "processing-activity-registries",
fallback: PageSkeleton,
queryLoader: ({ organizationId }: { organizationId: string }) =>
loadQuery(relayEnvironment, processingActivityRegistriesQuery, { organizationId }),
queryLoader: (params: Record<string, string>) =>
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<string, string>) =>
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<string, string>) =>
loadQuery(relayEnvironment, processingActivityRegistryNodeQuery, {
processingActivityRegistryId: params.registryId
}),
Component: lazy(
() => import("/pages/organizations/processingActivityRegistries/ProcessingActivityRegistryDetailsPage")
),
},
] satisfies AppRoute[];

View File

@@ -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 "";
}

View File

@@ -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 (
<div className={checkbox({ isFocused, checked })}>
<div className={checkbox({ isFocused, checked, disabled })}>
<input
className="absolute inset-0 opacity-0"
type="checkbox"
checked={checked}
onChange={(e) => onChange(e.target.checked)}
onFocus={() => setFocus(true)}
disabled={disabled}
onChange={(e) => !disabled && onChange(e.target.checked)}
onFocus={() => !disabled && setFocus(true)}
onBlur={() => setFocus(false)}
/>
{checked && <IconCheckmark1 size={12} />}

View File

@@ -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);

View File

@@ -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
}

View File

@@ -0,0 +1,54 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// 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"
}
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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"`

View File

@@ -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))
}