Add compliance frameworks

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-03-03 08:56:39 +01:00
parent 4d882e37b0
commit c17c53e80f
36 changed files with 5303 additions and 90 deletions

View File

@@ -0,0 +1,265 @@
/**
* @generated SignedSource<<8626547ee7655aabebf153f2429023d7>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type ComplianceFrameworkVisibility = "NONE" | "PUBLIC";
import { FragmentRefs } from "relay-runtime";
export type CompliancePageFrameworkList_compliancePageFragment$data = {
readonly canUpdate: boolean;
readonly complianceFrameworks: {
readonly __id: string;
readonly edges: ReadonlyArray<{
readonly node: {
readonly framework: {
readonly darkLogoURL: string | null | undefined;
readonly id: string;
readonly lightLogoURL: string | null | undefined;
readonly name: string;
};
readonly id: string;
readonly rank: number;
readonly visibility: ComplianceFrameworkVisibility;
};
}>;
};
readonly id: string;
readonly " $fragmentType": "CompliancePageFrameworkList_compliancePageFragment";
};
export type CompliancePageFrameworkList_compliancePageFragment$key = {
readonly " $data"?: CompliancePageFrameworkList_compliancePageFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"CompliancePageFrameworkList_compliancePageFragment">;
};
import CompliancePageFrameworkList_compliancePageRefetchQuery_graphql from './CompliancePageFrameworkList_compliancePageRefetchQuery.graphql';
const node: ReaderFragment = (function(){
var v0 = [
"complianceFrameworks"
],
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"argumentDefinitions": [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
{
"defaultValue": 100,
"kind": "LocalArgument",
"name": "first"
},
{
"defaultValue": {
"direction": "ASC",
"field": "RANK"
},
"kind": "LocalArgument",
"name": "order"
}
],
"kind": "Fragment",
"metadata": {
"connection": [
{
"count": "first",
"cursor": "after",
"direction": "forward",
"path": (v0/*: any*/)
}
],
"refetch": {
"connection": {
"forward": {
"count": "first",
"cursor": "after"
},
"backward": null,
"path": (v0/*: any*/)
},
"fragmentPathInResult": [
"node"
],
"operation": CompliancePageFrameworkList_compliancePageRefetchQuery_graphql,
"identifierInfo": {
"identifierField": "id",
"identifierQueryVariableName": "id"
}
}
},
"name": "CompliancePageFrameworkList_compliancePageFragment",
"selections": [
(v1/*: any*/),
{
"alias": "canUpdate",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:trust-center:update"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:trust-center:update\")"
},
{
"alias": "complianceFrameworks",
"args": [
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
],
"concreteType": "ComplianceFrameworkConnection",
"kind": "LinkedField",
"name": "__CompliancePageFrameworkList_complianceFrameworks_connection",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ComplianceFrameworkEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ComplianceFramework",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "rank",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "visibility",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "lightLogoURL",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "darkLogoURL",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
}
],
"storageKey": null
},
{
"kind": "ClientExtension",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__id",
"storageKey": null
}
]
}
],
"storageKey": null
}
],
"type": "TrustCenter",
"abstractKey": null
};
})();
(node as any).hash = "981aff9d27dc71027541f7c3ed6984a9";
export default node;

View File

