From 3e3c3a8ebb88f0871bb36600f6571e617a2417ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20R=C3=A9?= Date: Wed, 28 Jan 2026 16:17:45 +0400 Subject: [PATCH] Refactor compliance page audits page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Émile Ré --- ...CompliancePageAuditListFragment.graphql.ts | 116 +++++++++ ...ageAuditListItem_auditFragment.graphql.ts} | 32 +-- ...ListItem_compliancePageFragment.graphql.ts | 48 ++++ ..._updateAuditVisibilityMutation.graphql.ts} | 51 ++-- .../CompliancePageAuditsPageQuery.graphql.ts | 229 ++++++++++++++++++ .../core/TrustCenterGraphQuery.graphql.ts | 126 +--------- .../trustCenter/TrustCenterAuditsCard.tsx | 189 --------------- .../src/hooks/graph/TrustCenterAuditGraph.ts | 29 --- .../src/hooks/graph/TrustCenterGraph.ts | 8 - .../audits/CompliancePageAuditsPage.tsx | 37 +++ .../audits/CompliancePageAuditsPageLoader.tsx | 32 +++ .../_components/CompliancePageAuditList.tsx | 79 ++++++ .../CompliancePageAuditListItem.tsx | 119 +++++++++ .../organizations/compliance-page/routes.ts | 5 + .../trustCenter/TrustCenterAuditsTab.tsx | 36 --- apps/console/src/routes/trustCenterRoutes.ts | 7 - 16 files changed, 693 insertions(+), 450 deletions(-) create mode 100644 apps/console/src/__generated__/core/CompliancePageAuditListFragment.graphql.ts rename apps/console/src/__generated__/core/{TrustCenterAuditsCardFragment.graphql.ts => CompliancePageAuditListItem_auditFragment.graphql.ts} (68%) create mode 100644 apps/console/src/__generated__/core/CompliancePageAuditListItem_compliancePageFragment.graphql.ts rename apps/console/src/__generated__/core/{TrustCenterAuditGraphUpdateMutation.graphql.ts => CompliancePageAuditListItem_updateAuditVisibilityMutation.graphql.ts} (68%) create mode 100644 apps/console/src/__generated__/core/CompliancePageAuditsPageQuery.graphql.ts delete mode 100644 apps/console/src/components/trustCenter/TrustCenterAuditsCard.tsx delete mode 100644 apps/console/src/hooks/graph/TrustCenterAuditGraph.ts create mode 100644 apps/console/src/pages/organizations/compliance-page/audits/CompliancePageAuditsPage.tsx create mode 100644 apps/console/src/pages/organizations/compliance-page/audits/CompliancePageAuditsPageLoader.tsx create mode 100644 apps/console/src/pages/organizations/compliance-page/audits/_components/CompliancePageAuditList.tsx create mode 100644 apps/console/src/pages/organizations/compliance-page/audits/_components/CompliancePageAuditListItem.tsx delete mode 100644 apps/console/src/pages/organizations/trustCenter/TrustCenterAuditsTab.tsx diff --git a/apps/console/src/__generated__/core/CompliancePageAuditListFragment.graphql.ts b/apps/console/src/__generated__/core/CompliancePageAuditListFragment.graphql.ts new file mode 100644 index 000000000..d9957241a --- /dev/null +++ b/apps/console/src/__generated__/core/CompliancePageAuditListFragment.graphql.ts @@ -0,0 +1,116 @@ +/** + * @generated SignedSource<<0bf1290a489f4685a6057509b9eaed9c>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type CompliancePageAuditListFragment$data = { + readonly audits: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly " $fragmentSpreads": FragmentRefs<"CompliancePageAuditListItem_auditFragment">; + }; + }>; + }; + readonly compliancePage: { + readonly " $fragmentSpreads": FragmentRefs<"CompliancePageAuditListItem_compliancePageFragment">; + }; + readonly " $fragmentType": "CompliancePageAuditListFragment"; +}; +export type CompliancePageAuditListFragment$key = { + readonly " $data"?: CompliancePageAuditListFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"CompliancePageAuditListFragment">; +}; + +const node: ReaderFragment = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "CompliancePageAuditListFragment", + "selections": [ + { + "kind": "RequiredField", + "field": { + "alias": "compliancePage", + "args": null, + "concreteType": "TrustCenter", + "kind": "LinkedField", + "name": "trustCenter", + "plural": false, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "CompliancePageAuditListItem_compliancePageFragment" + } + ], + "storageKey": null + }, + "action": "THROW" + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 1000 + } + ], + "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": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "args": null, + "kind": "FragmentSpread", + "name": "CompliancePageAuditListItem_auditFragment" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "audits(first:1000)" + } + ], + "type": "Organization", + "abstractKey": null +}; + +(node as any).hash = "d307c5c23d18357bc09c1115989dd734"; + +export default node; diff --git a/apps/console/src/__generated__/core/TrustCenterAuditsCardFragment.graphql.ts b/apps/console/src/__generated__/core/CompliancePageAuditListItem_auditFragment.graphql.ts similarity index 68% rename from apps/console/src/__generated__/core/TrustCenterAuditsCardFragment.graphql.ts rename to apps/console/src/__generated__/core/CompliancePageAuditListItem_auditFragment.graphql.ts index 8e2e11b12..f5596db82 100644 --- a/apps/console/src/__generated__/core/TrustCenterAuditsCardFragment.graphql.ts +++ b/apps/console/src/__generated__/core/CompliancePageAuditListItem_auditFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<28248f2dbdad48cc6cfec3b35ce4c22f>> + * @generated SignedSource<<7de15e098b76ab6e91a10160c60c6c69>> * @lightSyntaxTransform * @nogrep */ @@ -12,8 +12,7 @@ import { ReaderFragment } from 'relay-runtime'; export type AuditState = "COMPLETED" | "IN_PROGRESS" | "NOT_STARTED" | "OUTDATED" | "REJECTED"; export type TrustCenterVisibility = "NONE" | "PRIVATE" | "PUBLIC"; import { FragmentRefs } from "relay-runtime"; -export type TrustCenterAuditsCardFragment$data = { - readonly createdAt: string; +export type CompliancePageAuditListItem_auditFragment$data = { readonly framework: { readonly name: string; }; @@ -21,13 +20,12 @@ export type TrustCenterAuditsCardFragment$data = { readonly name: string | null | undefined; readonly state: AuditState; readonly trustCenterVisibility: TrustCenterVisibility; - readonly validFrom: string | null | undefined; readonly validUntil: string | null | undefined; - readonly " $fragmentType": "TrustCenterAuditsCardFragment"; + readonly " $fragmentType": "CompliancePageAuditListItem_auditFragment"; }; -export type TrustCenterAuditsCardFragment$key = { - readonly " $data"?: TrustCenterAuditsCardFragment$data; - readonly " $fragmentSpreads": FragmentRefs<"TrustCenterAuditsCardFragment">; +export type CompliancePageAuditListItem_auditFragment$key = { + readonly " $data"?: CompliancePageAuditListItem_auditFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"CompliancePageAuditListItem_auditFragment">; }; const node: ReaderFragment = (function(){ @@ -42,7 +40,7 @@ return { "argumentDefinitions": [], "kind": "Fragment", "metadata": null, - "name": "TrustCenterAuditsCardFragment", + "name": "CompliancePageAuditListItem_auditFragment", "selections": [ { "alias": null, @@ -64,13 +62,6 @@ return { ], "storageKey": null }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "validFrom", - "storageKey": null - }, { "alias": null, "args": null, @@ -91,13 +82,6 @@ return { "kind": "ScalarField", "name": "trustCenterVisibility", "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "createdAt", - "storageKey": null } ], "type": "Audit", @@ -105,6 +89,6 @@ return { }; })(); -(node as any).hash = "c0f615fcad79ad39f60b48daacabdbbd"; +(node as any).hash = "495e75c50400e856ba08ed9f5840da67"; export default node; diff --git a/apps/console/src/__generated__/core/CompliancePageAuditListItem_compliancePageFragment.graphql.ts b/apps/console/src/__generated__/core/CompliancePageAuditListItem_compliancePageFragment.graphql.ts new file mode 100644 index 000000000..d57a0e4af --- /dev/null +++ b/apps/console/src/__generated__/core/CompliancePageAuditListItem_compliancePageFragment.graphql.ts @@ -0,0 +1,48 @@ +/** + * @generated SignedSource<<9a44b4f71be46d5e02c3f1c8587d6f32>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type CompliancePageAuditListItem_compliancePageFragment$data = { + readonly canUpdate: boolean; + readonly " $fragmentType": "CompliancePageAuditListItem_compliancePageFragment"; +}; +export type CompliancePageAuditListItem_compliancePageFragment$key = { + readonly " $data"?: CompliancePageAuditListItem_compliancePageFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"CompliancePageAuditListItem_compliancePageFragment">; +}; + +const node: ReaderFragment = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "CompliancePageAuditListItem_compliancePageFragment", + "selections": [ + { + "alias": "canUpdate", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:trust-center:update" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:trust-center:update\")" + } + ], + "type": "TrustCenter", + "abstractKey": null +}; + +(node as any).hash = "4744b831ee9ad55304d2159e8b2ebfd5"; + +export default node; diff --git a/apps/console/src/__generated__/core/TrustCenterAuditGraphUpdateMutation.graphql.ts b/apps/console/src/__generated__/core/CompliancePageAuditListItem_updateAuditVisibilityMutation.graphql.ts similarity index 68% rename from apps/console/src/__generated__/core/TrustCenterAuditGraphUpdateMutation.graphql.ts rename to apps/console/src/__generated__/core/CompliancePageAuditListItem_updateAuditVisibilityMutation.graphql.ts index 694e4a176..5344c295d 100644 --- a/apps/console/src/__generated__/core/TrustCenterAuditGraphUpdateMutation.graphql.ts +++ b/apps/console/src/__generated__/core/CompliancePageAuditListItem_updateAuditVisibilityMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<1f16f6e36a9d4a8de63d4e6f8e3d4c88>> + * @generated SignedSource<<4286fb5d45f1d4d8dba035c29219ab34>> * @lightSyntaxTransform * @nogrep */ @@ -20,21 +20,19 @@ export type UpdateAuditInput = { validFrom?: string | null | undefined; validUntil?: string | null | undefined; }; -export type TrustCenterAuditGraphUpdateMutation$variables = { +export type CompliancePageAuditListItem_updateAuditVisibilityMutation$variables = { input: UpdateAuditInput; }; -export type TrustCenterAuditGraphUpdateMutation$data = { +export type CompliancePageAuditListItem_updateAuditVisibilityMutation$data = { readonly updateAudit: { readonly audit: { - readonly id: string; - readonly trustCenterVisibility: TrustCenterVisibility; - readonly " $fragmentSpreads": FragmentRefs<"TrustCenterAuditsCardFragment">; + readonly " $fragmentSpreads": FragmentRefs<"CompliancePageAuditListItem_auditFragment">; }; }; }; -export type TrustCenterAuditGraphUpdateMutation = { - response: TrustCenterAuditGraphUpdateMutation$data; - variables: TrustCenterAuditGraphUpdateMutation$variables; +export type CompliancePageAuditListItem_updateAuditVisibilityMutation = { + response: CompliancePageAuditListItem_updateAuditVisibilityMutation$data; + variables: CompliancePageAuditListItem_updateAuditVisibilityMutation$variables; }; const node: ConcreteRequest = (function(){ @@ -60,13 +58,6 @@ v2 = { "storageKey": null }, v3 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "trustCenterVisibility", - "storageKey": null -}, -v4 = { "alias": null, "args": null, "kind": "ScalarField", @@ -78,7 +69,7 @@ return { "argumentDefinitions": (v0/*: any*/), "kind": "Fragment", "metadata": null, - "name": "TrustCenterAuditGraphUpdateMutation", + "name": "CompliancePageAuditListItem_updateAuditVisibilityMutation", "selections": [ { "alias": null, @@ -96,12 +87,10 @@ return { "name": "audit", "plural": false, "selections": [ - (v2/*: any*/), - (v3/*: any*/), { "args": null, "kind": "FragmentSpread", - "name": "TrustCenterAuditsCardFragment" + "name": "CompliancePageAuditListItem_auditFragment" } ], "storageKey": null @@ -117,7 +106,7 @@ return { "operation": { "argumentDefinitions": (v0/*: any*/), "kind": "Operation", - "name": "TrustCenterAuditGraphUpdateMutation", + "name": "CompliancePageAuditListItem_updateAuditVisibilityMutation", "selections": [ { "alias": null, @@ -137,7 +126,6 @@ return { "selections": [ (v2/*: any*/), (v3/*: any*/), - (v4/*: any*/), { "alias": null, "args": null, @@ -146,18 +134,11 @@ return { "name": "framework", "plural": false, "selections": [ - (v4/*: any*/), + (v3/*: any*/), (v2/*: any*/) ], "storageKey": null }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "validFrom", - "storageKey": null - }, { "alias": null, "args": null, @@ -176,7 +157,7 @@ return { "alias": null, "args": null, "kind": "ScalarField", - "name": "createdAt", + "name": "trustCenterVisibility", "storageKey": null } ], @@ -188,16 +169,16 @@ return { ] }, "params": { - "cacheID": "70742901eeb45d5e00e4e61d83b2f828", + "cacheID": "4363d4bbf56cf55359dc0a1ff19e1dbf", "id": null, "metadata": {}, - "name": "TrustCenterAuditGraphUpdateMutation", + "name": "CompliancePageAuditListItem_updateAuditVisibilityMutation", "operationKind": "mutation", - "text": "mutation TrustCenterAuditGraphUpdateMutation(\n $input: UpdateAuditInput!\n) {\n updateAudit(input: $input) {\n audit {\n id\n trustCenterVisibility\n ...TrustCenterAuditsCardFragment\n }\n }\n}\n\nfragment TrustCenterAuditsCardFragment on Audit {\n id\n name\n framework {\n name\n id\n }\n validFrom\n validUntil\n state\n trustCenterVisibility\n createdAt\n}\n" + "text": "mutation CompliancePageAuditListItem_updateAuditVisibilityMutation(\n $input: UpdateAuditInput!\n) {\n updateAudit(input: $input) {\n audit {\n ...CompliancePageAuditListItem_auditFragment\n id\n }\n }\n}\n\nfragment CompliancePageAuditListItem_auditFragment on Audit {\n id\n name\n framework {\n name\n id\n }\n validUntil\n state\n trustCenterVisibility\n}\n" } }; })(); -(node as any).hash = "c958ccce67f79bb75593e9fcb31ee9d8"; +(node as any).hash = "6868ffa86e630bac03c87aa363dc59e2"; export default node; diff --git a/apps/console/src/__generated__/core/CompliancePageAuditsPageQuery.graphql.ts b/apps/console/src/__generated__/core/CompliancePageAuditsPageQuery.graphql.ts new file mode 100644 index 000000000..3038455c5 --- /dev/null +++ b/apps/console/src/__generated__/core/CompliancePageAuditsPageQuery.graphql.ts @@ -0,0 +1,229 @@ +/** + * @generated SignedSource<<9b92fdee29c65d57e35647e37f427be9>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type CompliancePageAuditsPageQuery$variables = { + organizationId: string; +}; +export type CompliancePageAuditsPageQuery$data = { + readonly organization: { + readonly " $fragmentSpreads": FragmentRefs<"CompliancePageAuditListFragment">; + }; +}; +export type CompliancePageAuditsPageQuery = { + response: CompliancePageAuditsPageQuery$data; + variables: CompliancePageAuditsPageQuery$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 +}; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "CompliancePageAuditsPageQuery", + "selections": [ + { + "alias": "organization", + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "CompliancePageAuditListFragment" + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "CompliancePageAuditsPageQuery", + "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 + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": "compliancePage", + "args": null, + "concreteType": "TrustCenter", + "kind": "LinkedField", + "name": "trustCenter", + "plural": false, + "selections": [ + { + "alias": "canUpdate", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:trust-center:update" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:trust-center:update\")" + }, + (v2/*: any*/) + ], + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 1000 + } + ], + "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*/), + (v3/*: 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": "validUntil", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "state", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "trustCenterVisibility", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "audits(first:1000)" + } + ], + "type": "Organization", + "abstractKey": null + }, + (v2/*: any*/) + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "4efa36568b452a0075ed29fe7f5ed279", + "id": null, + "metadata": {}, + "name": "CompliancePageAuditsPageQuery", + "operationKind": "query", + "text": "query CompliancePageAuditsPageQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ...CompliancePageAuditListFragment\n id\n }\n}\n\nfragment CompliancePageAuditListFragment on Organization {\n compliancePage: trustCenter {\n ...CompliancePageAuditListItem_compliancePageFragment\n id\n }\n audits(first: 1000) {\n edges {\n node {\n id\n ...CompliancePageAuditListItem_auditFragment\n }\n }\n }\n}\n\nfragment CompliancePageAuditListItem_auditFragment on Audit {\n id\n name\n framework {\n name\n id\n }\n validUntil\n state\n trustCenterVisibility\n}\n\nfragment CompliancePageAuditListItem_compliancePageFragment on TrustCenter {\n canUpdate: permission(action: \"core:trust-center:update\")\n}\n" + } +}; +})(); + +(node as any).hash = "686edde90edd5f75bb7470e9e1e900c2"; + +export default node; diff --git a/apps/console/src/__generated__/core/TrustCenterGraphQuery.graphql.ts b/apps/console/src/__generated__/core/TrustCenterGraphQuery.graphql.ts index b126ee7ad..a0d05748b 100644 --- a/apps/console/src/__generated__/core/TrustCenterGraphQuery.graphql.ts +++ b/apps/console/src/__generated__/core/TrustCenterGraphQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<409b8c7ffaa92ad8d718689cb254228e>> * @lightSyntaxTransform * @nogrep */ @@ -15,14 +15,6 @@ export type TrustCenterGraphQuery$variables = { }; export type TrustCenterGraphQuery$data = { readonly organization: { - readonly audits?: { - readonly edges: ReadonlyArray<{ - readonly node: { - readonly id: string; - readonly " $fragmentSpreads": FragmentRefs<"TrustCenterAuditsCardFragment">; - }; - }>; - }; readonly canCreateTrustCenterFile?: boolean; readonly customDomain?: { readonly domain: string; @@ -459,45 +451,6 @@ return { ], "storageKey": "documents(first:100)" }, - { - "alias": null, - "args": (v9/*: 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": (v9/*: any*/), @@ -712,77 +665,6 @@ return { ], "storageKey": "documents(first:100)" }, - { - "alias": null, - "args": (v9/*: 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*/), - (v3/*: 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 - }, - (v15/*: any*/), - (v6/*: any*/) - ], - "storageKey": null - } - ], - "storageKey": null - } - ], - "storageKey": "audits(first:100)" - }, { "alias": null, "args": (v9/*: any*/), @@ -943,7 +825,7 @@ return { ] }, "params": { - "cacheID": "e04f245ca84bd7221a3e0187b8e988a5", + "cacheID": "9c65178da92b31263957b8ccc6747639", "id": null, "metadata": { "connection": [ @@ -960,11 +842,11 @@ return { }, "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 canCreateTrustCenterFile: permission(action: \"core:trust-center-file:create\")\n customDomain {\n id\n domain\n }\n trustCenter {\n id\n active\n ndaFileName\n ndaFileUrl\n createdAt\n updatedAt\n canUpdate: permission(action: \"core:trust-center:update\")\n canGetNDA: permission(action: \"core:trust-center:get-nda\")\n canUploadNDA: permission(action: \"core:trust-center:upload-nda\")\n canDeleteNDA: permission(action: \"core:trust-center:delete-nda\")\n canCreateReference: permission(action: \"core:trust-center-reference:create\")\n canCreateAccess: permission(action: \"core:trust-center-access:create\")\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 trustCenterFiles(first: 100) {\n edges {\n node {\n id\n ...TrustCenterFilesCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n slackConnections(first: 100) {\n edges {\n node {\n id\n channel\n channelId\n createdAt\n updatedAt\n }\n }\n }\n }\n id\n }\n}\n\nfragment TrustCenterAuditsCardFragment on Audit {\n id\n name\n framework {\n name\n id\n }\n validFrom\n validUntil\n state\n trustCenterVisibility\n createdAt\n}\n\nfragment TrustCenterDocumentsCardFragment on Document {\n id\n title\n createdAt\n documentType\n trustCenterVisibility\n versions(first: 1) {\n edges {\n node {\n id\n status\n }\n }\n }\n}\n\nfragment TrustCenterFilesCardFragment on TrustCenterFile {\n id\n name\n category\n fileUrl\n trustCenterVisibility\n createdAt\n updatedAt\n canUpdate: permission(action: \"core:trust-center-file:update\")\n canDelete: permission(action: \"core:trust-center-file:delete\")\n}\n\nfragment TrustCenterVendorsCardFragment on Vendor {\n id\n name\n category\n description\n showOnTrustCenter\n createdAt\n canUpdate: permission(action: \"core:vendor:update\")\n}\n" + "text": "query TrustCenterGraphQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n name\n canCreateTrustCenterFile: permission(action: \"core:trust-center-file:create\")\n customDomain {\n id\n domain\n }\n trustCenter {\n id\n active\n ndaFileName\n ndaFileUrl\n createdAt\n updatedAt\n canUpdate: permission(action: \"core:trust-center:update\")\n canGetNDA: permission(action: \"core:trust-center:get-nda\")\n canUploadNDA: permission(action: \"core:trust-center:upload-nda\")\n canDeleteNDA: permission(action: \"core:trust-center:delete-nda\")\n canCreateReference: permission(action: \"core:trust-center-reference:create\")\n canCreateAccess: permission(action: \"core:trust-center-access:create\")\n }\n documents(first: 100) {\n edges {\n node {\n id\n ...TrustCenterDocumentsCardFragment\n }\n }\n }\n vendors(first: 100) {\n edges {\n node {\n id\n ...TrustCenterVendorsCardFragment\n }\n }\n }\n trustCenterFiles(first: 100) {\n edges {\n node {\n id\n ...TrustCenterFilesCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n slackConnections(first: 100) {\n edges {\n node {\n id\n channel\n channelId\n createdAt\n updatedAt\n }\n }\n }\n }\n id\n }\n}\n\nfragment TrustCenterDocumentsCardFragment on Document {\n id\n title\n createdAt\n documentType\n trustCenterVisibility\n versions(first: 1) {\n edges {\n node {\n id\n status\n }\n }\n }\n}\n\nfragment TrustCenterFilesCardFragment on TrustCenterFile {\n id\n name\n category\n fileUrl\n trustCenterVisibility\n createdAt\n updatedAt\n canUpdate: permission(action: \"core:trust-center-file:update\")\n canDelete: permission(action: \"core:trust-center-file:delete\")\n}\n\nfragment TrustCenterVendorsCardFragment on Vendor {\n id\n name\n category\n description\n showOnTrustCenter\n createdAt\n canUpdate: permission(action: \"core:vendor:update\")\n}\n" } }; })(); -(node as any).hash = "c2590192391f38eab216d98c0c536118"; +(node as any).hash = "5f4dd8eb5f6ceb0dcb1d3ce3eff4978c"; export default node; diff --git a/apps/console/src/components/trustCenter/TrustCenterAuditsCard.tsx b/apps/console/src/components/trustCenter/TrustCenterAuditsCard.tsx deleted file mode 100644 index 0aa303c4b..000000000 --- a/apps/console/src/components/trustCenter/TrustCenterAuditsCard.tsx +++ /dev/null @@ -1,189 +0,0 @@ -import { - formatDate, - getAuditStateLabel, - getAuditStateVariant, - getTrustCenterVisibilityOptions, - sprintf, -} from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; -import { - Badge, - Button, - Field, - IconChevronDown, - Option, - Table, - Tbody, - Td, - Th, - Thead, - Tr, -} from "@probo/ui"; -import { useCallback, useMemo, useState } from "react"; -import { useFragment } from "react-relay"; -import { graphql } from "relay-runtime"; - -import type { TrustCenterAuditsCardFragment$key } from "#/__generated__/core/TrustCenterAuditsCardFragment.graphql"; -import { useOrganizationId } from "#/hooks/useOrganizationId"; - -const trustCenterAuditFragment = graphql` - fragment TrustCenterAuditsCardFragment on Audit { - id - name - framework { - name - } - validFrom - validUntil - state - trustCenterVisibility - createdAt - } -`; - -type Mutation = (p: { - variables: { - input: { - id: string; - trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC"; - } & Params; - }; -}) => Promise; - -type Props = { - audits: TrustCenterAuditsCardFragment$key[]; - params: Params; - disabled?: boolean; - onChangeVisibility: Mutation; - canUpdate: boolean; -}; - -export function TrustCenterAuditsCard(props: Props) { - const { __ } = useTranslate(); - const [limit, setLimit] = useState(100); - const audits = useMemo(() => { - return limit ? props.audits.slice(0, limit) : props.audits; - }, [props.audits, limit]); - const showMoreButton = limit !== null && props.audits.length > limit; - - const onChangeVisibility = async ( - auditId: string, - trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC", - ) => { - await props.onChangeVisibility({ - variables: { - input: { - id: auditId, - trustCenterVisibility, - ...props.params, - }, - }, - }); - }; - - return ( -
- - - - - - - - - - - - {audits.length === 0 && ( - - - - )} - {audits.map((audit, index) => ( - - ))} - -
{__("Framework")}{__("Name")}{__("Valid Until")}{__("State")}{__("Visibility")}
- {__("No audits available")} -
- {showMoreButton && ( - - )} -
- ); -} - -function AuditRow(props: { - auditFragmentRef: TrustCenterAuditsCardFragment$key; - onChangeVisibility: ( - auditId: string, - trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC", - ) => Promise; - disabled?: boolean; - canUpdate: boolean; -}) { - const { auditFragmentRef, onChangeVisibility, disabled, canUpdate } = props; - const audit = useFragment(trustCenterAuditFragment, auditFragmentRef); - const organizationId = useOrganizationId(); - const { __ } = useTranslate(); - - const handleValueChange = useCallback( - async (value: string) => { - const stringValue = typeof value === "string" ? value : ""; - const typedValue = stringValue as "NONE" | "PRIVATE" | "PUBLIC"; - await onChangeVisibility(audit.id, typedValue); - }, - [audit.id, onChangeVisibility], - ); - - const visibilityOptions = getTrustCenterVisibilityOptions(__); - - const validUntilFormatted = audit.validUntil - ? formatDate(audit.validUntil) - : __("No expiry"); - - return ( - - -
{audit.framework.name}
- - {audit.name || __("Untitled")} - {validUntilFormatted} - - - {getAuditStateLabel(__, audit.state)} - - - - void handleValueChange(value)} - disabled={disabled || !canUpdate} - className="w-[105px]" - > - {visibilityOptions.map(option => ( - - ))} - - - - ); -} diff --git a/apps/console/src/hooks/graph/TrustCenterAuditGraph.ts b/apps/console/src/hooks/graph/TrustCenterAuditGraph.ts deleted file mode 100644 index 01ed052c1..000000000 --- a/apps/console/src/hooks/graph/TrustCenterAuditGraph.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { useTranslate } from "@probo/i18n"; -import { graphql } from "relay-runtime"; - -import type { TrustCenterAuditGraphUpdateMutation } from "#/__generated__/core/TrustCenterAuditGraphUpdateMutation.graphql"; -import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; - -export const trustCenterAuditUpdateMutation = graphql` - mutation TrustCenterAuditGraphUpdateMutation($input: UpdateAuditInput!) { - updateAudit(input: $input) { - audit { - id - trustCenterVisibility - ...TrustCenterAuditsCardFragment - } - } - } -`; - -export function useTrustCenterAuditUpdate() { - const { __ } = useTranslate(); - - return useMutationWithToasts( - trustCenterAuditUpdateMutation, - { - successMessage: __("Audit visibility updated successfully."), - errorMessage: __("Failed to update audit visibility"), - }, - ); -} diff --git a/apps/console/src/hooks/graph/TrustCenterGraph.ts b/apps/console/src/hooks/graph/TrustCenterGraph.ts index 6080b8054..b84a99175 100644 --- a/apps/console/src/hooks/graph/TrustCenterGraph.ts +++ b/apps/console/src/hooks/graph/TrustCenterGraph.ts @@ -40,14 +40,6 @@ export const trustCenterQuery = graphql` } } } - audits(first: 100) { - edges { - node { - id - ...TrustCenterAuditsCardFragment - } - } - } vendors(first: 100) { edges { node { diff --git a/apps/console/src/pages/organizations/compliance-page/audits/CompliancePageAuditsPage.tsx b/apps/console/src/pages/organizations/compliance-page/audits/CompliancePageAuditsPage.tsx new file mode 100644 index 000000000..1f90aaf03 --- /dev/null +++ b/apps/console/src/pages/organizations/compliance-page/audits/CompliancePageAuditsPage.tsx @@ -0,0 +1,37 @@ +import { useTranslate } from "@probo/i18n"; +import { graphql, type PreloadedQuery, usePreloadedQuery } from "react-relay"; + +import type { CompliancePageAuditsPageQuery } from "#/__generated__/core/CompliancePageAuditsPageQuery.graphql"; + +import { CompliancePageAuditList } from "./_components/CompliancePageAuditList"; + +export const compliancePageAuditsPageQuery = graphql` + query CompliancePageAuditsPageQuery($organizationId: ID!) { + organization: node(id: $organizationId) { + ...CompliancePageAuditListFragment + } + } +`; + +export function CompliancePageAuditsPage(props: { queryRef: PreloadedQuery }) { + const { queryRef } = props; + + const { __ } = useTranslate(); + + const { organization } = usePreloadedQuery(compliancePageAuditsPageQuery, queryRef); + + return ( +
+
+
+

{__("Audits")}

+

+ {__("Manage audit reports and compliance certifications")} +

+
+
+ + +
+ ); +} diff --git a/apps/console/src/pages/organizations/compliance-page/audits/CompliancePageAuditsPageLoader.tsx b/apps/console/src/pages/organizations/compliance-page/audits/CompliancePageAuditsPageLoader.tsx new file mode 100644 index 000000000..6256fcfb8 --- /dev/null +++ b/apps/console/src/pages/organizations/compliance-page/audits/CompliancePageAuditsPageLoader.tsx @@ -0,0 +1,32 @@ +import { useEffect } from "react"; +import { useQueryLoader } from "react-relay"; + +import type { CompliancePageAuditsPageQuery } from "#/__generated__/core/CompliancePageAuditsPageQuery.graphql"; +import { LinkCardSkeleton } from "#/components/skeletons/LinkCardSkeleton"; +import { useOrganizationId } from "#/hooks/useOrganizationId"; +import { CoreRelayProvider } from "#/providers/CoreRelayProvider"; + +import { CompliancePageAuditsPage, compliancePageAuditsPageQuery } from "./CompliancePageAuditsPage"; + +function CompliancePageAuditsPageQueryLoader() { + const organizationId = useOrganizationId(); + const [queryRef, loadQuery] = useQueryLoader(compliancePageAuditsPageQuery); + + useEffect(() => { + if (!queryRef) { + loadQuery({ organizationId }); + } + }); + + if (!queryRef) return ; + + return ; +} + +export default function CompliancePageAuditsPageLoader() { + return ( + + + + ); +} diff --git a/apps/console/src/pages/organizations/compliance-page/audits/_components/CompliancePageAuditList.tsx b/apps/console/src/pages/organizations/compliance-page/audits/_components/CompliancePageAuditList.tsx new file mode 100644 index 000000000..093cc4fd4 --- /dev/null +++ b/apps/console/src/pages/organizations/compliance-page/audits/_components/CompliancePageAuditList.tsx @@ -0,0 +1,79 @@ +import { sprintf } from "@probo/helpers"; +import { useTranslate } from "@probo/i18n"; +import { Button, IconChevronDown, Table, Tbody, Td, Th, Thead, Tr } from "@probo/ui"; +import { useState } from "react"; +import { useFragment } from "react-relay"; +import { graphql } from "relay-runtime"; + +import type { CompliancePageAuditListFragment$key } from "#/__generated__/core/CompliancePageAuditListFragment.graphql"; + +import { CompliancePageAuditListItem } from "./CompliancePageAuditListItem"; + +const fragment = graphql` + fragment CompliancePageAuditListFragment on Organization { + compliancePage: trustCenter @required(action: THROW) { + ...CompliancePageAuditListItem_compliancePageFragment + } + audits(first: 1000) { + edges { + node { + id + ...CompliancePageAuditListItem_auditFragment + } + } + } + } +`; + +export function CompliancePageAuditList(props: { fragmentRef: CompliancePageAuditListFragment$key }) { + const { fragmentRef } = props; + + const { __ } = useTranslate(); + const [limit, setLimit] = useState(100); + + const { audits, compliancePage } = useFragment(fragment, fragmentRef); + + const showMoreButton = limit !== null && audits.edges.length > limit; + + return ( +
+ + + + + + + + + + + + {audits.edges.length === 0 && ( + + + + )} + {audits.edges.map(({ node: audit }) => ( + + ))} + +
{__("Framework")}{__("Name")}{__("Valid Until")}{__("State")}{__("Visibility")}
+ {__("No audits available")} +
+ {showMoreButton && ( + + )} +
+ ); +} diff --git a/apps/console/src/pages/organizations/compliance-page/audits/_components/CompliancePageAuditListItem.tsx b/apps/console/src/pages/organizations/compliance-page/audits/_components/CompliancePageAuditListItem.tsx new file mode 100644 index 000000000..590862384 --- /dev/null +++ b/apps/console/src/pages/organizations/compliance-page/audits/_components/CompliancePageAuditListItem.tsx @@ -0,0 +1,119 @@ +import { formatDate, getAuditStateLabel, getAuditStateVariant, getTrustCenterVisibilityOptions } from "@probo/helpers"; +import { useTranslate } from "@probo/i18n"; +import { Badge, Field, Option, Td, Tr } from "@probo/ui"; +import { useCallback } from "react"; +import { useFragment } from "react-relay"; +import { graphql } from "relay-runtime"; + +import type { CompliancePageAuditListItem_auditFragment$key } from "#/__generated__/core/CompliancePageAuditListItem_auditFragment.graphql"; +import type { CompliancePageAuditListItem_compliancePageFragment$key } from "#/__generated__/core/CompliancePageAuditListItem_compliancePageFragment.graphql"; +import type { CompliancePageAuditListItem_updateAuditVisibilityMutation } from "#/__generated__/core/CompliancePageAuditListItem_updateAuditVisibilityMutation.graphql"; +import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; +import { useOrganizationId } from "#/hooks/useOrganizationId"; + +const compliancePageFragment = graphql` + fragment CompliancePageAuditListItem_compliancePageFragment on TrustCenter { + canUpdate: permission(action: "core:trust-center:update") + } +`; + +const auditFragment = graphql` + fragment CompliancePageAuditListItem_auditFragment on Audit { + id + name + framework { + name + } + validUntil + state + trustCenterVisibility + } +`; + +const updateAuditVisibilityMutation = graphql` + mutation CompliancePageAuditListItem_updateAuditVisibilityMutation($input: UpdateAuditInput!) { + updateAudit(input: $input) { + audit { + ...CompliancePageAuditListItem_auditFragment + } + } + } +`; + +export function CompliancePageAuditListItem(props: { + auditFragmentRef: CompliancePageAuditListItem_auditFragment$key; + compliancePageFragmentRef: CompliancePageAuditListItem_compliancePageFragment$key; +}) { + const { auditFragmentRef, compliancePageFragmentRef } = props; + + const organizationId = useOrganizationId(); + const { __ } = useTranslate(); + + const compliancePage = useFragment( + compliancePageFragment, + compliancePageFragmentRef, + ); + const audit = useFragment(auditFragment, auditFragmentRef); + + const [updateAuditVisibility, isUpdatingAuditVisibility] = useMutationWithToasts< + CompliancePageAuditListItem_updateAuditVisibilityMutation + >( + updateAuditVisibilityMutation, + { + successMessage: __("Audit visibility updated successfully."), + errorMessage: __("Failed to update audit visibility"), + }, + ); + const handleVisibilityChange = useCallback( + async (value: string) => { + const stringValue = typeof value === "string" ? value : ""; + const typedValue = stringValue as "NONE" | "PRIVATE" | "PUBLIC"; + await updateAuditVisibility({ + variables: { + input: { + id: audit.id, + trustCenterVisibility: typedValue, + }, + }, + }); + }, + [audit.id, updateAuditVisibility], + ); + + const visibilityOptions = getTrustCenterVisibilityOptions(__); + const validUntilFormatted = audit.validUntil + ? formatDate(audit.validUntil) + : __("No expiry"); + + return ( + + +
{audit.framework.name}
+ + {audit.name || __("Untitled")} + {validUntilFormatted} + + + {getAuditStateLabel(__, audit.state)} + + + + void handleVisibilityChange(value)} + disabled={isUpdatingAuditVisibility || !compliancePage.canUpdate} + className="w-[105px]" + > + {visibilityOptions.map(option => ( + + ))} + + + + ); +} diff --git a/apps/console/src/pages/organizations/compliance-page/routes.ts b/apps/console/src/pages/organizations/compliance-page/routes.ts index 4baaa10df..bc729c88c 100644 --- a/apps/console/src/pages/organizations/compliance-page/routes.ts +++ b/apps/console/src/pages/organizations/compliance-page/routes.ts @@ -19,6 +19,11 @@ export const compliancePageRoutes = [ Fallback: LinkCardSkeleton, Component: lazy(() => import("#/pages/organizations/compliance-page/references/CompliancePageReferencesPageLoader")), }, + { + path: "audits", + Fallback: LinkCardSkeleton, + Component: lazy(() => import("#/pages/organizations/compliance-page/audits/CompliancePageAuditsPageLoader")), + }, ], }, ]; diff --git a/apps/console/src/pages/organizations/trustCenter/TrustCenterAuditsTab.tsx b/apps/console/src/pages/organizations/trustCenter/TrustCenterAuditsTab.tsx deleted file mode 100644 index e34260821..000000000 --- a/apps/console/src/pages/organizations/trustCenter/TrustCenterAuditsTab.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { useTranslate } from "@probo/i18n"; -import { Spinner } from "@probo/ui"; -import { useOutletContext } from "react-router"; - -import type { TrustCenterGraphQuery$data } from "#/__generated__/core/TrustCenterGraphQuery.graphql"; -import { TrustCenterAuditsCard } from "#/components/trustCenter/TrustCenterAuditsCard"; -import { useTrustCenterAuditUpdate } from "#/hooks/graph/TrustCenterAuditGraph"; - -export default function TrustCenterAuditsTab() { - const { __ } = useTranslate(); - const { organization } = useOutletContext(); - const [updateAuditVisibility, isUpdatingAudits] = useTrustCenterAuditUpdate(); - - const audits = (organization.audits?.edges ?? []).map(edge => edge.node); - - return ( -
-
-
-

{__("Audits")}

-

- {__("Manage audit reports and compliance certifications")} -

-
- {isUpdatingAudits && } -
- -
- ); -} diff --git a/apps/console/src/routes/trustCenterRoutes.ts b/apps/console/src/routes/trustCenterRoutes.ts index 5e8764080..6f2740833 100644 --- a/apps/console/src/routes/trustCenterRoutes.ts +++ b/apps/console/src/routes/trustCenterRoutes.ts @@ -29,13 +29,6 @@ export const trustCenterRoutes = [ lazy(() => import("#/pages/organizations/trustCenter/TrustCenterPage")), ), children: [ - { - path: "audits", - Fallback: LinkCardSkeleton, - Component: lazy( - () => import("#/pages/organizations/trustCenter/TrustCenterAuditsTab"), - ), - }, { path: "documents", Fallback: LinkCardSkeleton,