From ad1998a540c52148f437ea58f659987f76723a3d Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Mon, 23 Feb 2026 15:28:27 +0100 Subject: [PATCH] Fix no link button when list is empty Signed-off-by: Bryan Frimin --- ...MeasureControlsTabControlsQuery.graphql.ts | 60 +++++----- .../MeasureControlsTabFragment.graphql.ts | 60 +++++----- .../core/MeasureGraphNodeQuery.graphql.ts | 110 +++++++++--------- .../core/MeasureRisksTabFragment.graphql.ts | 60 +++++----- .../controls/LinkedControlsDialog.tsx | 4 +- .../measures/tabs/MeasureControlsTab.tsx | 20 ++-- .../measures/tabs/MeasureRisksTab.tsx | 20 ++-- 7 files changed, 163 insertions(+), 171 deletions(-) diff --git a/apps/console/src/__generated__/core/MeasureControlsTabControlsQuery.graphql.ts b/apps/console/src/__generated__/core/MeasureControlsTabControlsQuery.graphql.ts index b8556a446..d420bcc2f 100644 --- a/apps/console/src/__generated__/core/MeasureControlsTabControlsQuery.graphql.ts +++ b/apps/console/src/__generated__/core/MeasureControlsTabControlsQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<7a85ed904a58646c75806d80ef39fe3d>> * @lightSyntaxTransform * @nogrep */ @@ -212,6 +212,32 @@ return { { "kind": "InlineFragment", "selections": [ + { + "alias": "canCreateControlMeasureMapping", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:control:create-measure-mapping" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:control:create-measure-mapping\")" + }, + { + "alias": "canDeleteControlMeasureMapping", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:control:delete-measure-mapping" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:control:delete-measure-mapping\")" + }, { "alias": null, "args": (v15/*: any*/), @@ -237,32 +263,6 @@ return { "plural": false, "selections": [ (v14/*: any*/), - { - "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\")" - }, - { - "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\")" - }, (v16/*: any*/), { "alias": null, @@ -374,16 +374,16 @@ return { ] }, "params": { - "cacheID": "61b16a84cb9903560d86e0b5ee031abe", + "cacheID": "f70203cc76e2ffe7c817cba8aa3942a3", "id": null, "metadata": {}, "name": "MeasureControlsTabControlsQuery", "operationKind": "query", - "text": "query MeasureControlsTabControlsQuery(\n $after: CursorKey\n $before: CursorKey = null\n $filter: ControlFilter = null\n $first: Int = 20\n $last: Int = null\n $order: ControlOrder = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...MeasureControlsTabFragment_4cFWzS\n id\n }\n}\n\nfragment LinkedControlsCardFragment on Control {\n id\n name\n sectionTitle\n framework {\n id\n name\n }\n}\n\nfragment MeasureControlsTabFragment_4cFWzS on Measure {\n id\n controls(first: $first, after: $after, last: $last, before: $before, orderBy: $order, filter: $filter) {\n edges {\n node {\n id\n canCreateMeasureMapping: permission(action: \"core:control:create-measure-mapping\")\n canDeleteMeasureMapping: permission(action: \"core:control:delete-measure-mapping\")\n ...LinkedControlsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n" + "text": "query MeasureControlsTabControlsQuery(\n $after: CursorKey\n $before: CursorKey = null\n $filter: ControlFilter = null\n $first: Int = 20\n $last: Int = null\n $order: ControlOrder = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...MeasureControlsTabFragment_4cFWzS\n id\n }\n}\n\nfragment LinkedControlsCardFragment on Control {\n id\n name\n sectionTitle\n framework {\n id\n name\n }\n}\n\nfragment MeasureControlsTabFragment_4cFWzS on Measure {\n id\n canCreateControlMeasureMapping: permission(action: \"core:control:create-measure-mapping\")\n canDeleteControlMeasureMapping: permission(action: \"core:control:delete-measure-mapping\")\n controls(first: $first, after: $after, last: $last, before: $before, orderBy: $order, filter: $filter) {\n edges {\n node {\n id\n ...LinkedControlsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n" } }; })(); -(node as any).hash = "6cd1d286921188abc2a9fdc1c1e0ed08"; +(node as any).hash = "f1553367470d92ddfc910b2eea87109f"; export default node; diff --git a/apps/console/src/__generated__/core/MeasureControlsTabFragment.graphql.ts b/apps/console/src/__generated__/core/MeasureControlsTabFragment.graphql.ts index 75dea0ac5..9169d7523 100644 --- a/apps/console/src/__generated__/core/MeasureControlsTabFragment.graphql.ts +++ b/apps/console/src/__generated__/core/MeasureControlsTabFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<414658fc55873606e711cc4571e9fd9b>> + * @generated SignedSource<<54f7a965dd1b0943e08bbec66c11200d>> * @lightSyntaxTransform * @nogrep */ @@ -11,12 +11,12 @@ import { ReaderFragment } from 'relay-runtime'; import { FragmentRefs } from "relay-runtime"; export type MeasureControlsTabFragment$data = { + readonly canCreateControlMeasureMapping: boolean; + readonly canDeleteControlMeasureMapping: boolean; readonly controls: { readonly __id: string; readonly edges: ReadonlyArray<{ readonly node: { - readonly canCreateMeasureMapping: boolean; - readonly canDeleteMeasureMapping: boolean; readonly id: string; readonly " $fragmentSpreads": FragmentRefs<"LinkedControlsCardFragment">; }; @@ -111,6 +111,32 @@ return { "name": "MeasureControlsTabFragment", "selections": [ (v1/*: any*/), + { + "alias": "canCreateControlMeasureMapping", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:control:create-measure-mapping" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:control:create-measure-mapping\")" + }, + { + "alias": "canDeleteControlMeasureMapping", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:control:delete-measure-mapping" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:control:delete-measure-mapping\")" + }, { "alias": "controls", "args": [ @@ -147,32 +173,6 @@ return { "plural": false, "selections": [ (v1/*: any*/), - { - "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\")" - }, - { - "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\")" - }, { "args": null, "kind": "FragmentSpread", @@ -258,6 +258,6 @@ return { }; })(); -(node as any).hash = "6cd1d286921188abc2a9fdc1c1e0ed08"; +(node as any).hash = "f1553367470d92ddfc910b2eea87109f"; export default node; diff --git a/apps/console/src/__generated__/core/MeasureGraphNodeQuery.graphql.ts b/apps/console/src/__generated__/core/MeasureGraphNodeQuery.graphql.ts index 9995b7c88..9acca02dd 100644 --- a/apps/console/src/__generated__/core/MeasureGraphNodeQuery.graphql.ts +++ b/apps/console/src/__generated__/core/MeasureGraphNodeQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -353,6 +353,32 @@ return { (v12/*: any*/), (v13/*: any*/), (v14/*: any*/), + { + "alias": "canCreateRiskMeasureMapping", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:risk:create-measure-mapping" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:risk:create-measure-mapping\")" + }, + { + "alias": "canDeleteRiskMeasureMapping", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:risk:delete-measure-mapping" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:risk:delete-measure-mapping\")" + }, { "alias": null, "args": (v16/*: any*/), @@ -378,32 +404,6 @@ return { "plural": false, "selections": [ (v2/*: any*/), - { - "alias": "canCreateMeasureMapping", - "args": [ - { - "kind": "Literal", - "name": "action", - "value": "core:risk:create-measure-mapping" - } - ], - "kind": "ScalarField", - "name": "permission", - "storageKey": "permission(action:\"core:risk:create-measure-mapping\")" - }, - { - "alias": "canDeleteMeasureMapping", - "args": [ - { - "kind": "Literal", - "name": "action", - "value": "core:risk:delete-measure-mapping" - } - ], - "kind": "ScalarField", - "name": "permission", - "storageKey": "permission(action:\"core:risk:delete-measure-mapping\")" - }, (v3/*: any*/), { "alias": null, @@ -453,6 +453,32 @@ return { "kind": "LinkedHandle", "name": "risks" }, + { + "alias": "canCreateControlMeasureMapping", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:control:create-measure-mapping" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:control:create-measure-mapping\")" + }, + { + "alias": "canDeleteControlMeasureMapping", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:control:delete-measure-mapping" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:control:delete-measure-mapping\")" + }, { "alias": null, "args": (v21/*: any*/), @@ -478,32 +504,6 @@ return { "plural": false, "selections": [ (v2/*: any*/), - { - "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\")" - }, - { - "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\")" - }, (v3/*: any*/), { "alias": null, @@ -682,12 +682,12 @@ return { ] }, "params": { - "cacheID": "d8ac1210636ffd91eacb1bfe3452e26c", + "cacheID": "76cc28f60f7911b5b452f8384fe70fcb", "id": null, "metadata": {}, "name": "MeasureGraphNodeQuery", "operationKind": "query", - "text": "query MeasureGraphNodeQuery(\n $measureId: ID!\n) {\n node(id: $measureId) {\n __typename\n ... on Measure {\n id\n name\n description\n state\n category\n canUpdate: permission(action: \"core:measure:update\")\n canDelete: permission(action: \"core:measure:delete\")\n canListTasks: permission(action: \"core:task:list\")\n evidencesInfos: evidences(first: 0) {\n totalCount\n }\n risksInfos: risks(first: 0) {\n totalCount\n }\n controlsInfos: controls(first: 0) {\n totalCount\n }\n ...MeasureRisksTabFragment\n ...MeasureControlsTabFragment\n ...MeasureFormDialogMeasureFragment\n ...MeasureEvidencesTabFragment\n }\n id\n }\n}\n\nfragment LinkedControlsCardFragment on Control {\n id\n name\n sectionTitle\n framework {\n id\n name\n }\n}\n\nfragment LinkedRisksCardFragment on Risk {\n id\n name\n inherentRiskScore\n residualRiskScore\n}\n\nfragment MeasureControlsTabFragment on Measure {\n id\n controls(first: 20) {\n edges {\n node {\n id\n canCreateMeasureMapping: permission(action: \"core:control:create-measure-mapping\")\n canDeleteMeasureMapping: permission(action: \"core:control:delete-measure-mapping\")\n ...LinkedControlsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment MeasureEvidencesTabFragment on Measure {\n id\n canUploadEvidence: permission(action: \"core:measure:upload-evidence\")\n evidences(first: 50) {\n edges {\n node {\n id\n file {\n fileName\n mimeType\n size\n id\n }\n ...MeasureEvidencesTabFragment_evidence\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment MeasureEvidencesTabFragment_evidence on Evidence {\n id\n file {\n fileName\n mimeType\n size\n id\n }\n type\n createdAt\n canDelete: permission(action: \"core:evidence:delete\")\n}\n\nfragment MeasureFormDialogMeasureFragment on Measure {\n id\n description\n name\n category\n state\n}\n\nfragment MeasureRisksTabFragment on Measure {\n id\n risks(first: 100) {\n edges {\n node {\n id\n canCreateMeasureMapping: permission(action: \"core:risk:create-measure-mapping\")\n canDeleteMeasureMapping: permission(action: \"core:risk:delete-measure-mapping\")\n ...LinkedRisksCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n" + "text": "query MeasureGraphNodeQuery(\n $measureId: ID!\n) {\n node(id: $measureId) {\n __typename\n ... on Measure {\n id\n name\n description\n state\n category\n canUpdate: permission(action: \"core:measure:update\")\n canDelete: permission(action: \"core:measure:delete\")\n canListTasks: permission(action: \"core:task:list\")\n evidencesInfos: evidences(first: 0) {\n totalCount\n }\n risksInfos: risks(first: 0) {\n totalCount\n }\n controlsInfos: controls(first: 0) {\n totalCount\n }\n ...MeasureRisksTabFragment\n ...MeasureControlsTabFragment\n ...MeasureFormDialogMeasureFragment\n ...MeasureEvidencesTabFragment\n }\n id\n }\n}\n\nfragment LinkedControlsCardFragment on Control {\n id\n name\n sectionTitle\n framework {\n id\n name\n }\n}\n\nfragment LinkedRisksCardFragment on Risk {\n id\n name\n inherentRiskScore\n residualRiskScore\n}\n\nfragment MeasureControlsTabFragment on Measure {\n id\n canCreateControlMeasureMapping: permission(action: \"core:control:create-measure-mapping\")\n canDeleteControlMeasureMapping: permission(action: \"core:control:delete-measure-mapping\")\n controls(first: 20) {\n edges {\n node {\n id\n ...LinkedControlsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment MeasureEvidencesTabFragment on Measure {\n id\n canUploadEvidence: permission(action: \"core:measure:upload-evidence\")\n evidences(first: 50) {\n edges {\n node {\n id\n file {\n fileName\n mimeType\n size\n id\n }\n ...MeasureEvidencesTabFragment_evidence\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment MeasureEvidencesTabFragment_evidence on Evidence {\n id\n file {\n fileName\n mimeType\n size\n id\n }\n type\n createdAt\n canDelete: permission(action: \"core:evidence:delete\")\n}\n\nfragment MeasureFormDialogMeasureFragment on Measure {\n id\n description\n name\n category\n state\n}\n\nfragment MeasureRisksTabFragment on Measure {\n id\n canCreateRiskMeasureMapping: permission(action: \"core:risk:create-measure-mapping\")\n canDeleteRiskMeasureMapping: permission(action: \"core:risk:delete-measure-mapping\")\n risks(first: 100) {\n edges {\n node {\n id\n ...LinkedRisksCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n" } }; })(); diff --git a/apps/console/src/__generated__/core/MeasureRisksTabFragment.graphql.ts b/apps/console/src/__generated__/core/MeasureRisksTabFragment.graphql.ts index 9080685fc..ea2c56131 100644 --- a/apps/console/src/__generated__/core/MeasureRisksTabFragment.graphql.ts +++ b/apps/console/src/__generated__/core/MeasureRisksTabFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<4f367882dc2cd7bb8a8605d9192cd7f5>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -11,13 +11,13 @@ import { ReaderFragment } from 'relay-runtime'; import { FragmentRefs } from "relay-runtime"; export type MeasureRisksTabFragment$data = { + readonly canCreateRiskMeasureMapping: boolean; + readonly canDeleteRiskMeasureMapping: boolean; readonly id: string; readonly risks: { readonly __id: string; readonly edges: ReadonlyArray<{ readonly node: { - readonly canCreateMeasureMapping: boolean; - readonly canDeleteMeasureMapping: boolean; readonly id: string; readonly " $fragmentSpreads": FragmentRefs<"LinkedRisksCardFragment">; }; @@ -56,6 +56,32 @@ return { "name": "MeasureRisksTabFragment", "selections": [ (v0/*: any*/), + { + "alias": "canCreateRiskMeasureMapping", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:risk:create-measure-mapping" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:risk:create-measure-mapping\")" + }, + { + "alias": "canDeleteRiskMeasureMapping", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:risk:delete-measure-mapping" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:risk:delete-measure-mapping\")" + }, { "alias": "risks", "args": null, @@ -81,32 +107,6 @@ return { "plural": false, "selections": [ (v0/*: any*/), - { - "alias": "canCreateMeasureMapping", - "args": [ - { - "kind": "Literal", - "name": "action", - "value": "core:risk:create-measure-mapping" - } - ], - "kind": "ScalarField", - "name": "permission", - "storageKey": "permission(action:\"core:risk:create-measure-mapping\")" - }, - { - "alias": "canDeleteMeasureMapping", - "args": [ - { - "kind": "Literal", - "name": "action", - "value": "core:risk:delete-measure-mapping" - } - ], - "kind": "ScalarField", - "name": "permission", - "storageKey": "permission(action:\"core:risk:delete-measure-mapping\")" - }, { "args": null, "kind": "FragmentSpread", @@ -178,6 +178,6 @@ return { }; })(); -(node as any).hash = "a837a187026f5c75c67efcb4831d0b76"; +(node as any).hash = "abab542141a748635126f652c0d79761"; export default node; diff --git a/apps/console/src/components/controls/LinkedControlsDialog.tsx b/apps/console/src/components/controls/LinkedControlsDialog.tsx index 89915f176..82a222491 100644 --- a/apps/console/src/components/controls/LinkedControlsDialog.tsx +++ b/apps/console/src/components/controls/LinkedControlsDialog.tsx @@ -97,10 +97,10 @@ export function LinkedControlsDialog(props: Props) { return ( -
+
diff --git a/apps/console/src/pages/organizations/measures/tabs/MeasureControlsTab.tsx b/apps/console/src/pages/organizations/measures/tabs/MeasureControlsTab.tsx index 93d0d6ecd..bf27e2853 100644 --- a/apps/console/src/pages/organizations/measures/tabs/MeasureControlsTab.tsx +++ b/apps/console/src/pages/organizations/measures/tabs/MeasureControlsTab.tsx @@ -17,6 +17,12 @@ export const controlsFragment = graphql` ) @refetchable(queryName: "MeasureControlsTabControlsQuery") { id + canCreateControlMeasureMapping: permission( + action: "core:control:create-measure-mapping" + ) + canDeleteControlMeasureMapping: permission( + action: "core:control:delete-measure-mapping" + ) controls( first: $first after: $after @@ -29,12 +35,6 @@ export const controlsFragment = graphql` edges { node { id - canCreateMeasureMapping: permission( - action: "core:control:create-measure-mapping" - ) - canDeleteMeasureMapping: permission( - action: "core:control:delete-measure-mapping" - ) ...LinkedControlsCardFragment } } @@ -77,12 +77,8 @@ export default function MeasureControlsTab() { const connectionId = data.controls.__id; const controls = data.controls?.edges?.map(edge => edge.node) ?? []; - const canLinkControl = controls.some( - ({ canCreateMeasureMapping }) => canCreateMeasureMapping, - ); - const canUnlinkControl = controls.some( - ({ canDeleteMeasureMapping }) => canDeleteMeasureMapping, - ); + const canLinkControl = data.canCreateControlMeasureMapping; + const canUnlinkControl = data.canDeleteControlMeasureMapping; const readOnly = !canLinkControl && !canUnlinkControl; const incrementOptions = { diff --git a/apps/console/src/pages/organizations/measures/tabs/MeasureRisksTab.tsx b/apps/console/src/pages/organizations/measures/tabs/MeasureRisksTab.tsx index deddbcc2c..aed5efdef 100644 --- a/apps/console/src/pages/organizations/measures/tabs/MeasureRisksTab.tsx +++ b/apps/console/src/pages/organizations/measures/tabs/MeasureRisksTab.tsx @@ -8,17 +8,17 @@ import { useMutationWithIncrement } from "#/hooks/useMutationWithIncrement"; export const risksFragment = graphql` fragment MeasureRisksTabFragment on Measure { id + canCreateRiskMeasureMapping: permission( + action: "core:risk:create-measure-mapping" + ) + canDeleteRiskMeasureMapping: permission( + action: "core:risk:delete-measure-mapping" + ) risks(first: 100) @connection(key: "Measure__risks") { __id edges { node { id - canCreateMeasureMapping: permission( - action: "core:risk:create-measure-mapping" - ) - canDeleteMeasureMapping: permission( - action: "core:risk:delete-measure-mapping" - ) ...LinkedRisksCardFragment } } @@ -61,12 +61,8 @@ export default function MeasureRisksTab() { const connectionId = data.risks.__id; const risks = data.risks?.edges?.map(edge => edge.node) ?? []; - const canLinkRisk = risks.some( - ({ canCreateMeasureMapping }) => canCreateMeasureMapping, - ); - const canUnlinkRisk = risks.some( - ({ canDeleteMeasureMapping }) => canDeleteMeasureMapping, - ); + const canLinkRisk = data.canCreateRiskMeasureMapping; + const canUnlinkRisk = data.canDeleteRiskMeasureMapping; const readOnly = !canLinkRisk && !canUnlinkRisk; const incrementOptions = {