@@ -0,0 +1,335 @@
/**
* @generated SignedSource<<baca8afb1ea09de1d4e9cc721fa3318e>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type ComplianceFrameworkOrderField = "CREATED_AT" | "RANK";
export type OrderDirection = "ASC" | "DESC";
export type ComplianceFrameworkOrder = {
direction: OrderDirection;
field: ComplianceFrameworkOrderField;
};
export type CompliancePageFrameworkList_compliancePageRefetchQuery$variables = {
after?: string | null | undefined;
first?: number | null | undefined;
id: string;
order?: ComplianceFrameworkOrder | null | undefined;
};
export type CompliancePageFrameworkList_compliancePageRefetchQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"CompliancePageFrameworkList_compliancePageFragment">;
};
};
export type CompliancePageFrameworkList_compliancePageRefetchQuery = {
response: CompliancePageFrameworkList_compliancePageRefetchQuery$data;
variables: CompliancePageFrameworkList_compliancePageRefetchQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
v1 = {
"defaultValue": 100,
"kind": "LocalArgument",
"name": "first"
},
v2 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "id"
},
v3 = {
"defaultValue": {
"direction": "ASC",
"field": "RANK"
},
"kind": "LocalArgument",
"name": "order"
},
v4 = [
{
"kind": "Variable",
"name": "id",
"variableName": "id"
}
],
v5 = {
"kind": "Variable",
"name": "after",
"variableName": "after"
},
v6 = {
"kind": "Variable",
"name": "first",
"variableName": "first"
},
v7 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v8 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v9 = [
(v5/*: any*/),
(v6/*: any*/),
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
];
return {
"fragment": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v3/*: any*/)
],
"kind": "Fragment",
"metadata": null,
"name": "CompliancePageFrameworkList_compliancePageRefetchQuery",
"selections": [
{
"alias": null,
"args": (v4/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"args": [
(v5/*: any*/),
(v6/*: any*/),
{
"kind": "Variable",
"name": "order",
"variableName": "order"
}
],
"kind": "FragmentSpread",
"name": "CompliancePageFrameworkList_compliancePageFragment"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v3/*: any*/),
(v2/*: any*/)
],
"kind": "Operation",
"name": "CompliancePageFrameworkList_compliancePageRefetchQuery",
"selections": [
{
"alias": null,
"args": (v4/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v7/*: any*/),
(v8/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": "canUpdate",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:trust-center:update"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:trust-center:update\")"
},
{
"alias": null,
"args": (v9/*: any*/),
"concreteType": "ComplianceFrameworkConnection",
"kind": "LinkedField",
"name": "complianceFrameworks",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ComplianceFrameworkEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ComplianceFramework",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v8/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "rank",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "visibility",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v8/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "lightLogoURL",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "darkLogoURL",
"storageKey": null
}
],
"storageKey": null
},
(v7/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
}
],
"storageKey": null
},
{
"kind": "ClientExtension",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__id",
"storageKey": null
}
]
}
],
"storageKey": null
},
{
"alias": null,
"args": (v9/*: any*/),
"filters": [
"orderBy"
],
"handle": "connection",
"key": "CompliancePageFrameworkList_complianceFrameworks",
"kind": "LinkedHandle",
"name": "complianceFrameworks"
}
],
"type": "TrustCenter",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "c3c1d708940371ebc18c2c5272f0b26d",
"id": null,
"metadata": {},
"name": "CompliancePageFrameworkList_compliancePageRefetchQuery",
"operationKind": "query",
"text": "query CompliancePageFrameworkList_compliancePageRefetchQuery(\n $after: CursorKey = null\n $first: Int = 100\n $order: ComplianceFrameworkOrder = {field: RANK, direction: ASC}\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...CompliancePageFrameworkList_compliancePageFragment_gOVF5\n id\n }\n}\n\nfragment CompliancePageFrameworkList_compliancePageFragment_gOVF5 on TrustCenter {\n id\n canUpdate: permission(action: \"core:trust-center:update\")\n complianceFrameworks(first: $first, after: $after, orderBy: $order) {\n edges {\n node {\n id\n rank\n visibility\n framework {\n id\n name\n lightLogoURL\n darkLogoURL\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n"
}
};
})();
(node as any).hash = "981aff9d27dc71027541f7c3ed6984a9";
export default node;

View File

