diff --git a/apps/console/src/__generated__/core/ObligationGraphCreateMutation.graphql.ts b/apps/console/src/__generated__/core/ObligationGraphCreateMutation.graphql.ts index 8bfc4960c..61f1533dd 100644 --- a/apps/console/src/__generated__/core/ObligationGraphCreateMutation.graphql.ts +++ b/apps/console/src/__generated__/core/ObligationGraphCreateMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<46f875946badbe73d5c1ab10f442763d>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -34,6 +34,8 @@ export type ObligationGraphCreateMutation$data = { readonly node: { readonly actionsToBeImplemented: string | null | undefined; readonly area: string | null | undefined; + readonly canDelete: boolean; + readonly canUpdate: boolean; readonly createdAt: any; readonly dueDate: any | null | undefined; readonly id: string; @@ -186,6 +188,32 @@ v4 = { "kind": "ScalarField", "name": "createdAt", "storageKey": null + }, + { + "alias": "canUpdate", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:obligation:update" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:obligation:update\")" + }, + { + "alias": "canDelete", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:obligation:delete" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:obligation:delete\")" } ], "storageKey": null @@ -259,16 +287,16 @@ return { ] }, "params": { - "cacheID": "495da8600659a64f5d59ed86a56c8762", + "cacheID": "07c56edca205672276a394e621181187", "id": null, "metadata": {}, "name": "ObligationGraphCreateMutation", "operationKind": "mutation", - "text": "mutation ObligationGraphCreateMutation(\n $input: CreateObligationInput!\n) {\n createObligation(input: $input) {\n obligationEdge {\n node {\n id\n area\n source\n requirement\n actionsToBeImplemented\n regulator\n type\n lastReviewDate\n dueDate\n status\n owner {\n id\n fullName\n }\n createdAt\n }\n }\n }\n}\n" + "text": "mutation ObligationGraphCreateMutation(\n $input: CreateObligationInput!\n) {\n createObligation(input: $input) {\n obligationEdge {\n node {\n id\n area\n source\n requirement\n actionsToBeImplemented\n regulator\n type\n lastReviewDate\n dueDate\n status\n owner {\n id\n fullName\n }\n createdAt\n canUpdate: permission(action: \"core:obligation:update\")\n canDelete: permission(action: \"core:obligation:delete\")\n }\n }\n }\n}\n" } }; })(); -(node as any).hash = "e28cc6399325e7288ce7a71d3400acdb"; +(node as any).hash = "c4ab18948e2f118f433530ba3be77bda"; export default node; diff --git a/apps/console/src/__generated__/core/ObligationGraphListQuery.graphql.ts b/apps/console/src/__generated__/core/ObligationGraphListQuery.graphql.ts index 33a444579..02b269ff0 100644 --- a/apps/console/src/__generated__/core/ObligationGraphListQuery.graphql.ts +++ b/apps/console/src/__generated__/core/ObligationGraphListQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<02e8a94b4b1fde8cf24235afcfd5731a>> * @lightSyntaxTransform * @nogrep */ @@ -16,6 +16,7 @@ export type ObligationGraphListQuery$variables = { }; export type ObligationGraphListQuery$data = { readonly node: { + readonly canCreateObligation?: boolean; readonly " $fragmentSpreads": FragmentRefs<"ObligationsPageFragment">; }; }; @@ -44,30 +45,43 @@ v1 = [ "variableName": "organizationId" } ], -v2 = [ +v2 = { + "alias": "canCreateObligation", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:obligation:create" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:obligation:create\")" +}, +v3 = [ { "kind": "Variable", "name": "snapshotId", "variableName": "snapshotId" } ], -v3 = { +v4 = { "alias": null, "args": null, "kind": "ScalarField", "name": "__typename", "storageKey": null }, -v4 = { +v5 = { "alias": null, "args": null, "kind": "ScalarField", "name": "id", "storageKey": null }, -v5 = [ +v6 = [ { - "fields": (v2/*: any*/), + "fields": (v3/*: any*/), "kind": "ObjectValue", "name": "filter" }, @@ -95,8 +109,9 @@ return { { "kind": "InlineFragment", "selections": [ + (v2/*: any*/), { - "args": (v2/*: any*/), + "args": (v3/*: any*/), "kind": "FragmentSpread", "name": "ObligationsPageFragment" } @@ -125,14 +140,15 @@ return { "name": "node", "plural": false, "selections": [ - (v3/*: any*/), (v4/*: any*/), + (v5/*: any*/), { "kind": "InlineFragment", "selections": [ + (v2/*: any*/), { "alias": null, - "args": (v5/*: any*/), + "args": (v6/*: any*/), "concreteType": "ObligationConnection", "kind": "LinkedField", "name": "obligations", @@ -161,7 +177,7 @@ return { "name": "node", "plural": false, "selections": [ - (v4/*: any*/), + (v5/*: any*/), { "alias": null, "args": null, @@ -240,7 +256,7 @@ return { "name": "owner", "plural": false, "selections": [ - (v4/*: any*/), + (v5/*: any*/), { "alias": null, "args": null, @@ -265,7 +281,33 @@ return { "name": "updatedAt", "storageKey": null }, - (v3/*: any*/) + { + "alias": "canUpdate", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:obligation:update" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:obligation:update\")" + }, + { + "alias": "canDelete", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:obligation:delete" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:obligation:delete\")" + }, + (v4/*: any*/) ], "storageKey": null }, @@ -321,7 +363,7 @@ return { }, { "alias": null, - "args": (v5/*: any*/), + "args": (v6/*: any*/), "filters": [ "filter" ], @@ -340,16 +382,16 @@ return { ] }, "params": { - "cacheID": "761aab4336741b33cc256ec5527011e4", + "cacheID": "09f360edd84c4db5cf2bc3d01b207d46", "id": null, "metadata": {}, "name": "ObligationGraphListQuery", "operationKind": "query", - "text": "query ObligationGraphListQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ObligationsPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ObligationsPageFragment_3iomuz on Organization {\n id\n obligations(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" + "text": "query ObligationGraphListQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n canCreateObligation: permission(action: \"core:obligation:create\")\n ...ObligationsPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ObligationsPageFragment_3iomuz on Organization {\n id\n obligations(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n canUpdate: permission(action: \"core:obligation:update\")\n canDelete: permission(action: \"core:obligation:delete\")\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" } }; })(); -(node as any).hash = "f86996b031e65cde72543c222caf243f"; +(node as any).hash = "a17041086fd110cccb96aab8026d2b4b"; export default node; diff --git a/apps/console/src/__generated__/core/ObligationGraphNodeQuery.graphql.ts b/apps/console/src/__generated__/core/ObligationGraphNodeQuery.graphql.ts index c49fc44eb..e5a417b57 100644 --- a/apps/console/src/__generated__/core/ObligationGraphNodeQuery.graphql.ts +++ b/apps/console/src/__generated__/core/ObligationGraphNodeQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<3542cd7b93f38df062a93a1b9e325ff3>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -18,6 +18,8 @@ export type ObligationGraphNodeQuery$data = { readonly node: { readonly actionsToBeImplemented?: string | null | undefined; readonly area?: string | null | undefined; + readonly canDelete?: boolean; + readonly canUpdate?: boolean; readonly createdAt?: any; readonly dueDate?: any | null | undefined; readonly id?: string; @@ -195,6 +197,32 @@ v17 = { "kind": "ScalarField", "name": "updatedAt", "storageKey": null +}, +v18 = { + "alias": "canUpdate", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:obligation:update" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:obligation:update\")" +}, +v19 = { + "alias": "canDelete", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:obligation:delete" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:obligation:delete\")" }; return { "fragment": { @@ -229,7 +257,9 @@ return { (v14/*: any*/), (v15/*: any*/), (v16/*: any*/), - (v17/*: any*/) + (v17/*: any*/), + (v18/*: any*/), + (v19/*: any*/) ], "type": "Obligation", "abstractKey": null @@ -280,7 +310,9 @@ return { (v14/*: any*/), (v15/*: any*/), (v16/*: any*/), - (v17/*: any*/) + (v17/*: any*/), + (v18/*: any*/), + (v19/*: any*/) ], "type": "Obligation", "abstractKey": null @@ -291,16 +323,16 @@ return { ] }, "params": { - "cacheID": "049eff8ed7a7476c04d09b64c061c3a6", + "cacheID": "0be8ac1fa76f737698c91c6a8e6cf15b", "id": null, "metadata": {}, "name": "ObligationGraphNodeQuery", "operationKind": "query", - "text": "query ObligationGraphNodeQuery(\n $obligationId: ID!\n) {\n node(id: $obligationId) {\n __typename\n ... on Obligation {\n id\n snapshotId\n sourceId\n area\n source\n requirement\n actionsToBeImplemented\n regulator\n type\n lastReviewDate\n dueDate\n status\n owner {\n id\n fullName\n }\n organization {\n id\n name\n }\n createdAt\n updatedAt\n }\n id\n }\n}\n" + "text": "query ObligationGraphNodeQuery(\n $obligationId: ID!\n) {\n node(id: $obligationId) {\n __typename\n ... on Obligation {\n id\n snapshotId\n sourceId\n area\n source\n requirement\n actionsToBeImplemented\n regulator\n type\n lastReviewDate\n dueDate\n status\n owner {\n id\n fullName\n }\n organization {\n id\n name\n }\n createdAt\n updatedAt\n canUpdate: permission(action: \"core:obligation:update\")\n canDelete: permission(action: \"core:obligation:delete\")\n }\n id\n }\n}\n" } }; })(); -(node as any).hash = "c50090bdd31fc24e0fdb067677999f77"; +(node as any).hash = "6587fcee3deaaec8581e5f495b1edadc"; export default node; diff --git a/apps/console/src/__generated__/core/ObligationsPageFragment.graphql.ts b/apps/console/src/__generated__/core/ObligationsPageFragment.graphql.ts index 3c42a813d..9b85b1772 100644 --- a/apps/console/src/__generated__/core/ObligationsPageFragment.graphql.ts +++ b/apps/console/src/__generated__/core/ObligationsPageFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<27cacc02131c03f5aeaaff764e3bb226>> + * @generated SignedSource<<12b46e529db9caa863dc6f97eaee0c26>> * @lightSyntaxTransform * @nogrep */ @@ -19,6 +19,8 @@ export type ObligationsPageFragment$data = { readonly node: { readonly actionsToBeImplemented: string | null | undefined; readonly area: string | null | undefined; + readonly canDelete: boolean; + readonly canUpdate: boolean; readonly createdAt: any; readonly dueDate: any | null | undefined; readonly id: string; @@ -259,6 +261,32 @@ return { "name": "updatedAt", "storageKey": null }, + { + "alias": "canUpdate", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:obligation:update" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:obligation:update\")" + }, + { + "alias": "canDelete", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:obligation:delete" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:obligation:delete\")" + }, { "alias": null, "args": null, @@ -325,6 +353,6 @@ return { }; })(); -(node as any).hash = "a5dda6d90c9205f7c7d6ea6d84d760f1"; +(node as any).hash = "b80f122b447b6a979b4774851ad11ee5"; export default node; diff --git a/apps/console/src/__generated__/core/ObligationsPageRefetchQuery.graphql.ts b/apps/console/src/__generated__/core/ObligationsPageRefetchQuery.graphql.ts index 06fee343b..114cf9a1e 100644 --- a/apps/console/src/__generated__/core/ObligationsPageRefetchQuery.graphql.ts +++ b/apps/console/src/__generated__/core/ObligationsPageRefetchQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<3b2a48df3fdef9f91bc4520ed2448423>> + * @generated SignedSource<<70d87b06a0ba8d361312388f587e14a4>> * @lightSyntaxTransform * @nogrep */ @@ -289,6 +289,32 @@ return { "name": "updatedAt", "storageKey": null }, + { + "alias": "canUpdate", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:obligation:update" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:obligation:update\")" + }, + { + "alias": "canDelete", + "args": [ + { + "kind": "Literal", + "name": "action", + "value": "core:obligation:delete" + } + ], + "kind": "ScalarField", + "name": "permission", + "storageKey": "permission(action:\"core:obligation:delete\")" + }, (v8/*: any*/) ], "storageKey": null @@ -364,16 +390,16 @@ return { ] }, "params": { - "cacheID": "0500f4aee677d8d1ec53cd189e350395", + "cacheID": "df1ca965ec380e12537f713ce9786930", "id": null, "metadata": {}, "name": "ObligationsPageRefetchQuery", "operationKind": "query", - "text": "query ObligationsPageRefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ObligationsPageFragment_35e0S5\n id\n }\n}\n\nfragment ObligationsPageFragment_35e0S5 on Organization {\n id\n obligations(first: $first, after: $after, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" + "text": "query ObligationsPageRefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ObligationsPageFragment_35e0S5\n id\n }\n}\n\nfragment ObligationsPageFragment_35e0S5 on Organization {\n id\n obligations(first: $first, after: $after, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n canUpdate: permission(action: \"core:obligation:update\")\n canDelete: permission(action: \"core:obligation:delete\")\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" } }; })(); -(node as any).hash = "a5dda6d90c9205f7c7d6ea6d84d760f1"; +(node as any).hash = "b80f122b447b6a979b4774851ad11ee5"; export default node; diff --git a/apps/console/src/hooks/graph/ObligationGraph.ts b/apps/console/src/hooks/graph/ObligationGraph.ts index f9201d99a..eaff7c394 100644 --- a/apps/console/src/hooks/graph/ObligationGraph.ts +++ b/apps/console/src/hooks/graph/ObligationGraph.ts @@ -11,6 +11,7 @@ export const obligationsQuery = graphql` query ObligationGraphListQuery($organizationId: ID!, $snapshotId: ID) { node(id: $organizationId) { ... on Organization { + canCreateObligation: permission(action: "core:obligation:create") ...ObligationsPageFragment @arguments(snapshotId: $snapshotId) } } @@ -43,6 +44,8 @@ export const obligationNodeQuery = graphql` } createdAt updatedAt + canUpdate: permission(action: "core:obligation:update") + canDelete: permission(action: "core:obligation:delete") } } } @@ -71,6 +74,8 @@ export const createObligationMutation = graphql` fullName } createdAt + canUpdate: permission(action: "core:obligation:update") + canDelete: permission(action: "core:obligation:delete") } } } @@ -114,7 +119,7 @@ export const deleteObligationMutation = graphql` export const useDeleteObligation = ( obligation: { id: string }, - connectionId: string + connectionId: string, ) => { const { __ } = useTranslate(); const [mutate] = useMutationWithToasts(deleteObligationMutation, { @@ -136,9 +141,9 @@ export const useDeleteObligation = ( }), { message: __( - "This will permanently delete this obligation. This action cannot be undone." + "This will permanently delete this obligation. This action cannot be undone.", ), - } + }, ); }; }; diff --git a/apps/console/src/pages/organizations/obligations/ObligationDetailsPage.tsx b/apps/console/src/pages/organizations/obligations/ObligationDetailsPage.tsx index 8278b5859..fcadbf812 100644 --- a/apps/console/src/pages/organizations/obligations/ObligationDetailsPage.tsx +++ b/apps/console/src/pages/organizations/obligations/ObligationDetailsPage.tsx @@ -42,8 +42,6 @@ import { } from "@probo/helpers"; import { SnapshotBanner } from "/components/SnapshotBanner"; import type { ObligationGraphNodeQuery } from "/__generated__/core/ObligationGraphNodeQuery.graphql"; -import { use } from "react"; -import { PermissionsContext } from "/providers/PermissionsContext"; const updateObligationSchema = z.object({ area: z.string().optional(), @@ -63,17 +61,18 @@ type Props = { }; export default function ObligationDetailsPage(props: Props) { - const data = usePreloadedQuery( + const { queryRef } = props; + const { node: obligation } = usePreloadedQuery( obligationNodeQuery, - props.queryRef, + queryRef, ); - const obligation = data.node; const { __ } = useTranslate(); const { toast } = useToast(); const organizationId = useOrganizationId(); const { snapshotId } = useParams<{ snapshotId?: string }>(); const isSnapshotMode = Boolean(snapshotId); - const { isAuthorized } = use(PermissionsContext); + + const disabled = isSnapshotMode || !obligation.canUpdate; validateSnapshotConsistency(obligation, snapshotId); @@ -186,17 +185,16 @@ export default function ObligationDetailsPage(props: Props) { - {!isSnapshotMode && - isAuthorized("Obligation", "deleteObligation") && ( - - - {__("Delete")} - - - )} + {!isSnapshotMode && obligation.canDelete && ( + + + {__("Delete")} + + + )} @@ -209,7 +207,7 @@ export default function ObligationDetailsPage(props: Props) { @@ -220,7 +218,7 @@ export default function ObligationDetailsPage(props: Props) { @@ -237,7 +235,7 @@ export default function ObligationDetailsPage(props: Props) { onValueChange={field.onChange} value={field.value} className="w-full" - disabled={isSnapshotMode} + disabled={disabled} > {statusOptions.map((option) => (