diff --git a/apps/console/src/hooks/graph/ComplianceRegistryGraph.ts b/apps/console/src/hooks/graph/ComplianceRegistryGraph.ts index f157d3f4b..187ac404f 100644 --- a/apps/console/src/hooks/graph/ComplianceRegistryGraph.ts +++ b/apps/console/src/hooks/graph/ComplianceRegistryGraph.ts @@ -8,10 +8,10 @@ import { useMutationWithToasts } from "../useMutationWithToasts"; export const ComplianceRegistriesConnectionKey = "ComplianceRegistriesPage_complianceRegistries"; export const complianceRegistriesQuery = graphql` - query ComplianceRegistryGraphListQuery($organizationId: ID!) { + query ComplianceRegistryGraphListQuery($organizationId: ID!, $snapshotId: ID) { node(id: $organizationId) { ... on Organization { - ...ComplianceRegistriesPageFragment + ...ComplianceRegistriesPageFragment @arguments(snapshotId: $snapshotId) } } } @@ -22,6 +22,8 @@ export const complianceRegistryNodeQuery = graphql` node(id: $complianceRegistryId) { ... on ComplianceRegistry { id + snapshotId + sourceId referenceId area source diff --git a/apps/console/src/hooks/graph/__generated__/ComplianceRegistryGraphListQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/ComplianceRegistryGraphListQuery.graphql.ts index 66306a0ce..073e9c412 100644 --- a/apps/console/src/hooks/graph/__generated__/ComplianceRegistryGraphListQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/ComplianceRegistryGraphListQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<41975a1dcc769268a6255ea703ff26fe>> * @lightSyntaxTransform * @nogrep */ @@ -12,6 +12,7 @@ import { ConcreteRequest } from 'relay-runtime'; import { FragmentRefs } from "relay-runtime"; export type ComplianceRegistryGraphListQuery$variables = { organizationId: string; + snapshotId?: string | null | undefined; }; export type ComplianceRegistryGraphListQuery$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": "ComplianceRegistriesPageFragment" } @@ -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": "ComplianceRegistryConnection", "kind": "LinkedField", "name": "complianceRegistries", @@ -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, @@ -215,7 +247,7 @@ return { "name": "owner", "plural": false, "selections": [ - (v3/*: any*/), + (v4/*: any*/), { "alias": null, "args": null, @@ -240,7 +272,7 @@ return { "name": "updatedAt", "storageKey": null }, - (v2/*: any*/) + (v3/*: any*/) ], "storageKey": null }, @@ -292,12 +324,14 @@ return { ] } ], - "storageKey": "complianceRegistries(first:10)" + "storageKey": null }, { "alias": null, - "args": (v4/*: any*/), - "filters": null, + "args": (v5/*: any*/), + "filters": [ + "filter" + ], "handle": "connection", "key": "ComplianceRegistriesPage_complianceRegistries", "kind": "LinkedHandle", @@ -313,16 +347,16 @@ return { ] }, "params": { - "cacheID": "2852dc9732086326e7770650cbd00ad1", + "cacheID": "d578089841a93f60ae9ba5bc6e9175b0", "id": null, "metadata": {}, "name": "ComplianceRegistryGraphListQuery", "operationKind": "query", - "text": "query ComplianceRegistryGraphListQuery(\n $organizationId: ID!\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ComplianceRegistriesPageFragment\n }\n id\n }\n}\n\nfragment ComplianceRegistriesPageFragment on Organization {\n id\n complianceRegistries(first: 10) {\n totalCount\n edges {\n node {\n id\n referenceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" + "text": "query ComplianceRegistryGraphListQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ComplianceRegistriesPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ComplianceRegistriesPageFragment_3iomuz on Organization {\n id\n complianceRegistries(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n referenceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" } }; })(); -(node as any).hash = "363434c78eb3e27ac52b6da13c7432a1"; +(node as any).hash = "2c50dd58eb2d72e49bce300726f35a34"; export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ComplianceRegistryGraphNodeQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/ComplianceRegistryGraphNodeQuery.graphql.ts index 574c74a63..9f4bacda3 100644 --- a/apps/console/src/hooks/graph/__generated__/ComplianceRegistryGraphNodeQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/ComplianceRegistryGraphNodeQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -32,7 +32,9 @@ export type ComplianceRegistryGraphNodeQuery$data = { readonly referenceId?: string; readonly regulator?: string | null | undefined; readonly requirement?: string | null | undefined; + readonly snapshotId?: string | null | undefined; readonly source?: string | null | undefined; + readonly sourceId?: string | null | undefined; readonly status?: ComplianceRegistryStatus; readonly updatedAt?: any; }; @@ -68,66 +70,80 @@ v3 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "referenceId", + "name": "snapshotId", "storageKey": null }, v4 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "area", + "name": "sourceId", "storageKey": null }, v5 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "source", + "name": "referenceId", "storageKey": null }, v6 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "requirement", + "name": "area", "storageKey": null }, v7 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "actionsToBeImplemented", + "name": "source", "storageKey": null }, v8 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "regulator", + "name": "requirement", "storageKey": null }, v9 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "lastReviewDate", + "name": "actionsToBeImplemented", "storageKey": null }, v10 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "dueDate", + "name": "regulator", "storageKey": null }, v11 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "status", + "name": "lastReviewDate", "storageKey": null }, v12 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "dueDate", + "storageKey": null +}, +v13 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null +}, +v14 = { "alias": null, "args": null, "concreteType": "People", @@ -146,7 +162,7 @@ v12 = { ], "storageKey": null }, -v13 = { +v15 = { "alias": null, "args": null, "concreteType": "Organization", @@ -165,14 +181,14 @@ v13 = { ], "storageKey": null }, -v14 = { +v16 = { "alias": null, "args": null, "kind": "ScalarField", "name": "createdAt", "storageKey": null }, -v15 = { +v17 = { "alias": null, "args": null, "kind": "ScalarField", @@ -210,7 +226,9 @@ return { (v12/*: any*/), (v13/*: any*/), (v14/*: any*/), - (v15/*: any*/) + (v15/*: any*/), + (v16/*: any*/), + (v17/*: any*/) ], "type": "ComplianceRegistry", "abstractKey": null @@ -259,7 +277,9 @@ return { (v12/*: any*/), (v13/*: any*/), (v14/*: any*/), - (v15/*: any*/) + (v15/*: any*/), + (v16/*: any*/), + (v17/*: any*/) ], "type": "ComplianceRegistry", "abstractKey": null @@ -270,16 +290,16 @@ return { ] }, "params": { - "cacheID": "4b91258de0711b2821a26bef89b60b02", + "cacheID": "2c4649d3258530fd79420bc2ed8fd14a", "id": null, "metadata": {}, "name": "ComplianceRegistryGraphNodeQuery", "operationKind": "query", - "text": "query ComplianceRegistryGraphNodeQuery(\n $complianceRegistryId: ID!\n) {\n node(id: $complianceRegistryId) {\n __typename\n ... on ComplianceRegistry {\n id\n referenceId\n area\n source\n requirement\n actionsToBeImplemented\n regulator\n lastReviewDate\n dueDate\n status\n owner {\n id\n fullName\n }\n organization {\n id\n name\n }\n createdAt\n updatedAt\n }\n id\n }\n}\n" + "text": "query ComplianceRegistryGraphNodeQuery(\n $complianceRegistryId: ID!\n) {\n node(id: $complianceRegistryId) {\n __typename\n ... on ComplianceRegistry {\n id\n snapshotId\n sourceId\n referenceId\n area\n source\n requirement\n actionsToBeImplemented\n regulator\n lastReviewDate\n dueDate\n status\n owner {\n id\n fullName\n }\n organization {\n id\n name\n }\n createdAt\n updatedAt\n }\n id\n }\n}\n" } }; })(); -(node as any).hash = "1b3352776a5b514b7545111aeb780148"; +(node as any).hash = "b290ce12f57b586e64bac227777bc294"; export default node; diff --git a/apps/console/src/pages/organizations/complianceRegistries/ComplianceRegistriesPage.tsx b/apps/console/src/pages/organizations/complianceRegistries/ComplianceRegistriesPage.tsx index 5cc691be2..401aa0ee1 100644 --- a/apps/console/src/pages/organizations/complianceRegistries/ComplianceRegistriesPage.tsx +++ b/apps/console/src/pages/organizations/complianceRegistries/ComplianceRegistriesPage.tsx @@ -24,10 +24,12 @@ import { useMutation, type PreloadedQuery, } from "react-relay"; +import { useParams } from "react-router"; import { useOrganizationId } from "/hooks/useOrganizationId"; import { CreateComplianceRegistryDialog } from "./dialogs/CreateComplianceRegistryDialog"; import { deleteComplianceRegistryMutation } from "../../../hooks/graph/ComplianceRegistryGraph"; import { sprintf, promisifyMutation, getStatusVariant, getStatusLabel } from "@probo/helpers"; +import { SnapshotBanner } from "/components/SnapshotBanner"; import type { ComplianceRegistriesPageQuery } from "./__generated__/ComplianceRegistriesPageQuery.graphql"; import type { ComplianceRegistriesPageFragment$key, @@ -46,15 +48,22 @@ const complianceRegistriesPageFragment = graphql` @argumentDefinitions( first: { type: "Int", defaultValue: 10 } after: { type: "CursorKey" } + snapshotId: { type: "ID", defaultValue: null } ) { id - complianceRegistries(first: $first, after: $after) - @connection(key: "ComplianceRegistriesPage_complianceRegistries") { + complianceRegistries( + first: $first + after: $after + filter: { snapshotId: $snapshotId } + ) + @connection(key: "ComplianceRegistriesPage_complianceRegistries", filters: ["filter"]) { __id totalCount edges { node { id + snapshotId + sourceId referenceId area source @@ -83,15 +92,17 @@ const complianceRegistriesPageFragment = graphql` export default function ComplianceRegistriesPage({ queryRef }: ComplianceRegistriesPageProps) { const { __ } = useTranslate(); const organizationId = useOrganizationId(); + const { snapshotId } = useParams<{ snapshotId?: string }>(); + const isSnapshotMode = Boolean(snapshotId); usePageTitle(__("Compliance Registries")); const organization = usePreloadedQuery( graphql` - query ComplianceRegistriesPageQuery($organizationId: ID!) { + query ComplianceRegistriesPageQuery($organizationId: ID!, $snapshotId: ID) { node(id: $organizationId) { ... on Organization { - ...ComplianceRegistriesPageFragment + ...ComplianceRegistriesPageFragment @arguments(snapshotId: $snapshotId) } } } @@ -109,15 +120,20 @@ export default function ComplianceRegistriesPage({ queryRef }: ComplianceRegistr return (
+ {isSnapshotMode && snapshotId && ( + + )} - - - + {!snapshotId && ( + + + + )} {registries.length === 0 ? ( @@ -151,6 +167,7 @@ export default function ComplianceRegistriesPage({ queryRef }: ComplianceRegistr key={registry.id} registry={registry} connectionId={connectionId} + snapshotId={snapshotId} /> ))} @@ -176,14 +193,17 @@ export default function ComplianceRegistriesPage({ queryRef }: ComplianceRegistr function RegistryRow({ registry, connectionId, + snapshotId, }: { registry: ComplianceRegistry; connectionId: string; + snapshotId?: string; }) { const organizationId = useOrganizationId(); const { __ } = useTranslate(); const [deleteRegistry] = useMutation(deleteComplianceRegistryMutation); const confirm = useConfirm(); + const isSnapshotMode = Boolean(snapshotId); const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString(); @@ -211,8 +231,12 @@ function RegistryRow({ ); }; + const detailsUrl = isSnapshotMode + ? `/organizations/${organizationId}/snapshots/${snapshotId}/compliance-registries/${registry.id}` + : `/organizations/${organizationId}/compliance-registries/${registry.id}`; + return ( - + {registry.referenceId} @@ -234,15 +258,17 @@ function RegistryRow({ )} - - - {__("Delete")} - - + {!isSnapshotMode && ( + + + {__("Delete")} + + + )} ); diff --git a/apps/console/src/pages/organizations/complianceRegistries/ComplianceRegistryDetailsPage.tsx b/apps/console/src/pages/organizations/complianceRegistries/ComplianceRegistryDetailsPage.tsx index d645b71d9..2ed65b93b 100644 --- a/apps/console/src/pages/organizations/complianceRegistries/ComplianceRegistryDetailsPage.tsx +++ b/apps/console/src/pages/organizations/complianceRegistries/ComplianceRegistryDetailsPage.tsx @@ -25,12 +25,14 @@ import { Select, } from "@probo/ui"; import { useTranslate } from "@probo/i18n"; +import { useParams } from "react-router"; import { useOrganizationId } from "/hooks/useOrganizationId"; import { PeopleSelectField } from "/components/form/PeopleSelectField"; import { useFormWithSchema } from "/hooks/useFormWithSchema"; import { Controller } from "react-hook-form"; import z from "zod"; -import { getStatusVariant, getStatusLabel, formatDatetime, getComplianceRegistryStatusOptions } from "@probo/helpers"; +import { getStatusVariant, getStatusLabel, formatDatetime, getComplianceRegistryStatusOptions, validateSnapshotConsistency } from "@probo/helpers"; +import { SnapshotBanner } from "/components/SnapshotBanner"; import type { ComplianceRegistryGraphNodeQuery } from "/hooks/graph/__generated__/ComplianceRegistryGraphNodeQuery.graphql"; const updateRegistrySchema = z.object({ @@ -56,11 +58,15 @@ export default function ComplianceRegistryDetailsPage(props: Props) { const { __ } = useTranslate(); const { toast } = useToast(); const organizationId = useOrganizationId(); + const { snapshotId } = useParams<{ snapshotId?: string }>(); + const isSnapshotMode = Boolean(snapshotId); if (!registry) { return
{__("Compliance registry entry not found")}
; } + validateSnapshotConsistency(registry, snapshotId); + const updateRegistry = useUpdateComplianceRegistry(); const statusOptions = getComplianceRegistryStatusOptions(__); @@ -124,29 +130,38 @@ export default function ComplianceRegistryDetailsPage(props: Props) { } }); + const breadcrumbComplianceRegistriesUrl = isSnapshotMode + ? `/organizations/${organizationId}/snapshots/${snapshotId}/compliance-registries` + : `/organizations/${organizationId}/compliance-registries`; + return (
+ {isSnapshotMode && snapshotId && ( + + )}
- -
-

{registry.referenceId}

- - {getStatusLabel(registry.status || "OPEN")} - -
+ +
+

{registry.referenceId}

+ + {getStatusLabel(registry.status || "OPEN")} +
+
- - - {__("Delete")} - - + {!isSnapshotMode && ( + + + {__("Delete")} + + + )}
@@ -159,6 +174,7 @@ export default function ComplianceRegistryDetailsPage(props: Props) { @@ -172,6 +188,7 @@ export default function ComplianceRegistryDetailsPage(props: Props) { @@ -182,6 +199,7 @@ export default function ComplianceRegistryDetailsPage(props: Props) {
@@ -198,6 +216,7 @@ export default function ComplianceRegistryDetailsPage(props: Props) { onValueChange={field.onChange} value={field.value} className="w-full" + disabled={isSnapshotMode} > {statusOptions.map((option) => (
@@ -248,6 +269,7 @@ export default function ComplianceRegistryDetailsPage(props: Props) { @@ -258,6 +280,7 @@ export default function ComplianceRegistryDetailsPage(props: Props) { @@ -270,6 +293,7 @@ export default function ComplianceRegistryDetailsPage(props: Props) { {...register("requirement")} placeholder={__("Enter requirement")} rows={4} + disabled={isSnapshotMode} /> @@ -281,17 +305,20 @@ export default function ComplianceRegistryDetailsPage(props: Props) { {...register("actionsToBeImplemented")} placeholder={__("Enter actions to be implemented")} rows={4} + disabled={isSnapshotMode} /> -
- -
+ {!isSnapshotMode && ( +
+ +
+ )} diff --git a/apps/console/src/pages/organizations/complianceRegistries/__generated__/ComplianceRegistriesPageFragment.graphql.ts b/apps/console/src/pages/organizations/complianceRegistries/__generated__/ComplianceRegistriesPageFragment.graphql.ts index c5c94913c..c540ca903 100644 --- a/apps/console/src/pages/organizations/complianceRegistries/__generated__/ComplianceRegistriesPageFragment.graphql.ts +++ b/apps/console/src/pages/organizations/complianceRegistries/__generated__/ComplianceRegistriesPageFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<312905201e0a72d96dd29afeed17dee1>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -29,7 +29,9 @@ export type ComplianceRegistriesPageFragment$data = { readonly referenceId: string; readonly regulator: string | null | undefined; readonly requirement: string | null | undefined; + readonly snapshotId: string | null | undefined; readonly source: string | null | undefined; + readonly sourceId: string | null | undefined; readonly status: ComplianceRegistryStatus; readonly updatedAt: any; }; @@ -72,6 +74,11 @@ return { "defaultValue": 10, "kind": "LocalArgument", "name": "first" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "snapshotId" } ], "kind": "Fragment", @@ -108,7 +115,19 @@ return { (v1/*: any*/), { "alias": "complianceRegistries", - "args": null, + "args": [ + { + "fields": [ + { + "kind": "Variable", + "name": "snapshotId", + "variableName": "snapshotId" + } + ], + "kind": "ObjectValue", + "name": "filter" + } + ], "concreteType": "ComplianceRegistryConnection", "kind": "LinkedField", "name": "__ComplianceRegistriesPage_complianceRegistries_connection", @@ -138,6 +157,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, @@ -300,6 +333,6 @@ return { }; })(); -(node as any).hash = "b6b97d09ba132cbc1ffb006c23a33589"; +(node as any).hash = "b22ac157b9ba89ab14fe8363e56957ef"; export default node; diff --git a/apps/console/src/pages/organizations/complianceRegistries/__generated__/ComplianceRegistriesPageQuery.graphql.ts b/apps/console/src/pages/organizations/complianceRegistries/__generated__/ComplianceRegistriesPageQuery.graphql.ts index 0fbb00ffe..024e46d35 100644 --- a/apps/console/src/pages/organizations/complianceRegistries/__generated__/ComplianceRegistriesPageQuery.graphql.ts +++ b/apps/console/src/pages/organizations/complianceRegistries/__generated__/ComplianceRegistriesPageQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<794221c1dbbf8fd2d1808863d55d2c05>> * @lightSyntaxTransform * @nogrep */ @@ -12,6 +12,7 @@ import { ConcreteRequest } from 'relay-runtime'; import { FragmentRefs } from "relay-runtime"; export type ComplianceRegistriesPageQuery$variables = { organizationId: string; + snapshotId?: string | null | undefined; }; export type ComplianceRegistriesPageQuery$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": "ComplianceRegistriesPageFragment" } @@ -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": "ComplianceRegistryConnection", "kind": "LinkedField", "name": "complianceRegistries", @@ -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, @@ -215,7 +247,7 @@ return { "name": "owner", "plural": false, "selections": [ - (v3/*: any*/), + (v4/*: any*/), { "alias": null, "args": null, @@ -240,7 +272,7 @@ return { "name": "updatedAt", "storageKey": null }, - (v2/*: any*/) + (v3/*: any*/) ], "storageKey": null }, @@ -292,12 +324,14 @@ return { ] } ], - "storageKey": "complianceRegistries(first:10)" + "storageKey": null }, { "alias": null, - "args": (v4/*: any*/), - "filters": null, + "args": (v5/*: any*/), + "filters": [ + "filter" + ], "handle": "connection", "key": "ComplianceRegistriesPage_complianceRegistries", "kind": "LinkedHandle", @@ -313,16 +347,16 @@ return { ] }, "params": { - "cacheID": "e4fba5ed79a8d19c72d2814f1adf38c3", + "cacheID": "b63e74cea7f47c7e4f735ad2b52e1765", "id": null, "metadata": {}, "name": "ComplianceRegistriesPageQuery", "operationKind": "query", - "text": "query ComplianceRegistriesPageQuery(\n $organizationId: ID!\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ComplianceRegistriesPageFragment\n }\n id\n }\n}\n\nfragment ComplianceRegistriesPageFragment on Organization {\n id\n complianceRegistries(first: 10) {\n totalCount\n edges {\n node {\n id\n referenceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" + "text": "query ComplianceRegistriesPageQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ComplianceRegistriesPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ComplianceRegistriesPageFragment_3iomuz on Organization {\n id\n complianceRegistries(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n referenceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" } }; })(); -(node as any).hash = "3e8551eebdf52ee84fb3910ee77cfe15"; +(node as any).hash = "f0064c0d6d6e628923be30edb4b249db"; export default node; diff --git a/apps/console/src/pages/organizations/complianceRegistries/__generated__/ComplianceRegistriesPageRefetchQuery.graphql.ts b/apps/console/src/pages/organizations/complianceRegistries/__generated__/ComplianceRegistriesPageRefetchQuery.graphql.ts index bdcebc470..b0093d2df 100644 --- a/apps/console/src/pages/organizations/complianceRegistries/__generated__/ComplianceRegistriesPageRefetchQuery.graphql.ts +++ b/apps/console/src/pages/organizations/complianceRegistries/__generated__/ComplianceRegistriesPageRefetchQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<25a63f42437f72ee5aea5f2c6e324d4a>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -14,6 +14,7 @@ export type ComplianceRegistriesPageRefetchQuery$variables = { after?: any | null | undefined; first?: number | null | undefined; id: string; + snapshotId?: string | null | undefined; }; export type ComplianceRegistriesPageRefetchQuery$data = { readonly node: { @@ -26,73 +27,99 @@ export type ComplianceRegistriesPageRefetchQuery = { }; 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": "ComplianceRegistriesPageRefetchQuery", "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": "ComplianceRegistriesPageFragment" } @@ -105,26 +132,31 @@ return { }, "kind": "Request", "operation": { - "argumentDefinitions": (v0/*: any*/), + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/), + (v3/*: any*/), + (v2/*: any*/) + ], "kind": "Operation", "name": "ComplianceRegistriesPageRefetchQuery", "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": "ComplianceRegistryConnection", "kind": "LinkedField", "name": "complianceRegistries", @@ -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, @@ -225,7 +271,7 @@ return { "name": "owner", "plural": false, "selections": [ - (v4/*: any*/), + (v9/*: any*/), { "alias": null, "args": null, @@ -250,7 +296,7 @@ return { "name": "updatedAt", "storageKey": null }, - (v3/*: any*/) + (v8/*: any*/) ], "storageKey": null }, @@ -306,8 +352,10 @@ return { }, { "alias": null, - "args": (v2/*: any*/), - "filters": null, + "args": (v10/*: any*/), + "filters": [ + "filter" + ], "handle": "connection", "key": "ComplianceRegistriesPage_complianceRegistries", "kind": "LinkedHandle", @@ -323,16 +371,16 @@ return { ] }, "params": { - "cacheID": "2b10e1f8598c007ee1e3e93e39b51b0d", + "cacheID": "d14ed4a195ca3b570ad5ecd255cf17e8", "id": null, "metadata": {}, "name": "ComplianceRegistriesPageRefetchQuery", "operationKind": "query", - "text": "query ComplianceRegistriesPageRefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ComplianceRegistriesPageFragment_2HEEH6\n id\n }\n}\n\nfragment ComplianceRegistriesPageFragment_2HEEH6 on Organization {\n id\n complianceRegistries(first: $first, after: $after) {\n totalCount\n edges {\n node {\n id\n referenceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" + "text": "query ComplianceRegistriesPageRefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ComplianceRegistriesPageFragment_35e0S5\n id\n }\n}\n\nfragment ComplianceRegistriesPageFragment_35e0S5 on Organization {\n id\n complianceRegistries(first: $first, after: $after, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n referenceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" } }; })(); -(node as any).hash = "b6b97d09ba132cbc1ffb006c23a33589"; +(node as any).hash = "b22ac157b9ba89ab14fe8363e56957ef"; export default node; diff --git a/apps/console/src/pages/organizations/snapshots/dialog/SnapshotFormDialog.tsx b/apps/console/src/pages/organizations/snapshots/dialog/SnapshotFormDialog.tsx index 8a9653458..729ceaa51 100644 --- a/apps/console/src/pages/organizations/snapshots/dialog/SnapshotFormDialog.tsx +++ b/apps/console/src/pages/organizations/snapshots/dialog/SnapshotFormDialog.tsx @@ -19,6 +19,7 @@ import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; import { useOrganizationId } from "/hooks/useOrganizationId"; import { ControlledField } from "/components/form/ControlledField"; import { SnapshotTypeOptions } from "/components/form/SnapshotTypeOptions"; +import { snapshotTypes } from "@probo/helpers"; const snapshotCreateMutation = graphql` mutation SnapshotFormDialogCreateMutation( @@ -42,7 +43,7 @@ const snapshotCreateMutation = graphql` const snapshotSchema = z.object({ name: z.string().min(2, { message: "Name is required" }), description: z.string().optional(), - type: z.enum(["DATA", "NONCONFORMITY_REGISTRIES"]), + type: z.enum(snapshotTypes), }); type Props = { diff --git a/apps/console/src/routes/complianceRegistryRoutes.ts b/apps/console/src/routes/complianceRegistryRoutes.ts index 90d32993d..dc78805d8 100644 --- a/apps/console/src/routes/complianceRegistryRoutes.ts +++ b/apps/console/src/routes/complianceRegistryRoutes.ts @@ -9,8 +9,23 @@ export const complianceRegistryRoutes = [ { path: "compliance-registries", fallback: PageSkeleton, - queryLoader: ({ organizationId }: { organizationId: string }) => - loadQuery(relayEnvironment, complianceRegistriesQuery, { organizationId }), + queryLoader: (params: Record) => + loadQuery(relayEnvironment, complianceRegistriesQuery, { + organizationId: params.organizationId, + snapshotId: null + }), + Component: lazy( + () => import("/pages/organizations/complianceRegistries/ComplianceRegistriesPage") + ), + }, + { + path: "snapshots/:snapshotId/compliance-registries", + fallback: PageSkeleton, + queryLoader: (params: Record) => + loadQuery(relayEnvironment, complianceRegistriesQuery, { + organizationId: params.organizationId, + snapshotId: params.snapshotId + }), Component: lazy( () => import("/pages/organizations/complianceRegistries/ComplianceRegistriesPage") ), @@ -26,4 +41,15 @@ export const complianceRegistryRoutes = [ () => import("/pages/organizations/complianceRegistries/ComplianceRegistryDetailsPage") ), }, + { + path: "snapshots/:snapshotId/compliance-registries/:registryId", + fallback: PageSkeleton, + queryLoader: (params: Record) => + loadQuery(relayEnvironment, complianceRegistryNodeQuery, { + complianceRegistryId: params.registryId + }), + Component: lazy( + () => import("/pages/organizations/complianceRegistries/ComplianceRegistryDetailsPage") + ), + }, ] satisfies AppRoute[]; diff --git a/packages/helpers/src/snapshots.ts b/packages/helpers/src/snapshots.ts index 1d4f3203d..6bd016110 100644 --- a/packages/helpers/src/snapshots.ts +++ b/packages/helpers/src/snapshots.ts @@ -3,6 +3,7 @@ type Translator = (s: string) => string; export const snapshotTypes = [ "DATA", "NONCONFORMITY_REGISTRIES", + "COMPLIANCE_REGISTRIES", ] as const; export function getSnapshotTypeLabel(__: Translator, type: string | null | undefined) { @@ -34,6 +35,8 @@ export function getSnapshotTypeUrlPath(type?: string): string { return "/data"; case "NONCONFORMITY_REGISTRIES": return "/nonconformity-registries"; + case "COMPLIANCE_REGISTRIES": + return "/compliance-registries"; default: return ""; } diff --git a/pkg/coredata/compliance_registry.go b/pkg/coredata/compliance_registry.go index 73d798cc8..7430972bd 100644 --- a/pkg/coredata/compliance_registry.go +++ b/pkg/coredata/compliance_registry.go @@ -40,6 +40,8 @@ type ( LastReviewDate *time.Time `db:"last_review_date"` DueDate *time.Time `db:"due_date"` Status ComplianceRegistryStatus `db:"status"` + SnapshotID *gid.GID `db:"snapshot_id"` + SourceID *gid.GID `db:"source_id"` CreatedAt time.Time `db:"created_at"` UpdatedAt time.Time `db:"updated_at"` } @@ -74,6 +76,8 @@ func (cr *ComplianceRegistry) LoadByID( SELECT id, organization_id, + snapshot_id, + source_id, reference_id, area, source, @@ -119,6 +123,7 @@ func (crs *ComplianceRegistries) CountByOrganizationID( conn pg.Conn, scope Scoper, organizationID gid.GID, + filter *ComplianceRegistryFilter, ) (int, error) { q := ` SELECT @@ -128,12 +133,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) @@ -152,6 +159,7 @@ func (crs *ComplianceRegistries) LoadByOrganizationID( scope Scoper, organizationID gid.GID, cursor *page.Cursor[ComplianceRegistryOrderField], + filter *ComplianceRegistryFilter, ) error { q := ` SELECT @@ -167,6 +175,8 @@ SELECT last_review_date, due_date, status, + snapshot_id, + source_id, created_at, updated_at FROM @@ -175,12 +185,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) @@ -218,6 +230,8 @@ INSERT INTO compliance_registries ( last_review_date, due_date, status, + snapshot_id, + source_id, created_at, updated_at ) VALUES ( @@ -234,6 +248,8 @@ INSERT INTO compliance_registries ( @last_review_date, @due_date, @status, + @snapshot_id, + @source_id, @created_at, @updated_at ) @@ -253,6 +269,8 @@ INSERT INTO compliance_registries ( "last_review_date": cr.LastReviewDate, "due_date": cr.DueDate, "status": cr.Status, + "snapshot_id": cr.SnapshotID, + "source_id": cr.SourceID, "created_at": cr.CreatedAt, "updated_at": cr.UpdatedAt, } @@ -286,6 +304,7 @@ UPDATE compliance_registries SET WHERE %s AND id = @id + AND snapshot_id IS NULL ` q = fmt.Sprintf(q, scope.SQLFragment()) @@ -324,6 +343,7 @@ DELETE FROM compliance_registries WHERE %s AND id = @id + AND snapshot_id IS NULL ` q = fmt.Sprintf(q, scope.SQLFragment()) @@ -338,3 +358,64 @@ WHERE return nil } + +func (crs ComplianceRegistries) Snapshot(ctx context.Context, conn pg.Conn, scope Scoper, organizationID, snapshotID gid.GID) error { + query := ` +INSERT INTO compliance_registries ( + id, + tenant_id, + snapshot_id, + source_id, + organization_id, + reference_id, + area, + source, + requirement, + actions_to_be_implemented, + regulator, + owner_id, + last_review_date, + due_date, + status, + created_at, + updated_at +) +SELECT + generate_gid(decode_base64_unpadded(@tenant_id), @compliance_registry_entity_type), + @tenant_id, + @snapshot_id, + r.id, + r.organization_id, + r.reference_id, + r.area, + r.source, + r.requirement, + r.actions_to_be_implemented, + r.regulator, + r.owner_id, + r.last_review_date, + r.due_date, + r.status, + r.created_at, + r.updated_at +FROM compliance_registries r +WHERE %s AND r.organization_id = @organization_id AND r.snapshot_id IS NULL + ` + + query = fmt.Sprintf(query, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{ + "tenant_id": scope.GetTenantID(), + "snapshot_id": snapshotID, + "organization_id": organizationID, + "compliance_registry_entity_type": ComplianceRegistryEntityType, + } + maps.Copy(args, scope.SQLArguments()) + + _, err := conn.Exec(ctx, query, args) + if err != nil { + return fmt.Errorf("cannot insert compliance registry snapshots: %w", err) + } + + return nil +} diff --git a/pkg/coredata/compliance_registry_filter.go b/pkg/coredata/compliance_registry_filter.go new file mode 100644 index 000000000..1143e8d42 --- /dev/null +++ b/pkg/coredata/compliance_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 ( + ComplianceRegistryFilter struct { + snapshotID **gid.GID + } +) + +func NewComplianceRegistryFilter(snapshotID **gid.GID) *ComplianceRegistryFilter { + return &ComplianceRegistryFilter{ + snapshotID: snapshotID, + } +} + +func (f *ComplianceRegistryFilter) SQLArguments() pgx.NamedArgs { + args := pgx.NamedArgs{} + + if f.snapshotID != nil && *f.snapshotID != nil { + args["filter_snapshot_id"] = **f.snapshotID + } + + return args +} + +func (f *ComplianceRegistryFilter) 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/datum_filter.go b/pkg/coredata/datum_filter.go index f0985b0a3..a3816fc61 100644 --- a/pkg/coredata/datum_filter.go +++ b/pkg/coredata/datum_filter.go @@ -25,13 +25,7 @@ type ( } ) -func NewDatumFilter() *DatumFilter { - return &DatumFilter{ - snapshotID: nil, - } -} - -func NewDatumFilterBySnapshotID(snapshotID **gid.GID) *DatumFilter { +func NewDatumFilter(snapshotID **gid.GID) *DatumFilter { return &DatumFilter{ snapshotID: snapshotID, } diff --git a/pkg/coredata/migrations/20250828T201559Z.sql b/pkg/coredata/migrations/20250828T201559Z.sql new file mode 100644 index 000000000..2d8814e51 --- /dev/null +++ b/pkg/coredata/migrations/20250828T201559Z.sql @@ -0,0 +1,11 @@ +ALTER TABLE compliance_registries ADD COLUMN snapshot_id TEXT; +ALTER TABLE compliance_registries ADD COLUMN source_id TEXT; + +ALTER TABLE compliance_registries ADD CONSTRAINT compliance_registries_snapshot_id_fkey + FOREIGN KEY (snapshot_id) + REFERENCES snapshots(id) + ON UPDATE CASCADE + ON DELETE CASCADE; + +ALTER TABLE compliance_registries ADD CONSTRAINT compliance_registries_source_id_snapshot_id_key + UNIQUE (source_id, snapshot_id); diff --git a/pkg/coredata/nonconformity_registry_filter.go b/pkg/coredata/nonconformity_registry_filter.go index bc5aa2b84..45775ca71 100644 --- a/pkg/coredata/nonconformity_registry_filter.go +++ b/pkg/coredata/nonconformity_registry_filter.go @@ -25,18 +25,12 @@ type ( } ) -func NewNonconformityRegistryFilter() *NonconformityRegistryFilter { +func NewNonconformityRegistryFilter(snapshotID **gid.GID) *NonconformityRegistryFilter { return &NonconformityRegistryFilter{ snapshotID: nil, } } -func NewNonconformityRegistryFilterBySnapshotID(snapshotID **gid.GID) *NonconformityRegistryFilter { - return &NonconformityRegistryFilter{ - snapshotID: snapshotID, - } -} - func (f *NonconformityRegistryFilter) SQLArguments() pgx.NamedArgs { args := pgx.NamedArgs{} diff --git a/pkg/coredata/snapshottable.go b/pkg/coredata/snapshottable.go index 75ad8e005..7e4802c62 100644 --- a/pkg/coredata/snapshottable.go +++ b/pkg/coredata/snapshottable.go @@ -32,6 +32,8 @@ func GetSnapshottable(snapshotType SnapshotsType) (Snapshottable, error) { return Data{}, nil case SnapshotsTypeNonConformityRegistries: return NonconformityRegistries{}, nil + case SnapshotsTypeComplianceRegistries: + return ComplianceRegistries{}, nil default: return nil, fmt.Errorf("unsupported snapshot type: %s", snapshotType) } diff --git a/pkg/coredata/vendor_filter.go b/pkg/coredata/vendor_filter.go index c60de0b0e..45ba1a4ca 100644 --- a/pkg/coredata/vendor_filter.go +++ b/pkg/coredata/vendor_filter.go @@ -26,20 +26,10 @@ type ( } ) -func NewVendorFilter() *VendorFilter { - return &VendorFilter{} -} - -func NewVendorTrustCenterFilter() *VendorFilter { - showOnTrustCenter := true +func NewVendorFilter(snapshotID **gid.GID, showOnTrustCenter *bool) *VendorFilter { return &VendorFilter{ - showOnTrustCenter: &showOnTrustCenter, - } -} - -func NewVendorFilterBySnapshotID(snapshotID **gid.GID) *VendorFilter { - return &VendorFilter{ - snapshotID: snapshotID, + snapshotID: snapshotID, + showOnTrustCenter: showOnTrustCenter, } } diff --git a/pkg/probo/compliance_registry_service.go b/pkg/probo/compliance_registry_service.go index 6f5cad1d2..6c90463f6 100644 --- a/pkg/probo/compliance_registry_service.go +++ b/pkg/probo/compliance_registry_service.go @@ -231,9 +231,10 @@ func (s *ComplianceRegistryService) Delete( return err } -func (s ComplianceRegistryService) CountByOrganizationID( +func (s ComplianceRegistryService) CountForOrganizationID( ctx context.Context, organizationID gid.GID, + filter *coredata.ComplianceRegistryFilter, ) (int, error) { var count int @@ -241,7 +242,7 @@ func (s ComplianceRegistryService) CountByOrganizationID( ctx, func(conn pg.Conn) (err error) { registries := coredata.ComplianceRegistries{} - count, err = registries.CountByOrganizationID(ctx, conn, s.svc.scope, organizationID) + count, err = registries.CountByOrganizationID(ctx, conn, s.svc.scope, organizationID, filter) if err != nil { return fmt.Errorf("cannot count compliance registries: %w", err) } @@ -261,13 +262,14 @@ func (s ComplianceRegistryService) ListForOrganizationID( ctx context.Context, organizationID gid.GID, cursor *page.Cursor[coredata.ComplianceRegistryOrderField], + filter *coredata.ComplianceRegistryFilter, ) (*page.Page[*coredata.ComplianceRegistry, coredata.ComplianceRegistryOrderField], error) { var registries coredata.ComplianceRegistries err := s.svc.pg.WithConn( ctx, func(conn pg.Conn) error { - err := registries.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor) + err := registries.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor, filter) if err != nil { return fmt.Errorf("cannot load compliance registries: %w", err) } diff --git a/pkg/server/api/console/v1/schema.graphql b/pkg/server/api/console/v1/schema.graphql index 983f4d792..fd2e2f655 100644 --- a/pkg/server/api/console/v1/schema.graphql +++ b/pkg/server/api/console/v1/schema.graphql @@ -1110,6 +1110,10 @@ input NonconformityRegistryFilter { snapshotId: ID } +input ComplianceRegistryFilter { + snapshotId: ID +} + # Core Types type TrustCenter implements Node { id: ID! @@ -1258,6 +1262,7 @@ type Organization implements Node { last: Int before: CursorKey orderBy: ComplianceRegistryOrder + filter: ComplianceRegistryFilter ): ComplianceRegistryConnection! @goField(forceResolver: true) continualImprovementRegistries( @@ -1721,6 +1726,8 @@ type NonconformityRegistry implements Node { type ComplianceRegistry implements Node { id: ID! + snapshotId: ID + sourceId: ID organization: Organization! @goField(forceResolver: true) referenceId: String! area: String diff --git a/pkg/server/api/console/v1/schema/schema.go b/pkg/server/api/console/v1/schema/schema.go index 6145ff623..75270a20e 100644 --- a/pkg/server/api/console/v1/schema/schema.go +++ b/pkg/server/api/console/v1/schema/schema.go @@ -183,7 +183,9 @@ type ComplexityRoot struct { ReferenceID func(childComplexity int) int Regulator func(childComplexity int) int Requirement func(childComplexity int) int + SnapshotID func(childComplexity int) int Source func(childComplexity int) int + SourceID func(childComplexity int) int Status func(childComplexity int) int UpdatedAt func(childComplexity int) int } @@ -871,7 +873,7 @@ type ComplexityRoot struct { Organization struct { Assets func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AssetOrderBy) int Audits func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditOrderBy) int - ComplianceRegistries func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ComplianceRegistryOrderBy) int + ComplianceRegistries func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ComplianceRegistryOrderBy, filter *types.ComplianceRegistryFilter) int Connectors func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ConnectorOrder) int ContinualImprovementRegistries func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ContinualImprovementRegistriesOrderBy) int Controls func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) int @@ -1669,7 +1671,7 @@ type OrganizationResolver interface { Data(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DatumOrderBy, filter *types.DatumFilter) (*types.DatumConnection, error) Audits(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditOrderBy) (*types.AuditConnection, error) 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) (*types.ComplianceRegistryConnection, 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) (*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) Snapshots(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SnapshotOrderBy) (*types.SnapshotConnection, error) @@ -2155,6 +2157,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.ComplianceRegistry.Requirement(childComplexity), true + case "ComplianceRegistry.snapshotId": + if e.complexity.ComplianceRegistry.SnapshotID == nil { + break + } + + return e.complexity.ComplianceRegistry.SnapshotID(childComplexity), true + case "ComplianceRegistry.source": if e.complexity.ComplianceRegistry.Source == nil { break @@ -2162,6 +2171,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.ComplianceRegistry.Source(childComplexity), true + case "ComplianceRegistry.sourceId": + if e.complexity.ComplianceRegistry.SourceID == nil { + break + } + + return e.complexity.ComplianceRegistry.SourceID(childComplexity), true + case "ComplianceRegistry.status": if e.complexity.ComplianceRegistry.Status == nil { break @@ -5370,7 +5386,7 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return 0, false } - return e.complexity.Organization.ComplianceRegistries(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.ComplianceRegistryOrderBy)), true + return e.complexity.Organization.ComplianceRegistries(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.ComplianceRegistryOrderBy), args["filter"].(*types.ComplianceRegistryFilter)), true case "Organization.connectors": if e.complexity.Organization.Connectors == nil { @@ -7655,6 +7671,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputBulkPublishDocumentVersionsInput, ec.unmarshalInputBulkRequestSignaturesInput, ec.unmarshalInputCancelSignatureRequestInput, + ec.unmarshalInputComplianceRegistryFilter, ec.unmarshalInputComplianceRegistryOrder, ec.unmarshalInputConfirmEmailInput, ec.unmarshalInputConnectorOrder, @@ -9002,6 +9019,10 @@ input NonconformityRegistryFilter { snapshotId: ID } +input ComplianceRegistryFilter { + snapshotId: ID +} + # Core Types type TrustCenter implements Node { id: ID! @@ -9150,6 +9171,7 @@ type Organization implements Node { last: Int before: CursorKey orderBy: ComplianceRegistryOrder + filter: ComplianceRegistryFilter ): ComplianceRegistryConnection! @goField(forceResolver: true) continualImprovementRegistries( @@ -9613,6 +9635,8 @@ type NonconformityRegistry implements Node { type ComplianceRegistry implements Node { id: ID! + snapshotId: ID + sourceId: ID organization: Organization! @goField(forceResolver: true) referenceId: String! area: String @@ -15993,6 +16017,11 @@ func (ec *executionContext) field_Organization_complianceRegistries_args(ctx con return nil, err } args["orderBy"] = arg4 + arg5, err := ec.field_Organization_complianceRegistries_argsFilter(ctx, rawArgs) + if err != nil { + return nil, err + } + args["filter"] = arg5 return args, nil } func (ec *executionContext) field_Organization_complianceRegistries_argsFirst( @@ -16060,6 +16089,19 @@ func (ec *executionContext) field_Organization_complianceRegistries_argsOrderBy( return zeroVal, nil } +func (ec *executionContext) field_Organization_complianceRegistries_argsFilter( + ctx context.Context, + rawArgs map[string]any, +) (*types.ComplianceRegistryFilter, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("filter")) + if tmp, ok := rawArgs["filter"]; ok { + return ec.unmarshalOComplianceRegistryFilter2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐComplianceRegistryFilter(ctx, tmp) + } + + var zeroVal *types.ComplianceRegistryFilter + return zeroVal, nil +} + func (ec *executionContext) field_Organization_connectors_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -21086,6 +21128,88 @@ func (ec *executionContext) fieldContext_ComplianceRegistry_id(_ context.Context return fc, nil } +func (ec *executionContext) _ComplianceRegistry_snapshotId(ctx context.Context, field graphql.CollectedField, obj *types.ComplianceRegistry) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ComplianceRegistry_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_ComplianceRegistry_snapshotId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ComplianceRegistry", + 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) _ComplianceRegistry_sourceId(ctx context.Context, field graphql.CollectedField, obj *types.ComplianceRegistry) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ComplianceRegistry_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_ComplianceRegistry_sourceId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ComplianceRegistry", + 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) _ComplianceRegistry_organization(ctx context.Context, field graphql.CollectedField, obj *types.ComplianceRegistry) (ret graphql.Marshaler) { fc, err := ec.fieldContext_ComplianceRegistry_organization(ctx, field) if err != nil { @@ -21942,6 +22066,10 @@ func (ec *executionContext) fieldContext_ComplianceRegistryEdge_node(_ context.C switch field.Name { case "id": return ec.fieldContext_ComplianceRegistry_id(ctx, field) + case "snapshotId": + return ec.fieldContext_ComplianceRegistry_snapshotId(ctx, field) + case "sourceId": + return ec.fieldContext_ComplianceRegistry_sourceId(ctx, field) case "organization": return ec.fieldContext_ComplianceRegistry_organization(ctx, field) case "referenceId": @@ -41945,7 +42073,7 @@ func (ec *executionContext) _Organization_complianceRegistries(ctx context.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().ComplianceRegistries(rctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.ComplianceRegistryOrderBy)) + return ec.resolvers.Organization().ComplianceRegistries(rctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.ComplianceRegistryOrderBy), fc.Args["filter"].(*types.ComplianceRegistryFilter)) }) if err != nil { ec.Error(ctx, err) @@ -49630,6 +49758,10 @@ func (ec *executionContext) fieldContext_UpdateComplianceRegistryPayload_complia switch field.Name { case "id": return ec.fieldContext_ComplianceRegistry_id(ctx, field) + case "snapshotId": + return ec.fieldContext_ComplianceRegistry_snapshotId(ctx, field) + case "sourceId": + return ec.fieldContext_ComplianceRegistry_sourceId(ctx, field) case "organization": return ec.fieldContext_ComplianceRegistry_organization(ctx, field) case "referenceId": @@ -59434,6 +59566,33 @@ func (ec *executionContext) unmarshalInputCancelSignatureRequestInput(ctx contex return it, nil } +func (ec *executionContext) unmarshalInputComplianceRegistryFilter(ctx context.Context, obj any) (types.ComplianceRegistryFilter, error) { + var it types.ComplianceRegistryFilter + 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) unmarshalInputComplianceRegistryOrder(ctx context.Context, obj any) (types.ComplianceRegistryOrderBy, error) { var it types.ComplianceRegistryOrderBy asMap := map[string]any{} @@ -66673,6 +66832,10 @@ func (ec *executionContext) _ComplianceRegistry(ctx context.Context, sel ast.Sel if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } + case "snapshotId": + out.Values[i] = ec._ComplianceRegistry_snapshotId(ctx, field, obj) + case "sourceId": + out.Values[i] = ec._ComplianceRegistry_sourceId(ctx, field, obj) case "organization": field := field @@ -86692,6 +86855,14 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast return res } +func (ec *executionContext) unmarshalOComplianceRegistryFilter2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐComplianceRegistryFilter(ctx context.Context, v any) (*types.ComplianceRegistryFilter, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputComplianceRegistryFilter(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalOComplianceRegistryOrder2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐComplianceRegistryOrderBy(ctx context.Context, v any) (*types.ComplianceRegistryOrderBy, error) { if v == nil { return nil, nil diff --git a/pkg/server/api/console/v1/types/compliance_registry.go b/pkg/server/api/console/v1/types/compliance_registry.go index 645b39810..b1ca632ea 100644 --- a/pkg/server/api/console/v1/types/compliance_registry.go +++ b/pkg/server/api/console/v1/types/compliance_registry.go @@ -30,6 +30,7 @@ type ( Resolver any ParentID gid.GID + Filter *ComplianceRegistryFilter } ) @@ -37,6 +38,7 @@ func NewComplianceRegistryConnection( p *page.Page[*coredata.ComplianceRegistry, coredata.ComplianceRegistryOrderField], parentType any, parentID gid.GID, + filter *ComplianceRegistryFilter, ) *ComplianceRegistryConnection { edges := make([]*ComplianceRegistryEdge, len(p.Data)) for i, registry := range p.Data { @@ -49,12 +51,15 @@ func NewComplianceRegistryConnection( Resolver: parentType, ParentID: parentID, + Filter: filter, } } func NewComplianceRegistry(cr *coredata.ComplianceRegistry) *ComplianceRegistry { return &ComplianceRegistry{ ID: cr.ID, + SnapshotID: cr.SnapshotID, + SourceID: cr.SourceID, ReferenceID: cr.ReferenceID, Area: cr.Area, Source: cr.Source, diff --git a/pkg/server/api/console/v1/types/types.go b/pkg/server/api/console/v1/types/types.go index a88d6c677..0736c9c83 100644 --- a/pkg/server/api/console/v1/types/types.go +++ b/pkg/server/api/console/v1/types/types.go @@ -109,6 +109,8 @@ type CancelSignatureRequestPayload struct { type ComplianceRegistry struct { ID gid.GID `json:"id"` + SnapshotID *gid.GID `json:"snapshotId,omitempty"` + SourceID *gid.GID `json:"sourceId,omitempty"` Organization *Organization `json:"organization"` ReferenceID string `json:"referenceId"` Area *string `json:"area,omitempty"` @@ -132,6 +134,10 @@ type ComplianceRegistryEdge struct { Node *ComplianceRegistry `json:"node"` } +type ComplianceRegistryFilter struct { + SnapshotID *gid.GID `json:"snapshotId,omitempty"` +} + type ConfirmEmailInput struct { Token string `json:"token"` } diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go index 6e6ee50fc..c2edcacdd 100644 --- a/pkg/server/api/console/v1/v1_resolver.go +++ b/pkg/server/api/console/v1/v1_resolver.go @@ -260,7 +260,12 @@ func (r *complianceRegistryConnectionResolver) TotalCount(ctx context.Context, o switch obj.Resolver.(type) { case *organizationResolver: - count, err := prb.ComplianceRegistries.CountByOrganizationID(ctx, obj.ParentID) + complianceRegistryFilter := coredata.NewComplianceRegistryFilter(nil) + if obj.Filter != nil { + complianceRegistryFilter = coredata.NewComplianceRegistryFilter(&obj.Filter.SnapshotID) + } + + count, err := prb.ComplianceRegistries.CountForOrganizationID(ctx, obj.ParentID, complianceRegistryFilter) if err != nil { panic(fmt.Errorf("cannot count compliance registries: %w", err)) } @@ -3313,9 +3318,9 @@ func (r *nonconformityRegistryConnectionResolver) TotalCount(ctx context.Context switch obj.Resolver.(type) { case *organizationResolver: - nonconformityRegistryFilter := coredata.NewNonconformityRegistryFilterBySnapshotID(nil) + nonconformityRegistryFilter := coredata.NewNonconformityRegistryFilter(nil) if obj.Filter != nil { - nonconformityRegistryFilter = coredata.NewNonconformityRegistryFilterBySnapshotID(&obj.Filter.SnapshotID) + nonconformityRegistryFilter = coredata.NewNonconformityRegistryFilter(&obj.Filter.SnapshotID) } count, err := prb.NonconformityRegistries.CountForOrganizationID(ctx, obj.ParentID, nonconformityRegistryFilter) @@ -3455,7 +3460,7 @@ func (r *organizationResolver) Vendors(ctx context.Context, obj *types.Organizat cursor := types.NewCursor(first, after, last, before, pageOrderBy) var nilSnapshotID *gid.GID = nil - vendorFilter := coredata.NewVendorFilterBySnapshotID(&nilSnapshotID) + vendorFilter := coredata.NewVendorFilter(&nilSnapshotID, nil) page, err := prb.Vendors.ListForOrganizationID(ctx, obj.ID, cursor, vendorFilter) if err != nil { @@ -3652,9 +3657,9 @@ func (r *organizationResolver) Data(ctx context.Context, obj *types.Organization cursor := types.NewCursor(first, after, last, before, pageOrderBy) - datumFilter := coredata.NewDatumFilterBySnapshotID(nil) + datumFilter := coredata.NewDatumFilter(nil) if filter != nil { - datumFilter = coredata.NewDatumFilterBySnapshotID(&filter.SnapshotID) + datumFilter = coredata.NewDatumFilter(&filter.SnapshotID) } page, err := prb.Data.ListForOrganizationID(ctx, obj.ID, cursor, datumFilter) @@ -3707,9 +3712,9 @@ func (r *organizationResolver) NonconformityRegistries(ctx context.Context, obj cursor := types.NewCursor(first, after, last, before, pageOrderBy) - nonconformityRegistryFilter := coredata.NewNonconformityRegistryFilterBySnapshotID(nil) + nonconformityRegistryFilter := coredata.NewNonconformityRegistryFilter(nil) if filter != nil { - nonconformityRegistryFilter = coredata.NewNonconformityRegistryFilterBySnapshotID(&filter.SnapshotID) + nonconformityRegistryFilter = coredata.NewNonconformityRegistryFilter(&filter.SnapshotID) } page, err := prb.NonconformityRegistries.ListForOrganizationID(ctx, obj.ID, cursor, nonconformityRegistryFilter) @@ -3721,7 +3726,7 @@ func (r *organizationResolver) NonconformityRegistries(ctx context.Context, obj } // ComplianceRegistries is the resolver for the complianceRegistries field. -func (r *organizationResolver) ComplianceRegistries(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ComplianceRegistryOrderBy) (*types.ComplianceRegistryConnection, error) { +func (r *organizationResolver) 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) { prb := r.ProboService(ctx, obj.ID.TenantID()) pageOrderBy := page.OrderBy[coredata.ComplianceRegistryOrderField]{ @@ -3737,12 +3742,17 @@ func (r *organizationResolver) ComplianceRegistries(ctx context.Context, obj *ty cursor := types.NewCursor(first, after, last, before, pageOrderBy) - page, err := prb.ComplianceRegistries.ListForOrganizationID(ctx, obj.ID, cursor) + complianceRegistryFilter := coredata.NewComplianceRegistryFilter(nil) + if filter != nil { + complianceRegistryFilter = coredata.NewComplianceRegistryFilter(&filter.SnapshotID) + } + + page, err := prb.ComplianceRegistries.ListForOrganizationID(ctx, obj.ID, cursor, complianceRegistryFilter) if err != nil { panic(fmt.Errorf("cannot list organization compliance registries: %w", err)) } - return types.NewComplianceRegistryConnection(page, r, obj.ID), nil + return types.NewComplianceRegistryConnection(page, r, obj.ID, filter), nil } // ContinualImprovementRegistries is the resolver for the continualImprovementRegistries field. diff --git a/pkg/trust/vendor_service.go b/pkg/trust/vendor_service.go index f6947a488..d4274c2ff 100644 --- a/pkg/trust/vendor_service.go +++ b/pkg/trust/vendor_service.go @@ -63,7 +63,8 @@ func (s VendorService) ListForOrganizationId( err := s.svc.pg.WithConn( ctx, func(conn pg.Conn) error { - filter := coredata.NewVendorTrustCenterFilter() + showOnTrustCenter := true + filter := coredata.NewVendorFilter(nil, &showOnTrustCenter) err := vendors.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor, filter) if err != nil { return fmt.Errorf("cannot load vendors: %w", err)