@@ -0,0 +1,119 @@
/**
* @generated SignedSource<<2980fa2d2a72851686e88a7b5402d720>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type CreateComplianceFrameworkInput = {
frameworkId: string;
trustCenterId: string;
};
export type CompliancePageFrameworkList_createMutation$variables = {
input: CreateComplianceFrameworkInput;
};
export type CompliancePageFrameworkList_createMutation$data = {
readonly createComplianceFramework: {
readonly complianceFrameworkEdge: {
readonly node: {
readonly id: string;
};
};
};
};
export type CompliancePageFrameworkList_createMutation = {
response: CompliancePageFrameworkList_createMutation$data;
variables: CompliancePageFrameworkList_createMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "CreateComplianceFrameworkPayload",
"kind": "LinkedField",
"name": "createComplianceFramework",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ComplianceFrameworkEdge",
"kind": "LinkedField",
"name": "complianceFrameworkEdge",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ComplianceFramework",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "CompliancePageFrameworkList_createMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "CompliancePageFrameworkList_createMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "9caebfdeda321fb743a8d789c7e25e82",
"id": null,
"metadata": {},
"name": "CompliancePageFrameworkList_createMutation",
"operationKind": "mutation",
"text": "mutation CompliancePageFrameworkList_createMutation(\n $input: CreateComplianceFrameworkInput!\n) {\n createComplianceFramework(input: $input) {\n complianceFrameworkEdge {\n node {\n id\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "41815aaef15ed1754b4d81c1d982a2c6";
export default node;

View File

@@ -0,0 +1,92 @@
/**
* @generated SignedSource<<0f29d441e95842685f0311839d3b45ef>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type DeleteComplianceFrameworkInput = {
id: string;
};
export type CompliancePageFrameworkList_deleteMutation$variables = {
input: DeleteComplianceFrameworkInput;
};
export type CompliancePageFrameworkList_deleteMutation$data = {
readonly deleteComplianceFramework: {
readonly deletedComplianceFrameworkId: string;
};
};
export type CompliancePageFrameworkList_deleteMutation = {
response: CompliancePageFrameworkList_deleteMutation$data;
variables: CompliancePageFrameworkList_deleteMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "DeleteComplianceFrameworkPayload",
"kind": "LinkedField",
"name": "deleteComplianceFramework",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deletedComplianceFrameworkId",
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "CompliancePageFrameworkList_deleteMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "CompliancePageFrameworkList_deleteMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "5792168e44352169568a1378b621df16",
"id": null,
"metadata": {},
"name": "CompliancePageFrameworkList_deleteMutation",
"operationKind": "mutation",
"text": "mutation CompliancePageFrameworkList_deleteMutation(\n $input: DeleteComplianceFrameworkInput!\n) {\n deleteComplianceFramework(input: $input) {\n deletedComplianceFrameworkId\n }\n}\n"
}
};
})();
(node as any).hash = "fed45c59adf7d88aec4bbb7eb61840c3";
export default node;

View File

@@ -0,0 +1,114 @@
/**
* @generated SignedSource<<3c6052dff7f71548026fb23353e215b2>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type UpdateComplianceFrameworkInput = {
id: string;
rank: number;
};
export type CompliancePageFrameworkList_updateRankMutation$variables = {
input: UpdateComplianceFrameworkInput;
};
export type CompliancePageFrameworkList_updateRankMutation$data = {
readonly updateComplianceFramework: {
readonly complianceFramework: {
readonly id: string;
readonly rank: number;
};
};
};
export type CompliancePageFrameworkList_updateRankMutation = {
response: CompliancePageFrameworkList_updateRankMutation$data;
variables: CompliancePageFrameworkList_updateRankMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "UpdateComplianceFrameworkPayload",
"kind": "LinkedField",
"name": "updateComplianceFramework",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ComplianceFramework",
"kind": "LinkedField",
"name": "complianceFramework",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "rank",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "CompliancePageFrameworkList_updateRankMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "CompliancePageFrameworkList_updateRankMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "429989dd7550f3c5466a8098f5167592",
"id": null,
"metadata": {},
"name": "CompliancePageFrameworkList_updateRankMutation",
"operationKind": "mutation",
"text": "mutation CompliancePageFrameworkList_updateRankMutation(\n $input: UpdateComplianceFrameworkInput!\n) {\n updateComplianceFramework(input: $input) {\n complianceFramework {\n id\n rank\n }\n }\n}\n"
}
};
})();
(node as any).hash = "a60d166f55bbe09a53349b400355ffc0";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<18bb7ea1b507c374c33d9f4f7a56db2d>>
* @generated SignedSource<<cf316aa4cda5fc4c9aebae8f0f10c365>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -17,6 +17,7 @@ export type CompliancePageOverviewPageQuery$data = {
readonly organization: {
readonly compliancePage?: {
readonly canGetNDA: boolean;
readonly " $fragmentSpreads": FragmentRefs<"CompliancePageFrameworkList_compliancePageFragment">;
} | null | undefined;
readonly " $fragmentSpreads": FragmentRefs<"CompliancePageNDASectionFragment" | "CompliancePageSlackSectionFragment" | "CompliancePageStatusSectionFragment">;
};
@@ -55,12 +56,35 @@ v2 = {
"storageKey": "permission(action:\"core:trust-center:get-nda\")"
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v4 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
},
v5 = {
"kind": "Literal",
"name": "first",
"value": 100
},
v6 = [
(v5/*: any*/),
{
"kind": "Literal",
"name": "orderBy",
"value": {
"direction": "ASC",
"field": "RANK"
}
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
@@ -87,7 +111,12 @@ return {
"name": "trustCenter",
"plural": false,
"selections": [
(v2/*: any*/)
(v2/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
"name": "CompliancePageFrameworkList_compliancePageFragment"
}
],
"storageKey": null
}
@@ -131,13 +160,7 @@ return {
"name": "node",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
(v3/*: any*/),
{
"kind": "InlineFragment",
"selections": [
@@ -150,14 +173,7 @@ return {
"plural": false,
"selections": [
(v2/*: any*/),
(v3/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
(v4/*: any*/),
{
"alias": "canUpdate",
"args": [
@@ -171,6 +187,150 @@ return {
"name": "permission",
"storageKey": "permission(action:\"core:trust-center:update\")"
},
{
"alias": null,
"args": (v6/*: any*/),
"concreteType": "ComplianceFrameworkConnection",
"kind": "LinkedField",
"name": "complianceFrameworks",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ComplianceFrameworkEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ComplianceFramework",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v4/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "rank",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "visibility",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v4/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "lightLogoURL",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "darkLogoURL",
"storageKey": null
}
],
"storageKey": null
},
(v3/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
}
],
"storageKey": null
},
{
"kind": "ClientExtension",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__id",
"storageKey": null
}
]
}
],
"storageKey": "complianceFrameworks(first:100,orderBy:{\"direction\":\"ASC\",\"field\":\"RANK\"})"
},
{
"alias": null,
"args": (v6/*: any*/),
"filters": [
"orderBy"
],
"handle": "connection",
"key": "CompliancePageFrameworkList_complianceFrameworks",
"kind": "LinkedHandle",
"name": "complianceFrameworks"
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -229,18 +389,14 @@ return {
"name": "domain",
"storageKey": null
},
(v3/*: any*/)
(v4/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": [
{
"kind": "Literal",
"name": "first",
"value": 100
}
(v5/*: any*/)
],
"concreteType": "SlackConnectionConnection",
"kind": "LinkedField",
@@ -263,7 +419,7 @@ return {
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
(v4/*: any*/),
{
"alias": null,
"args": null,
@@ -291,23 +447,23 @@ return {
"type": "Organization",
"abstractKey": null
},
(v3/*: any*/)
(v4/*: any*/)
],
"storageKey": null
}
]
},
"params": {
"cacheID": "0041132d3ac46a3193d9acbd6f27bdf5",
"cacheID": "e6cc68fe4df4a8dffc558f6db82ead9c",
"id": null,
"metadata": {},
"name": "CompliancePageOverviewPageQuery",
"operationKind": "query",
"text": "query CompliancePageOverviewPageQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n compliancePage: trustCenter {\n canGetNDA: permission(action: \"core:trust-center:get-nda\")\n id\n }\n }\n ...CompliancePageStatusSectionFragment\n ...CompliancePageNDASectionFragment\n ...CompliancePageSlackSectionFragment\n id\n }\n}\n\nfragment CompliancePageNDASectionFragment on Organization {\n compliancePage: trustCenter {\n id\n ndaFileName\n ndaFileUrl\n canUpdate: permission(action: \"core:trust-center:update\")\n canUploadNDA: permission(action: \"core:trust-center:upload-nda\")\n canDeleteNDA: permission(action: \"core:trust-center:delete-nda\")\n }\n}\n\nfragment CompliancePageSlackSectionFragment on Organization {\n compliancePage: trustCenter {\n canUpdate: permission(action: \"core:trust-center:update\")\n id\n }\n slackConnections(first: 100) {\n edges {\n node {\n id\n channel\n createdAt\n }\n }\n }\n}\n\nfragment CompliancePageStatusSectionFragment on Organization {\n customDomain {\n domain\n id\n }\n compliancePage: trustCenter {\n id\n active\n canUpdate: permission(action: \"core:trust-center:update\")\n }\n}\n"
"text": "query CompliancePageOverviewPageQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n compliancePage: trustCenter {\n canGetNDA: permission(action: \"core:trust-center:get-nda\")\n ...CompliancePageFrameworkList_compliancePageFragment\n id\n }\n }\n ...CompliancePageStatusSectionFragment\n ...CompliancePageNDASectionFragment\n ...CompliancePageSlackSectionFragment\n id\n }\n}\n\nfragment CompliancePageFrameworkList_compliancePageFragment on TrustCenter {\n id\n canUpdate: permission(action: \"core:trust-center:update\")\n complianceFrameworks(first: 100, orderBy: {field: RANK, direction: ASC}) {\n edges {\n node {\n id\n rank\n visibility\n framework {\n id\n name\n lightLogoURL\n darkLogoURL\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment CompliancePageNDASectionFragment on Organization {\n compliancePage: trustCenter {\n id\n ndaFileName\n ndaFileUrl\n canUpdate: permission(action: \"core:trust-center:update\")\n canUploadNDA: permission(action: \"core:trust-center:upload-nda\")\n canDeleteNDA: permission(action: \"core:trust-center:delete-nda\")\n }\n}\n\nfragment CompliancePageSlackSectionFragment on Organization {\n compliancePage: trustCenter {\n canUpdate: permission(action: \"core:trust-center:update\")\n id\n }\n slackConnections(first: 100) {\n edges {\n node {\n id\n channel\n createdAt\n }\n }\n }\n}\n\nfragment CompliancePageStatusSectionFragment on Organization {\n customDomain {\n domain\n id\n }\n compliancePage: trustCenter {\n id\n active\n canUpdate: permission(action: \"core:trust-center:update\")\n }\n}\n"
}
};
})();
(node as any).hash = "689133b7f1c380266e6f15a60c527c91";
(node as any).hash = "be0dff83941c21755ea2ff77a865805b";
export default node;

