Fix framework pages permissions handling

Signed-off-by: Émile Ré <nemile.re@gmail.com>
This commit is contained in:
Émile Ré
2025-12-31 17:49:56 +01:00
committed by Bryan Frimin
parent 269f963b48
commit 095254a73d
11 changed files with 663 additions and 188 deletions

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<1c21fa202a0315a19517c79eb93932f3>>
* @generated SignedSource<<7f57391fcdf09c326854f1cc2e0008c2>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -12,6 +12,10 @@ import { ReaderFragment } from 'relay-runtime';
export type ControlStatus = "EXCLUDED" | "INCLUDED";
import { FragmentRefs } from "relay-runtime";
export type FrameworkDetailPageFragment$data = {
readonly canCreateControl: boolean;
readonly canDelete: boolean;
readonly canExport: boolean;
readonly canUpdate: boolean;
readonly controls: {
readonly __id: string;
readonly edges: ReadonlyArray<{
@@ -84,6 +88,58 @@ return {
"name": "darkLogoURL",
"storageKey": null
},
{
"alias": "canExport",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:franework:export"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:franework:export\")"
},
{
"alias": "canUpdate",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:update"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:update\")"
},
{
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:delete\")"
},
{
"alias": "canCreateControl",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:create"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:create\")"
},
{
"alias": null,
"args": null,
@@ -191,6 +247,6 @@ return {
};
})();
(node as any).hash = "e7be231a4f5cbad12945d2ca627cc442";
(node as any).hash = "c88994d5f1872bfe21cfe65e1911b76a";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<af136d6db1a014d6241ad2c9c6dd5f55>>
* @generated SignedSource<<3e99dde71cf9c37ef1ec401a9e76bb6c>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -173,6 +173,32 @@ return {
"kind": "ScalarField",
"name": "darkLogoURL",
"storageKey": null
},
{
"alias": "canUpdate",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:update"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:update\")"
},
{
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:delete\")"
}
],
"storageKey": null
@@ -202,12 +228,12 @@ return {
]
},
"params": {
"cacheID": "c66177d87b59d87fdf7cbc9268af431a",
"cacheID": "a26c4f5b9c310055da331176905fc712",
"id": null,
"metadata": {},
"name": "FrameworkFormDialogMutation",
"operationKind": "mutation",
"text": "mutation FrameworkFormDialogMutation(\n $input: CreateFrameworkInput!\n) {\n createFramework(input: $input) {\n frameworkEdge {\n node {\n id\n ...FrameworksPageCardFragment\n }\n }\n }\n}\n\nfragment FrameworksPageCardFragment on Framework {\n id\n name\n description\n lightLogoURL\n darkLogoURL\n}\n"
"text": "mutation FrameworkFormDialogMutation(\n $input: CreateFrameworkInput!\n) {\n createFramework(input: $input) {\n frameworkEdge {\n node {\n id\n ...FrameworksPageCardFragment\n }\n }\n }\n}\n\nfragment FrameworksPageCardFragment on Framework {\n id\n name\n description\n lightLogoURL\n darkLogoURL\n canUpdate: permission(action: \"core:framework:update\")\n canDelete: permission(action: \"core:framework:delete\")\n}\n"
}
};
})();

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<ec1b843d1afb3a82c747b8580b528fda>>
* @generated SignedSource<<194328b415c68a01a447d4646639b3c0>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -25,6 +25,20 @@ export type FrameworkGraphControlNodeQuery$data = {
};
}>;
};
readonly canCreateAuditMapping?: boolean;
readonly canCreateDocumentMapping?: boolean;
readonly canCreateMeasureMapping?: boolean;
readonly canCreateObligationMapping?: boolean;
readonly canCreateSnapshotMapping?: boolean;
readonly canCreateStateOfApplicabilityMapping?: boolean;
readonly canDelete?: boolean;
readonly canDeleteAuditMapping?: boolean;
readonly canDeleteDocumentMapping?: boolean;
readonly canDeleteMeasureMapping?: boolean;
readonly canDeleteObligationMapping?: boolean;
readonly canDeleteSnapshotMapping?: boolean;
readonly canDeleteStateOfApplicabilityMapping?: boolean;
readonly canUpdate?: boolean;
readonly description?: string | null | undefined;
readonly documents?: {
readonly __id: string;
@@ -142,20 +156,202 @@ v7 = {
"storageKey": null
},
v8 = {
"alias": "canUpdate",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:update"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:update\")"
},
v9 = {
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:delete\")"
},
v10 = {
"alias": "canCreateMeasureMapping",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:create-measure-mapping"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:create-measure-mapping\")"
},
v11 = {
"alias": "canDeleteMeasureMapping",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:delete-measure-mapping"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:delete-measure-mapping\")"
},
v12 = {
"alias": "canCreateDocumentMapping",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:create-document-mapping"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:create-document-mapping\")"
},
v13 = {
"alias": "canDeleteDocumentMapping",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:delete-document-mapping"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:delete-document-mapping\")"
},
v14 = {
"alias": "canCreateAuditMapping",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:create-audit-mapping"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:create-audit-mapping\")"
},
v15 = {
"alias": "canDeleteAuditMapping",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:delete-audit-mapping"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:delete-audit-mapping\")"
},
v16 = {
"alias": "canCreateSnapshotMapping",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:create-snapshot-mapping"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:create-snapshot-mapping\")"
},
v17 = {
"alias": "canDeleteSnapshotMapping",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:delete-snapshot-mapping"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:delete-snapshot-mapping\")"
},
v18 = {
"alias": "canCreateStateOfApplicabilityMapping",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:state-of-applicability-control-mapping:create"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:state-of-applicability-control-mapping:create\")"
},
v19 = {
"alias": "canDeleteStateOfApplicabilityMapping",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:state-of-applicability-control-mapping:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:state-of-applicability-control-mapping:delete\")"
},
v20 = {
"alias": "canCreateObligationMapping",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:obligation-control-mapping:create"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:obligation-control-mapping:create\")"
},
v21 = {
"alias": "canDeleteObligationMapping",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:obligation-control-mapping:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:obligation-control-mapping:delete\")"
},
v22 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v9 = {
v23 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
},
v10 = {
v24 = {
"alias": null,
"args": null,
"concreteType": "PageInfo",
@@ -180,7 +376,7 @@ v10 = {
],
"storageKey": null
},
v11 = {
v25 = {
"kind": "ClientExtension",
"selections": [
{
@@ -192,25 +388,25 @@ v11 = {
}
]
},
v12 = [
v26 = [
{
"kind": "Literal",
"name": "first",
"value": 100
}
],
v13 = [
v27 = [
(v2/*: any*/),
(v3/*: any*/)
],
v14 = {
v28 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "state",
"storageKey": null
},
v15 = {
v29 = {
"alias": null,
"args": null,
"kind": "ScalarField",
@@ -241,6 +437,20 @@ return {
(v5/*: any*/),
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
(v11/*: any*/),
(v12/*: any*/),
(v13/*: any*/),
(v14/*: any*/),
(v15/*: any*/),
(v16/*: any*/),
(v17/*: any*/),
(v18/*: any*/),
(v19/*: any*/),
(v20/*: any*/),
(v21/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
@@ -276,16 +486,16 @@ return {
"kind": "FragmentSpread",
"name": "LinkedStatesOfApplicabilityCardFragment"
},
(v8/*: any*/)
(v22/*: any*/)
],
"storageKey": null
},
(v9/*: any*/)
(v23/*: any*/)
],
"storageKey": null
},
(v10/*: any*/),
(v11/*: any*/)
(v24/*: any*/),
(v25/*: any*/)
],
"storageKey": null
},
@@ -319,16 +529,16 @@ return {
"kind": "FragmentSpread",
"name": "LinkedMeasuresCardFragment"
},
(v8/*: any*/)
(v22/*: any*/)
],
"storageKey": null
},
(v9/*: any*/)
(v23/*: any*/)
],
"storageKey": null
},
(v10/*: any*/),
(v11/*: any*/)
(v24/*: any*/),
(v25/*: any*/)
],
"storageKey": null
},
@@ -362,16 +572,16 @@ return {
"kind": "FragmentSpread",
"name": "LinkedDocumentsCardFragment"
},
(v8/*: any*/)
(v22/*: any*/)
],
"storageKey": null
},
(v9/*: any*/)
(v23/*: any*/)
],
"storageKey": null
},
(v10/*: any*/),
(v11/*: any*/)
(v24/*: any*/),
(v25/*: any*/)
],
"storageKey": null
},
@@ -405,16 +615,16 @@ return {
"kind": "FragmentSpread",
"name": "LinkedAuditsCardFragment"
},
(v8/*: any*/)
(v22/*: any*/)
],
"storageKey": null
},
(v9/*: any*/)
(v23/*: any*/)
],
"storageKey": null
},
(v10/*: any*/),
(v11/*: any*/)
(v24/*: any*/),
(v25/*: any*/)
],
"storageKey": null
},
@@ -448,16 +658,16 @@ return {
"kind": "FragmentSpread",
"name": "LinkedObligationsCardFragment"
},
(v8/*: any*/)
(v22/*: any*/)
],
"storageKey": null
},
(v9/*: any*/)
(v23/*: any*/)
],
"storageKey": null
},
(v10/*: any*/),
(v11/*: any*/)
(v24/*: any*/),
(v25/*: any*/)
],
"storageKey": null
},
@@ -491,16 +701,16 @@ return {
"kind": "FragmentSpread",
"name": "LinkedSnapshotsCardFragment"
},
(v8/*: any*/)
(v22/*: any*/)
],
"storageKey": null
},
(v9/*: any*/)
(v23/*: any*/)
],
"storageKey": null
},
(v10/*: any*/),
(v11/*: any*/)
(v24/*: any*/),
(v25/*: any*/)
],
"storageKey": null
}
@@ -529,7 +739,7 @@ return {
"name": "node",
"plural": false,
"selections": [
(v8/*: any*/),
(v22/*: any*/),
(v2/*: any*/),
{
"kind": "InlineFragment",
@@ -539,6 +749,20 @@ return {
(v5/*: any*/),
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
(v11/*: any*/),
(v12/*: any*/),
(v13/*: any*/),
(v14/*: any*/),
(v15/*: any*/),
(v16/*: any*/),
(v17/*: any*/),
(v18/*: any*/),
(v19/*: any*/),
(v20/*: any*/),
(v21/*: any*/),
{
"alias": null,
"args": null,
@@ -548,7 +772,7 @@ return {
},
{
"alias": null,
"args": (v12/*: any*/),
"args": (v26/*: any*/),
"concreteType": "StateOfApplicabilityControlConnection",
"kind": "LinkedField",
"name": "stateOfApplicabilityControls",
@@ -592,7 +816,7 @@ return {
"kind": "LinkedField",
"name": "stateOfApplicability",
"plural": false,
"selections": (v13/*: any*/),
"selections": (v27/*: any*/),
"storageKey": null
},
{
@@ -609,22 +833,22 @@ return {
"name": "justification",
"storageKey": null
},
(v8/*: any*/)
(v22/*: any*/)
],
"storageKey": null
},
(v9/*: any*/)
(v23/*: any*/)
],
"storageKey": null
},
(v10/*: any*/),
(v11/*: any*/)
(v24/*: any*/),
(v25/*: any*/)
],
"storageKey": "stateOfApplicabilityControls(first:100)"
},
{
"alias": null,
"args": (v12/*: any*/),
"args": (v26/*: any*/),
"filters": null,
"handle": "connection",
"key": "FrameworkGraphControl_stateOfApplicabilityControls",
@@ -633,7 +857,7 @@ return {
},
{
"alias": null,
"args": (v12/*: any*/),
"args": (v26/*: any*/),
"concreteType": "MeasureConnection",
"kind": "LinkedField",
"name": "measures",
@@ -657,23 +881,23 @@ return {
"selections": [
(v2/*: any*/),
(v3/*: any*/),
(v14/*: any*/),
(v8/*: any*/)
(v28/*: any*/),
(v22/*: any*/)
],
"storageKey": null
},
(v9/*: any*/)
(v23/*: any*/)
],
"storageKey": null
},
(v10/*: any*/),
(v11/*: any*/)
(v24/*: any*/),
(v25/*: any*/)
],
"storageKey": "measures(first:100)"
},
{
"alias": null,
"args": (v12/*: any*/),
"args": (v26/*: any*/),
"filters": null,
"handle": "connection",
"key": "FrameworkGraphControl_measures",
@@ -682,7 +906,7 @@ return {
},
{
"alias": null,
"args": (v12/*: any*/),
"args": (v26/*: any*/),
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "documents",
@@ -712,7 +936,7 @@ return {
"name": "title",
"storageKey": null
},
(v15/*: any*/),
(v29/*: any*/),
{
"alias": null,
"args": null,
@@ -761,22 +985,22 @@ return {
],
"storageKey": "versions(first:1)"
},
(v8/*: any*/)
(v22/*: any*/)
],
"storageKey": null
},
(v9/*: any*/)
(v23/*: any*/)
],
"storageKey": null
},
(v10/*: any*/),
(v11/*: any*/)
(v24/*: any*/),
(v25/*: any*/)
],
"storageKey": "documents(first:100)"
},
{
"alias": null,
"args": (v12/*: any*/),
"args": (v26/*: any*/),
"filters": null,
"handle": "connection",
"key": "FrameworkGraphControl_documents",
@@ -785,7 +1009,7 @@ return {
},
{
"alias": null,
"args": (v12/*: any*/),
"args": (v26/*: any*/),
"concreteType": "AuditConnection",
"kind": "LinkedField",
"name": "audits",
@@ -809,8 +1033,8 @@ return {
"selections": [
(v2/*: any*/),
(v3/*: any*/),
(v15/*: any*/),
(v14/*: any*/),
(v29/*: any*/),
(v28/*: any*/),
{
"alias": null,
"args": null,
@@ -832,25 +1056,25 @@ return {
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": (v13/*: any*/),
"selections": (v27/*: any*/),
"storageKey": null
},
(v8/*: any*/)
(v22/*: any*/)
],
"storageKey": null
},
(v9/*: any*/)
(v23/*: any*/)
],
"storageKey": null
},
(v10/*: any*/),
(v11/*: any*/)
(v24/*: any*/),
(v25/*: any*/)
],
"storageKey": "audits(first:100)"
},
{
"alias": null,
"args": (v12/*: any*/),
"args": (v26/*: any*/),
"filters": null,
"handle": "connection",
"key": "FrameworkGraphControl_audits",
@@ -859,7 +1083,7 @@ return {
},
{
"alias": null,
"args": (v12/*: any*/),
"args": (v26/*: any*/),
"concreteType": "ObligationConnection",
"kind": "LinkedField",
"name": "obligations",
@@ -923,22 +1147,22 @@ return {
],
"storageKey": null
},
(v8/*: any*/)
(v22/*: any*/)
],
"storageKey": null
},
(v9/*: any*/)
(v23/*: any*/)
],
"storageKey": null
},
(v10/*: any*/),
(v11/*: any*/)
(v24/*: any*/),
(v25/*: any*/)
],
"storageKey": "obligations(first:100)"
},
{
"alias": null,
"args": (v12/*: any*/),
"args": (v26/*: any*/),
"filters": null,
"handle": "connection",
"key": "FrameworkGraphControl_obligations",
@@ -947,7 +1171,7 @@ return {
},
{
"alias": null,
"args": (v12/*: any*/),
"args": (v26/*: any*/),
"concreteType": "SnapshotConnection",
"kind": "LinkedField",
"name": "snapshots",
@@ -979,23 +1203,23 @@ return {
"name": "type",
"storageKey": null
},
(v15/*: any*/),
(v8/*: any*/)
(v29/*: any*/),
(v22/*: any*/)
],
"storageKey": null
},
(v9/*: any*/)
(v23/*: any*/)
],
"storageKey": null
},
(v10/*: any*/),
(v11/*: any*/)
(v24/*: any*/),
(v25/*: any*/)
],
"storageKey": "snapshots(first:100)"
},
{
"alias": null,
"args": (v12/*: any*/),
"args": (v26/*: any*/),
"filters": null,
"handle": "connection",
"key": "FrameworkGraphControl_snapshots",
@@ -1012,7 +1236,7 @@ return {
]
},
"params": {
"cacheID": "f7773b474bf5f22e9a7075c685839001",
"cacheID": "83f936f5dced0f50c645aa6ef30efedc",
"id": null,
"metadata": {
"connection": [
@@ -1074,11 +1298,11 @@ return {
},
"name": "FrameworkGraphControlNodeQuery",
"operationKind": "query",
"text": "query FrameworkGraphControlNodeQuery(\n $controlId: ID!\n) {\n node(id: $controlId) {\n __typename\n ... on Control {\n id\n name\n sectionTitle\n description\n status\n exclusionJustification\n ...FrameworkControlDialogFragment\n stateOfApplicabilityControls(first: 100) {\n edges {\n node {\n id\n ...LinkedStatesOfApplicabilityCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n measures(first: 100) {\n edges {\n node {\n id\n ...LinkedMeasuresCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n documents(first: 100) {\n edges {\n node {\n id\n ...LinkedDocumentsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n audits(first: 100) {\n edges {\n node {\n id\n ...LinkedAuditsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n obligations(first: 100) {\n edges {\n node {\n id\n ...LinkedObligationsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n snapshots(first: 100) {\n edges {\n node {\n id\n ...LinkedSnapshotsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n\nfragment FrameworkControlDialogFragment on Control {\n id\n name\n description\n sectionTitle\n status\n exclusionJustification\n bestPractice\n}\n\nfragment LinkedAuditsCardFragment on Audit {\n id\n name\n createdAt\n state\n validFrom\n validUntil\n framework {\n id\n name\n }\n}\n\nfragment LinkedDocumentsCardFragment on Document {\n id\n title\n createdAt\n documentType\n versions(first: 1) {\n edges {\n node {\n id\n status\n }\n }\n }\n}\n\nfragment LinkedMeasuresCardFragment on Measure {\n id\n name\n state\n}\n\nfragment LinkedObligationsCardFragment on Obligation {\n id\n requirement\n area\n source\n status\n owner {\n fullName\n id\n }\n}\n\nfragment LinkedSnapshotsCardFragment on Snapshot {\n id\n name\n description\n type\n createdAt\n}\n\nfragment LinkedStatesOfApplicabilityCardFragment on StateOfApplicabilityControl {\n id\n stateOfApplicabilityId\n controlId\n stateOfApplicability {\n id\n name\n }\n applicability\n justification\n}\n"
"text": "query FrameworkGraphControlNodeQuery(\n $controlId: ID!\n) {\n node(id: $controlId) {\n __typename\n ... on Control {\n id\n name\n sectionTitle\n description\n status\n exclusionJustification\n canUpdate: permission(action: \"core:control:update\")\n canDelete: permission(action: \"core:control:delete\")\n canCreateMeasureMapping: permission(action: \"core:control:create-measure-mapping\")\n canDeleteMeasureMapping: permission(action: \"core:control:delete-measure-mapping\")\n canCreateDocumentMapping: permission(action: \"core:control:create-document-mapping\")\n canDeleteDocumentMapping: permission(action: \"core:control:delete-document-mapping\")\n canCreateAuditMapping: permission(action: \"core:control:create-audit-mapping\")\n canDeleteAuditMapping: permission(action: \"core:control:delete-audit-mapping\")\n canCreateSnapshotMapping: permission(action: \"core:control:create-snapshot-mapping\")\n canDeleteSnapshotMapping: permission(action: \"core:control:delete-snapshot-mapping\")\n canCreateStateOfApplicabilityMapping: permission(action: \"core:control:state-of-applicability-control-mapping:create\")\n canDeleteStateOfApplicabilityMapping: permission(action: \"core:control:state-of-applicability-control-mapping:delete\")\n canCreateObligationMapping: permission(action: \"core:control:obligation-control-mapping:create\")\n canDeleteObligationMapping: permission(action: \"core:control:obligation-control-mapping:delete\")\n ...FrameworkControlDialogFragment\n stateOfApplicabilityControls(first: 100) {\n edges {\n node {\n id\n ...LinkedStatesOfApplicabilityCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n measures(first: 100) {\n edges {\n node {\n id\n ...LinkedMeasuresCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n documents(first: 100) {\n edges {\n node {\n id\n ...LinkedDocumentsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n audits(first: 100) {\n edges {\n node {\n id\n ...LinkedAuditsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n obligations(first: 100) {\n edges {\n node {\n id\n ...LinkedObligationsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n snapshots(first: 100) {\n edges {\n node {\n id\n ...LinkedSnapshotsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n\nfragment FrameworkControlDialogFragment on Control {\n id\n name\n description\n sectionTitle\n status\n exclusionJustification\n bestPractice\n}\n\nfragment LinkedAuditsCardFragment on Audit {\n id\n name\n createdAt\n state\n validFrom\n validUntil\n framework {\n id\n name\n }\n}\n\nfragment LinkedDocumentsCardFragment on Document {\n id\n title\n createdAt\n documentType\n versions(first: 1) {\n edges {\n node {\n id\n status\n }\n }\n }\n}\n\nfragment LinkedMeasuresCardFragment on Measure {\n id\n name\n state\n}\n\nfragment LinkedObligationsCardFragment on Obligation {\n id\n requirement\n area\n source\n status\n owner {\n fullName\n id\n }\n}\n\nfragment LinkedSnapshotsCardFragment on Snapshot {\n id\n name\n description\n type\n createdAt\n}\n\nfragment LinkedStatesOfApplicabilityCardFragment on StateOfApplicabilityControl {\n id\n stateOfApplicabilityId\n controlId\n stateOfApplicability {\n id\n name\n }\n applicability\n justification\n}\n"
}
};
})();
(node as any).hash = "b28838e3c3c4cdd68906247d129799c8";
(node as any).hash = "755f62f220b1a05bf44dd770974691a9";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<7aaf0b32e40fe8c723a28ab9590b62b5>>
* @generated SignedSource<<063d92802621a02aff6b40a9cb2266c2>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -15,10 +15,13 @@ export type FrameworkGraphListQuery$variables = {
};
export type FrameworkGraphListQuery$data = {
readonly organization: {
readonly canCreateFramework?: boolean;
readonly frameworks?: {
readonly __id: string;
readonly edges: ReadonlyArray<{
readonly node: {
readonly canDelete: boolean;
readonly canUpdate: boolean;
readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"FrameworksPageCardFragment">;
};
@@ -55,20 +58,59 @@ v2 = {
"storageKey": null
},
v3 = {
"alias": "canCreateFramework",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:create"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:create\")"
},
v4 = {
"alias": "canUpdate",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:update"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:update\")"
},
v5 = {
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:delete\")"
},
v6 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v4 = {
v7 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
},
v5 = {
v8 = {
"alias": null,
"args": null,
"concreteType": "PageInfo",
@@ -93,7 +135,7 @@ v5 = {
],
"storageKey": null
},
v6 = {
v9 = {
"kind": "ClientExtension",
"selections": [
{
@@ -105,7 +147,7 @@ v6 = {
}
]
},
v7 = [
v10 = [
{
"kind": "Literal",
"name": "first",
@@ -131,6 +173,7 @@ return {
"kind": "InlineFragment",
"selections": [
(v2/*: any*/),
(v3/*: any*/),
{
"alias": "frameworks",
"args": null,
@@ -156,21 +199,23 @@ return {
"plural": false,
"selections": [
(v2/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
"name": "FrameworksPageCardFragment"
},
(v3/*: any*/)
(v6/*: any*/)
],
"storageKey": null
},
(v4/*: any*/)
(v7/*: any*/)
],
"storageKey": null
},
(v5/*: any*/),
(v6/*: any*/)
(v8/*: any*/),
(v9/*: any*/)
],
"storageKey": null
}
@@ -199,14 +244,15 @@ return {
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
(v6/*: any*/),
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": (v7/*: any*/),
"args": (v10/*: any*/),
"concreteType": "FrameworkConnection",
"kind": "LinkedField",
"name": "frameworks",
@@ -229,6 +275,8 @@ return {
"plural": false,
"selections": [
(v2/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
{
"alias": null,
"args": null,
@@ -257,22 +305,22 @@ return {
"name": "darkLogoURL",
"storageKey": null
},
(v3/*: any*/)
(v6/*: any*/)
],
"storageKey": null
},
(v4/*: any*/)
(v7/*: any*/)
],
"storageKey": null
},
(v5/*: any*/),
(v6/*: any*/)
(v8/*: any*/),
(v9/*: any*/)
],
"storageKey": "frameworks(first:100)"
},
{
"alias": null,
"args": (v7/*: any*/),
"args": (v10/*: any*/),
"filters": null,
"handle": "connection",
"key": "FrameworksListQuery_frameworks",
@@ -289,7 +337,7 @@ return {
]
},
"params": {
"cacheID": "90e970007a500be89809ac0f2a77bccd",
"cacheID": "2d16147e68885223a69b3597e96d694b",
"id": null,
"metadata": {
"connection": [
@@ -306,11 +354,11 @@ return {
},
"name": "FrameworkGraphListQuery",
"operationKind": "query",
"text": "query FrameworkGraphListQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n frameworks(first: 100) {\n edges {\n node {\n id\n ...FrameworksPageCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n\nfragment FrameworksPageCardFragment on Framework {\n id\n name\n description\n lightLogoURL\n darkLogoURL\n}\n"
"text": "query FrameworkGraphListQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n canCreateFramework: permission(action: \"core:framework:create\")\n frameworks(first: 100) {\n edges {\n node {\n id\n canUpdate: permission(action: \"core:framework:update\")\n canDelete: permission(action: \"core:framework:delete\")\n ...FrameworksPageCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n\nfragment FrameworksPageCardFragment on Framework {\n id\n name\n description\n lightLogoURL\n darkLogoURL\n canUpdate: permission(action: \"core:framework:update\")\n canDelete: permission(action: \"core:framework:delete\")\n}\n"
}
};
})();
(node as any).hash = "4aaead183328e669aba942992db6f89c";
(node as any).hash = "f8d3a38faddf4285b8f495f54f3d988e";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<43528dc19e67fdeca407f5081e6252b9>>
* @generated SignedSource<<bbc7e1cc0c5c3f72d0297ff14a1dff77>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -137,6 +137,58 @@ return {
"name": "darkLogoURL",
"storageKey": null
},
{
"alias": "canExport",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:franework:export"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:franework:export\")"
},
{
"alias": "canUpdate",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:update"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:update\")"
},
{
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:delete\")"
},
{
"alias": "canCreateControl",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:control:create"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:control:create\")"
},
{
"alias": null,
"args": null,
@@ -249,12 +301,12 @@ return {
]
},
"params": {
"cacheID": "5af3d5c9f8d466c5d6a78d7bd5da70d1",
"cacheID": "2a82ae6447b93b0fa6b570571694052b",
"id": null,
"metadata": {},
"name": "FrameworkGraphNodeQuery",
"operationKind": "query",
"text": "query FrameworkGraphNodeQuery(\n $frameworkId: ID!\n) {\n node(id: $frameworkId) {\n __typename\n ... on Framework {\n id\n name\n ...FrameworkDetailPageFragment\n }\n id\n }\n}\n\nfragment FrameworkDetailPageFragment on Framework {\n id\n name\n description\n lightLogoURL\n darkLogoURL\n organization {\n name\n id\n }\n controls(first: 250, orderBy: {field: SECTION_TITLE, direction: ASC}) {\n edges {\n node {\n id\n sectionTitle\n name\n status\n exclusionJustification\n bestPractice\n }\n }\n }\n}\n"
"text": "query FrameworkGraphNodeQuery(\n $frameworkId: ID!\n) {\n node(id: $frameworkId) {\n __typename\n ... on Framework {\n id\n name\n ...FrameworkDetailPageFragment\n }\n id\n }\n}\n\nfragment FrameworkDetailPageFragment on Framework {\n id\n name\n description\n lightLogoURL\n darkLogoURL\n canExport: permission(action: \"core:franework:export\")\n canUpdate: permission(action: \"core:framework:update\")\n canDelete: permission(action: \"core:framework:delete\")\n canCreateControl: permission(action: \"core:control:create\")\n organization {\n name\n id\n }\n controls(first: 250, orderBy: {field: SECTION_TITLE, direction: ASC}) {\n edges {\n node {\n id\n sectionTitle\n name\n status\n exclusionJustification\n bestPractice\n }\n }\n }\n}\n"
}
};
})();

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<412cc494e90709fca575c68f6deef112>>
* @generated SignedSource<<d797330ab78ac421e3c64cebdb2ec975>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -11,6 +11,8 @@
import { ReaderFragment } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type FrameworksPageCardFragment$data = {
readonly canDelete: boolean;
readonly canUpdate: boolean;
readonly darkLogoURL: string | null | undefined;
readonly description: string | null | undefined;
readonly id: string;
@@ -63,12 +65,38 @@ const node: ReaderFragment = {
"kind": "ScalarField",
"name": "darkLogoURL",
"storageKey": null
},
{
"alias": "canUpdate",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:update"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:update\")"
},
{
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:delete\")"
}
],
"type": "Framework",
"abstractKey": null
};
(node as any).hash = "fe86a14971741a77f587ae015ebf0a22";
(node as any).hash = "dfb64192cedec377c8df8a6d8251e815";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<2256362d89b6b5c2f5c707acb44d283e>>
* @generated SignedSource<<b24323b7c04c927d73fb16ffe3c86532>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -172,6 +172,32 @@ return {
"kind": "ScalarField",
"name": "darkLogoURL",
"storageKey": null
},
{
"alias": "canUpdate",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:update"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:update\")"
},
{
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:framework:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:framework:delete\")"
}
],
"storageKey": null
@@ -201,12 +227,12 @@ return {
]
},
"params": {
"cacheID": "5584472f1e68fac3d766662c6d5dab90",
"cacheID": "6521d91ba0bd6d9d59567cd2a05d0f35",
"id": null,
"metadata": {},
"name": "FrameworksPageImportMutation",
"operationKind": "mutation",
"text": "mutation FrameworksPageImportMutation(\n $input: ImportFrameworkInput!\n) {\n importFramework(input: $input) {\n frameworkEdge {\n node {\n id\n ...FrameworksPageCardFragment\n }\n }\n }\n}\n\nfragment FrameworksPageCardFragment on Framework {\n id\n name\n description\n lightLogoURL\n darkLogoURL\n}\n"
"text": "mutation FrameworksPageImportMutation(\n $input: ImportFrameworkInput!\n) {\n importFramework(input: $input) {\n frameworkEdge {\n node {\n id\n ...FrameworksPageCardFragment\n }\n }\n }\n}\n\nfragment FrameworksPageCardFragment on Framework {\n id\n name\n description\n lightLogoURL\n darkLogoURL\n canUpdate: permission(action: \"core:framework:update\")\n canDelete: permission(action: \"core:framework:delete\")\n}\n"
}
};
})();

