Fix no link button when list is empty

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2026-02-23 15:28:27 +01:00
committed by Sacha Al Himdani
parent 06aa781bb2
commit ad1998a540
7 changed files with 163 additions and 171 deletions

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<bf973ac1452f812480abe7160f4529e8>>
* @generated SignedSource<<de5873ce63a31aa710f82a582f05a45a>>
* @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"
}
};
})();

View File

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

View File

@@ -97,10 +97,10 @@ export function LinkedControlsDialog(props: Props) {
return (
<Dialog trigger={props.children} title={__("Link controls")}>
<DialogContent>
<div className="flex items-center gap-2 sticky top-0 relative py-4 bg-linear-to-b from-50% from-level-2 to-level-2/0 px-6">
<div className="flex items-center gap-2 sticky top-0 py-4 bg-linear-to-b from-50% from-level-2 to-level-2/0 px-6">
<Input
icon={IconMagnifyingGlass}
placeholder={__("Search measures...")}
placeholder={__("Search controls...")}
onValueChange={onSearch}
/>
</div>

View File

@@ -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 = {

View File

@@ -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 = {