View File

@@ -1,8 +1,10 @@
import { useTranslate } from "@probo/i18n";
import { type PreloadedQuery, usePreloadedQuery } from "react-relay";
import { graphql } from "relay-runtime";
import type { CompliancePageOverviewPageQuery } from "#/__generated__/core/CompliancePageOverviewPageQuery.graphql";
import { CompliancePageFrameworkList } from "./_components/CompliancePageFrameworkList";
import { CompliancePageNDASection } from "./_components/CompliancePageNDASection";
import { CompliancePageSlackSection } from "./_components/CompliancePageSlackSection";
import { CompliancePageStatusSection } from "./_components/CompliancePageStatusSection";
@@ -13,6 +15,7 @@ export const compliancePageOverviewPageQuery = graphql`
... on Organization {
compliancePage: trustCenter {
canGetNDA: permission(action: "core:trust-center:get-nda")
...CompliancePageFrameworkList_compliancePageFragment
}
}
...CompliancePageStatusSectionFragment
@@ -25,6 +28,8 @@ export const compliancePageOverviewPageQuery = graphql`
export function CompliancePageOverviewPage(props: { queryRef: PreloadedQuery<CompliancePageOverviewPageQuery> }) {
const { queryRef } = props;
const { __ } = useTranslate();
const { organization } = usePreloadedQuery<CompliancePageOverviewPageQuery>(
compliancePageOverviewPageQuery,
queryRef,
@@ -39,6 +44,18 @@ export function CompliancePageOverviewPage(props: { queryRef: PreloadedQuery<Com
)}
<CompliancePageSlackSection fragmentRef={organization} />
{organization.compliancePage && (
<div className="space-y-4">
<div>
<h3 className="text-base font-medium">{__("Frameworks")}</h3>
<p className="text-sm text-txt-tertiary">
{__("Select which frameworks to display as badges on your compliance page")}
</p>
</div>
<CompliancePageFrameworkList compliancePageRef={organization.compliancePage} />
</div>
)}
</div>
);
}