View File

@@ -12,12 +12,15 @@ export const frameworksQuery = graphql`
organization: node(id: $organizationId) {
... on Organization {
id
canCreateFramework: permission(action: "core:framework:create")
frameworks(first: 100)
@connection(key: "FrameworksListQuery_frameworks") {
__id
edges {
node {
id
canUpdate: permission(action: "core:framework:update")
canDelete: permission(action: "core:framework:delete")
...FrameworksPageCardFragment
}
}
@@ -40,7 +43,7 @@ const deleteFrameworkMutation = graphql`
export const useDeleteFrameworkMutation = (
framework: { id: string; name: string },
connectionId: string
connectionId: string,
) => {
const [commitDelete] = useMutationWithToasts(deleteFrameworkMutation, {
errorMessage: "Failed to delete framework",
@@ -66,14 +69,14 @@ export const useDeleteFrameworkMutation = (
{
message: sprintf(
__(
'This will permanently delete framework "%s". This action cannot be undone.'
'This will permanently delete framework "%s". This action cannot be undone.',
),
framework.name
framework.name,
),
}
},
);
},
[framework, connectionId, commitDelete, confirm, __]
[framework, connectionId, commitDelete, confirm, __],
);
};
@@ -99,6 +102,44 @@ export const frameworkControlNodeQuery = graphql`
description
status
exclusionJustification
canUpdate: permission(action: "core:control:update")
canDelete: permission(action: "core:control:delete")
canCreateMeasureMapping: permission(
action: "core:control:create-measure-mapping"
)
canDeleteMeasureMapping: permission(
action: "core:control:delete-measure-mapping"
)
canCreateDocumentMapping: permission(
action: "core:control:create-document-mapping"
)
canDeleteDocumentMapping: permission(
action: "core:control:delete-document-mapping"
)
canCreateAuditMapping: permission(
action: "core:control:create-audit-mapping"
)
canDeleteAuditMapping: permission(
action: "core:control:delete-audit-mapping"
)
canCreateSnapshotMapping: permission(
action: "core:control:create-snapshot-mapping"
)
canDeleteSnapshotMapping: permission(
action: "core:control:delete-snapshot-mapping"
)
canCreateStateOfApplicabilityMapping: permission(
action: "core:control:state-of-applicability-control-mapping:create"
)
canDeleteStateOfApplicabilityMapping: permission(
action: "core:control:state-of-applicability-control-mapping:delete"
)
canCreateObligationMapping: permission(
action: "core:control:obligation-control-mapping:create"
)
canDeleteObligationMapping: permission(
action: "core:control:obligation-control-mapping:delete"
)
...FrameworkControlDialogFragment
stateOfApplicabilityControls(first: 100)
@connection(key: "FrameworkGraphControl_stateOfApplicabilityControls") {
@@ -130,8 +171,7 @@ export const frameworkControlNodeQuery = graphql`
}
}
}
audits(first: 100)
@connection(key: "FrameworkGraphControl_audits") {
audits(first: 100) @connection(key: "FrameworkGraphControl_audits") {
__id
edges {
node {

View File

@@ -29,8 +29,6 @@ import { promisifyMutation } from "@probo/helpers";
import type { FrameworkGraphControlNodeQuery } from "/__generated__/core/FrameworkGraphControlNodeQuery.graphql";
import { frameworkControlNodeQuery } from "/hooks/graph/FrameworkGraph";
import type { FrameworkDetailPageFragment$data } from "/__generated__/core/FrameworkDetailPageFragment.graphql";
import { use } from "react";
import { PermissionsContext } from "/providers/PermissionsContext";
const attachStateOfApplicabilityMutation = graphql`
mutation FrameworkControlPageAttachStateOfApplicabilityMutation(
@@ -227,11 +225,6 @@ export default function FrameworkControlPage({ queryRef }: Props) {
const organizationId = useOrganizationId();
const confirm = useConfirm();
const navigate = useNavigate();
const { isAuthorized } = use(PermissionsContext);
const [detachStateOfApplicability, isDetachingStateOfApplicability] =
useMutation(detachStateOfApplicabilityMutation);
const [attachStateOfApplicability, isAttachingStateOfApplicability] =
useMutation(attachStateOfApplicabilityMutation);
const [detachMeasure, isDetachingMeasure] = useMutation(
detachMeasureMutation,
);
@@ -253,6 +246,11 @@ export default function FrameworkControlPage({ queryRef }: Props) {
attachSnapshotMutation,
);
const [deleteControl] = useMutation(deleteControlMutation);
const [attachStateOfApplicability, isAttachingStateOfApplicability] =
useMutation(attachStateOfApplicabilityMutation);
const [detachStateOfApplicability, isDetachingStateOfApplicability] =
useMutation(detachStateOfApplicabilityMutation);
const [attachObligation, isAttachingObligation] = useMutation(
attachObligationMutation,
);
@@ -260,61 +258,33 @@ export default function FrameworkControlPage({ queryRef }: Props) {
detachObligationMutation,
);
const canLinkStateOfApplicability = isAuthorized(
"Control",
"createStateOfApplicabilityControlMapping",
);
const canUnlinkStateOfApplicability = isAuthorized(
"Control",
"deleteStateOfApplicabilityControlMapping",
);
const canLinkStateOfApplicability =
control.canCreateStateOfApplicabilityMapping;
const canUnlinkStateOfApplicability =
control.canDeleteStateOfApplicabilityMapping;
const statesOfApplicabilityReadOnly =
!canLinkStateOfApplicability && !canUnlinkStateOfApplicability;
const canLinkMeasure = isAuthorized(
"Control",
"createControlMeasureMapping",
);
const canUnlinkMeasure = isAuthorized(
"Control",
"deleteControlMeasureMapping",
);
const canLinkMeasure = control.canCreateMeasureMapping;
const canUnlinkMeasure = control.canDeleteMeasureMapping;
const measuresReadOnly = !canLinkMeasure && !canUnlinkMeasure;
const canLinkDocument = isAuthorized(
"Control",
"createControlDocumentMapping",
);
const canUnlinkDocument = isAuthorized(
"Control",
"deleteControlDocumentMapping",
);
const canLinkDocument = control.canCreateDocumentMapping;
const canUnlinkDocument = control.canDeleteDocumentMapping;
const documentsReadOnly = !canLinkDocument && !canUnlinkDocument;
const canLinkAudit = isAuthorized("Control", "createControlAuditMapping");
const canUnlinkAudit = isAuthorized("Control", "deleteControlAuditMapping");
const canLinkAudit = control.canCreateAuditMapping;
const canUnlinkAudit = control.canDeleteAuditMapping;
const auditsReadOnly = !canLinkAudit && !canUnlinkAudit;
const canLinkObligation = isAuthorized(
"Control",
"createControlObligationMapping",
);
const canUnlinkObligation = isAuthorized(
"Control",
"deleteControlObligationMapping",
);
const obligationsReadOnly = !canLinkObligation && !canUnlinkObligation;
const canLinkSnapshot = isAuthorized(
"Control",
"createControlSnapshotMapping",
);
const canUnlinkSnapshot = isAuthorized(
"Control",
"deleteControlSnapshotMapping",
);
const canLinkSnapshot = control.canCreateSnapshotMapping;
const canUnlinkSnapshot = control.canDeleteSnapshotMapping;
const snapshotsReadOnly = !canLinkSnapshot && !canUnlinkSnapshot;
const canLinkObligation = control.canCreateObligationMapping;
const canUnlinkObligation = control.canDeleteObligationMapping;
const obligationsReadOnly = !canLinkObligation && !canUnlinkObligation;
const withErrorHandling =
<T extends MutationParameters>(
mutationFn: (config: UseMutationConfig<T>) => void,
@@ -382,7 +352,7 @@ export default function FrameworkControlPage({ queryRef }: Props) {
</div>
</div>
<div className="flex gap-2">
{isAuthorized("Control", "updateControl") && (
{control.canUpdate && (
<FrameworkControlDialog
frameworkId={framework.id}
connectionId={connectionId}
@@ -393,7 +363,7 @@ export default function FrameworkControlPage({ queryRef }: Props) {
</Button>
</FrameworkControlDialog>
)}
{isAuthorized("Control", "deleteControl") && (
{control.canDelete && (
<ActionDropdown variant="secondary">
<DropdownItem
icon={IconTrashCan}

View File

@@ -31,8 +31,6 @@ import type { FrameworkDetailPageExportFrameworkMutation } from "/__generated__/
import { FrameworkFormDialog } from "./dialogs/FrameworkFormDialog";
import { FrameworkControlDialog } from "./dialogs/FrameworkControlDialog";
import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
import { use } from "react";
import { PermissionsContext } from "/providers/PermissionsContext";
const frameworkDetailFragment = graphql`
fragment FrameworkDetailPageFragment on Framework {
@@ -41,6 +39,10 @@ const frameworkDetailFragment = graphql`
description
lightLogoURL
darkLogoURL
canExport: permission(action: "core:franework:export")
canUpdate: permission(action: "core:framework:update")
canDelete: permission(action: "core:framework:delete")
canCreateControl: permission(action: "core:control:create")
organization {
name
}
@@ -88,10 +90,15 @@ type Props = {
};
export default function FrameworkDetailPage(props: Props) {
const { queryRef } = props;
const { __ } = useTranslate();
const { controlId } = useParams<{ controlId?: string }>();
const organizationId = useOrganizationId();
const data = usePreloadedQuery(frameworkNodeQuery, props.queryRef);
const data = usePreloadedQuery<FrameworkGraphNodeQuery>(
frameworkNodeQuery,
queryRef,
);
const framework = useFragment<FrameworkDetailPageFragment$key>(
frameworkDetailFragment,
data.node,
@@ -106,7 +113,6 @@ export default function FrameworkDetailPage(props: Props) {
framework,
ConnectionHandler.getConnectionID(organizationId, connectionListKey)!,
);
const { isAuthorized } = use(PermissionsContext);
const [generateFrameworkStateOfApplicability] =
useMutationWithToasts<FrameworkDetailPageGenerateFrameworkStateOfApplicabilityMutation>(
generateFrameworkStateOfApplicabilityMutation,
@@ -155,7 +161,7 @@ export default function FrameworkDetailPage(props: Props) {
</>
}
>
{isAuthorized("Framework", "updateFramework") && (
{framework.canUpdate && (
<FrameworkFormDialog
organizationId={organizationId}
framework={framework}
@@ -202,7 +208,7 @@ export default function FrameworkDetailPage(props: Props) {
>
{__("Export Framework")}
</DropdownItem>
{isAuthorized("Framework", "deleteFramework") && (
{framework.canDelete && (
<DropdownItem
icon={IconTrashCan}
variant="danger"
@@ -231,7 +237,7 @@ export default function FrameworkDetailPage(props: Props) {
active={selectedControl?.id === control.id}
/>
))}
{isAuthorized("Organization", "createControl") && (
{framework.canCreateControl && (
<FrameworkControlDialog
frameworkId={framework.id}
connectionId={connectionId}

View File

@@ -27,9 +27,8 @@ import {
import { Link } from "react-router";
import type { FrameworksPageCardFragment$key } from "/__generated__/core/FrameworksPageCardFragment.graphql";
import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
import { useState, type ChangeEventHandler, use } from "react";
import { useState, type ChangeEventHandler } from "react";
import { FrameworkFormDialog } from "./dialogs/FrameworkFormDialog";
import { PermissionsContext } from "/providers/PermissionsContext";
type Props = {
queryRef: PreloadedQuery<FrameworkGraphListQuery>;
@@ -53,7 +52,6 @@ const importFrameworkMutation = graphql`
export default function FrameworksPage(props: Props) {
const { __ } = useTranslate();
const { isAuthorized } = use(PermissionsContext);
usePageTitle(__("Frameworks"));
const data = usePreloadedQuery(frameworksQuery, props.queryRef);
const connectionId = data.organization.frameworks!.__id;
@@ -120,9 +118,9 @@ export default function FrameworksPage(props: Props) {
const isLoading = isUploading || isImporting;
const hasAnyAction =
isAuthorized("Framework", "updateFramework") ||
isAuthorized("Framework", "deleteFramework");
const hasAnyAction = frameworks.some(
({ canUpdate, canDelete }) => canUpdate || canDelete,
);
return (
<div className="space-y-6">
@@ -135,7 +133,7 @@ export default function FrameworksPage(props: Props) {
title={__("Frameworks")}
description={__("Manage your compliance frameworks")}
>
{isAuthorized("Organization", "createFramework") && (
{data.organization.canCreateFramework && (
<>
<FileButton
variant="secondary"
@@ -175,6 +173,8 @@ const frameworkCardFragment = graphql`
description
lightLogoURL
darkLogoURL
canUpdate: permission(action: "core:framework:update")
canDelete: permission(action: "core:framework:delete")
}
`;
@@ -187,7 +187,6 @@ type FrameworkCardProps = {
function FrameworkCard(props: FrameworkCardProps) {
const framework = useFragment(frameworkCardFragment, props.framework);
const { isAuthorized } = use(PermissionsContext);
const deleteFramework = useDeleteFrameworkMutation(
framework,
props.connectionId,
@@ -210,7 +209,7 @@ function FrameworkCard(props: FrameworkCardProps) {
/>
{props.hasAnyAction && (
<ActionDropdown className="z-10 relative">
{isAuthorized("Framework", "updateFramework") && (
{framework.canUpdate && (
<DropdownItem
icon={IconPencil}
onClick={() => {
@@ -220,7 +219,7 @@ function FrameworkCard(props: FrameworkCardProps) {
{__("Edit")}
</DropdownItem>
)}
{isAuthorized("Framework", "deleteFramework") && (
{framework.canDelete && (
<DropdownItem
icon={IconTrashCan}
onClick={() => deleteFramework()}