From 32c47a198882a38d023f6aae21ab360497814a04 Mon Sep 17 00:00:00 2001 From: Sacha Al Himdani Date: Thu, 24 Jul 2025 21:11:46 +0200 Subject: [PATCH] Add trust center configuration Signed-off-by: Sacha Al Himdani --- .../trustCenter/TrustCenterAuditsCard.tsx | 175 +++ .../trustCenter/TrustCenterDocumentDialog.tsx | 99 ++ .../trustCenter/TrustCenterDocumentsCard.tsx | 177 +++ .../trustCenter/TrustCenterVendorsCard.tsx | 166 +++ .../TrustCenterAuditsCardFragment.graphql.ts | 104 ++ ...ustCenterDocumentDialogFragment.graphql.ts | 58 + ...rustCenterDocumentsCardFragment.graphql.ts | 134 +++ .../TrustCenterVendorsCardFragment.graphql.ts | 83 ++ .../useVendorFormMutation.graphql.ts | 3 +- .../src/hooks/graph/TrustCenterAuditGraph.ts | 28 + .../hooks/graph/TrustCenterDocumentGraph.ts | 46 + .../src/hooks/graph/TrustCenterGraph.ts | 68 ++ .../src/hooks/graph/TrustCenterVendorGraph.ts | 28 + .../AuditGraphUpdateMutation.graphql.ts | 3 +- ...tCenterAuditGraphUpdateMutation.graphql.ts | 118 ++ .../TrustCenterDocumentGraphQuery.graphql.ts | 288 +++++ ...nterDocumentGraphUpdateMutation.graphql.ts | 222 ++++ .../TrustCenterGraphQuery.graphql.ts | 558 +++++++++ .../TrustCenterGraphUpdateMutation.graphql.ts | 131 +++ ...CenterVendorGraphUpdateMutation.graphql.ts | 133 +++ apps/console/src/layouts/MainLayout.tsx | 6 + .../pages/organizations/TrustCenterPage.tsx | 240 ++++ .../trustCenter/TrustCenterAuditsTab.tsx | 39 + .../trustCenter/TrustCenterDocumentsTab.tsx | 39 + .../trustCenter/TrustCenterVendorsTab.tsx | 39 + apps/console/src/routes.tsx | 2 + apps/console/src/routes/trustCenterRoutes.ts | 49 + packages/ui/src/Atoms/Tabs/Tabs.tsx | 4 +- pkg/coredata/audit.go | 58 +- pkg/coredata/document.go | 12 + pkg/coredata/entity_type_reg.go | 1 + pkg/coredata/migrations/20250724T135155Z.sql | 51 + pkg/coredata/trust_center.go | 213 ++++ pkg/coredata/trust_center_order_field.go | 38 + pkg/coredata/vendor.go | 8 + pkg/probo/audit_service.go | 29 +- pkg/probo/document_service.go | 16 +- pkg/probo/organization_service.go | 17 +- pkg/probo/service.go | 2 + pkg/probo/trust_center_service.go | 124 ++ pkg/probo/vendor_service.go | 6 + pkg/server/api/console/v1/schema.graphql | 30 + pkg/server/api/console/v1/schema/schema.go | 1041 ++++++++++++++++- pkg/server/api/console/v1/types/audit.go | 13 +- pkg/server/api/console/v1/types/document.go | 1 + .../api/console/v1/types/trust_center.go | 29 + pkg/server/api/console/v1/types/types.go | 104 +- pkg/server/api/console/v1/types/vendor.go | 1 + pkg/server/api/console/v1/v1_resolver.go | 47 +- 49 files changed, 4755 insertions(+), 126 deletions(-) create mode 100644 apps/console/src/components/trustCenter/TrustCenterAuditsCard.tsx create mode 100644 apps/console/src/components/trustCenter/TrustCenterDocumentDialog.tsx create mode 100644 apps/console/src/components/trustCenter/TrustCenterDocumentsCard.tsx create mode 100644 apps/console/src/components/trustCenter/TrustCenterVendorsCard.tsx create mode 100644 apps/console/src/components/trustCenter/__generated__/TrustCenterAuditsCardFragment.graphql.ts create mode 100644 apps/console/src/components/trustCenter/__generated__/TrustCenterDocumentDialogFragment.graphql.ts create mode 100644 apps/console/src/components/trustCenter/__generated__/TrustCenterDocumentsCardFragment.graphql.ts create mode 100644 apps/console/src/components/trustCenter/__generated__/TrustCenterVendorsCardFragment.graphql.ts create mode 100644 apps/console/src/hooks/graph/TrustCenterAuditGraph.ts create mode 100644 apps/console/src/hooks/graph/TrustCenterDocumentGraph.ts create mode 100644 apps/console/src/hooks/graph/TrustCenterGraph.ts create mode 100644 apps/console/src/hooks/graph/TrustCenterVendorGraph.ts create mode 100644 apps/console/src/hooks/graph/__generated__/TrustCenterAuditGraphUpdateMutation.graphql.ts create mode 100644 apps/console/src/hooks/graph/__generated__/TrustCenterDocumentGraphQuery.graphql.ts create mode 100644 apps/console/src/hooks/graph/__generated__/TrustCenterDocumentGraphUpdateMutation.graphql.ts create mode 100644 apps/console/src/hooks/graph/__generated__/TrustCenterGraphQuery.graphql.ts create mode 100644 apps/console/src/hooks/graph/__generated__/TrustCenterGraphUpdateMutation.graphql.ts create mode 100644 apps/console/src/hooks/graph/__generated__/TrustCenterVendorGraphUpdateMutation.graphql.ts create mode 100644 apps/console/src/pages/organizations/TrustCenterPage.tsx create mode 100644 apps/console/src/pages/organizations/trustCenter/TrustCenterAuditsTab.tsx create mode 100644 apps/console/src/pages/organizations/trustCenter/TrustCenterDocumentsTab.tsx create mode 100644 apps/console/src/pages/organizations/trustCenter/TrustCenterVendorsTab.tsx create mode 100644 apps/console/src/routes/trustCenterRoutes.ts create mode 100644 pkg/coredata/migrations/20250724T135155Z.sql create mode 100644 pkg/coredata/trust_center.go create mode 100644 pkg/coredata/trust_center_order_field.go create mode 100644 pkg/probo/trust_center_service.go create mode 100644 pkg/server/api/console/v1/types/trust_center.go diff --git a/apps/console/src/components/trustCenter/TrustCenterAuditsCard.tsx b/apps/console/src/components/trustCenter/TrustCenterAuditsCard.tsx new file mode 100644 index 000000000..c19f3def1 --- /dev/null +++ b/apps/console/src/components/trustCenter/TrustCenterAuditsCard.tsx @@ -0,0 +1,175 @@ +import { graphql } from "relay-runtime"; +import { + Card, + Button, + Tr, + Td, + Table, + Thead, + Tbody, + Th, + IconChevronDown, + IconCheckmark1, + IconCrossLargeX, + Badge, +} from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { useFragment } from "react-relay"; +import { useMemo, useState } from "react"; +import { sprintf, getAuditStateVariant, getAuditStateLabel } from "@probo/helpers"; +import { useOrganizationId } from "/hooks/useOrganizationId"; +import clsx from "clsx"; +import type { TrustCenterAuditsCardFragment$key } from "./__generated__/TrustCenterAuditsCardFragment.graphql"; + +const trustCenterAuditFragment = graphql` + fragment TrustCenterAuditsCardFragment on Audit { + id + framework { + name + } + validFrom + validUntil + state + showOnTrustCenter + createdAt + } +`; + +type Mutation = (p: { + variables: { + input: { + id: string; + showOnTrustCenter: boolean; + } & Params; + }; +}) => void; + +type Props = { + audits: TrustCenterAuditsCardFragment$key[]; + params: Params; + disabled?: boolean; + onToggleVisibility: Mutation; + variant?: "card" | "table"; +}; + +export function TrustCenterAuditsCard(props: Props) { + const { __ } = useTranslate(); + const [limit, setLimit] = useState(4); + const audits = useMemo(() => { + return limit ? props.audits.slice(0, limit) : props.audits; + }, [props.audits, limit]); + const showMoreButton = limit !== null && props.audits.length > limit; + const variant = props.variant ?? "table"; + + const onToggleVisibility = (auditId: string, showOnTrustCenter: boolean) => { + props.onToggleVisibility({ + variables: { + input: { + id: auditId, + showOnTrustCenter, + ...props.params, + }, + }, + }); + }; + + const Wrapper = variant === "card" ? Card : "div"; + + return ( + + + + + + + + + + + + + {audits.length === 0 && ( + + + + )} + {audits.map((audit, index) => ( + + ))} + +
{__("Framework")}{__("Valid Until")}{__("State")}{__("Visibility")}
+ {__("No audits available")} +
+ {showMoreButton && ( + + )} +
+ ); +} + +function AuditRow(props: { + audit: TrustCenterAuditsCardFragment$key; + onToggleVisibility: (auditId: string, showOnTrustCenter: boolean) => void; + disabled?: boolean; +}) { + const audit = useFragment(trustCenterAuditFragment, props.audit); + const organizationId = useOrganizationId(); + const { __ } = useTranslate(); + + const validUntilFormatted = audit.validUntil + ? new Date(audit.validUntil).toLocaleDateString() + : __("No expiry"); + + return ( + + +
+ {audit.framework.name} +
+ + {validUntilFormatted} + + + {getAuditStateLabel(__, audit.state)} + + + +
+ {audit.showOnTrustCenter ? ( + <> + + {__("Visible")} + + ) : ( + <> + + {__("Hidden")} + + )} +
+ + + + + + ); +} diff --git a/apps/console/src/components/trustCenter/TrustCenterDocumentDialog.tsx b/apps/console/src/components/trustCenter/TrustCenterDocumentDialog.tsx new file mode 100644 index 000000000..69e783833 --- /dev/null +++ b/apps/console/src/components/trustCenter/TrustCenterDocumentDialog.tsx @@ -0,0 +1,99 @@ +import { useTranslate } from "@probo/i18n"; +import { + Dialog, + DialogContent, + DialogFooter, + Button, + useDialogRef, +} from "@probo/ui"; +import { type ReactNode } from "react"; +import { useFragment, graphql } from "react-relay"; +import type { TrustCenterDocumentsCardFragment$key } from "./__generated__/TrustCenterDocumentsCardFragment.graphql"; + +const trustCenterDocumentDialogFragment = graphql` + fragment TrustCenterDocumentDialogFragment on Document { + id + title + showOnTrustCenter + } +`; + +type Props = { + children: ReactNode; + documents: (TrustCenterDocumentsCardFragment$key & { id: string })[]; + onToggleVisibility: (documentId: string, showOnTrustCenter: boolean) => void; + disabled?: boolean; +}; + +export default function TrustCenterDocumentDialog({ + children, + documents, + onToggleVisibility, + disabled, +}: Props) { + const { __ } = useTranslate(); + const dialogRef = useDialogRef(); + + return ( + <> + !disabled && dialogRef.current?.open()}> + {children} + + + +
+ {__("Manage Document Visibility on Trust Center")} +
+
+

+ {__("Control which documents are visible on your public trust center.")} +

+
+ {documents.map((documentKey) => ( + + ))} +
+
+ + + +
+
+ + ); +} + +function DocumentDialogRow({ + document: documentKey, + onToggleVisibility, + disabled, +}: { + document: TrustCenterDocumentsCardFragment$key & { id: string }; + onToggleVisibility: (documentId: string, showOnTrustCenter: boolean) => void; + disabled?: boolean; +}) { + const document = useFragment(trustCenterDocumentDialogFragment, documentKey); + const { __ } = useTranslate(); + + return ( +
+
+
{document.title}
+
+ +
+ ); +} diff --git a/apps/console/src/components/trustCenter/TrustCenterDocumentsCard.tsx b/apps/console/src/components/trustCenter/TrustCenterDocumentsCard.tsx new file mode 100644 index 000000000..97fc5cde3 --- /dev/null +++ b/apps/console/src/components/trustCenter/TrustCenterDocumentsCard.tsx @@ -0,0 +1,177 @@ +import { graphql } from "relay-runtime"; +import { + Card, + Button, + Tr, + Td, + Table, + Thead, + Tbody, + Th, + IconChevronDown, + IconCheckmark1, + IconCrossLargeX, + DocumentVersionBadge, + DocumentTypeBadge, +} from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import type { TrustCenterDocumentsCardFragment$key } from "./__generated__/TrustCenterDocumentsCardFragment.graphql"; +import { useFragment } from "react-relay"; +import { useMemo, useState } from "react"; +import { sprintf } from "@probo/helpers"; +import { useOrganizationId } from "/hooks/useOrganizationId"; +import clsx from "clsx"; + +const trustCenterDocumentFragment = graphql` + fragment TrustCenterDocumentsCardFragment on Document { + id + title + createdAt + documentType + showOnTrustCenter + versions(first: 1) { + edges { + node { + id + status + } + } + } + } +`; + +type Mutation = (p: { + variables: { + input: { + id: string; + showOnTrustCenter: boolean; + } & Params; + }; +}) => void; + +type Props = { + documents: TrustCenterDocumentsCardFragment$key[]; + params: Params; + disabled?: boolean; + onToggleVisibility: Mutation; + variant?: "card" | "table"; +}; + +export function TrustCenterDocumentsCard(props: Props) { + const { __ } = useTranslate(); + const [limit, setLimit] = useState(4); + const documents = useMemo(() => { + return limit ? props.documents.slice(0, limit) : props.documents; + }, [props.documents, limit]); + const showMoreButton = limit !== null && props.documents.length > limit; + const variant = props.variant ?? "table"; + + const onToggleVisibility = (documentId: string, showOnTrustCenter: boolean) => { + props.onToggleVisibility({ + variables: { + input: { + id: documentId, + showOnTrustCenter, + ...props.params, + }, + }, + }); + }; + + const Wrapper = variant === "card" ? Card : "div"; + + return ( + + + + + + + + + + + + + {documents.length === 0 && ( + + + + )} + {documents.map((document, index) => ( + + ))} + + +
{__("Name")}{__("Type")}{__("State")}{__("Visibility")}
+ {__("No documents available")} +
+ {showMoreButton && ( + + )} +
+ ); +} + +function DocumentRow(props: { + document: TrustCenterDocumentsCardFragment$key; + onToggleVisibility: (documentId: string, showOnTrustCenter: boolean) => void; + disabled?: boolean; +}) { + const document = useFragment(trustCenterDocumentFragment, props.document); + const organizationId = useOrganizationId(); + const { __ } = useTranslate(); + + return ( + + +
+ {document.title} +
+ + + + + + + + +
+ {document.showOnTrustCenter ? ( + <> + + {__("Visible")} + + ) : ( + <> + + {__("Hidden")} + + )} +
+ + + + + + ); +} diff --git a/apps/console/src/components/trustCenter/TrustCenterVendorsCard.tsx b/apps/console/src/components/trustCenter/TrustCenterVendorsCard.tsx new file mode 100644 index 000000000..8fc656d74 --- /dev/null +++ b/apps/console/src/components/trustCenter/TrustCenterVendorsCard.tsx @@ -0,0 +1,166 @@ +import { graphql } from "relay-runtime"; +import { + Card, + Button, + Tr, + Td, + Table, + Thead, + Tbody, + Th, + IconChevronDown, + IconCheckmark1, + IconCrossLargeX, + Badge, +} from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { useFragment } from "react-relay"; +import { useMemo, useState } from "react"; +import { sprintf } from "@probo/helpers"; +import { useOrganizationId } from "/hooks/useOrganizationId"; +import clsx from "clsx"; +import type { TrustCenterVendorsCardFragment$key } from "./__generated__/TrustCenterVendorsCardFragment.graphql"; + +const trustCenterVendorFragment = graphql` + fragment TrustCenterVendorsCardFragment on Vendor { + id + name + category + description + showOnTrustCenter + createdAt + } +`; + +type Mutation = (p: { + variables: { + input: { + id: string; + showOnTrustCenter: boolean; + } & Params; + }; +}) => void; + +type Props = { + vendors: TrustCenterVendorsCardFragment$key[]; + params: Params; + disabled?: boolean; + onToggleVisibility: Mutation; + variant?: "card" | "table"; +}; + +export function TrustCenterVendorsCard(props: Props) { + const { __ } = useTranslate(); + const [limit, setLimit] = useState(4); + const vendors = useMemo(() => { + return limit ? props.vendors.slice(0, limit) : props.vendors; + }, [props.vendors, limit]); + const showMoreButton = limit !== null && props.vendors.length > limit; + const variant = props.variant ?? "table"; + + const onToggleVisibility = (vendorId: string, showOnTrustCenter: boolean) => { + props.onToggleVisibility({ + variables: { + input: { + id: vendorId, + showOnTrustCenter, + ...props.params, + }, + }, + }); + }; + + const Wrapper = variant === "card" ? Card : "div"; + + return ( + + + + + + + + + + + + {vendors.length === 0 && ( + + + + )} + {vendors.map((vendor, index) => ( + + ))} + +
{__("Name")}{__("Category")}{__("Visibility")}
+ {__("No vendors available")} +
+ {showMoreButton && ( + + )} +
+ ); +} + +function VendorRow(props: { + vendor: TrustCenterVendorsCardFragment$key; + onToggleVisibility: (vendorId: string, showOnTrustCenter: boolean) => void; + disabled?: boolean; +}) { + const vendor = useFragment(trustCenterVendorFragment, props.vendor); + const organizationId = useOrganizationId(); + const { __ } = useTranslate(); + + return ( + + +
+ {vendor.name} +
+ + + + {vendor.category} + + + +
+ {vendor.showOnTrustCenter ? ( + <> + + {__("Visible")} + + ) : ( + <> + + {__("Hidden")} + + )} +
+ + + + + + ); +} diff --git a/apps/console/src/components/trustCenter/__generated__/TrustCenterAuditsCardFragment.graphql.ts b/apps/console/src/components/trustCenter/__generated__/TrustCenterAuditsCardFragment.graphql.ts new file mode 100644 index 000000000..4e8cd42ab --- /dev/null +++ b/apps/console/src/components/trustCenter/__generated__/TrustCenterAuditsCardFragment.graphql.ts @@ -0,0 +1,104 @@ +/** + * @generated SignedSource<<794277d17daabd92807ccfaa5a1c2dbb>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +export type AuditState = "COMPLETED" | "IN_PROGRESS" | "NOT_STARTED" | "OUTDATED" | "REJECTED"; +import { FragmentRefs } from "relay-runtime"; +export type TrustCenterAuditsCardFragment$data = { + readonly createdAt: any; + readonly framework: { + readonly name: string; + }; + readonly id: string; + readonly showOnTrustCenter: boolean; + readonly state: AuditState; + readonly validFrom: any | null | undefined; + readonly validUntil: any | null | undefined; + readonly " $fragmentType": "TrustCenterAuditsCardFragment"; +}; +export type TrustCenterAuditsCardFragment$key = { + readonly " $data"?: TrustCenterAuditsCardFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"TrustCenterAuditsCardFragment">; +}; + +const node: ReaderFragment = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "TrustCenterAuditsCardFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "Framework", + "kind": "LinkedField", + "name": "framework", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "validFrom", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "validUntil", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "state", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "showOnTrustCenter", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + } + ], + "type": "Audit", + "abstractKey": null +}; + +(node as any).hash = "9c9291dffd5c057c0e70e2567a897362"; + +export default node; diff --git a/apps/console/src/components/trustCenter/__generated__/TrustCenterDocumentDialogFragment.graphql.ts b/apps/console/src/components/trustCenter/__generated__/TrustCenterDocumentDialogFragment.graphql.ts new file mode 100644 index 000000000..76dbb5209 --- /dev/null +++ b/apps/console/src/components/trustCenter/__generated__/TrustCenterDocumentDialogFragment.graphql.ts @@ -0,0 +1,58 @@ +/** + * @generated SignedSource<<3ff483dcc660e6b45d676db7fc05a30e>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type TrustCenterDocumentDialogFragment$data = { + readonly id: string; + readonly showOnTrustCenter: boolean; + readonly title: string; + readonly " $fragmentType": "TrustCenterDocumentDialogFragment"; +}; +export type TrustCenterDocumentDialogFragment$key = { + readonly " $data"?: TrustCenterDocumentDialogFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"TrustCenterDocumentDialogFragment">; +}; + +const node: ReaderFragment = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "TrustCenterDocumentDialogFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "title", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "showOnTrustCenter", + "storageKey": null + } + ], + "type": "Document", + "abstractKey": null +}; + +(node as any).hash = "d886df25fdf197161a91bbc693c9fac8"; + +export default node; diff --git a/apps/console/src/components/trustCenter/__generated__/TrustCenterDocumentsCardFragment.graphql.ts b/apps/console/src/components/trustCenter/__generated__/TrustCenterDocumentsCardFragment.graphql.ts new file mode 100644 index 000000000..3cb30e8b2 --- /dev/null +++ b/apps/console/src/components/trustCenter/__generated__/TrustCenterDocumentsCardFragment.graphql.ts @@ -0,0 +1,134 @@ +/** + * @generated SignedSource<<711a0b67f3e93814ae3297a2578373c6>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +export type DocumentStatus = "DRAFT" | "PUBLISHED"; +export type DocumentType = "ISMS" | "OTHER" | "POLICY"; +import { FragmentRefs } from "relay-runtime"; +export type TrustCenterDocumentsCardFragment$data = { + readonly createdAt: any; + readonly documentType: DocumentType; + readonly id: string; + readonly showOnTrustCenter: boolean; + readonly title: string; + readonly versions: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly status: DocumentStatus; + }; + }>; + }; + readonly " $fragmentType": "TrustCenterDocumentsCardFragment"; +}; +export type TrustCenterDocumentsCardFragment$key = { + readonly " $data"?: TrustCenterDocumentsCardFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"TrustCenterDocumentsCardFragment">; +}; + +const node: ReaderFragment = (function(){ +var v0 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}; +return { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "TrustCenterDocumentsCardFragment", + "selections": [ + (v0/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "title", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "documentType", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "showOnTrustCenter", + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 1 + } + ], + "concreteType": "DocumentVersionConnection", + "kind": "LinkedField", + "name": "versions", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentVersionEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentVersion", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v0/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "versions(first:1)" + } + ], + "type": "Document", + "abstractKey": null +}; +})(); + +(node as any).hash = "88d5e5e3a2d9f4b730428efcea644f25"; + +export default node; diff --git a/apps/console/src/components/trustCenter/__generated__/TrustCenterVendorsCardFragment.graphql.ts b/apps/console/src/components/trustCenter/__generated__/TrustCenterVendorsCardFragment.graphql.ts new file mode 100644 index 000000000..39dd28be8 --- /dev/null +++ b/apps/console/src/components/trustCenter/__generated__/TrustCenterVendorsCardFragment.graphql.ts @@ -0,0 +1,83 @@ +/** + * @generated SignedSource<> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +export type VendorCategory = "ANALYTICS" | "CLOUD_MONITORING" | "CLOUD_PROVIDER" | "COLLABORATION" | "CUSTOMER_SUPPORT" | "DATA_STORAGE_AND_PROCESSING" | "DOCUMENT_MANAGEMENT" | "EMPLOYEE_MANAGEMENT" | "ENGINEERING" | "FINANCE" | "IDENTITY_PROVIDER" | "IT" | "MARKETING" | "OFFICE_OPERATIONS" | "OTHER" | "PASSWORD_MANAGEMENT" | "PRODUCT_AND_DESIGN" | "PROFESSIONAL_SERVICES" | "RECRUITING" | "SALES" | "SECURITY" | "VERSION_CONTROL"; +import { FragmentRefs } from "relay-runtime"; +export type TrustCenterVendorsCardFragment$data = { + readonly category: VendorCategory; + readonly createdAt: any; + readonly description: string | null | undefined; + readonly id: string; + readonly name: string; + readonly showOnTrustCenter: boolean; + readonly " $fragmentType": "TrustCenterVendorsCardFragment"; +}; +export type TrustCenterVendorsCardFragment$key = { + readonly " $data"?: TrustCenterVendorsCardFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"TrustCenterVendorsCardFragment">; +}; + +const node: ReaderFragment = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "TrustCenterVendorsCardFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "category", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "showOnTrustCenter", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + } + ], + "type": "Vendor", + "abstractKey": null +}; + +(node as any).hash = "72b637589fd9299b5e982450fccbfd12"; + +export default node; diff --git a/apps/console/src/hooks/forms/__generated__/useVendorFormMutation.graphql.ts b/apps/console/src/hooks/forms/__generated__/useVendorFormMutation.graphql.ts index 45bf92dcf..7caa9b286 100644 --- a/apps/console/src/hooks/forms/__generated__/useVendorFormMutation.graphql.ts +++ b/apps/console/src/hooks/forms/__generated__/useVendorFormMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<95aa70195a3e90acb366441fd037c2f2>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -26,6 +26,7 @@ export type UpdateVendorInput = { securityOwnerId?: string | null | undefined; securityPageUrl?: string | null | undefined; serviceLevelAgreementUrl?: string | null | undefined; + showOnTrustCenter?: boolean | null | undefined; statusPageUrl?: string | null | undefined; subprocessorsListUrl?: string | null | undefined; termsOfServiceUrl?: string | null | undefined; diff --git a/apps/console/src/hooks/graph/TrustCenterAuditGraph.ts b/apps/console/src/hooks/graph/TrustCenterAuditGraph.ts new file mode 100644 index 000000000..4994c4294 --- /dev/null +++ b/apps/console/src/hooks/graph/TrustCenterAuditGraph.ts @@ -0,0 +1,28 @@ +import { graphql } from "relay-runtime"; +import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; +import { useTranslate } from "@probo/i18n"; +import type { TrustCenterAuditGraphUpdateMutation } from "./__generated__/TrustCenterAuditGraphUpdateMutation.graphql"; + +export const trustCenterAuditUpdateMutation = graphql` + mutation TrustCenterAuditGraphUpdateMutation($input: UpdateAuditInput!) { + updateAudit(input: $input) { + audit { + id + showOnTrustCenter + ...TrustCenterAuditsCardFragment + } + } + } +`; + +export function useTrustCenterAuditUpdate() { + const { __ } = useTranslate(); + + return useMutationWithToasts( + trustCenterAuditUpdateMutation, + { + successMessage: __("Audit visibility updated successfully."), + errorMessage: __("Failed to update audit visibility. Please try again."), + } + ); +} diff --git a/apps/console/src/hooks/graph/TrustCenterDocumentGraph.ts b/apps/console/src/hooks/graph/TrustCenterDocumentGraph.ts new file mode 100644 index 000000000..faf2362cf --- /dev/null +++ b/apps/console/src/hooks/graph/TrustCenterDocumentGraph.ts @@ -0,0 +1,46 @@ +import { graphql } from "relay-runtime"; +import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; +import { useTranslate } from "@probo/i18n"; +import type { TrustCenterDocumentGraphUpdateMutation } from "./__generated__/TrustCenterDocumentGraphUpdateMutation.graphql"; + +export const trustCenterDocumentsQuery = graphql` + query TrustCenterDocumentGraphQuery($organizationId: ID!) { + organization: node(id: $organizationId) { + ... on Organization { + id + documents(first: 100) { + edges { + node { + id + ...TrustCenterDocumentsCardFragment + } + } + } + } + } + } +`; + +export const updateDocumentVisibilityMutation = graphql` + mutation TrustCenterDocumentGraphUpdateMutation($input: UpdateDocumentInput!) { + updateDocument(input: $input) { + document { + id + showOnTrustCenter + ...TrustCenterDocumentsCardFragment + } + } + } +`; + +export function useUpdateDocumentVisibilityMutation() { + const { __ } = useTranslate(); + + return useMutationWithToasts( + updateDocumentVisibilityMutation, + { + successMessage: __("Document visibility updated successfully."), + errorMessage: __("Failed to update document visibility. Please try again."), + } + ); +} diff --git a/apps/console/src/hooks/graph/TrustCenterGraph.ts b/apps/console/src/hooks/graph/TrustCenterGraph.ts new file mode 100644 index 000000000..c4973682c --- /dev/null +++ b/apps/console/src/hooks/graph/TrustCenterGraph.ts @@ -0,0 +1,68 @@ +import { graphql } from "relay-runtime"; +import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; +import type { TrustCenterGraphUpdateMutation } from "./__generated__/TrustCenterGraphUpdateMutation.graphql"; + +export const trustCenterQuery = graphql` + query TrustCenterGraphQuery($organizationId: ID!) { + organization: node(id: $organizationId) { + ... on Organization { + id + name + trustCenter { + id + active + slug + createdAt + updatedAt + } + documents(first: 100) { + edges { + node { + id + ...TrustCenterDocumentsCardFragment + } + } + } + audits(first: 100) { + edges { + node { + id + ...TrustCenterAuditsCardFragment + } + } + } + vendors(first: 100) { + edges { + node { + id + ...TrustCenterVendorsCardFragment + } + } + } + } + } + } +`; + +export const updateTrustCenterMutation = graphql` + mutation TrustCenterGraphUpdateMutation($input: UpdateTrustCenterInput!) { + updateTrustCenter(input: $input) { + trustCenter { + id + active + slug + updatedAt + } + } + } +`; + +export function useUpdateTrustCenterMutation() { + return useMutationWithToasts( + updateTrustCenterMutation, + { + successMessage: "Trust center updated successfully", + errorMessage: "Failed to update trust center", + } + ); +} diff --git a/apps/console/src/hooks/graph/TrustCenterVendorGraph.ts b/apps/console/src/hooks/graph/TrustCenterVendorGraph.ts new file mode 100644 index 000000000..85a38402d --- /dev/null +++ b/apps/console/src/hooks/graph/TrustCenterVendorGraph.ts @@ -0,0 +1,28 @@ +import { graphql } from "relay-runtime"; +import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; +import { useTranslate } from "@probo/i18n"; +import type { TrustCenterVendorGraphUpdateMutation } from "./__generated__/TrustCenterVendorGraphUpdateMutation.graphql"; + +export const trustCenterVendorUpdateMutation = graphql` + mutation TrustCenterVendorGraphUpdateMutation($input: UpdateVendorInput!) { + updateVendor(input: $input) { + vendor { + id + showOnTrustCenter + ...TrustCenterVendorsCardFragment + } + } + } +`; + +export function useTrustCenterVendorUpdate() { + const { __ } = useTranslate(); + + return useMutationWithToasts( + trustCenterVendorUpdateMutation, + { + successMessage: __("Vendor visibility updated successfully."), + errorMessage: __("Failed to update vendor visibility. Please try again."), + } + ); +} diff --git a/apps/console/src/hooks/graph/__generated__/AuditGraphUpdateMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/AuditGraphUpdateMutation.graphql.ts index 08edab12b..5e52f038a 100644 --- a/apps/console/src/hooks/graph/__generated__/AuditGraphUpdateMutation.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/AuditGraphUpdateMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -12,6 +12,7 @@ import { ConcreteRequest } from 'relay-runtime'; export type AuditState = "COMPLETED" | "IN_PROGRESS" | "NOT_STARTED" | "OUTDATED" | "REJECTED"; export type UpdateAuditInput = { id: string; + showOnTrustCenter?: boolean | null | undefined; state?: AuditState | null | undefined; validFrom?: any | null | undefined; validUntil?: any | null | undefined; diff --git a/apps/console/src/hooks/graph/__generated__/TrustCenterAuditGraphUpdateMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/TrustCenterAuditGraphUpdateMutation.graphql.ts new file mode 100644 index 000000000..943b26edb --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/TrustCenterAuditGraphUpdateMutation.graphql.ts @@ -0,0 +1,118 @@ +/** + * @generated SignedSource<<92803a3585816e3db509c46a86d083e9>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type AuditState = "COMPLETED" | "IN_PROGRESS" | "NOT_STARTED" | "OUTDATED" | "REJECTED"; +export type UpdateAuditInput = { + id: string; + showOnTrustCenter?: boolean | null | undefined; + state?: AuditState | null | undefined; + validFrom?: any | null | undefined; + validUntil?: any | null | undefined; +}; +export type TrustCenterAuditGraphUpdateMutation$variables = { + input: UpdateAuditInput; +}; +export type TrustCenterAuditGraphUpdateMutation$data = { + readonly updateAudit: { + readonly audit: { + readonly id: string; + readonly showOnTrustCenter: boolean; + }; + }; +}; +export type TrustCenterAuditGraphUpdateMutation = { + response: TrustCenterAuditGraphUpdateMutation$data; + variables: TrustCenterAuditGraphUpdateMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "UpdateAuditPayload", + "kind": "LinkedField", + "name": "updateAudit", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Audit", + "kind": "LinkedField", + "name": "audit", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "showOnTrustCenter", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "TrustCenterAuditGraphUpdateMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "TrustCenterAuditGraphUpdateMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "1ecc930abe6daebb184b1e55ccebc65c", + "id": null, + "metadata": {}, + "name": "TrustCenterAuditGraphUpdateMutation", + "operationKind": "mutation", + "text": "mutation TrustCenterAuditGraphUpdateMutation(\n $input: UpdateAuditInput!\n) {\n updateAudit(input: $input) {\n audit {\n id\n showOnTrustCenter\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "ebf90264b72bb993d60f48d1d3fc4fb7"; + +export default node; diff --git a/apps/console/src/hooks/graph/__generated__/TrustCenterDocumentGraphQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/TrustCenterDocumentGraphQuery.graphql.ts new file mode 100644 index 000000000..83173ebdd --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/TrustCenterDocumentGraphQuery.graphql.ts @@ -0,0 +1,288 @@ +/** + * @generated SignedSource<<6676a9b480eeef26f00ff97963b39b86>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type TrustCenterDocumentGraphQuery$variables = { + organizationId: string; +}; +export type TrustCenterDocumentGraphQuery$data = { + readonly organization: { + readonly documents?: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly " $fragmentSpreads": FragmentRefs<"TrustCenterDocumentsCardFragment">; + }; + }>; + }; + readonly id?: string; + }; +}; +export type TrustCenterDocumentGraphQuery = { + response: TrustCenterDocumentGraphQuery$data; + variables: TrustCenterDocumentGraphQuery$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "organizationId" + } +], +v1 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "organizationId" + } +], +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v3 = [ + { + "kind": "Literal", + "name": "first", + "value": 100 + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "TrustCenterDocumentGraphQuery", + "selections": [ + { + "alias": "organization", + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "kind": "InlineFragment", + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": (v3/*: any*/), + "concreteType": "DocumentConnection", + "kind": "LinkedField", + "name": "documents", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Document", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "args": null, + "kind": "FragmentSpread", + "name": "TrustCenterDocumentsCardFragment" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "documents(first:100)" + } + ], + "type": "Organization", + "abstractKey": null + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "TrustCenterDocumentGraphQuery", + "selections": [ + { + "alias": "organization", + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + (v2/*: any*/), + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": (v3/*: any*/), + "concreteType": "DocumentConnection", + "kind": "LinkedField", + "name": "documents", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Document", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "title", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "documentType", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "showOnTrustCenter", + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 1 + } + ], + "concreteType": "DocumentVersionConnection", + "kind": "LinkedField", + "name": "versions", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentVersionEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentVersion", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "versions(first:1)" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "documents(first:100)" + } + ], + "type": "Organization", + "abstractKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "f8e5f4d7adcf1e794bc046ef21317f89", + "id": null, + "metadata": {}, + "name": "TrustCenterDocumentGraphQuery", + "operationKind": "query", + "text": "query TrustCenterDocumentGraphQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n documents(first: 100) {\n edges {\n node {\n id\n ...TrustCenterDocumentsCardFragment\n }\n }\n }\n }\n id\n }\n}\n\nfragment TrustCenterDocumentsCardFragment on Document {\n id\n title\n createdAt\n documentType\n showOnTrustCenter\n versions(first: 1) {\n edges {\n node {\n id\n status\n }\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "f4e34ac09a2b56c2298bc319d9701f4d"; + +export default node; diff --git a/apps/console/src/hooks/graph/__generated__/TrustCenterDocumentGraphUpdateMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/TrustCenterDocumentGraphUpdateMutation.graphql.ts new file mode 100644 index 000000000..d44de8589 --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/TrustCenterDocumentGraphUpdateMutation.graphql.ts @@ -0,0 +1,222 @@ +/** + * @generated SignedSource<<5b8f324da8c4dc9302cb6f821062757d>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type DocumentType = "ISMS" | "OTHER" | "POLICY"; +export type UpdateDocumentInput = { + content?: string | null | undefined; + createdBy?: string | null | undefined; + documentType?: DocumentType | null | undefined; + id: string; + ownerId?: string | null | undefined; + showOnTrustCenter?: boolean | null | undefined; + title?: string | null | undefined; +}; +export type TrustCenterDocumentGraphUpdateMutation$variables = { + input: UpdateDocumentInput; +}; +export type TrustCenterDocumentGraphUpdateMutation$data = { + readonly updateDocument: { + readonly document: { + readonly id: string; + readonly showOnTrustCenter: boolean; + readonly " $fragmentSpreads": FragmentRefs<"TrustCenterDocumentsCardFragment">; + }; + }; +}; +export type TrustCenterDocumentGraphUpdateMutation = { + response: TrustCenterDocumentGraphUpdateMutation$data; + variables: TrustCenterDocumentGraphUpdateMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } +], +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v3 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "showOnTrustCenter", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "TrustCenterDocumentGraphUpdateMutation", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": "UpdateDocumentPayload", + "kind": "LinkedField", + "name": "updateDocument", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Document", + "kind": "LinkedField", + "name": "document", + "plural": false, + "selections": [ + (v2/*: any*/), + (v3/*: any*/), + { + "args": null, + "kind": "FragmentSpread", + "name": "TrustCenterDocumentsCardFragment" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "TrustCenterDocumentGraphUpdateMutation", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": "UpdateDocumentPayload", + "kind": "LinkedField", + "name": "updateDocument", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Document", + "kind": "LinkedField", + "name": "document", + "plural": false, + "selections": [ + (v2/*: any*/), + (v3/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "title", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "documentType", + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 1 + } + ], + "concreteType": "DocumentVersionConnection", + "kind": "LinkedField", + "name": "versions", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentVersionEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentVersion", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "versions(first:1)" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "b112314d6ef35feebf49bd2f8c636b33", + "id": null, + "metadata": {}, + "name": "TrustCenterDocumentGraphUpdateMutation", + "operationKind": "mutation", + "text": "mutation TrustCenterDocumentGraphUpdateMutation(\n $input: UpdateDocumentInput!\n) {\n updateDocument(input: $input) {\n document {\n id\n showOnTrustCenter\n ...TrustCenterDocumentsCardFragment\n }\n }\n}\n\nfragment TrustCenterDocumentsCardFragment on Document {\n id\n title\n createdAt\n documentType\n showOnTrustCenter\n versions(first: 1) {\n edges {\n node {\n id\n status\n }\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "46f72a664d3edb0e5665b1ecea69e31a"; + +export default node; diff --git a/apps/console/src/hooks/graph/__generated__/TrustCenterGraphQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/TrustCenterGraphQuery.graphql.ts new file mode 100644 index 000000000..59c8982ec --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/TrustCenterGraphQuery.graphql.ts @@ -0,0 +1,558 @@ +/** + * @generated SignedSource<<46a922efef96e5c7d015bd0f27467bf3>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type TrustCenterGraphQuery$variables = { + organizationId: string; +}; +export type TrustCenterGraphQuery$data = { + readonly organization: { + readonly audits?: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly " $fragmentSpreads": FragmentRefs<"TrustCenterAuditsCardFragment">; + }; + }>; + }; + readonly documents?: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly " $fragmentSpreads": FragmentRefs<"TrustCenterDocumentsCardFragment">; + }; + }>; + }; + readonly id?: string; + readonly name?: string; + readonly trustCenter?: { + readonly active: boolean; + readonly createdAt: any; + readonly id: string; + readonly slug: string; + readonly updatedAt: any; + } | null | undefined; + readonly vendors?: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly " $fragmentSpreads": FragmentRefs<"TrustCenterVendorsCardFragment">; + }; + }>; + }; + }; +}; +export type TrustCenterGraphQuery = { + response: TrustCenterGraphQuery$data; + variables: TrustCenterGraphQuery$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "organizationId" + } +], +v1 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "organizationId" + } +], +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v3 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v4 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null +}, +v5 = { + "alias": null, + "args": null, + "concreteType": "TrustCenter", + "kind": "LinkedField", + "name": "trustCenter", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "active", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "slug", + "storageKey": null + }, + (v4/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + } + ], + "storageKey": null +}, +v6 = [ + { + "kind": "Literal", + "name": "first", + "value": 100 + } +], +v7 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "showOnTrustCenter", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "TrustCenterGraphQuery", + "selections": [ + { + "alias": "organization", + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "kind": "InlineFragment", + "selections": [ + (v2/*: any*/), + (v3/*: any*/), + (v5/*: any*/), + { + "alias": null, + "args": (v6/*: any*/), + "concreteType": "DocumentConnection", + "kind": "LinkedField", + "name": "documents", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Document", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "args": null, + "kind": "FragmentSpread", + "name": "TrustCenterDocumentsCardFragment" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "documents(first:100)" + }, + { + "alias": null, + "args": (v6/*: any*/), + "concreteType": "AuditConnection", + "kind": "LinkedField", + "name": "audits", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "AuditEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Audit", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "args": null, + "kind": "FragmentSpread", + "name": "TrustCenterAuditsCardFragment" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "audits(first:100)" + }, + { + "alias": null, + "args": (v6/*: any*/), + "concreteType": "VendorConnection", + "kind": "LinkedField", + "name": "vendors", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Vendor", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "args": null, + "kind": "FragmentSpread", + "name": "TrustCenterVendorsCardFragment" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "vendors(first:100)" + } + ], + "type": "Organization", + "abstractKey": null + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "TrustCenterGraphQuery", + "selections": [ + { + "alias": "organization", + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + (v2/*: any*/), + { + "kind": "InlineFragment", + "selections": [ + (v3/*: any*/), + (v5/*: any*/), + { + "alias": null, + "args": (v6/*: any*/), + "concreteType": "DocumentConnection", + "kind": "LinkedField", + "name": "documents", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Document", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "title", + "storageKey": null + }, + (v4/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "documentType", + "storageKey": null + }, + (v7/*: any*/), + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 1 + } + ], + "concreteType": "DocumentVersionConnection", + "kind": "LinkedField", + "name": "versions", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentVersionEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentVersion", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "versions(first:1)" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "documents(first:100)" + }, + { + "alias": null, + "args": (v6/*: any*/), + "concreteType": "AuditConnection", + "kind": "LinkedField", + "name": "audits", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "AuditEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Audit", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Framework", + "kind": "LinkedField", + "name": "framework", + "plural": false, + "selections": [ + (v3/*: any*/), + (v2/*: any*/) + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "validFrom", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "validUntil", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "state", + "storageKey": null + }, + (v7/*: any*/), + (v4/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "audits(first:100)" + }, + { + "alias": null, + "args": (v6/*: any*/), + "concreteType": "VendorConnection", + "kind": "LinkedField", + "name": "vendors", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Vendor", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + (v3/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "category", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null + }, + (v7/*: any*/), + (v4/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "vendors(first:100)" + } + ], + "type": "Organization", + "abstractKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "a22d734ee326d24f3f67ffecf4653b2f", + "id": null, + "metadata": {}, + "name": "TrustCenterGraphQuery", + "operationKind": "query", + "text": "query TrustCenterGraphQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n name\n trustCenter {\n id\n active\n slug\n createdAt\n updatedAt\n }\n documents(first: 100) {\n edges {\n node {\n id\n ...TrustCenterDocumentsCardFragment\n }\n }\n }\n audits(first: 100) {\n edges {\n node {\n id\n ...TrustCenterAuditsCardFragment\n }\n }\n }\n vendors(first: 100) {\n edges {\n node {\n id\n ...TrustCenterVendorsCardFragment\n }\n }\n }\n }\n id\n }\n}\n\nfragment TrustCenterAuditsCardFragment on Audit {\n id\n framework {\n name\n id\n }\n validFrom\n validUntil\n state\n showOnTrustCenter\n createdAt\n}\n\nfragment TrustCenterDocumentsCardFragment on Document {\n id\n title\n createdAt\n documentType\n showOnTrustCenter\n versions(first: 1) {\n edges {\n node {\n id\n status\n }\n }\n }\n}\n\nfragment TrustCenterVendorsCardFragment on Vendor {\n id\n name\n category\n description\n showOnTrustCenter\n createdAt\n}\n" + } +}; +})(); + +(node as any).hash = "260529b3ca03240b07989f278bb7a539"; + +export default node; diff --git a/apps/console/src/hooks/graph/__generated__/TrustCenterGraphUpdateMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/TrustCenterGraphUpdateMutation.graphql.ts new file mode 100644 index 000000000..1769c43fa --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/TrustCenterGraphUpdateMutation.graphql.ts @@ -0,0 +1,131 @@ +/** + * @generated SignedSource<> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type UpdateTrustCenterInput = { + active?: boolean | null | undefined; + slug?: string | null | undefined; + trustCenterId: string; +}; +export type TrustCenterGraphUpdateMutation$variables = { + input: UpdateTrustCenterInput; +}; +export type TrustCenterGraphUpdateMutation$data = { + readonly updateTrustCenter: { + readonly trustCenter: { + readonly active: boolean; + readonly id: string; + readonly slug: string; + readonly updatedAt: any; + }; + }; +}; +export type TrustCenterGraphUpdateMutation = { + response: TrustCenterGraphUpdateMutation$data; + variables: TrustCenterGraphUpdateMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "UpdateTrustCenterPayload", + "kind": "LinkedField", + "name": "updateTrustCenter", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "TrustCenter", + "kind": "LinkedField", + "name": "trustCenter", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "active", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "slug", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "TrustCenterGraphUpdateMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "TrustCenterGraphUpdateMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "18e80937923185923d9b427819334337", + "id": null, + "metadata": {}, + "name": "TrustCenterGraphUpdateMutation", + "operationKind": "mutation", + "text": "mutation TrustCenterGraphUpdateMutation(\n $input: UpdateTrustCenterInput!\n) {\n updateTrustCenter(input: $input) {\n trustCenter {\n id\n active\n slug\n updatedAt\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "988f3baf354e729d6cc9482129040898"; + +export default node; diff --git a/apps/console/src/hooks/graph/__generated__/TrustCenterVendorGraphUpdateMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/TrustCenterVendorGraphUpdateMutation.graphql.ts new file mode 100644 index 000000000..2e150807b --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/TrustCenterVendorGraphUpdateMutation.graphql.ts @@ -0,0 +1,133 @@ +/** + * @generated SignedSource<<012c4e605372a38efef4780c63d40888>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type VendorCategory = "ANALYTICS" | "CLOUD_MONITORING" | "CLOUD_PROVIDER" | "COLLABORATION" | "CUSTOMER_SUPPORT" | "DATA_STORAGE_AND_PROCESSING" | "DOCUMENT_MANAGEMENT" | "EMPLOYEE_MANAGEMENT" | "ENGINEERING" | "FINANCE" | "IDENTITY_PROVIDER" | "IT" | "MARKETING" | "OFFICE_OPERATIONS" | "OTHER" | "PASSWORD_MANAGEMENT" | "PRODUCT_AND_DESIGN" | "PROFESSIONAL_SERVICES" | "RECRUITING" | "SALES" | "SECURITY" | "VERSION_CONTROL"; +export type UpdateVendorInput = { + businessAssociateAgreementUrl?: string | null | undefined; + businessOwnerId?: string | null | undefined; + category?: VendorCategory | null | undefined; + certifications?: ReadonlyArray | null | undefined; + dataProcessingAgreementUrl?: string | null | undefined; + description?: string | null | undefined; + headquarterAddress?: string | null | undefined; + id: string; + legalName?: string | null | undefined; + name?: string | null | undefined; + privacyPolicyUrl?: string | null | undefined; + securityOwnerId?: string | null | undefined; + securityPageUrl?: string | null | undefined; + serviceLevelAgreementUrl?: string | null | undefined; + showOnTrustCenter?: boolean | null | undefined; + statusPageUrl?: string | null | undefined; + subprocessorsListUrl?: string | null | undefined; + termsOfServiceUrl?: string | null | undefined; + trustPageUrl?: string | null | undefined; + websiteUrl?: string | null | undefined; +}; +export type TrustCenterVendorGraphUpdateMutation$variables = { + input: UpdateVendorInput; +}; +export type TrustCenterVendorGraphUpdateMutation$data = { + readonly updateVendor: { + readonly vendor: { + readonly id: string; + readonly showOnTrustCenter: boolean; + }; + }; +}; +export type TrustCenterVendorGraphUpdateMutation = { + response: TrustCenterVendorGraphUpdateMutation$data; + variables: TrustCenterVendorGraphUpdateMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "UpdateVendorPayload", + "kind": "LinkedField", + "name": "updateVendor", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Vendor", + "kind": "LinkedField", + "name": "vendor", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "showOnTrustCenter", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "TrustCenterVendorGraphUpdateMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "TrustCenterVendorGraphUpdateMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "44e483af96833ea9efb1567fa5983282", + "id": null, + "metadata": {}, + "name": "TrustCenterVendorGraphUpdateMutation", + "operationKind": "mutation", + "text": "mutation TrustCenterVendorGraphUpdateMutation(\n $input: UpdateVendorInput!\n) {\n updateVendor(input: $input) {\n vendor {\n id\n showOnTrustCenter\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "e561918e67c08f1e3fae85dfb04591d1"; + +export default node; diff --git a/apps/console/src/layouts/MainLayout.tsx b/apps/console/src/layouts/MainLayout.tsx index 6c2d42b9a..fc399afed 100644 --- a/apps/console/src/layouts/MainLayout.tsx +++ b/apps/console/src/layouts/MainLayout.tsx @@ -14,6 +14,7 @@ import { IconTodo, IconListStack, IconBox, + IconShield, Layout, SidebarItem, UserDropdown as UserDropdownRoot, @@ -137,6 +138,11 @@ export function MainLayout() { icon={IconCheckmark1} to={`${prefix}/audits`} /> + ; +}; + +export default function TrustCenterPage({ queryRef }: Props) { + const { __ } = useTranslate(); + const { toast } = useToast(); + const organizationId = useOrganizationId(); + const location = useLocation(); + const { organization } = usePreloadedQuery(trustCenterQuery, queryRef); + + const [updateTrustCenter, isUpdating] = useUpdateTrustCenterMutation(); + const [isActive, setIsActive] = useState(organization.trustCenter?.active || false); + const [slug, setSlug] = useState(organization.trustCenter?.slug || ""); + const [isUpdatingSlug, setIsUpdatingSlug] = useState(false); + + usePageTitle(__("Trust Center")); + + const handleToggleActive = async (active: boolean) => { + if (!organization.trustCenter?.id) { + toast({ + title: __("Error"), + description: __("Trust center not found"), + variant: "error", + }); + return; + } + + setIsActive(active); + + updateTrustCenter({ + variables: { + input: { + trustCenterId: organization.trustCenter.id, + active, + }, + }, + onError: () => { + setIsActive(!active); + }, + }); + }; + + const handleSlugUpdate = async () => { + if (!organization.trustCenter?.id) { + toast({ + title: __("Error"), + description: __("Trust center not found"), + variant: "error", + }); + return; + } + + if (!slug.trim()) { + toast({ + title: __("Error"), + description: __("Slug cannot be empty"), + variant: "error", + }); + return; + } + + setIsUpdatingSlug(true); + + updateTrustCenter({ + variables: { + input: { + trustCenterId: organization.trustCenter.id, + slug: slug.trim(), + }, + }, + onCompleted: () => { + setIsUpdatingSlug(false); + }, + onError: () => { + setIsUpdatingSlug(false); + setSlug(organization.trustCenter?.slug || ""); + }, + }); + }; + + const trustCenterUrl = organization.trustCenter?.slug + ? `${window.location.origin}/trust/${organization.trustCenter.slug}` + : null; + + + return ( +
+ + +
+
+

{__("Trust Center Status")}

+ {isUpdating && } +
+ +
+
+

{__("Activate Trust Center")}

+

+ {__("Make your trust center publicly accessible to build customer confidence")} +

+
+ +
+ + {isActive && trustCenterUrl && ( +
+
+
+

+ {__("Your Trust Center is Live!")} +

+

+ {__("Your customers can now access your trust center at:")} +

+ + {trustCenterUrl} + +
+ +
+
+ )} + + {!isActive && ( +
+

+ {__("Trust Center is Inactive")} +

+

+ {__("Your trust center is currently not accessible to the public. Enable it to start sharing your compliance status.")} +

+
+ )} +
+
+
+
+

{__("Configuration")}

+ {isUpdatingSlug && } +
+ +
+ +
+
+ setSlug(e.target.value)} + placeholder={__("your-organization")} + className="min-w-[200px]" + /> +
+ +
+
+
+
+
+
+

{__("Content")}

+ + + + {__("Audits")} + + + + {__("Vendors")} + + + {__("Documents")} + + + + +
+
+ ); +} diff --git a/apps/console/src/pages/organizations/trustCenter/TrustCenterAuditsTab.tsx b/apps/console/src/pages/organizations/trustCenter/TrustCenterAuditsTab.tsx new file mode 100644 index 000000000..9772f0284 --- /dev/null +++ b/apps/console/src/pages/organizations/trustCenter/TrustCenterAuditsTab.tsx @@ -0,0 +1,39 @@ +import { Card, Spinner } from "@probo/ui"; +import { useOutletContext } from "react-router"; +import { TrustCenterAuditsCard } from "/components/trustCenter/TrustCenterAuditsCard"; +import { useTrustCenterAuditUpdate } from "/hooks/graph/TrustCenterAuditGraph"; +import type { TrustCenterAuditsCardFragment$key } from "/components/trustCenter/__generated__/TrustCenterAuditsCardFragment.graphql"; + +type ContextType = { + organization: { + audits?: { + edges: Array<{ + node: TrustCenterAuditsCardFragment$key; + }>; + }; + }; +}; + +export default function TrustCenterAuditsTab() { + const { organization } = useOutletContext(); + const [updateAuditVisibility, isUpdatingAudits] = useTrustCenterAuditUpdate(); + + const audits = (organization.audits?.edges ?? []).map((edge) => edge.node); + + return ( +
+
+ {isUpdatingAudits && } +
+ + + +
+ ); +} diff --git a/apps/console/src/pages/organizations/trustCenter/TrustCenterDocumentsTab.tsx b/apps/console/src/pages/organizations/trustCenter/TrustCenterDocumentsTab.tsx new file mode 100644 index 000000000..e2a4b3223 --- /dev/null +++ b/apps/console/src/pages/organizations/trustCenter/TrustCenterDocumentsTab.tsx @@ -0,0 +1,39 @@ +import { Card, Spinner } from "@probo/ui"; +import { useOutletContext } from "react-router"; +import { TrustCenterDocumentsCard } from "/components/trustCenter/TrustCenterDocumentsCard"; +import { useUpdateDocumentVisibilityMutation } from "/hooks/graph/TrustCenterDocumentGraph"; +import type { TrustCenterDocumentsCardFragment$key } from "/components/trustCenter/__generated__/TrustCenterDocumentsCardFragment.graphql"; + +type ContextType = { + organization: { + documents?: { + edges: Array<{ + node: TrustCenterDocumentsCardFragment$key; + }>; + }; + }; +}; + +export default function TrustCenterDocumentsTab() { + const { organization } = useOutletContext(); + const [updateDocumentVisibility, isUpdatingDocuments] = useUpdateDocumentVisibilityMutation(); + + const documents = organization.documents?.edges?.map((edge) => edge.node) || []; + + return ( +
+
+ {isUpdatingDocuments && } +
+ + + +
+ ); +} diff --git a/apps/console/src/pages/organizations/trustCenter/TrustCenterVendorsTab.tsx b/apps/console/src/pages/organizations/trustCenter/TrustCenterVendorsTab.tsx new file mode 100644 index 000000000..2a1601553 --- /dev/null +++ b/apps/console/src/pages/organizations/trustCenter/TrustCenterVendorsTab.tsx @@ -0,0 +1,39 @@ +import { Card, Spinner } from "@probo/ui"; +import { useOutletContext } from "react-router"; +import { TrustCenterVendorsCard } from "/components/trustCenter/TrustCenterVendorsCard"; +import { useTrustCenterVendorUpdate } from "/hooks/graph/TrustCenterVendorGraph"; +import type { TrustCenterVendorsCardFragment$key } from "/components/trustCenter/__generated__/TrustCenterVendorsCardFragment.graphql"; + +type ContextType = { + organization: { + vendors?: { + edges: Array<{ + node: TrustCenterVendorsCardFragment$key; + }>; + }; + }; +}; + +export default function TrustCenterVendorsTab() { + const { organization } = useOutletContext(); + const [updateVendorVisibility, isUpdatingVendors] = useTrustCenterVendorUpdate(); + + const vendors = organization.vendors?.edges?.map((edge) => edge.node) || []; + + return ( +
+
+ {isUpdatingVendors && } +
+ + + +
+ ); +} diff --git a/apps/console/src/routes.tsx b/apps/console/src/routes.tsx index 01b26f2cc..a937731ea 100644 --- a/apps/console/src/routes.tsx +++ b/apps/console/src/routes.tsx @@ -28,6 +28,7 @@ import { taskRoutes } from "./routes/taskRoutes.ts"; import { dataRoutes } from "./routes/dataRoutes.ts"; import { assetRoutes } from "./routes/assetRoutes.ts"; import { auditRoutes } from "./routes/auditRoutes.ts"; +import { trustCenterRoutes } from "./routes/trustCenterRoutes.ts"; import { lazy } from "@probo/react-lazy"; /** @@ -136,6 +137,7 @@ const routes = [ ...assetRoutes, ...dataRoutes, ...auditRoutes, + ...trustCenterRoutes, { path: "*", Component: PageError, diff --git a/apps/console/src/routes/trustCenterRoutes.ts b/apps/console/src/routes/trustCenterRoutes.ts new file mode 100644 index 000000000..5c1ac85a4 --- /dev/null +++ b/apps/console/src/routes/trustCenterRoutes.ts @@ -0,0 +1,49 @@ +import { loadQuery } from "react-relay"; +import { relayEnvironment } from "/providers/RelayProviders"; +import { PageSkeleton } from "/components/skeletons/PageSkeleton"; +import { LinkCardSkeleton } from "/components/skeletons/LinkCardSkeleton"; +import { lazy } from "@probo/react-lazy"; +import { trustCenterQuery } from "../hooks/graph/TrustCenterGraph"; +import type { AppRoute } from "/routes"; + +export const trustCenterRoutes = [ + { + path: "trust-center", + fallback: PageSkeleton, + queryLoader: ({ organizationId }) => + loadQuery(relayEnvironment, trustCenterQuery, { organizationId }), + Component: lazy( + () => import("/pages/organizations/TrustCenterPage") + ), + children: [ + { + index: true, + fallback: LinkCardSkeleton, + Component: lazy( + () => import("/pages/organizations/trustCenter/TrustCenterAuditsTab") + ), + }, + { + path: "audits", + fallback: LinkCardSkeleton, + Component: lazy( + () => import("/pages/organizations/trustCenter/TrustCenterAuditsTab") + ), + }, + { + path: "vendors", + fallback: LinkCardSkeleton, + Component: lazy( + () => import("/pages/organizations/trustCenter/TrustCenterVendorsTab") + ), + }, + { + path: "documents", + fallback: LinkCardSkeleton, + Component: lazy( + () => import("/pages/organizations/trustCenter/TrustCenterDocumentsTab") + ), + }, + ], + }, +] satisfies AppRoute[]; diff --git a/packages/ui/src/Atoms/Tabs/Tabs.tsx b/packages/ui/src/Atoms/Tabs/Tabs.tsx index 399a05dc1..0534054d1 100644 --- a/packages/ui/src/Atoms/Tabs/Tabs.tsx +++ b/packages/ui/src/Atoms/Tabs/Tabs.tsx @@ -1,5 +1,5 @@ import type { HTMLAttributes, PropsWithChildren } from "react"; -import { NavLink } from "react-router"; +import { NavLink, type NavLinkProps } from "react-router"; import { Root, List } from "@radix-ui/react-tabs"; import { Slot, type AsChildProps } from "../Slot"; import { tv } from "tailwind-variants"; @@ -41,7 +41,7 @@ export function TabItem({ return ; } -export function TabLink(props: PropsWithChildren<{ to: string }>) { +export function TabLink(props: PropsWithChildren boolean }>) { return ( cls.item({ active: params.isActive })} diff --git a/pkg/coredata/audit.go b/pkg/coredata/audit.go index f0f411665..3ea52b6f8 100644 --- a/pkg/coredata/audit.go +++ b/pkg/coredata/audit.go @@ -28,15 +28,16 @@ import ( type ( Audit struct { - ID gid.GID `db:"id"` - OrganizationID gid.GID `db:"organization_id"` - FrameworkID gid.GID `db:"framework_id"` - ReportID *gid.GID `db:"report_id"` - ValidFrom *time.Time `db:"valid_from"` - ValidUntil *time.Time `db:"valid_until"` - State AuditState `db:"state"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` + ID gid.GID `db:"id"` + OrganizationID gid.GID `db:"organization_id"` + FrameworkID gid.GID `db:"framework_id"` + ReportID *gid.GID `db:"report_id"` + ValidFrom *time.Time `db:"valid_from"` + ValidUntil *time.Time `db:"valid_until"` + State AuditState `db:"state"` + ShowOnTrustCenter bool `db:"show_on_trust_center"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` } Audits []*Audit @@ -72,6 +73,7 @@ SELECT valid_from, valid_until, state, + show_on_trust_center, created_at, updated_at FROM @@ -150,6 +152,7 @@ SELECT valid_from, valid_until, state, + show_on_trust_center, created_at, updated_at FROM @@ -196,6 +199,7 @@ INSERT INTO audits ( valid_from, valid_until, state, + show_on_trust_center, created_at, updated_at ) VALUES ( @@ -207,22 +211,24 @@ INSERT INTO audits ( @valid_from, @valid_until, @state, + @show_on_trust_center, @created_at, @updated_at ) ` args := pgx.StrictNamedArgs{ - "id": a.ID, - "tenant_id": scope.GetTenantID(), - "organization_id": a.OrganizationID, - "framework_id": a.FrameworkID, - "report_id": a.ReportID, - "valid_from": a.ValidFrom, - "valid_until": a.ValidUntil, - "state": a.State, - "created_at": a.CreatedAt, - "updated_at": a.UpdatedAt, + "id": a.ID, + "tenant_id": scope.GetTenantID(), + "organization_id": a.OrganizationID, + "framework_id": a.FrameworkID, + "report_id": a.ReportID, + "valid_from": a.ValidFrom, + "valid_until": a.ValidUntil, + "state": a.State, + "show_on_trust_center": a.ShowOnTrustCenter, + "created_at": a.CreatedAt, + "updated_at": a.UpdatedAt, } _, err := conn.Exec(ctx, q, args) @@ -245,6 +251,7 @@ SET valid_from = @valid_from, valid_until = @valid_until, state = @state, + show_on_trust_center = @show_on_trust_center, updated_at = @updated_at WHERE %s @@ -254,12 +261,13 @@ WHERE q = fmt.Sprintf(q, scope.SQLFragment()) args := pgx.StrictNamedArgs{ - "id": a.ID, - "report_id": a.ReportID, - "valid_from": a.ValidFrom, - "valid_until": a.ValidUntil, - "state": a.State, - "updated_at": a.UpdatedAt, + "id": a.ID, + "report_id": a.ReportID, + "valid_from": a.ValidFrom, + "valid_until": a.ValidUntil, + "state": a.State, + "show_on_trust_center": a.ShowOnTrustCenter, + "updated_at": a.UpdatedAt, } maps.Copy(args, scope.SQLArguments()) diff --git a/pkg/coredata/document.go b/pkg/coredata/document.go index 5c49d5c47..baf0f2f25 100644 --- a/pkg/coredata/document.go +++ b/pkg/coredata/document.go @@ -34,6 +34,7 @@ type ( Title string `db:"title"` DocumentType DocumentType `db:"document_type"` CurrentPublishedVersion *int `db:"current_published_version"` + ShowOnTrustCenter bool `db:"show_on_trust_center"` CreatedAt time.Time `db:"created_at"` UpdatedAt time.Time `db:"updated_at"` } @@ -68,6 +69,7 @@ SELECT title, document_type, current_published_version, + show_on_trust_center, created_at, updated_at FROM @@ -147,6 +149,7 @@ SELECT title, document_type, current_published_version, + show_on_trust_center, created_at, updated_at FROM @@ -195,6 +198,7 @@ INSERT INTO title, document_type, current_published_version, + show_on_trust_center, created_at, updated_at ) @@ -206,6 +210,7 @@ VALUES ( @title, @document_type, @current_published_version, + @show_on_trust_center, @created_at, @updated_at ); @@ -219,6 +224,7 @@ VALUES ( "title": p.Title, "document_type": p.DocumentType, "current_published_version": p.CurrentPublishedVersion, + "show_on_trust_center": p.ShowOnTrustCenter, "created_at": p.CreatedAt, "updated_at": p.UpdatedAt, } @@ -257,6 +263,7 @@ SET current_published_version = @current_published_version, owner_id = @owner_id, document_type = @document_type, + show_on_trust_center = @show_on_trust_center, updated_at = @updated_at WHERE %s AND id = @document_id @@ -270,6 +277,7 @@ WHERE %s "current_published_version": p.CurrentPublishedVersion, "owner_id": p.OwnerID, "document_type": p.DocumentType, + "show_on_trust_center": p.ShowOnTrustCenter, } maps.Copy(args, scope.SQLArguments()) @@ -342,6 +350,7 @@ WITH plcs AS ( p.title, p.document_type, p.current_published_version, + p.show_on_trust_center, p.created_at, p.updated_at FROM @@ -358,6 +367,7 @@ SELECT title, document_type, current_published_version, + show_on_trust_center, created_at, updated_at FROM @@ -448,6 +458,7 @@ WITH plcs AS ( p.title, p.document_type, p.current_published_version, + p.show_on_trust_center, p.created_at, p.updated_at FROM @@ -464,6 +475,7 @@ SELECT title, document_type, current_published_version, + show_on_trust_center, created_at, updated_at FROM diff --git a/pkg/coredata/entity_type_reg.go b/pkg/coredata/entity_type_reg.go index 9c492db2c..8223db995 100644 --- a/pkg/coredata/entity_type_reg.go +++ b/pkg/coredata/entity_type_reg.go @@ -37,4 +37,5 @@ const ( DatumEntityType AuditEntityType ReportEntityType + TrustCenterEntityType ) diff --git a/pkg/coredata/migrations/20250724T135155Z.sql b/pkg/coredata/migrations/20250724T135155Z.sql new file mode 100644 index 000000000..bcecbca6c --- /dev/null +++ b/pkg/coredata/migrations/20250724T135155Z.sql @@ -0,0 +1,51 @@ +CREATE EXTENSION IF NOT EXISTS unaccent; + +CREATE TABLE trust_centers ( + id TEXT PRIMARY KEY, + organization_id TEXT NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, + tenant_id TEXT NOT NULL, + active BOOLEAN NOT NULL, + slug TEXT NOT NULL CHECK (slug ~ '^[a-z0-9_-]+$'), + created_at TIMESTAMP WITH TIME ZONE NOT NULL, + updated_at TIMESTAMP WITH TIME ZONE NOT NULL, + UNIQUE(slug) +); + +INSERT INTO trust_centers ( + id, + organization_id, + tenant_id, + active, + slug, + created_at, + updated_at +) +SELECT + generate_gid(decode_base64_unpadded(o.tenant_id), 22), + o.id, + o.tenant_id, + false, + LOWER( + REGEXP_REPLACE( + REGEXP_REPLACE( + unaccent(o.name), + '[^a-zA-Z0-9\s]', '', 'g' + ), + '\s+', '-', 'g' + ) + ), + NOW(), + NOW() +FROM organizations o; + +ALTER TABLE documents ADD COLUMN show_on_trust_center BOOLEAN NOT NULL DEFAULT false; + +ALTER TABLE audits ADD COLUMN show_on_trust_center BOOLEAN NOT NULL DEFAULT false; + +ALTER TABLE vendors ADD COLUMN show_on_trust_center BOOLEAN NOT NULL DEFAULT false; + +ALTER TABLE documents ALTER COLUMN show_on_trust_center DROP DEFAULT; + +ALTER TABLE audits ALTER COLUMN show_on_trust_center DROP DEFAULT; + +ALTER TABLE vendors ALTER COLUMN show_on_trust_center DROP DEFAULT; diff --git a/pkg/coredata/trust_center.go b/pkg/coredata/trust_center.go new file mode 100644 index 000000000..ff0687fe4 --- /dev/null +++ b/pkg/coredata/trust_center.go @@ -0,0 +1,213 @@ +// 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 ( + "context" + "fmt" + "maps" + "time" + + "github.com/getprobo/probo/pkg/gid" + "github.com/getprobo/probo/pkg/page" + "github.com/jackc/pgx/v5" + "go.gearno.de/kit/pg" +) + +type ( + TrustCenter struct { + ID gid.GID `db:"id"` + OrganizationID gid.GID `db:"organization_id"` + TenantID gid.TenantID `db:"tenant_id"` + Active bool `db:"active"` + Slug string `db:"slug"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` + } + + TrustCenters []*TrustCenter +) + +func (tc *TrustCenter) CursorKey(orderBy TrustCenterOrderField) page.CursorKey { + switch orderBy { + case TrustCenterOrderFieldCreatedAt: + return page.NewCursorKey(tc.ID, tc.CreatedAt) + } + + panic(fmt.Sprintf("unsupported order by: %s", orderBy)) +} + +func (tc *TrustCenter) LoadByID( + ctx context.Context, + conn pg.Conn, + scope Scoper, + trustCenterID gid.GID, +) error { + q := ` +SELECT + id, + organization_id, + tenant_id, + active, + slug, + created_at, + updated_at +FROM + trust_centers +WHERE + %s + AND id = @trust_center_id +LIMIT 1; +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{"trust_center_id": trustCenterID} + maps.Copy(args, scope.SQLArguments()) + + rows, err := conn.Query(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot query trust center: %w", err) + } + + trustCenter, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[TrustCenter]) + if err != nil { + return fmt.Errorf("cannot collect trust center: %w", err) + } + + *tc = trustCenter + + return nil +} + +func (tc *TrustCenter) LoadByOrganizationID( + ctx context.Context, + conn pg.Conn, + scope Scoper, + organizationID gid.GID, +) error { + q := ` +SELECT + id, + organization_id, + tenant_id, + active, + slug, + created_at, + updated_at +FROM + trust_centers +WHERE + %s + AND organization_id = @organization_id +LIMIT 1; +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{"organization_id": organizationID} + maps.Copy(args, scope.SQLArguments()) + + rows, err := conn.Query(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot query trust center: %w", err) + } + + trustCenter, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[TrustCenter]) + if err != nil { + return fmt.Errorf("cannot collect trust center: %w", err) + } + + *tc = trustCenter + + return nil +} + +func (tc *TrustCenter) Insert( + ctx context.Context, + conn pg.Conn, + scope Scoper, +) error { + q := ` +INSERT INTO trust_centers ( + id, + organization_id, + tenant_id, + active, + slug, + created_at, + updated_at +) VALUES ( + @id, + @organization_id, + @tenant_id, + @active, + @slug, + @created_at, + @updated_at +) +` + + args := pgx.StrictNamedArgs{ + "id": tc.ID, + "organization_id": tc.OrganizationID, + "tenant_id": tc.TenantID, + "active": tc.Active, + "slug": tc.Slug, + "created_at": tc.CreatedAt, + "updated_at": tc.UpdatedAt, + } + + _, err := conn.Exec(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot insert trust center: %w", err) + } + + return nil +} + +func (tc *TrustCenter) Update( + ctx context.Context, + conn pg.Conn, + scope Scoper, +) error { + q := ` +UPDATE trust_centers +SET + active = @active, + slug = @slug, + updated_at = @updated_at +WHERE + %s + AND id = @id +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{ + "id": tc.ID, + "active": tc.Active, + "slug": tc.Slug, + "updated_at": tc.UpdatedAt, + } + maps.Copy(args, scope.SQLArguments()) + + _, err := conn.Exec(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot update trust center: %w", err) + } + + return nil +} diff --git a/pkg/coredata/trust_center_order_field.go b/pkg/coredata/trust_center_order_field.go new file mode 100644 index 000000000..f0aea7b1d --- /dev/null +++ b/pkg/coredata/trust_center_order_field.go @@ -0,0 +1,38 @@ +// 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 + +type TrustCenterOrderField string + +const ( + TrustCenterOrderFieldCreatedAt TrustCenterOrderField = "CREATED_AT" +) + +func (p TrustCenterOrderField) Column() string { + return string(p) +} + +func (p TrustCenterOrderField) String() string { + return string(p) +} + +func (p TrustCenterOrderField) MarshalText() ([]byte, error) { + return []byte(p.String()), nil +} + +func (p *TrustCenterOrderField) UnmarshalText(text []byte) error { + *p = TrustCenterOrderField(text) + return nil +} diff --git a/pkg/coredata/vendor.go b/pkg/coredata/vendor.go index 3952fa40c..a1376db44 100644 --- a/pkg/coredata/vendor.go +++ b/pkg/coredata/vendor.go @@ -49,6 +49,7 @@ type ( TermsOfServiceURL *string `db:"terms_of_service_url"` SecurityPageURL *string `db:"security_page_url"` TrustPageURL *string `db:"trust_page_url"` + ShowOnTrustCenter bool `db:"show_on_trust_center"` CreatedAt time.Time `db:"created_at"` UpdatedAt time.Time `db:"updated_at"` } @@ -98,6 +99,7 @@ SELECT terms_of_service_url, security_page_url, trust_page_url, + show_on_trust_center, created_at, updated_at FROM @@ -158,6 +160,7 @@ INSERT INTO terms_of_service_url, security_page_url, trust_page_url, + show_on_trust_center, created_at, updated_at ) @@ -183,6 +186,7 @@ VALUES ( @terms_of_service_url, @security_page_url, @trust_page_url, + @show_on_trust_center, @created_at, @updated_at ) @@ -210,6 +214,7 @@ VALUES ( "terms_of_service_url": v.TermsOfServiceURL, "security_page_url": v.SecurityPageURL, "trust_page_url": v.TrustPageURL, + "show_on_trust_center": v.ShowOnTrustCenter, "created_at": v.CreatedAt, "updated_at": v.UpdatedAt, } @@ -297,6 +302,7 @@ SELECT terms_of_service_url, security_page_url, trust_page_url, + show_on_trust_center, created_at, updated_at FROM @@ -353,6 +359,7 @@ SET trust_page_url = @trust_page_url, business_owner_id = @business_owner_id, security_owner_id = @security_owner_id, + show_on_trust_center = @show_on_trust_center, updated_at = @updated_at WHERE %s AND id = @vendor_id @@ -380,6 +387,7 @@ WHERE %s "trust_page_url": v.TrustPageURL, "business_owner_id": v.BusinessOwnerID, "security_owner_id": v.SecurityOwnerID, + "show_on_trust_center": v.ShowOnTrustCenter, } maps.Copy(args, scope.SQLArguments()) diff --git a/pkg/probo/audit_service.go b/pkg/probo/audit_service.go index 2cad2b91d..cee0e6255 100644 --- a/pkg/probo/audit_service.go +++ b/pkg/probo/audit_service.go @@ -39,10 +39,11 @@ type ( } UpdateAuditRequest struct { - ID gid.GID - ValidFrom *time.Time - ValidUntil *time.Time - State *coredata.AuditState + ID gid.GID + ValidFrom *time.Time + ValidUntil *time.Time + State *coredata.AuditState + ShowOnTrustCenter *bool } UpdateAuditStateRequest struct { @@ -87,14 +88,15 @@ func (s *AuditService) Create( now := time.Now() audit := &coredata.Audit{ - ID: gid.New(s.svc.scope.GetTenantID(), coredata.AuditEntityType), - OrganizationID: req.OrganizationID, - FrameworkID: req.FrameworkID, - ValidFrom: req.ValidFrom, - ValidUntil: req.ValidUntil, - State: coredata.AuditStateNotStarted, - CreatedAt: now, - UpdatedAt: now, + ID: gid.New(s.svc.scope.GetTenantID(), coredata.AuditEntityType), + OrganizationID: req.OrganizationID, + FrameworkID: req.FrameworkID, + ValidFrom: req.ValidFrom, + ValidUntil: req.ValidUntil, + State: coredata.AuditStateNotStarted, + ShowOnTrustCenter: false, + CreatedAt: now, + UpdatedAt: now, } if req.State != nil { @@ -151,6 +153,9 @@ func (s *AuditService) Update( if req.State != nil { audit.State = *req.State } + if req.ShowOnTrustCenter != nil { + audit.ShowOnTrustCenter = *req.ShowOnTrustCenter + } audit.UpdatedAt = time.Now() diff --git a/pkg/probo/document_service.go b/pkg/probo/document_service.go index fbe29c38e..20695ee48 100644 --- a/pkg/probo/document_service.go +++ b/pkg/probo/document_service.go @@ -297,11 +297,12 @@ func (s *DocumentService) Create( people := &coredata.People{} document := &coredata.Document{ - ID: documentID, - Title: req.Title, - DocumentType: req.DocumentType, - CreatedAt: now, - UpdatedAt: now, + ID: documentID, + Title: req.Title, + DocumentType: req.DocumentType, + ShowOnTrustCenter: false, + CreatedAt: now, + UpdatedAt: now, } documentVersion := &coredata.DocumentVersion{ @@ -984,6 +985,7 @@ func (s *DocumentService) Update( newOwnerID *gid.GID, documentType *coredata.DocumentType, title *string, + showOnTrustCenter *bool, ) (*coredata.Document, error) { document := &coredata.Document{} people := &coredata.People{} @@ -1011,6 +1013,10 @@ func (s *DocumentService) Update( document.Title = *title } + if showOnTrustCenter != nil { + document.ShowOnTrustCenter = *showOnTrustCenter + } + document.UpdatedAt = now if err := document.Update(ctx, tx, s.svc.scope); err != nil { diff --git a/pkg/probo/organization_service.go b/pkg/probo/organization_service.go index 00fbe8e91..58a79214b 100644 --- a/pkg/probo/organization_service.go +++ b/pkg/probo/organization_service.go @@ -29,6 +29,7 @@ import ( "github.com/getprobo/probo/pkg/coredata" "github.com/getprobo/probo/pkg/filevalidation" "github.com/getprobo/probo/pkg/gid" + "github.com/getprobo/probo/pkg/slug" "go.gearno.de/crypto/uuid" "go.gearno.de/kit/pg" ) @@ -65,13 +66,27 @@ func (s OrganizationService) Create( UpdatedAt: now, } - err := s.svc.pg.WithConn( + err := s.svc.pg.WithTx( ctx, func(tx pg.Conn) error { if err := organization.Insert(ctx, tx); err != nil { return fmt.Errorf("cannot insert organization: %w", err) } + trustCenter := &coredata.TrustCenter{ + ID: gid.New(s.svc.scope.GetTenantID(), coredata.TrustCenterEntityType), + OrganizationID: organization.ID, + TenantID: organization.TenantID, + Active: false, + Slug: slug.Make(organization.Name), + CreatedAt: now, + UpdatedAt: now, + } + + if err := trustCenter.Insert(ctx, tx, s.svc.scope); err != nil { + return fmt.Errorf("cannot insert trust center: %w", err) + } + return nil }, ) diff --git a/pkg/probo/service.go b/pkg/probo/service.go index 71de5bb49..69a36c65b 100644 --- a/pkg/probo/service.go +++ b/pkg/probo/service.go @@ -65,6 +65,7 @@ type ( Data *DatumService Audits *AuditService Reports *ReportService + TrustCenters *TrustCenterService } ) @@ -144,5 +145,6 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { tenantService.Data = &DatumService{svc: tenantService} tenantService.Audits = &AuditService{svc: tenantService} tenantService.Reports = &ReportService{svc: tenantService} + tenantService.TrustCenters = &TrustCenterService{svc: tenantService} return tenantService } diff --git a/pkg/probo/trust_center_service.go b/pkg/probo/trust_center_service.go new file mode 100644 index 000000000..bc0987bed --- /dev/null +++ b/pkg/probo/trust_center_service.go @@ -0,0 +1,124 @@ +// 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 probo + +import ( + "context" + "fmt" + "time" + + "github.com/getprobo/probo/pkg/coredata" + "github.com/getprobo/probo/pkg/gid" + "go.gearno.de/kit/pg" +) + +type ( + TrustCenterService struct { + svc *TenantService + } + + UpdateTrustCenterRequest struct { + ID gid.GID + Active *bool + Slug *string + } +) + +func (s TrustCenterService) Get( + ctx context.Context, + trustCenterID gid.GID, +) (*coredata.TrustCenter, error) { + trustCenter := &coredata.TrustCenter{} + + err := s.svc.pg.WithConn( + ctx, + func(conn pg.Conn) error { + err := trustCenter.LoadByID(ctx, conn, s.svc.scope, trustCenterID) + if err != nil { + return fmt.Errorf("cannot load trust center: %w", err) + } + + return nil + }, + ) + + if err != nil { + return nil, err + } + + return trustCenter, nil +} + +func (s TrustCenterService) GetByOrganizationID( + ctx context.Context, + organizationID gid.GID, +) (*coredata.TrustCenter, error) { + trustCenter := &coredata.TrustCenter{} + + err := s.svc.pg.WithConn( + ctx, + func(conn pg.Conn) error { + err := trustCenter.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID) + if err != nil { + return fmt.Errorf("cannot load trust center: %w", err) + } + + return nil + }, + ) + + if err != nil { + return nil, err + } + + return trustCenter, nil +} + +func (s *TrustCenterService) Update( + ctx context.Context, + req *UpdateTrustCenterRequest, +) (*coredata.TrustCenter, error) { + trustCenter := &coredata.TrustCenter{} + + err := s.svc.pg.WithTx( + ctx, + func(conn pg.Conn) error { + if err := trustCenter.LoadByID(ctx, conn, s.svc.scope, req.ID); err != nil { + return fmt.Errorf("cannot load trust center: %w", err) + } + + if req.Active != nil { + trustCenter.Active = *req.Active + } + if req.Slug != nil { + trustCenter.Slug = *req.Slug + } + + trustCenter.UpdatedAt = time.Now() + + if err := trustCenter.Update(ctx, conn, s.svc.scope); err != nil { + return fmt.Errorf("cannot update trust center: %w", err) + } + + return nil + }, + ) + + if err != nil { + return nil, err + } + + return trustCenter, nil +} diff --git a/pkg/probo/vendor_service.go b/pkg/probo/vendor_service.go index 526335dee..07faea001 100644 --- a/pkg/probo/vendor_service.go +++ b/pkg/probo/vendor_service.go @@ -72,6 +72,7 @@ type ( StatusPageURL *string BusinessOwnerID *gid.GID SecurityOwnerID *gid.GID + ShowOnTrustCenter *bool } AssessVendorRequest struct { @@ -259,6 +260,10 @@ func (s VendorService) Update( vendor.SecurityPageURL = req.SecurityPageURL } + if req.ShowOnTrustCenter != nil { + vendor.ShowOnTrustCenter = *req.ShowOnTrustCenter + } + if req.TrustPageURL != nil { vendor.TrustPageURL = req.TrustPageURL } @@ -385,6 +390,7 @@ func (s VendorService) Create( TrustPageURL: req.TrustPageURL, StatusPageURL: req.StatusPageURL, TermsOfServiceURL: req.TermsOfServiceURL, + ShowOnTrustCenter: false, } err := s.svc.pg.WithTx( diff --git a/pkg/server/api/console/v1/schema.graphql b/pkg/server/api/console/v1/schema.graphql index f2dd1683f..b37d01fc8 100644 --- a/pkg/server/api/console/v1/schema.graphql +++ b/pkg/server/api/console/v1/schema.graphql @@ -703,6 +703,14 @@ input RiskFilter { } # Core Types +type TrustCenter implements Node { + id: ID! + active: Boolean! + slug: String! + createdAt: Datetime! + updatedAt: Datetime! +} + type Organization implements Node { id: ID! name: String! @@ -816,6 +824,8 @@ type Organization implements Node { orderBy: AuditOrder ): AuditConnection! @goField(forceResolver: true) + trustCenter: TrustCenter @goField(forceResolver: true) + createdAt: Datetime! updatedAt: Datetime! } @@ -891,6 +901,7 @@ type Vendor implements Node { headquarterAddress: String legalName: String websiteUrl: String + showOnTrustCenter: Boolean! createdAt: Datetime! updatedAt: Datetime! } @@ -1052,6 +1063,7 @@ type Document implements Node { description: String! documentType: DocumentType! currentPublishedVersion: Int + showOnTrustCenter: Boolean! owner: People! @goField(forceResolver: true) organization: Organization! @goField(forceResolver: true) @@ -1134,6 +1146,7 @@ type Audit implements Node { report: Report @goField(forceResolver: true) reportUrl: String @goField(forceResolver: true) state: AuditState! + showOnTrustCenter: Boolean! createdAt: Datetime! updatedAt: Datetime! } @@ -1397,6 +1410,10 @@ type Mutation { input: UpdateOrganizationInput! ): UpdateOrganizationPayload! + updateTrustCenter( + input: UpdateTrustCenterInput! + ): UpdateTrustCenterPayload! + # User mutations confirmEmail(input: ConfirmEmailInput!): ConfirmEmailPayload! inviteUser(input: InviteUserInput!): InviteUserPayload! @@ -1563,6 +1580,12 @@ input UpdateOrganizationInput { logo: Upload } +input UpdateTrustCenterInput { + trustCenterId: ID! + active: Boolean + slug: String +} + input CreateVendorInput { organizationId: ID! name: String! @@ -1605,6 +1628,7 @@ input UpdateVendorInput { trustPageUrl: String businessOwnerId: ID securityOwnerId: ID + showOnTrustCenter: Boolean } input DeleteVendorInput { @@ -1836,6 +1860,7 @@ input UpdateDocumentInput { ownerId: ID createdBy: ID documentType: DocumentType + showOnTrustCenter: Boolean } input ExportDocumentVersionPDFInput { @@ -1897,6 +1922,7 @@ input UpdateAuditInput { validFrom: Datetime validUntil: Datetime state: AuditState + showOnTrustCenter: Boolean } input DeleteAuditInput { @@ -1921,6 +1947,10 @@ type UpdateOrganizationPayload { organization: Organization! } +type UpdateTrustCenterPayload { + trustCenter: TrustCenter! +} + type CreateControlPayload { controlEdge: ControlEdge! } diff --git a/pkg/server/api/console/v1/schema/schema.go b/pkg/server/api/console/v1/schema/schema.go index 3bb883823..7b350327a 100644 --- a/pkg/server/api/console/v1/schema/schema.go +++ b/pkg/server/api/console/v1/schema/schema.go @@ -115,16 +115,17 @@ type ComplexityRoot struct { } Audit struct { - CreatedAt func(childComplexity int) int - Framework func(childComplexity int) int - ID func(childComplexity int) int - Organization func(childComplexity int) int - Report func(childComplexity int) int - ReportURL func(childComplexity int) int - State func(childComplexity int) int - UpdatedAt func(childComplexity int) int - ValidFrom func(childComplexity int) int - ValidUntil func(childComplexity int) int + CreatedAt func(childComplexity int) int + Framework func(childComplexity int) int + ID func(childComplexity int) int + Organization func(childComplexity int) int + Report func(childComplexity int) int + ReportURL func(childComplexity int) int + ShowOnTrustCenter func(childComplexity int) int + State func(childComplexity int) int + UpdatedAt func(childComplexity int) int + ValidFrom func(childComplexity int) int + ValidUntil func(childComplexity int) int } AuditConnection struct { @@ -386,6 +387,7 @@ type ComplexityRoot struct { ID func(childComplexity int) int Organization func(childComplexity int) int Owner func(childComplexity int) int + ShowOnTrustCenter func(childComplexity int) int Title func(childComplexity int) int UpdatedAt func(childComplexity int) int Versions func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionOrderBy, filter *types.DocumentVersionFilter) int @@ -619,6 +621,7 @@ type ComplexityRoot struct { UpdatePeople func(childComplexity int, input types.UpdatePeopleInput) int UpdateRisk func(childComplexity int, input types.UpdateRiskInput) int UpdateTask func(childComplexity int, input types.UpdateTaskInput) int + UpdateTrustCenter func(childComplexity int, input types.UpdateTrustCenterInput) int UpdateVendor func(childComplexity int, input types.UpdateVendorInput) int UploadAuditReport func(childComplexity int, input types.UploadAuditReportInput) int UploadMeasureEvidence func(childComplexity int, input types.UploadMeasureEvidenceInput) int @@ -627,24 +630,25 @@ 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 - Connectors func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ConnectorOrder) int - Controls func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) int - CreatedAt func(childComplexity int) int - Data func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DatumOrderBy) int - Documents func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) int - Frameworks func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.FrameworkOrderBy) int - ID func(childComplexity int) int - LogoURL func(childComplexity int) int - Measures func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) int - Name func(childComplexity int) int - Peoples func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PeopleOrderBy) int - Risks func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RiskOrderBy, filter *types.RiskFilter) int - Tasks func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TaskOrderBy) int - UpdatedAt func(childComplexity int) int - Users func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.UserOrderBy) int - Vendors func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorOrderBy) int + 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 + Connectors func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ConnectorOrder) int + Controls func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) int + CreatedAt func(childComplexity int) int + Data func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DatumOrderBy) int + Documents func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) int + Frameworks func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.FrameworkOrderBy) int + ID func(childComplexity int) int + LogoURL func(childComplexity int) int + Measures func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) int + Name func(childComplexity int) int + Peoples func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PeopleOrderBy) int + Risks func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RiskOrderBy, filter *types.RiskFilter) int + Tasks func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TaskOrderBy) int + TrustCenter func(childComplexity int) int + UpdatedAt func(childComplexity int) int + Users func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.UserOrderBy) int + Vendors func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorOrderBy) int } OrganizationConnection struct { @@ -789,6 +793,14 @@ type ComplexityRoot struct { Node func(childComplexity int) int } + TrustCenter struct { + Active func(childComplexity int) int + CreatedAt func(childComplexity int) int + ID func(childComplexity int) int + Slug func(childComplexity int) int + UpdatedAt func(childComplexity int) int + } + UnassignTaskPayload struct { Task func(childComplexity int) int } @@ -841,6 +853,10 @@ type ComplexityRoot struct { Task func(childComplexity int) int } + UpdateTrustCenterPayload struct { + TrustCenter func(childComplexity int) int + } + UpdateVendorPayload struct { Vendor func(childComplexity int) int } @@ -899,6 +915,7 @@ type ComplexityRoot struct { SecurityOwner func(childComplexity int) int SecurityPageURL func(childComplexity int) int ServiceLevelAgreementURL func(childComplexity int) int + ShowOnTrustCenter func(childComplexity int) int StatusPageURL func(childComplexity int) int SubprocessorsListURL func(childComplexity int) int TermsOfServiceURL func(childComplexity int) int @@ -1058,6 +1075,7 @@ type MeasureConnectionResolver interface { type MutationResolver interface { CreateOrganization(ctx context.Context, input types.CreateOrganizationInput) (*types.CreateOrganizationPayload, error) UpdateOrganization(ctx context.Context, input types.UpdateOrganizationInput) (*types.UpdateOrganizationPayload, error) + UpdateTrustCenter(ctx context.Context, input types.UpdateTrustCenterInput) (*types.UpdateTrustCenterPayload, error) ConfirmEmail(ctx context.Context, input types.ConfirmEmailInput) (*types.ConfirmEmailPayload, error) InviteUser(ctx context.Context, input types.InviteUserInput) (*types.InviteUserPayload, error) RemoveUser(ctx context.Context, input types.RemoveUserInput) (*types.RemoveUserPayload, error) @@ -1144,6 +1162,7 @@ type OrganizationResolver interface { Assets(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AssetOrderBy) (*types.AssetConnection, error) Data(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DatumOrderBy) (*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) + TrustCenter(ctx context.Context, obj *types.Organization) (*types.TrustCenter, error) } type PeopleConnectionResolver interface { TotalCount(ctx context.Context, obj *types.PeopleConnection) (int, error) @@ -1393,6 +1412,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Audit.ReportURL(childComplexity), true + case "Audit.showOnTrustCenter": + if e.complexity.Audit.ShowOnTrustCenter == nil { + break + } + + return e.complexity.Audit.ShowOnTrustCenter(childComplexity), true + case "Audit.state": if e.complexity.Audit.State == nil { break @@ -2155,6 +2181,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Document.Owner(childComplexity), true + case "Document.showOnTrustCenter": + if e.complexity.Document.ShowOnTrustCenter == nil { + break + } + + return e.complexity.Document.ShowOnTrustCenter(childComplexity), true + case "Document.title": if e.complexity.Document.Title == nil { break @@ -3631,6 +3664,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Mutation.UpdateTask(childComplexity, args["input"].(types.UpdateTaskInput)), true + case "Mutation.updateTrustCenter": + if e.complexity.Mutation.UpdateTrustCenter == nil { + break + } + + args, err := ec.field_Mutation_updateTrustCenter_args(ctx, rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.UpdateTrustCenter(childComplexity, args["input"].(types.UpdateTrustCenterInput)), true + case "Mutation.updateVendor": if e.complexity.Mutation.UpdateVendor == nil { break @@ -3851,6 +3896,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Organization.Tasks(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.TaskOrderBy)), true + case "Organization.trustCenter": + if e.complexity.Organization.TrustCenter == nil { + break + } + + return e.complexity.Organization.TrustCenter(childComplexity), true + case "Organization.updatedAt": if e.complexity.Organization.UpdatedAt == nil { break @@ -4481,6 +4533,41 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.TaskEdge.Node(childComplexity), true + case "TrustCenter.active": + if e.complexity.TrustCenter.Active == nil { + break + } + + return e.complexity.TrustCenter.Active(childComplexity), true + + case "TrustCenter.createdAt": + if e.complexity.TrustCenter.CreatedAt == nil { + break + } + + return e.complexity.TrustCenter.CreatedAt(childComplexity), true + + case "TrustCenter.id": + if e.complexity.TrustCenter.ID == nil { + break + } + + return e.complexity.TrustCenter.ID(childComplexity), true + + case "TrustCenter.slug": + if e.complexity.TrustCenter.Slug == nil { + break + } + + return e.complexity.TrustCenter.Slug(childComplexity), true + + case "TrustCenter.updatedAt": + if e.complexity.TrustCenter.UpdatedAt == nil { + break + } + + return e.complexity.TrustCenter.UpdatedAt(childComplexity), true + case "UnassignTaskPayload.task": if e.complexity.UnassignTaskPayload.Task == nil { break @@ -4572,6 +4659,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.UpdateTaskPayload.Task(childComplexity), true + case "UpdateTrustCenterPayload.trustCenter": + if e.complexity.UpdateTrustCenterPayload.TrustCenter == nil { + break + } + + return e.complexity.UpdateTrustCenterPayload.TrustCenter(childComplexity), true + case "UpdateVendorPayload.vendor": if e.complexity.UpdateVendorPayload.Vendor == nil { break @@ -4818,6 +4912,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Vendor.ServiceLevelAgreementURL(childComplexity), true + case "Vendor.showOnTrustCenter": + if e.complexity.Vendor.ShowOnTrustCenter == nil { + break + } + + return e.complexity.Vendor.ShowOnTrustCenter(childComplexity), true + case "Vendor.statusPageUrl": if e.complexity.Vendor.StatusPageURL == nil { break @@ -5206,6 +5307,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputUpdatePeopleInput, ec.unmarshalInputUpdateRiskInput, ec.unmarshalInputUpdateTaskInput, + ec.unmarshalInputUpdateTrustCenterInput, ec.unmarshalInputUpdateVendorInput, ec.unmarshalInputUploadAuditReportInput, ec.unmarshalInputUploadMeasureEvidenceInput, @@ -6017,6 +6119,14 @@ input RiskFilter { } # Core Types +type TrustCenter implements Node { + id: ID! + active: Boolean! + slug: String! + createdAt: Datetime! + updatedAt: Datetime! +} + type Organization implements Node { id: ID! name: String! @@ -6130,6 +6240,8 @@ type Organization implements Node { orderBy: AuditOrder ): AuditConnection! @goField(forceResolver: true) + trustCenter: TrustCenter @goField(forceResolver: true) + createdAt: Datetime! updatedAt: Datetime! } @@ -6205,6 +6317,7 @@ type Vendor implements Node { headquarterAddress: String legalName: String websiteUrl: String + showOnTrustCenter: Boolean! createdAt: Datetime! updatedAt: Datetime! } @@ -6366,6 +6479,7 @@ type Document implements Node { description: String! documentType: DocumentType! currentPublishedVersion: Int + showOnTrustCenter: Boolean! owner: People! @goField(forceResolver: true) organization: Organization! @goField(forceResolver: true) @@ -6448,6 +6562,7 @@ type Audit implements Node { report: Report @goField(forceResolver: true) reportUrl: String @goField(forceResolver: true) state: AuditState! + showOnTrustCenter: Boolean! createdAt: Datetime! updatedAt: Datetime! } @@ -6711,6 +6826,10 @@ type Mutation { input: UpdateOrganizationInput! ): UpdateOrganizationPayload! + updateTrustCenter( + input: UpdateTrustCenterInput! + ): UpdateTrustCenterPayload! + # User mutations confirmEmail(input: ConfirmEmailInput!): ConfirmEmailPayload! inviteUser(input: InviteUserInput!): InviteUserPayload! @@ -6877,6 +6996,12 @@ input UpdateOrganizationInput { logo: Upload } +input UpdateTrustCenterInput { + trustCenterId: ID! + active: Boolean + slug: String +} + input CreateVendorInput { organizationId: ID! name: String! @@ -6919,6 +7044,7 @@ input UpdateVendorInput { trustPageUrl: String businessOwnerId: ID securityOwnerId: ID + showOnTrustCenter: Boolean } input DeleteVendorInput { @@ -7150,6 +7276,7 @@ input UpdateDocumentInput { ownerId: ID createdBy: ID documentType: DocumentType + showOnTrustCenter: Boolean } input ExportDocumentVersionPDFInput { @@ -7211,6 +7338,7 @@ input UpdateAuditInput { validFrom: Datetime validUntil: Datetime state: AuditState + showOnTrustCenter: Boolean } input DeleteAuditInput { @@ -7235,6 +7363,10 @@ type UpdateOrganizationPayload { organization: Organization! } +type UpdateTrustCenterPayload { + trustCenter: TrustCenter! +} + type CreateControlPayload { controlEdge: ControlEdge! } @@ -10637,6 +10769,29 @@ func (ec *executionContext) field_Mutation_updateTask_argsInput( return zeroVal, nil } +func (ec *executionContext) field_Mutation_updateTrustCenter_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_updateTrustCenter_argsInput(ctx, rawArgs) + if err != nil { + return nil, err + } + args["input"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_updateTrustCenter_argsInput( + ctx context.Context, + rawArgs map[string]any, +) (types.UpdateTrustCenterInput, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNUpdateTrustCenterInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateTrustCenterInput(ctx, tmp) + } + + var zeroVal types.UpdateTrustCenterInput + return zeroVal, nil +} + func (ec *executionContext) field_Mutation_updateVendor_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -13030,6 +13185,8 @@ func (ec *executionContext) fieldContext_AssessVendorPayload_vendor(_ context.Co return ec.fieldContext_Vendor_legalName(ctx, field) case "websiteUrl": return ec.fieldContext_Vendor_websiteUrl(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Vendor_showOnTrustCenter(ctx, field) case "createdAt": return ec.fieldContext_Vendor_createdAt(ctx, field) case "updatedAt": @@ -13505,6 +13662,8 @@ func (ec *executionContext) fieldContext_Asset_organization(_ context.Context, f return ec.fieldContext_Organization_data(ctx, field) case "audits": return ec.fieldContext_Organization_audits(ctx, field) + case "trustCenter": + return ec.fieldContext_Organization_trustCenter(ctx, field) case "createdAt": return ec.fieldContext_Organization_createdAt(ctx, field) case "updatedAt": @@ -14049,6 +14208,8 @@ func (ec *executionContext) fieldContext_Audit_organization(_ context.Context, f return ec.fieldContext_Organization_data(ctx, field) case "audits": return ec.fieldContext_Organization_audits(ctx, field) + case "trustCenter": + return ec.fieldContext_Organization_trustCenter(ctx, field) case "createdAt": return ec.fieldContext_Organization_createdAt(ctx, field) case "updatedAt": @@ -14346,6 +14507,50 @@ func (ec *executionContext) fieldContext_Audit_state(_ context.Context, field gr return fc, nil } +func (ec *executionContext) _Audit_showOnTrustCenter(ctx context.Context, field graphql.CollectedField, obj *types.Audit) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Audit_showOnTrustCenter(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.ShowOnTrustCenter, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Audit_showOnTrustCenter(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Audit", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Audit_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.Audit) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Audit_createdAt(ctx, field) if err != nil { @@ -14681,6 +14886,8 @@ func (ec *executionContext) fieldContext_AuditEdge_node(_ context.Context, field return ec.fieldContext_Audit_reportUrl(ctx, field) case "state": return ec.fieldContext_Audit_state(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Audit_showOnTrustCenter(ctx, field) case "createdAt": return ec.fieldContext_Audit_createdAt(ctx, field) case "updatedAt": @@ -17681,6 +17888,8 @@ func (ec *executionContext) fieldContext_Datum_organization(_ context.Context, f return ec.fieldContext_Organization_data(ctx, field) case "audits": return ec.fieldContext_Organization_audits(ctx, field) + case "trustCenter": + return ec.fieldContext_Organization_trustCenter(ctx, field) case "createdAt": return ec.fieldContext_Organization_createdAt(ctx, field) case "updatedAt": @@ -18177,6 +18386,8 @@ func (ec *executionContext) fieldContext_DeleteAuditReportPayload_audit(_ contex return ec.fieldContext_Audit_reportUrl(ctx, field) case "state": return ec.fieldContext_Audit_state(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Audit_showOnTrustCenter(ctx, field) case "createdAt": return ec.fieldContext_Audit_createdAt(ctx, field) case "updatedAt": @@ -19241,6 +19452,50 @@ func (ec *executionContext) fieldContext_Document_currentPublishedVersion(_ cont return fc, nil } +func (ec *executionContext) _Document_showOnTrustCenter(ctx context.Context, field graphql.CollectedField, obj *types.Document) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Document_showOnTrustCenter(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.ShowOnTrustCenter, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Document_showOnTrustCenter(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Document", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Document_owner(ctx context.Context, field graphql.CollectedField, obj *types.Document) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Document_owner(ctx, field) if err != nil { @@ -19378,6 +19633,8 @@ func (ec *executionContext) fieldContext_Document_organization(_ context.Context return ec.fieldContext_Organization_data(ctx, field) case "audits": return ec.fieldContext_Organization_audits(ctx, field) + case "trustCenter": + return ec.fieldContext_Organization_trustCenter(ctx, field) case "createdAt": return ec.fieldContext_Organization_createdAt(ctx, field) case "updatedAt": @@ -19842,6 +20099,8 @@ func (ec *executionContext) fieldContext_DocumentEdge_node(_ context.Context, fi return ec.fieldContext_Document_documentType(ctx, field) case "currentPublishedVersion": return ec.fieldContext_Document_currentPublishedVersion(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Document_showOnTrustCenter(ctx, field) case "owner": return ec.fieldContext_Document_owner(ctx, field) case "organization": @@ -19954,6 +20213,8 @@ func (ec *executionContext) fieldContext_DocumentVersion_document(_ context.Cont return ec.fieldContext_Document_documentType(ctx, field) case "currentPublishedVersion": return ec.fieldContext_Document_currentPublishedVersion(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Document_showOnTrustCenter(ctx, field) case "owner": return ec.fieldContext_Document_owner(ctx, field) case "organization": @@ -22533,6 +22794,8 @@ func (ec *executionContext) fieldContext_Framework_organization(_ context.Contex return ec.fieldContext_Organization_data(ctx, field) case "audits": return ec.fieldContext_Organization_audits(ctx, field) + case "trustCenter": + return ec.fieldContext_Organization_trustCenter(ctx, field) case "createdAt": return ec.fieldContext_Organization_createdAt(ctx, field) case "updatedAt": @@ -24167,6 +24430,65 @@ func (ec *executionContext) fieldContext_Mutation_updateOrganization(ctx context return fc, nil } +func (ec *executionContext) _Mutation_updateTrustCenter(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_updateTrustCenter(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 ec.resolvers.Mutation().UpdateTrustCenter(rctx, fc.Args["input"].(types.UpdateTrustCenterInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*types.UpdateTrustCenterPayload) + fc.Result = res + return ec.marshalNUpdateTrustCenterPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateTrustCenterPayload(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_updateTrustCenter(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "trustCenter": + return ec.fieldContext_UpdateTrustCenterPayload_trustCenter(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type UpdateTrustCenterPayload", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_updateTrustCenter_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Mutation_confirmEmail(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Mutation_confirmEmail(ctx, field) if err != nil { @@ -29263,6 +29585,59 @@ func (ec *executionContext) fieldContext_Organization_audits(ctx context.Context return fc, nil } +func (ec *executionContext) _Organization_trustCenter(ctx context.Context, field graphql.CollectedField, obj *types.Organization) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Organization_trustCenter(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 ec.resolvers.Organization().TrustCenter(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*types.TrustCenter) + fc.Result = res + return ec.marshalOTrustCenter2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐTrustCenter(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Organization_trustCenter(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Organization", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_TrustCenter_id(ctx, field) + case "active": + return ec.fieldContext_TrustCenter_active(ctx, field) + case "slug": + return ec.fieldContext_TrustCenter_slug(ctx, field) + case "createdAt": + return ec.fieldContext_TrustCenter_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_TrustCenter_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type TrustCenter", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Organization_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.Organization) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Organization_createdAt(ctx, field) if err != nil { @@ -29570,6 +29945,8 @@ func (ec *executionContext) fieldContext_OrganizationEdge_node(_ context.Context return ec.fieldContext_Organization_data(ctx, field) case "audits": return ec.fieldContext_Organization_audits(ctx, field) + case "trustCenter": + return ec.fieldContext_Organization_trustCenter(ctx, field) case "createdAt": return ec.fieldContext_Organization_createdAt(ctx, field) case "updatedAt": @@ -30561,6 +30938,8 @@ func (ec *executionContext) fieldContext_PublishDocumentVersionPayload_document( return ec.fieldContext_Document_documentType(ctx, field) case "currentPublishedVersion": return ec.fieldContext_Document_currentPublishedVersion(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Document_showOnTrustCenter(ctx, field) case "owner": return ec.fieldContext_Document_owner(ctx, field) case "organization": @@ -31973,6 +32352,8 @@ func (ec *executionContext) fieldContext_Risk_organization(_ context.Context, fi return ec.fieldContext_Organization_data(ctx, field) case "audits": return ec.fieldContext_Organization_audits(ctx, field) + case "trustCenter": + return ec.fieldContext_Organization_trustCenter(ctx, field) case "createdAt": return ec.fieldContext_Organization_createdAt(ctx, field) case "updatedAt": @@ -33061,6 +33442,8 @@ func (ec *executionContext) fieldContext_Task_organization(_ context.Context, fi return ec.fieldContext_Organization_data(ctx, field) case "audits": return ec.fieldContext_Organization_audits(ctx, field) + case "trustCenter": + return ec.fieldContext_Organization_trustCenter(ctx, field) case "createdAt": return ec.fieldContext_Organization_createdAt(ctx, field) case "updatedAt": @@ -33550,6 +33933,226 @@ func (ec *executionContext) fieldContext_TaskEdge_node(_ context.Context, field return fc, nil } +func (ec *executionContext) _TrustCenter_id(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenter) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_TrustCenter_id(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.ID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(gid.GID) + fc.Result = res + return ec.marshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_TrustCenter_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "TrustCenter", + 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) _TrustCenter_active(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenter) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_TrustCenter_active(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.Active, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_TrustCenter_active(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "TrustCenter", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _TrustCenter_slug(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenter) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_TrustCenter_slug(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.Slug, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_TrustCenter_slug(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "TrustCenter", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _TrustCenter_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenter) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_TrustCenter_createdAt(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.CreatedAt, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNDatetime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_TrustCenter_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "TrustCenter", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Datetime does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _TrustCenter_updatedAt(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenter) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_TrustCenter_updatedAt(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.UpdatedAt, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNDatetime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_TrustCenter_updatedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "TrustCenter", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Datetime does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _UnassignTaskPayload_task(ctx context.Context, field graphql.CollectedField, obj *types.UnassignTaskPayload) (ret graphql.Marshaler) { fc, err := ec.fieldContext_UnassignTaskPayload_task(ctx, field) if err != nil { @@ -33743,6 +34346,8 @@ func (ec *executionContext) fieldContext_UpdateAuditPayload_audit(_ context.Cont return ec.fieldContext_Audit_reportUrl(ctx, field) case "state": return ec.fieldContext_Audit_state(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Audit_showOnTrustCenter(ctx, field) case "createdAt": return ec.fieldContext_Audit_createdAt(ctx, field) case "updatedAt": @@ -33933,6 +34538,8 @@ func (ec *executionContext) fieldContext_UpdateDocumentPayload_document(_ contex return ec.fieldContext_Document_documentType(ctx, field) case "currentPublishedVersion": return ec.fieldContext_Document_currentPublishedVersion(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Document_showOnTrustCenter(ctx, field) case "owner": return ec.fieldContext_Document_owner(ctx, field) case "organization": @@ -34223,6 +34830,8 @@ func (ec *executionContext) fieldContext_UpdateOrganizationPayload_organization( return ec.fieldContext_Organization_data(ctx, field) case "audits": return ec.fieldContext_Organization_audits(ctx, field) + case "trustCenter": + return ec.fieldContext_Organization_trustCenter(ctx, field) case "createdAt": return ec.fieldContext_Organization_createdAt(ctx, field) case "updatedAt": @@ -34454,6 +35063,62 @@ func (ec *executionContext) fieldContext_UpdateTaskPayload_task(_ context.Contex return fc, nil } +func (ec *executionContext) _UpdateTrustCenterPayload_trustCenter(ctx context.Context, field graphql.CollectedField, obj *types.UpdateTrustCenterPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_UpdateTrustCenterPayload_trustCenter(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.TrustCenter, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*types.TrustCenter) + fc.Result = res + return ec.marshalNTrustCenter2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐTrustCenter(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_UpdateTrustCenterPayload_trustCenter(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "UpdateTrustCenterPayload", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_TrustCenter_id(ctx, field) + case "active": + return ec.fieldContext_TrustCenter_active(ctx, field) + case "slug": + return ec.fieldContext_TrustCenter_slug(ctx, field) + case "createdAt": + return ec.fieldContext_TrustCenter_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_TrustCenter_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type TrustCenter", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _UpdateVendorPayload_vendor(ctx context.Context, field graphql.CollectedField, obj *types.UpdateVendorPayload) (ret graphql.Marshaler) { fc, err := ec.fieldContext_UpdateVendorPayload_vendor(ctx, field) if err != nil { @@ -34537,6 +35202,8 @@ func (ec *executionContext) fieldContext_UpdateVendorPayload_vendor(_ context.Co return ec.fieldContext_Vendor_legalName(ctx, field) case "websiteUrl": return ec.fieldContext_Vendor_websiteUrl(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Vendor_showOnTrustCenter(ctx, field) case "createdAt": return ec.fieldContext_Vendor_createdAt(ctx, field) case "updatedAt": @@ -34603,6 +35270,8 @@ func (ec *executionContext) fieldContext_UploadAuditReportPayload_audit(_ contex return ec.fieldContext_Audit_reportUrl(ctx, field) case "state": return ec.fieldContext_Audit_state(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Audit_showOnTrustCenter(ctx, field) case "createdAt": return ec.fieldContext_Audit_createdAt(ctx, field) case "updatedAt": @@ -35508,6 +36177,8 @@ func (ec *executionContext) fieldContext_Vendor_organization(_ context.Context, return ec.fieldContext_Organization_data(ctx, field) case "audits": return ec.fieldContext_Organization_audits(ctx, field) + case "trustCenter": + return ec.fieldContext_Organization_trustCenter(ctx, field) case "createdAt": return ec.fieldContext_Organization_createdAt(ctx, field) case "updatedAt": @@ -36303,6 +36974,50 @@ func (ec *executionContext) fieldContext_Vendor_websiteUrl(_ context.Context, fi return fc, nil } +func (ec *executionContext) _Vendor_showOnTrustCenter(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Vendor_showOnTrustCenter(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.ShowOnTrustCenter, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Vendor_showOnTrustCenter(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Vendor", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Vendor_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Vendor_createdAt(ctx, field) if err != nil { @@ -36518,6 +37233,8 @@ func (ec *executionContext) fieldContext_VendorComplianceReport_vendor(_ context return ec.fieldContext_Vendor_legalName(ctx, field) case "websiteUrl": return ec.fieldContext_Vendor_websiteUrl(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Vendor_showOnTrustCenter(ctx, field) case "createdAt": return ec.fieldContext_Vendor_createdAt(ctx, field) case "updatedAt": @@ -37321,6 +38038,8 @@ func (ec *executionContext) fieldContext_VendorEdge_node(_ context.Context, fiel return ec.fieldContext_Vendor_legalName(ctx, field) case "websiteUrl": return ec.fieldContext_Vendor_websiteUrl(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Vendor_showOnTrustCenter(ctx, field) case "createdAt": return ec.fieldContext_Vendor_createdAt(ctx, field) case "updatedAt": @@ -37459,6 +38178,8 @@ func (ec *executionContext) fieldContext_VendorRiskAssessment_vendor(_ context.C return ec.fieldContext_Vendor_legalName(ctx, field) case "websiteUrl": return ec.fieldContext_Vendor_websiteUrl(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Vendor_showOnTrustCenter(ctx, field) case "createdAt": return ec.fieldContext_Vendor_createdAt(ctx, field) case "updatedAt": @@ -43148,7 +43869,7 @@ func (ec *executionContext) unmarshalInputUpdateAuditInput(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"id", "validFrom", "validUntil", "state"} + fieldsInOrder := [...]string{"id", "validFrom", "validUntil", "state", "showOnTrustCenter"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -43183,6 +43904,13 @@ func (ec *executionContext) unmarshalInputUpdateAuditInput(ctx context.Context, return it, err } it.State = data + case "showOnTrustCenter": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("showOnTrustCenter")) + data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) + if err != nil { + return it, err + } + it.ShowOnTrustCenter = data } } @@ -43313,7 +44041,7 @@ func (ec *executionContext) unmarshalInputUpdateDocumentInput(ctx context.Contex asMap[k] = v } - fieldsInOrder := [...]string{"id", "title", "content", "ownerId", "createdBy", "documentType"} + fieldsInOrder := [...]string{"id", "title", "content", "ownerId", "createdBy", "documentType", "showOnTrustCenter"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -43362,6 +44090,13 @@ func (ec *executionContext) unmarshalInputUpdateDocumentInput(ctx context.Contex return it, err } it.DocumentType = data + case "showOnTrustCenter": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("showOnTrustCenter")) + data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) + if err != nil { + return it, err + } + it.ShowOnTrustCenter = data } } @@ -43774,6 +44509,47 @@ func (ec *executionContext) unmarshalInputUpdateTaskInput(ctx context.Context, o return it, nil } +func (ec *executionContext) unmarshalInputUpdateTrustCenterInput(ctx context.Context, obj any) (types.UpdateTrustCenterInput, error) { + var it types.UpdateTrustCenterInput + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"trustCenterId", "active", "slug"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "trustCenterId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("trustCenterId")) + data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v) + if err != nil { + return it, err + } + it.TrustCenterID = data + case "active": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("active")) + data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) + if err != nil { + return it, err + } + it.Active = data + case "slug": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("slug")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.Slug = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputUpdateVendorInput(ctx context.Context, obj any) (types.UpdateVendorInput, error) { var it types.UpdateVendorInput asMap := map[string]any{} @@ -43781,7 +44557,7 @@ func (ec *executionContext) unmarshalInputUpdateVendorInput(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"id", "name", "description", "statusPageUrl", "termsOfServiceUrl", "privacyPolicyUrl", "serviceLevelAgreementUrl", "dataProcessingAgreementUrl", "businessAssociateAgreementUrl", "subprocessorsListUrl", "websiteUrl", "legalName", "headquarterAddress", "category", "certifications", "securityPageUrl", "trustPageUrl", "businessOwnerId", "securityOwnerId"} + fieldsInOrder := [...]string{"id", "name", "description", "statusPageUrl", "termsOfServiceUrl", "privacyPolicyUrl", "serviceLevelAgreementUrl", "dataProcessingAgreementUrl", "businessAssociateAgreementUrl", "subprocessorsListUrl", "websiteUrl", "legalName", "headquarterAddress", "category", "certifications", "securityPageUrl", "trustPageUrl", "businessOwnerId", "securityOwnerId", "showOnTrustCenter"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -43921,6 +44697,13 @@ func (ec *executionContext) unmarshalInputUpdateVendorInput(ctx context.Context, return it, err } it.SecurityOwnerID = data + case "showOnTrustCenter": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("showOnTrustCenter")) + data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) + if err != nil { + return it, err + } + it.ShowOnTrustCenter = data } } @@ -44256,6 +45039,13 @@ func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj return graphql.Null } return ec._User(ctx, sel, obj) + case types.TrustCenter: + return ec._TrustCenter(ctx, sel, &obj) + case *types.TrustCenter: + if obj == nil { + return graphql.Null + } + return ec._TrustCenter(ctx, sel, obj) case types.Task: return ec._Task(ctx, sel, &obj) case *types.Task: @@ -44955,6 +45745,11 @@ func (ec *executionContext) _Audit(ctx context.Context, sel ast.SelectionSet, ob if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } + case "showOnTrustCenter": + out.Values[i] = ec._Audit_showOnTrustCenter(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } case "createdAt": out.Values[i] = ec._Audit_createdAt(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -47535,6 +48330,11 @@ func (ec *executionContext) _Document(ctx context.Context, sel ast.SelectionSet, } case "currentPublishedVersion": out.Values[i] = ec._Document_currentPublishedVersion(ctx, field, obj) + case "showOnTrustCenter": + out.Values[i] = ec._Document_showOnTrustCenter(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } case "owner": field := field @@ -49603,6 +50403,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } + case "updateTrustCenter": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_updateTrustCenter(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "confirmEmail": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_confirmEmail(ctx, field) @@ -50637,6 +51444,39 @@ func (ec *executionContext) _Organization(ctx context.Context, sel ast.Selection continue } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + case "trustCenter": + field := field + + innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Organization_trustCenter(ctx, field, obj) + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "createdAt": out.Values[i] = ec._Organization_createdAt(ctx, field, obj) @@ -52181,6 +53021,65 @@ func (ec *executionContext) _TaskEdge(ctx context.Context, sel ast.SelectionSet, return out } +var trustCenterImplementors = []string{"TrustCenter", "Node"} + +func (ec *executionContext) _TrustCenter(ctx context.Context, sel ast.SelectionSet, obj *types.TrustCenter) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, trustCenterImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("TrustCenter") + case "id": + out.Values[i] = ec._TrustCenter_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "active": + out.Values[i] = ec._TrustCenter_active(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "slug": + out.Values[i] = ec._TrustCenter_slug(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "createdAt": + out.Values[i] = ec._TrustCenter_createdAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "updatedAt": + out.Values[i] = ec._TrustCenter_updatedAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var unassignTaskPayloadImplementors = []string{"UnassignTaskPayload"} func (ec *executionContext) _UnassignTaskPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UnassignTaskPayload) graphql.Marshaler { @@ -52688,6 +53587,45 @@ func (ec *executionContext) _UpdateTaskPayload(ctx context.Context, sel ast.Sele return out } +var updateTrustCenterPayloadImplementors = []string{"UpdateTrustCenterPayload"} + +func (ec *executionContext) _UpdateTrustCenterPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UpdateTrustCenterPayload) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, updateTrustCenterPayloadImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("UpdateTrustCenterPayload") + case "trustCenter": + out.Values[i] = ec._UpdateTrustCenterPayload_trustCenter(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var updateVendorPayloadImplementors = []string{"UpdateVendorPayload"} func (ec *executionContext) _UpdateVendorPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UpdateVendorPayload) graphql.Marshaler { @@ -53294,6 +54232,11 @@ func (ec *executionContext) _Vendor(ctx context.Context, sel ast.SelectionSet, o out.Values[i] = ec._Vendor_legalName(ctx, field, obj) case "websiteUrl": out.Values[i] = ec._Vendor_websiteUrl(ctx, field, obj) + case "showOnTrustCenter": + out.Values[i] = ec._Vendor_showOnTrustCenter(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } case "createdAt": out.Values[i] = ec._Vendor_createdAt(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -57651,6 +58594,16 @@ var ( } ) +func (ec *executionContext) marshalNTrustCenter2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐTrustCenter(ctx context.Context, sel ast.SelectionSet, v *types.TrustCenter) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._TrustCenter(ctx, sel, v) +} + func (ec *executionContext) unmarshalNUnassignTaskInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUnassignTaskInput(ctx context.Context, v any) (types.UnassignTaskInput, error) { res, err := ec.unmarshalInputUnassignTaskInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -57898,6 +58851,25 @@ func (ec *executionContext) marshalNUpdateTaskPayload2ᚖgithubᚗcomᚋgetprobo return ec._UpdateTaskPayload(ctx, sel, v) } +func (ec *executionContext) unmarshalNUpdateTrustCenterInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateTrustCenterInput(ctx context.Context, v any) (types.UpdateTrustCenterInput, error) { + res, err := ec.unmarshalInputUpdateTrustCenterInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNUpdateTrustCenterPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateTrustCenterPayload(ctx context.Context, sel ast.SelectionSet, v types.UpdateTrustCenterPayload) graphql.Marshaler { + return ec._UpdateTrustCenterPayload(ctx, sel, &v) +} + +func (ec *executionContext) marshalNUpdateTrustCenterPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateTrustCenterPayload(ctx context.Context, sel ast.SelectionSet, v *types.UpdateTrustCenterPayload) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._UpdateTrustCenterPayload(ctx, sel, v) +} + func (ec *executionContext) unmarshalNUpdateVendorInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateVendorInput(ctx context.Context, v any) (types.UpdateVendorInput, error) { res, err := ec.unmarshalInputUpdateVendorInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -59526,6 +60498,13 @@ var ( } ) +func (ec *executionContext) marshalOTrustCenter2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐTrustCenter(ctx context.Context, sel ast.SelectionSet, v *types.TrustCenter) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._TrustCenter(ctx, sel, v) +} + func (ec *executionContext) unmarshalOUpload2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx context.Context, v any) (*graphql.Upload, error) { if v == nil { return nil, nil diff --git a/pkg/server/api/console/v1/types/audit.go b/pkg/server/api/console/v1/types/audit.go index 44591295e..8e77e051e 100644 --- a/pkg/server/api/console/v1/types/audit.go +++ b/pkg/server/api/console/v1/types/audit.go @@ -54,12 +54,13 @@ func NewAuditConnection( func NewAudit(a *coredata.Audit) *Audit { return &Audit{ - ID: a.ID, - ValidFrom: a.ValidFrom, - ValidUntil: a.ValidUntil, - State: a.State, - CreatedAt: a.CreatedAt, - UpdatedAt: a.UpdatedAt, + ID: a.ID, + ValidFrom: a.ValidFrom, + ValidUntil: a.ValidUntil, + State: a.State, + ShowOnTrustCenter: a.ShowOnTrustCenter, + CreatedAt: a.CreatedAt, + UpdatedAt: a.UpdatedAt, } } diff --git a/pkg/server/api/console/v1/types/document.go b/pkg/server/api/console/v1/types/document.go index dc4d0433a..36f226247 100644 --- a/pkg/server/api/console/v1/types/document.go +++ b/pkg/server/api/console/v1/types/document.go @@ -79,6 +79,7 @@ func NewDocument(document *coredata.Document) *Document { Title: document.Title, DocumentType: document.DocumentType, CurrentPublishedVersion: document.CurrentPublishedVersion, + ShowOnTrustCenter: document.ShowOnTrustCenter, CreatedAt: document.CreatedAt, UpdatedAt: document.UpdatedAt, } diff --git a/pkg/server/api/console/v1/types/trust_center.go b/pkg/server/api/console/v1/types/trust_center.go new file mode 100644 index 000000000..4d609e700 --- /dev/null +++ b/pkg/server/api/console/v1/types/trust_center.go @@ -0,0 +1,29 @@ +// 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 types + +import ( + "github.com/getprobo/probo/pkg/coredata" +) + +func NewTrustCenter(tc *coredata.TrustCenter) *TrustCenter { + return &TrustCenter{ + ID: tc.ID, + Active: tc.Active, + Slug: tc.Slug, + CreatedAt: tc.CreatedAt, + UpdatedAt: tc.UpdatedAt, + } +} diff --git a/pkg/server/api/console/v1/types/types.go b/pkg/server/api/console/v1/types/types.go index 82be470ba..b4ef06d7a 100644 --- a/pkg/server/api/console/v1/types/types.go +++ b/pkg/server/api/console/v1/types/types.go @@ -57,16 +57,17 @@ type AssignTaskPayload struct { } type Audit struct { - ID gid.GID `json:"id"` - Organization *Organization `json:"organization"` - Framework *Framework `json:"framework"` - ValidFrom *time.Time `json:"validFrom,omitempty"` - ValidUntil *time.Time `json:"validUntil,omitempty"` - Report *Report `json:"report,omitempty"` - ReportURL *string `json:"reportUrl,omitempty"` - State coredata.AuditState `json:"state"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` + ID gid.GID `json:"id"` + Organization *Organization `json:"organization"` + Framework *Framework `json:"framework"` + ValidFrom *time.Time `json:"validFrom,omitempty"` + ValidUntil *time.Time `json:"validUntil,omitempty"` + Report *Report `json:"report,omitempty"` + ReportURL *string `json:"reportUrl,omitempty"` + State coredata.AuditState `json:"state"` + ShowOnTrustCenter bool `json:"showOnTrustCenter"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` } func (Audit) IsNode() {} @@ -582,6 +583,7 @@ type Document struct { Description string `json:"description"` DocumentType coredata.DocumentType `json:"documentType"` CurrentPublishedVersion *int `json:"currentPublishedVersion,omitempty"` + ShowOnTrustCenter bool `json:"showOnTrustCenter"` Owner *People `json:"owner"` Organization *Organization `json:"organization"` Versions *DocumentVersionConnection `json:"versions"` @@ -800,24 +802,25 @@ type Mutation struct { } type Organization struct { - ID gid.GID `json:"id"` - Name string `json:"name"` - LogoURL *string `json:"logoUrl,omitempty"` - Users *UserConnection `json:"users"` - Connectors *ConnectorConnection `json:"connectors"` - Frameworks *FrameworkConnection `json:"frameworks"` - Controls *ControlConnection `json:"controls"` - Vendors *VendorConnection `json:"vendors"` - Peoples *PeopleConnection `json:"peoples"` - Documents *DocumentConnection `json:"documents"` - Measures *MeasureConnection `json:"measures"` - Risks *RiskConnection `json:"risks"` - Tasks *TaskConnection `json:"tasks"` - Assets *AssetConnection `json:"assets"` - Data *DatumConnection `json:"data"` - Audits *AuditConnection `json:"audits"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` + ID gid.GID `json:"id"` + Name string `json:"name"` + LogoURL *string `json:"logoUrl,omitempty"` + Users *UserConnection `json:"users"` + Connectors *ConnectorConnection `json:"connectors"` + Frameworks *FrameworkConnection `json:"frameworks"` + Controls *ControlConnection `json:"controls"` + Vendors *VendorConnection `json:"vendors"` + Peoples *PeopleConnection `json:"peoples"` + Documents *DocumentConnection `json:"documents"` + Measures *MeasureConnection `json:"measures"` + Risks *RiskConnection `json:"risks"` + Tasks *TaskConnection `json:"tasks"` + Assets *AssetConnection `json:"assets"` + Data *DatumConnection `json:"data"` + Audits *AuditConnection `json:"audits"` + TrustCenter *TrustCenter `json:"trustCenter,omitempty"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` } func (Organization) IsNode() {} @@ -992,6 +995,17 @@ type TaskEdge struct { Node *Task `json:"node"` } +type TrustCenter struct { + ID gid.GID `json:"id"` + Active bool `json:"active"` + Slug string `json:"slug"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} + +func (TrustCenter) IsNode() {} +func (this TrustCenter) GetID() gid.GID { return this.ID } + type UnassignTaskInput struct { TaskID gid.GID `json:"taskId"` } @@ -1016,10 +1030,11 @@ type UpdateAssetPayload struct { } type UpdateAuditInput struct { - ID gid.GID `json:"id"` - ValidFrom *time.Time `json:"validFrom,omitempty"` - ValidUntil *time.Time `json:"validUntil,omitempty"` - State *coredata.AuditState `json:"state,omitempty"` + ID gid.GID `json:"id"` + ValidFrom *time.Time `json:"validFrom,omitempty"` + ValidUntil *time.Time `json:"validUntil,omitempty"` + State *coredata.AuditState `json:"state,omitempty"` + ShowOnTrustCenter *bool `json:"showOnTrustCenter,omitempty"` } type UpdateAuditPayload struct { @@ -1052,12 +1067,13 @@ type UpdateDatumPayload struct { } type UpdateDocumentInput struct { - ID gid.GID `json:"id"` - Title *string `json:"title,omitempty"` - Content *string `json:"content,omitempty"` - OwnerID *gid.GID `json:"ownerId,omitempty"` - CreatedBy *gid.GID `json:"createdBy,omitempty"` - DocumentType *coredata.DocumentType `json:"documentType,omitempty"` + ID gid.GID `json:"id"` + Title *string `json:"title,omitempty"` + Content *string `json:"content,omitempty"` + OwnerID *gid.GID `json:"ownerId,omitempty"` + CreatedBy *gid.GID `json:"createdBy,omitempty"` + DocumentType *coredata.DocumentType `json:"documentType,omitempty"` + ShowOnTrustCenter *bool `json:"showOnTrustCenter,omitempty"` } type UpdateDocumentPayload struct { @@ -1151,6 +1167,16 @@ type UpdateTaskPayload struct { Task *Task `json:"task"` } +type UpdateTrustCenterInput struct { + TrustCenterID gid.GID `json:"trustCenterId"` + Active *bool `json:"active,omitempty"` + Slug *string `json:"slug,omitempty"` +} + +type UpdateTrustCenterPayload struct { + TrustCenter *TrustCenter `json:"trustCenter"` +} + type UpdateVendorInput struct { ID gid.GID `json:"id"` Name *string `json:"name,omitempty"` @@ -1171,6 +1197,7 @@ type UpdateVendorInput struct { TrustPageURL *string `json:"trustPageUrl,omitempty"` BusinessOwnerID *gid.GID `json:"businessOwnerId,omitempty"` SecurityOwnerID *gid.GID `json:"securityOwnerId,omitempty"` + ShowOnTrustCenter *bool `json:"showOnTrustCenter,omitempty"` } type UpdateVendorPayload struct { @@ -1261,6 +1288,7 @@ type Vendor struct { HeadquarterAddress *string `json:"headquarterAddress,omitempty"` LegalName *string `json:"legalName,omitempty"` WebsiteURL *string `json:"websiteUrl,omitempty"` + ShowOnTrustCenter bool `json:"showOnTrustCenter"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` } diff --git a/pkg/server/api/console/v1/types/vendor.go b/pkg/server/api/console/v1/types/vendor.go index 70ebbe47e..de1ca6c8e 100644 --- a/pkg/server/api/console/v1/types/vendor.go +++ b/pkg/server/api/console/v1/types/vendor.go @@ -79,6 +79,7 @@ func NewVendor(v *coredata.Vendor) *Vendor { LegalName: v.LegalName, WebsiteURL: v.WebsiteURL, Category: v.Category, + ShowOnTrustCenter: v.ShowOnTrustCenter, UpdatedAt: v.UpdatedAt, CreatedAt: v.CreatedAt, } diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go index ee3fb0d9e..0f2eea48c 100644 --- a/pkg/server/api/console/v1/v1_resolver.go +++ b/pkg/server/api/console/v1/v1_resolver.go @@ -980,6 +980,24 @@ func (r *mutationResolver) UpdateOrganization(ctx context.Context, input types.U }, nil } +// UpdateTrustCenter is the resolver for the updateTrustCenter field. +func (r *mutationResolver) UpdateTrustCenter(ctx context.Context, input types.UpdateTrustCenterInput) (*types.UpdateTrustCenterPayload, error) { + prb := r.ProboService(ctx, input.TrustCenterID.TenantID()) + + trustCenter, err := prb.TrustCenters.Update(ctx, &probo.UpdateTrustCenterRequest{ + ID: input.TrustCenterID, + Active: input.Active, + Slug: input.Slug, + }) + if err != nil { + return nil, fmt.Errorf("cannot update trust center: %w", err) + } + + return &types.UpdateTrustCenterPayload{ + TrustCenter: types.NewTrustCenter(trustCenter), + }, nil +} + // ConfirmEmail is the resolver for the confirmEmail field. func (r *mutationResolver) ConfirmEmail(ctx context.Context, input types.ConfirmEmailInput) (*types.ConfirmEmailPayload, error) { err := r.usrmgrSvc.ConfirmEmail(ctx, input.Token) @@ -1158,6 +1176,7 @@ func (r *mutationResolver) UpdateVendor(ctx context.Context, input types.UpdateV Certifications: input.Certifications, BusinessOwnerID: input.BusinessOwnerID, SecurityOwnerID: input.SecurityOwnerID, + ShowOnTrustCenter: input.ShowOnTrustCenter, }) if err != nil { return nil, fmt.Errorf("cannot update vendor: %w", err) @@ -1879,6 +1898,7 @@ func (r *mutationResolver) UpdateDocument(ctx context.Context, input types.Updat input.OwnerID, input.DocumentType, input.Title, + input.ShowOnTrustCenter, ) if err != nil { @@ -2300,10 +2320,11 @@ func (r *mutationResolver) UpdateAudit(ctx context.Context, input types.UpdateAu prb := r.ProboService(ctx, input.ID.TenantID()) req := probo.UpdateAuditRequest{ - ID: input.ID, - ValidFrom: input.ValidFrom, - ValidUntil: input.ValidUntil, - State: input.State, + ID: input.ID, + ValidFrom: input.ValidFrom, + ValidUntil: input.ValidUntil, + State: input.State, + ShowOnTrustCenter: input.ShowOnTrustCenter, } audit, err := prb.Audits.Update(ctx, &req) @@ -2718,6 +2739,18 @@ func (r *organizationResolver) Audits(ctx context.Context, obj *types.Organizati return types.NewAuditConnection(page, r, obj.ID), nil } +// TrustCenter is the resolver for the trustCenter field. +func (r *organizationResolver) TrustCenter(ctx context.Context, obj *types.Organization) (*types.TrustCenter, error) { + prb := r.ProboService(ctx, obj.ID.TenantID()) + + trustCenter, err := prb.TrustCenters.GetByOrganizationID(ctx, obj.ID) + if err != nil { + return nil, fmt.Errorf("cannot get trust center: %w", err) + } + + return types.NewTrustCenter(trustCenter), nil +} + // TotalCount is the resolver for the totalCount field. func (r *peopleConnectionResolver) TotalCount(ctx context.Context, obj *types.PeopleConnection) (int, error) { prb := r.ProboService(ctx, obj.ParentID.TenantID()) @@ -2849,6 +2882,12 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error panic(fmt.Errorf("cannot get report: %w", err)) } return types.NewReport(report), nil + case coredata.TrustCenterEntityType: + trustCenter, err := prb.TrustCenters.GetByOrganizationID(ctx, id) + if err != nil { + panic(fmt.Errorf("cannot get trust center: %w", err)) + } + return types.NewTrustCenter(trustCenter), nil default: }