View File

@@ -0,0 +1,358 @@
import { useTranslate } from "@probo/i18n";
import { Badge, Field, FrameworkLogo, Option, Table, Tbody, Td, Th, Thead, Tr } from "@probo/ui";
import { useCallback, useState, useTransition } from "react";
import { useRefetchableFragment } from "react-relay";
import { ConnectionHandler, graphql } from "relay-runtime";
import type { CompliancePageFrameworkList_compliancePageFragment$key } from "#/__generated__/core/CompliancePageFrameworkList_compliancePageFragment.graphql";
import type { CompliancePageFrameworkList_compliancePageFragment$data } from "#/__generated__/core/CompliancePageFrameworkList_compliancePageFragment.graphql";
import type { CompliancePageFrameworkList_compliancePageRefetchQuery } from "#/__generated__/core/CompliancePageFrameworkList_compliancePageRefetchQuery.graphql";
import type { CompliancePageFrameworkList_createMutation } from "#/__generated__/core/CompliancePageFrameworkList_createMutation.graphql";
import type { CompliancePageFrameworkList_deleteMutation } from "#/__generated__/core/CompliancePageFrameworkList_deleteMutation.graphql";
import type { CompliancePageFrameworkList_updateRankMutation } from "#/__generated__/core/CompliancePageFrameworkList_updateRankMutation.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
const compliancePageFragment = graphql`
fragment CompliancePageFrameworkList_compliancePageFragment on TrustCenter
@refetchable(queryName: "CompliancePageFrameworkList_compliancePageRefetchQuery")
@argumentDefinitions(
first: { type: Int, defaultValue: 100 }
after: { type: CursorKey, defaultValue: null }
order: { type: ComplianceFrameworkOrder, defaultValue: { field: RANK, direction: ASC } }
) {
id
canUpdate: permission(action: "core:trust-center:update")
complianceFrameworks(first: $first, after: $after, orderBy: $order)
@connection(key: "CompliancePageFrameworkList_complianceFrameworks", filters: ["orderBy"]) {
__id
edges {
node {
id
rank
visibility
framework {
id
name
lightLogoURL
darkLogoURL
}
}
}
}
}
`;
const createMutation = graphql`
mutation CompliancePageFrameworkList_createMutation($input: CreateComplianceFrameworkInput!) {
createComplianceFramework(input: $input) {
complianceFrameworkEdge {
node {
id
}
}
}
}
`;
const updateRankMutation = graphql`
mutation CompliancePageFrameworkList_updateRankMutation($input: UpdateComplianceFrameworkInput!) {
updateComplianceFramework(input: $input) {
complianceFramework {
id
rank
}
}
}
`;
const deleteMutation = graphql`
mutation CompliancePageFrameworkList_deleteMutation($input: DeleteComplianceFrameworkInput!) {
deleteComplianceFramework(input: $input) {
deletedComplianceFrameworkId
}
}
`;
type Edge = CompliancePageFrameworkList_compliancePageFragment$data["complianceFrameworks"]["edges"][number];
function CompliancePageFrameworkListItem(props: {
edge: Edge;
compliancePage: CompliancePageFrameworkList_compliancePageFragment$data;
draggedCfId: string | null;
dragOverCfId: string | null;
onDragStart: (cfId: string) => void;
onDragEnd: () => void;
onDragOver: (e: React.DragEvent, cfId: string) => void;
onDrop: (cfId: string) => void;
onRefetch: () => void;
}) {
const { edge, draggedCfId, dragOverCfId, onDragStart, onDragEnd, onDragOver, onDrop, onRefetch } = props;
const { __ } = useTranslate();
const [isMouseDown, setIsMouseDown] = useState(false);
const compliancePage = props.compliancePage;
const { id, visibility, framework } = edge.node;
const isPublic = visibility === "PUBLIC";
const canDrag = isPublic && compliancePage.canUpdate;
const isDragging = draggedCfId === id;
const isDropTarget = dragOverCfId === id && draggedCfId !== id;
const [createComplianceFramework, isCreating] = useMutationWithToasts<CompliancePageFrameworkList_createMutation>(
createMutation,
{
successMessage: __("Framework visibility updated successfully."),
errorMessage: __("Failed to update framework visibility"),
},
);
const [deleteComplianceFramework, isDeleting] = useMutationWithToasts<CompliancePageFrameworkList_deleteMutation>(
deleteMutation,
{
successMessage: __("Framework visibility updated successfully."),
errorMessage: __("Failed to update framework visibility"),
},
);
const isLoading = isCreating || isDeleting;
const handleVisibilityChange = useCallback(
async (value: string) => {
if (value === "PUBLIC" && !isPublic) {
await createComplianceFramework({
variables: {
input: {
trustCenterId: compliancePage.id,
frameworkId: framework.id,
},
},
onCompleted: (_, errors) => {
if (!errors?.length) {
onRefetch();
}
},
});
} else if (value === "NONE" && isPublic) {
await deleteComplianceFramework({
variables: {
input: { id },
},
onCompleted: (_, errors) => {
if (!errors?.length) {
onRefetch();
}
},
});
}
},
[compliancePage.id, framework.id, id, isPublic, onRefetch, createComplianceFramework, deleteComplianceFramework],
);
const visibilityOptions = [
{ value: "PUBLIC", label: __("Public"), variant: "success" as const },
{ value: "NONE", label: __("None"), variant: "neutral" as const },
];
const rowClassName = [
canDrag && isDragging && "opacity-50 cursor-grabbing",
canDrag && !isDragging && !isMouseDown && "cursor-grab",
canDrag && !isDragging && isMouseDown && "cursor-grabbing",
isDropTarget && "!bg-primary-50 border-y-2 border-primary-500",
]
.filter(Boolean)
.join(" ");
return (
<Tr
draggable={canDrag}
onDragStart={canDrag ? () => onDragStart(id) : undefined}
onDragEnd={canDrag ? onDragEnd : undefined}
onDragOver={canDrag ? e => onDragOver(e, id) : undefined}
onDrop={
canDrag
? (e) => {
e.preventDefault();
onDrop(id);
}
: undefined
}
onMouseDown={canDrag ? () => setIsMouseDown(true) : undefined}
onMouseUp={canDrag ? () => setIsMouseDown(false) : undefined}
onMouseLeave={canDrag ? () => setIsMouseDown(false) : undefined}
className={rowClassName}
>
<Td>
<div className="flex items-center gap-3">
<FrameworkLogo
className="size-8"
lightLogoURL={framework.lightLogoURL}
darkLogoURL={framework.darkLogoURL}
name={framework.name}
/>
{framework.name}
</div>
</Td>
<Td noLink width={130} className="pr-0">
<Field
type="select"
value={visibility}
onValueChange={value => void handleVisibilityChange(value)}
disabled={isLoading || !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>
);
}
export function CompliancePageFrameworkList(props: {
compliancePageRef: CompliancePageFrameworkList_compliancePageFragment$key;
}) {
const { __ } = useTranslate();
const [, startTransition] = useTransition();
const [compliancePage, refetch] = useRefetchableFragment<
CompliancePageFrameworkList_compliancePageRefetchQuery,
CompliancePageFrameworkList_compliancePageFragment$key
>(compliancePageFragment, props.compliancePageRef);
const [updateRank] = useMutationWithToasts<CompliancePageFrameworkList_updateRankMutation>(
updateRankMutation,
{
successMessage: __("Order updated successfully"),
errorMessage: __("Failed to update order"),
},
);
const [draggedCfId, setDraggedCfId] = useState<string | null>(null);
const [dragOverCfId, setDragOverCfId] = useState<string | null>(null);
const allEdges = compliancePage.complianceFrameworks.edges;
const publicEdges = allEdges.filter(e => e.node.visibility === "PUBLIC");
const handleDragStart = (cfId: string) => {
setDraggedCfId(cfId);
};
const handleDragEnd = () => {
setDraggedCfId(null);
setDragOverCfId(null);
};
const handleDragOver = (e: React.DragEvent, cfId: string) => {
e.preventDefault();
if (draggedCfId !== cfId) {
setDragOverCfId(cfId);
}
};
const handleDrop = async (targetCfId: string) => {
if (!draggedCfId || draggedCfId === targetCfId) {
setDraggedCfId(null);
setDragOverCfId(null);
return;
}
const targetEdge = publicEdges.find(e => e.node.id === targetCfId);
if (!targetEdge) {
setDraggedCfId(null);
setDragOverCfId(null);
return;
}
const draggedId = draggedCfId;
await updateRank({
variables: {
input: {
id: draggedId,
rank: targetEdge.node.rank,
},
},
updater: (store) => {
const trustCenterRecord = store.get(compliancePage.id);
if (!trustCenterRecord) return;
const connection = ConnectionHandler.getConnection(
trustCenterRecord,
"CompliancePageFrameworkList_complianceFrameworks",
{ orderBy: { field: "RANK", direction: "ASC" } },
);
if (!connection) return;
const edges = connection.getLinkedRecords("edges");
if (!edges) return;
const fromIdx = edges.findIndex(e => e.getLinkedRecord("node")?.getDataID() === draggedId);
const toIdx = edges.findIndex(e => e.getLinkedRecord("node")?.getDataID() === targetCfId);
if (fromIdx === -1 || toIdx === -1) return;
const reordered = [...edges];
const [moved] = reordered.splice(fromIdx, 1);
reordered.splice(toIdx, 0, moved);
connection.setLinkedRecords(reordered, "edges");
},
onCompleted: (_, errors) => {
startTransition(() => {
refetch({}, { fetchPolicy: errors?.length ? "network-only" : "store-and-network" });
});
},
});
setDraggedCfId(null);
setDragOverCfId(null);
};
const hasMultiplePublic = publicEdges.length > 1;
return (
<>
<Table>
<Thead>
<Tr>
<Th>{__("Framework")}</Th>
<Th>{__("Visibility")}</Th>
</Tr>
</Thead>
<Tbody>
{allEdges.length === 0 && (
<Tr>
<Td colSpan={2} className="text-center text-txt-secondary">
{__("No frameworks available")}
</Td>
</Tr>
)}
{allEdges.map(edge => (
<CompliancePageFrameworkListItem
key={edge.node.id}
edge={edge}
compliancePage={compliancePage}
draggedCfId={draggedCfId}
dragOverCfId={dragOverCfId}
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
onDragOver={handleDragOver}
onDrop={cfId => void handleDrop(cfId)}
onRefetch={() => startTransition(() => { refetch({}, { fetchPolicy: "store-and-network" }); })}
/>
))}
</Tbody>
</Table>
{hasMultiplePublic && compliancePage.canUpdate && (
<p className="text-sm text-txt-tertiary">
{__("Drag and drop public frameworks to change their displayed order")}
</p>
)}
</>
);
}

View File

@@ -126,7 +126,7 @@ export function CompliancePageReferenceList(props: {
</Tbody>
</Table>
<p className="text-xs text-txt-tertiary">
<p className="text-sm text-txt-tertiary">
{__("Drag and drop references to change their displayed order")}
</p>
</>