Refactor compliance page audits page

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-01-28 16:17:45 +04:00
parent 07ea130536
commit 3e3c3a8ebb
16 changed files with 693 additions and 450 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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<Params> = (p: {
variables: {
input: {
id: string;
trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC";
} & Params;
};
}) => Promise<void>;
type Props<Params> = {
audits: TrustCenterAuditsCardFragment$key[];
params: Params;
disabled?: boolean;
onChangeVisibility: Mutation<Params>;
canUpdate: boolean;
};
export function TrustCenterAuditsCard<Params>(props: Props<Params>) {
const { __ } = useTranslate();
const [limit, setLimit] = useState<number | null>(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 (
<div className="space-y-[10px]">
<Table>
<Thead>
<Tr>
<Th>{__("Framework")}</Th>
<Th>{__("Name")}</Th>
<Th>{__("Valid Until")}</Th>
<Th>{__("State")}</Th>
<Th>{__("Visibility")}</Th>
</Tr>
</Thead>
<Tbody>
{audits.length === 0 && (
<Tr>
<Td colSpan={6} className="text-center text-txt-secondary">
{__("No audits available")}
</Td>
</Tr>
)}
{audits.map((audit, index) => (
<AuditRow
key={index}
auditFragmentRef={audit}
canUpdate={props.canUpdate}
onChangeVisibility={onChangeVisibility}
disabled={props.disabled}
/>
))}
</Tbody>
</Table>
{showMoreButton && (
<Button
variant="tertiary"
onClick={() => setLimit(null)}
className="mt-3 mx-auto"
icon={IconChevronDown}
>
{sprintf(__("Show %s more"), props.audits.length - limit)}
</Button>
)}
</div>
);
}
function AuditRow(props: {
auditFragmentRef: TrustCenterAuditsCardFragment$key;
onChangeVisibility: (
auditId: string,
trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC",
) => Promise<void>;
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 (
<Tr to={`/organizations/${organizationId}/audits/${audit.id}`}>
<Td>
<div className="flex gap-4 items-center">{audit.framework.name}</div>
</Td>
<Td>{audit.name || __("Untitled")}</Td>
<Td>{validUntilFormatted}</Td>
<Td>
<Badge variant={getAuditStateVariant(audit.state)}>
{getAuditStateLabel(__, audit.state)}
</Badge>
</Td>
<Td noLink width={130} className="pr-0">
<Field
type="select"
value={audit.trustCenterVisibility}
onValueChange={value => void handleValueChange(value)}
disabled={disabled || !canUpdate}
className="w-[105px]"
>
{visibilityOptions.map(option => (
<Option key={option.value} value={option.value}>
<div className="flex items-center justify-between w-full">
<Badge variant={option.variant}>{option.label}</Badge>
</div>
</Option>
))}
</Field>
</Td>
</Tr>
);
}

View File

@@ -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<TrustCenterAuditGraphUpdateMutation>(
trustCenterAuditUpdateMutation,
{
successMessage: __("Audit visibility updated successfully."),
errorMessage: __("Failed to update audit visibility"),
},
);
}

View File

@@ -40,14 +40,6 @@ export const trustCenterQuery = graphql`
}
}
}
audits(first: 100) {
edges {
node {
id
...TrustCenterAuditsCardFragment
}
}
}
vendors(first: 100) {
edges {
node {

View File

@@ -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<CompliancePageAuditsPageQuery> }) {
const { queryRef } = props;
const { __ } = useTranslate();
const { organization } = usePreloadedQuery<CompliancePageAuditsPageQuery>(compliancePageAuditsPageQuery, queryRef);
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<h3 className="text-base font-medium">{__("Audits")}</h3>
<p className="text-sm text-txt-tertiary">
{__("Manage audit reports and compliance certifications")}
</p>
</div>
</div>
<CompliancePageAuditList fragmentRef={organization} />
</div>
);
}

View File

@@ -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>(compliancePageAuditsPageQuery);
useEffect(() => {
if (!queryRef) {
loadQuery({ organizationId });
}
});
if (!queryRef) return <LinkCardSkeleton />;
return <CompliancePageAuditsPage queryRef={queryRef} />;
}
export default function CompliancePageAuditsPageLoader() {
return (
<CoreRelayProvider>
<CompliancePageAuditsPageQueryLoader />
</CoreRelayProvider>
);
}

View File

@@ -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<number | null>(100);
const { audits, compliancePage } = useFragment<CompliancePageAuditListFragment$key>(fragment, fragmentRef);
const showMoreButton = limit !== null && audits.edges.length > limit;
return (
<div className="space-y-[10px]">
<Table>
<Thead>
<Tr>
<Th>{__("Framework")}</Th>
<Th>{__("Name")}</Th>
<Th>{__("Valid Until")}</Th>
<Th>{__("State")}</Th>
<Th>{__("Visibility")}</Th>
</Tr>
</Thead>
<Tbody>
{audits.edges.length === 0 && (
<Tr>
<Td colSpan={6} className="text-center text-txt-secondary">
{__("No audits available")}
</Td>
</Tr>
)}
{audits.edges.map(({ node: audit }) => (
<CompliancePageAuditListItem
key={audit.id}
auditFragmentRef={audit}
compliancePageFragmentRef={compliancePage}
/>
))}
</Tbody>
</Table>
{showMoreButton && (
<Button
variant="tertiary"
onClick={() => setLimit(null)}
className="mt-3 mx-auto"
icon={IconChevronDown}
>
{sprintf(__("Show %s more"), audits.edges.length - limit)}
</Button>
)}
</div>
);
}

View File

@@ -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<CompliancePageAuditListItem_compliancePageFragment$key>(
compliancePageFragment,
compliancePageFragmentRef,
);
const audit = useFragment<CompliancePageAuditListItem_auditFragment$key>(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 (
<Tr to={`/organizations/${organizationId}/audits/${audit.id}`}>
<Td>
<div className="flex gap-4 items-center">{audit.framework.name}</div>
</Td>
<Td>{audit.name || __("Untitled")}</Td>
<Td>{validUntilFormatted}</Td>
<Td>
<Badge variant={getAuditStateVariant(audit.state)}>
{getAuditStateLabel(__, audit.state)}
</Badge>
</Td>
<Td noLink width={130} className="pr-0">
<Field
type="select"
value={audit.trustCenterVisibility}
onValueChange={value => void handleVisibilityChange(value)}
disabled={isUpdatingAuditVisibility || !compliancePage.canUpdate}
className="w-[105px]"
>
{visibilityOptions.map(option => (
<Option key={option.value} value={option.value}>
<div className="flex items-center justify-between w-full">
<Badge variant={option.variant}>{option.label}</Badge>
</div>
</Option>
))}
</Field>
</Td>
</Tr>
);
}

View File

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

View File

@@ -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<TrustCenterGraphQuery$data>();
const [updateAuditVisibility, isUpdatingAudits] = useTrustCenterAuditUpdate();
const audits = (organization.audits?.edges ?? []).map(edge => edge.node);
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<h3 className="text-base font-medium">{__("Audits")}</h3>
<p className="text-sm text-txt-tertiary">
{__("Manage audit reports and compliance certifications")}
</p>
</div>
{isUpdatingAudits && <Spinner />}
</div>
<TrustCenterAuditsCard
audits={audits}
params={{}}
disabled={isUpdatingAudits}
onChangeVisibility={updateAuditVisibility}
canUpdate={!!organization.trustCenter?.canUpdate}
/>
</div>
);
}

View File

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