Fix snapshot pages permissions handling

Signed-off-by: Émile Ré <nemile.re@gmail.com>
This commit is contained in:
Émile Ré
2026-01-02 11:52:00 +01:00
committed by Bryan Frimin
parent 9cc6d143f6
commit ea2438e345
9 changed files with 982 additions and 847 deletions

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<14e03b23c216da916e36cecb49aefa6d>>
* @generated SignedSource<<5c57612f8793f7b056bf0046febe42ca>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -17,6 +17,9 @@ export type ProcessingActivityGraphListQuery$variables = {
export type ProcessingActivityGraphListQuery$data = {
readonly node: {
readonly canCreateProcessingActivity?: boolean;
readonly canExportDataProtectionImpactAssessments?: boolean;
readonly canExportProcessingActivities?: boolean;
readonly canExportTransferImpactAssessments?: boolean;
readonly " $fragmentSpreads": FragmentRefs<"ProcessingActivitiesPageDPIAFragment" | "ProcessingActivitiesPageFragment" | "ProcessingActivitiesPageTIAFragment">;
};
};
@@ -58,30 +61,69 @@ v2 = {
"name": "permission",
"storageKey": "permission(action:\"core:processing-activity:create\")"
},
v3 = [
v3 = {
"alias": "canExportProcessingActivities",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:processing-activity:export"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:processing-activity:export\")"
},
v4 = {
"alias": "canExportDataProtectionImpactAssessments",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:data-protection-impact-assessment:export"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:data-protection-impact-assessment:export\")"
},
v5 = {
"alias": "canExportTransferImpactAssessments",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:transfer-impact-assessment:export"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:transfer-impact-assessment:export\")"
},
v6 = [
{
"kind": "Variable",
"name": "snapshotId",
"variableName": "snapshotId"
}
],
v4 = {
v7 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v5 = {
v8 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v6 = [
v9 = [
{
"fields": (v3/*: any*/),
"fields": (v6/*: any*/),
"kind": "ObjectValue",
"name": "filter"
},
@@ -91,42 +133,42 @@ v6 = [
"value": 10
}
],
v7 = {
v10 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "totalCount",
"storageKey": null
},
v8 = {
v11 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
v9 = {
v12 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
v10 = {
v13 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
v11 = {
v14 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
},
v12 = {
v15 = {
"alias": null,
"args": null,
"concreteType": "PageInfo",
@@ -151,7 +193,7 @@ v12 = {
],
"storageKey": null
},
v13 = {
v16 = {
"kind": "ClientExtension",
"selections": [
{
@@ -163,10 +205,10 @@ v13 = {
}
]
},
v14 = [
v17 = [
"filter"
],
v15 = {
v18 = {
"alias": null,
"args": null,
"concreteType": "ProcessingActivity",
@@ -174,8 +216,8 @@ v15 = {
"name": "processingActivity",
"plural": false,
"selections": [
(v5/*: any*/),
(v8/*: any*/)
(v8/*: any*/),
(v11/*: any*/)
],
"storageKey": null
};
@@ -198,18 +240,21 @@ return {
"kind": "InlineFragment",
"selections": [
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
{
"args": (v3/*: any*/),
"args": (v6/*: any*/),
"kind": "FragmentSpread",
"name": "ProcessingActivitiesPageFragment"
},
{
"args": (v3/*: any*/),
"args": (v6/*: any*/),
"kind": "FragmentSpread",
"name": "ProcessingActivitiesPageDPIAFragment"
},
{
"args": (v3/*: any*/),
"args": (v6/*: any*/),
"kind": "FragmentSpread",
"name": "ProcessingActivitiesPageTIAFragment"
}
@@ -238,21 +283,24 @@ return {
"name": "node",
"plural": false,
"selections": [
(v4/*: any*/),
(v5/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
{
"kind": "InlineFragment",
"selections": [
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
{
"alias": null,
"args": (v6/*: any*/),
"args": (v9/*: any*/),
"concreteType": "ProcessingActivityConnection",
"kind": "LinkedField",
"name": "processingActivities",
"plural": false,
"selections": [
(v7/*: any*/),
(v10/*: any*/),
{
"alias": null,
"args": null,
@@ -269,7 +317,7 @@ return {
"name": "node",
"plural": false,
"selections": [
(v5/*: any*/),
(v8/*: any*/),
{
"alias": null,
"args": null,
@@ -284,7 +332,7 @@ return {
"name": "sourceId",
"storageKey": null
},
(v8/*: any*/),
(v11/*: any*/),
{
"alias": null,
"args": null,
@@ -327,8 +375,8 @@ return {
"name": "internationalTransfers",
"storageKey": null
},
(v9/*: any*/),
(v10/*: any*/),
(v12/*: any*/),
(v13/*: any*/),
{
"alias": "canUpdate",
"args": [
@@ -355,23 +403,23 @@ return {
"name": "permission",
"storageKey": "permission(action:\"core:processing-activity:delete\")"
},
(v4/*: any*/)
(v7/*: any*/)
],
"storageKey": null
},
(v11/*: any*/)
(v14/*: any*/)
],
"storageKey": null
},
(v12/*: any*/),
(v13/*: any*/)
(v15/*: any*/),
(v16/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": (v6/*: any*/),
"filters": (v14/*: any*/),
"args": (v9/*: any*/),
"filters": (v17/*: any*/),
"handle": "connection",
"key": "ProcessingActivitiesPage_processingActivities",
"kind": "LinkedHandle",
@@ -379,13 +427,13 @@ return {
},
{
"alias": null,
"args": (v6/*: any*/),
"args": (v9/*: any*/),
"concreteType": "DataProtectionImpactAssessmentConnection",
"kind": "LinkedField",
"name": "dataProtectionImpactAssessments",
"plural": false,
"selections": [
(v7/*: any*/),
(v10/*: any*/),
{
"alias": null,
"args": null,
@@ -402,7 +450,7 @@ return {
"name": "node",
"plural": false,
"selections": [
(v5/*: any*/),
(v8/*: any*/),
{
"alias": null,
"args": null,
@@ -424,26 +472,26 @@ return {
"name": "residualRisk",
"storageKey": null
},
(v15/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
(v4/*: any*/)
(v18/*: any*/),
(v12/*: any*/),
(v13/*: any*/),
(v7/*: any*/)
],
"storageKey": null
},
(v11/*: any*/)
(v14/*: any*/)
],
"storageKey": null
},
(v12/*: any*/),
(v13/*: any*/)
(v15/*: any*/),
(v16/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": (v6/*: any*/),
"filters": (v14/*: any*/),
"args": (v9/*: any*/),
"filters": (v17/*: any*/),
"handle": "connection",
"key": "ProcessingActivitiesPage_dataProtectionImpactAssessments",
"kind": "LinkedHandle",
@@ -451,13 +499,13 @@ return {
},
{
"alias": null,
"args": (v6/*: any*/),
"args": (v9/*: any*/),
"concreteType": "TransferImpactAssessmentConnection",
"kind": "LinkedField",
"name": "transferImpactAssessments",
"plural": false,
"selections": [
(v7/*: any*/),
(v10/*: any*/),
{
"alias": null,
"args": null,
@@ -474,7 +522,7 @@ return {
"name": "node",
"plural": false,
"selections": [
(v5/*: any*/),
(v8/*: any*/),
{
"alias": null,
"args": null,
@@ -496,26 +544,26 @@ return {
"name": "localLawRisk",
"storageKey": null
},
(v15/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
(v4/*: any*/)
(v18/*: any*/),
(v12/*: any*/),
(v13/*: any*/),
(v7/*: any*/)
],
"storageKey": null
},
(v11/*: any*/)
(v14/*: any*/)
],
"storageKey": null
},
(v12/*: any*/),
(v13/*: any*/)
(v15/*: any*/),
(v16/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": (v6/*: any*/),
"filters": (v14/*: any*/),
"args": (v9/*: any*/),
"filters": (v17/*: any*/),
"handle": "connection",
"key": "ProcessingActivitiesPage_transferImpactAssessments",
"kind": "LinkedHandle",
@@ -531,16 +579,16 @@ return {
]
},
"params": {
"cacheID": "1d48f2badad2cfdbc1d36a06756a9ec7",
"cacheID": "84a26e65e3de62f76f034786cf174f80",
"id": null,
"metadata": {},
"name": "ProcessingActivityGraphListQuery",
"operationKind": "query",
"text": "query ProcessingActivityGraphListQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n canCreateProcessingActivity: permission(action: \"core:processing-activity:create\")\n ...ProcessingActivitiesPageFragment_3iomuz\n ...ProcessingActivitiesPageDPIAFragment_3iomuz\n ...ProcessingActivitiesPageTIAFragment_3iomuz\n }\n id\n }\n}\n\nfragment ProcessingActivitiesPageDPIAFragment_3iomuz on Organization {\n id\n dataProtectionImpactAssessments(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n description\n potentialRisk\n residualRisk\n processingActivity {\n id\n name\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n\nfragment ProcessingActivitiesPageFragment_3iomuz on Organization {\n id\n processingActivities(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n lawfulBasis\n location\n internationalTransfers\n createdAt\n updatedAt\n canUpdate: permission(action: \"core:processing-activity:update\")\n canDelete: permission(action: \"core:processing-activity:delete\")\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n\nfragment ProcessingActivitiesPageTIAFragment_3iomuz on Organization {\n id\n transferImpactAssessments(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n dataSubjects\n transfer\n localLawRisk\n processingActivity {\n id\n name\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
"text": "query ProcessingActivityGraphListQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n canCreateProcessingActivity: permission(action: \"core:processing-activity:create\")\n canExportProcessingActivities: permission(action: \"core:processing-activity:export\")\n canExportDataProtectionImpactAssessments: permission(action: \"core:data-protection-impact-assessment:export\")\n canExportTransferImpactAssessments: permission(action: \"core:transfer-impact-assessment:export\")\n ...ProcessingActivitiesPageFragment_3iomuz\n ...ProcessingActivitiesPageDPIAFragment_3iomuz\n ...ProcessingActivitiesPageTIAFragment_3iomuz\n }\n id\n }\n}\n\nfragment ProcessingActivitiesPageDPIAFragment_3iomuz on Organization {\n id\n dataProtectionImpactAssessments(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n description\n potentialRisk\n residualRisk\n processingActivity {\n id\n name\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n\nfragment ProcessingActivitiesPageFragment_3iomuz on Organization {\n id\n processingActivities(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n lawfulBasis\n location\n internationalTransfers\n createdAt\n updatedAt\n canUpdate: permission(action: \"core:processing-activity:update\")\n canDelete: permission(action: \"core:processing-activity:delete\")\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n\nfragment ProcessingActivitiesPageTIAFragment_3iomuz on Organization {\n id\n transferImpactAssessments(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n dataSubjects\n transfer\n localLawRisk\n processingActivity {\n id\n name\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
}
};
})();
(node as any).hash = "7a0d589abac7bbd3710a0caad37d6273";
(node as any).hash = "6efb688e3142c0eceb054ded9df044de";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<7d676ad166c7c858dc8dbc909ed500ea>>
* @generated SignedSource<<8fe6c01dea59b2ae2d04050e3cb959d1>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -24,6 +24,7 @@ export type SnapshotFormDialogCreateMutation$data = {
readonly createSnapshot: {
readonly snapshotEdge: {
readonly node: {
readonly canDelete: boolean;
readonly createdAt: string;
readonly description: string | null | undefined;
readonly id: string;
@@ -106,6 +107,19 @@ v3 = {
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:snapshot:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:snapshot:delete\")"
}
],
"storageKey": null
@@ -179,16 +193,16 @@ return {
]
},
"params": {
"cacheID": "e60d598bc7f5c4958168405725664334",
"cacheID": "5165891e3f49f2b9e3d1a0b29a0f8bf6",
"id": null,
"metadata": {},
"name": "SnapshotFormDialogCreateMutation",
"operationKind": "mutation",
"text": "mutation SnapshotFormDialogCreateMutation(\n $input: CreateSnapshotInput!\n) {\n createSnapshot(input: $input) {\n snapshotEdge {\n node {\n id\n name\n description\n type\n createdAt\n }\n }\n }\n}\n"
"text": "mutation SnapshotFormDialogCreateMutation(\n $input: CreateSnapshotInput!\n) {\n createSnapshot(input: $input) {\n snapshotEdge {\n node {\n id\n name\n description\n type\n createdAt\n canDelete: permission(action: \"core:snapshot:delete\")\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "b03087e1699a90953aad7cdedaeee1a4";
(node as any).hash = "1a844eb9af4ea94b194deaf65ba068a0";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<f4a719bca36d682b094afe419b9129e8>>
* @generated SignedSource<<55bde95f500bc2496ce224e275e49984>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -15,6 +15,7 @@ export type SnapshotGraphListQuery$variables = {
};
export type SnapshotGraphListQuery$data = {
readonly organization: {
readonly canCreateSnapshot?: boolean;
readonly " $fragmentSpreads": FragmentRefs<"SnapshotsPageFragment">;
};
};
@@ -39,20 +40,33 @@ v1 = [
}
],
v2 = {
"alias": "canCreateSnapshot",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:snapshot:create"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:snapshot:create\")"
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v3 = [
v4 = [
{
"kind": "Literal",
"name": "first",
"value": 100
}
],
v4 = {
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
@@ -77,6 +91,7 @@ return {
{
"kind": "InlineFragment",
"selections": [
(v2/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
@@ -107,13 +122,14 @@ return {
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v3/*: any*/),
{
"kind": "InlineFragment",
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": (v3/*: any*/),
"args": (v4/*: any*/),
"concreteType": "SnapshotConnection",
"kind": "LinkedField",
"name": "snapshots",
@@ -135,7 +151,7 @@ return {
"name": "node",
"plural": false,
"selections": [
(v4/*: any*/),
(v5/*: any*/),
{
"alias": null,
"args": null,
@@ -164,7 +180,20 @@ return {
"name": "createdAt",
"storageKey": null
},
(v2/*: any*/)
{
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:snapshot:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:snapshot:delete\")"
},
(v3/*: any*/)
],
"storageKey": null
},
@@ -220,7 +249,7 @@ return {
},
{
"alias": null,
"args": (v3/*: any*/),
"args": (v4/*: any*/),
"filters": null,
"handle": "connection",
"key": "SnapshotsGraphListQuery__snapshots",
@@ -231,23 +260,23 @@ return {
"type": "Organization",
"abstractKey": null
},
(v4/*: any*/)
(v5/*: any*/)
],
"storageKey": null
}
]
},
"params": {
"cacheID": "eda538d8a5e4e94551012bbb6b8da92f",
"cacheID": "5925e1c6f87d598008baeef50bf620c7",
"id": null,
"metadata": {},
"name": "SnapshotGraphListQuery",
"operationKind": "query",
"text": "query SnapshotGraphListQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n ...SnapshotsPageFragment\n }\n id\n }\n}\n\nfragment SnapshotsPageFragment on Organization {\n snapshots(first: 100) {\n edges {\n node {\n id\n name\n description\n type\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n"
"text": "query SnapshotGraphListQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n canCreateSnapshot: permission(action: \"core:snapshot:create\")\n ...SnapshotsPageFragment\n }\n id\n }\n}\n\nfragment SnapshotsPageFragment on Organization {\n snapshots(first: 100) {\n edges {\n node {\n id\n name\n description\n type\n createdAt\n canDelete: permission(action: \"core:snapshot:delete\")\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n"
}
};
})();
(node as any).hash = "0f264bca502a59b7f8b8ec729d0ce1ff";
(node as any).hash = "18d12720fafef47af62376e8461fd19f";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<8aa2e602e0b579ac6a320207afa7c558>>
* @generated SignedSource<<a4f24e8f6dd08074e60067f638eacfd9>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -16,6 +16,7 @@ export type SnapshotsPageFragment$data = {
readonly __id: string;
readonly edges: ReadonlyArray<{
readonly node: {
readonly canDelete: boolean;
readonly createdAt: string;
readonly description: string | null | undefined;
readonly id: string;
@@ -107,6 +108,19 @@ const node: ReaderFragment = {
"name": "createdAt",
"storageKey": null
},
{
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:snapshot:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:snapshot:delete\")"
},
{
"alias": null,
"args": null,
@@ -172,6 +186,6 @@ const node: ReaderFragment = {
"abstractKey": null
};
(node as any).hash = "700dede55fd00f2b57dbbb6ed2e2613d";
(node as any).hash = "d924051b479e33aa7fb627e7ad8ad664";
export default node;

View File

@@ -19,6 +19,15 @@ export const processingActivitiesQuery = graphql`
canCreateProcessingActivity: permission(
action: "core:processing-activity:create"
)
canExportProcessingActivities: permission(
action: "core:processing-activity:export"
)
canExportDataProtectionImpactAssessments: permission(
action: "core:data-protection-impact-assessment:export"
)
canExportTransferImpactAssessments: permission(
action: "core:transfer-impact-assessment:export"
)
...ProcessingActivitiesPageFragment @arguments(snapshotId: $snapshotId)
...ProcessingActivitiesPageDPIAFragment
@arguments(snapshotId: $snapshotId)

View File

@@ -11,6 +11,7 @@ export const snapshotsQuery = graphql`
query SnapshotGraphListQuery($organizationId: ID!) {
organization: node(id: $organizationId) {
... on Organization {
canCreateSnapshot: permission(action: "core:snapshot:create")
...SnapshotsPageFragment
}
}
@@ -67,7 +68,7 @@ export const deleteSnapshotMutation = graphql`
export const useDeleteSnapshot = (
snapshot: { id: string; name: string },
connectionId: string
connectionId: string,
) => {
const { __ } = useTranslate();
const [mutate] = useMutationWithToasts(deleteSnapshotMutation, {
@@ -90,11 +91,11 @@ export const useDeleteSnapshot = (
{
message: sprintf(
__(
"This will permanently delete the snapshot %s. This action cannot be undone."
"This will permanently delete the snapshot %s. This action cannot be undone.",
),
snapshot.name
snapshot.name,
),
}
},
);
};
};

View File

@@ -35,8 +35,6 @@ import type { NodeOf } from "/types";
import SnapshotFormDialog from "./dialog/SnapshotFormDialog";
import { usePageTitle } from "@probo/hooks";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { PermissionsContext } from "/providers/PermissionsContext";
import { use } from "react";
type Props = {
queryRef: PreloadedQuery<SnapshotGraphListQuery>;
@@ -54,6 +52,7 @@ const snapshotsFragment = graphql`
description
type
createdAt
canDelete: permission(action: "core:snapshot:delete")
}
}
}
@@ -73,10 +72,9 @@ export default function SnapshotsPage(props: Props) {
);
const connectionId = data.snapshots.__id;
const snapshots = data.snapshots.edges.map((edge) => edge.node);
const { isAuthorized } = use(PermissionsContext);
usePageTitle(__("Snapshots"));
const hasAnyAction = isAuthorized("Snapshot", "deleteSnapshot");
const hasAnyAction = snapshots.some(({ canDelete }) => canDelete);
return (
<div className="space-y-6">
@@ -86,7 +84,7 @@ export default function SnapshotsPage(props: Props) {
"Snapshots capture point-in-time views of your organization's compliance state. Create snapshots to track progress over time.",
)}
>
{isAuthorized("Organization", "createSnapshot") && (
{organization.canCreateSnapshot && (
<SnapshotFormDialog connection={connectionId}>
<Button variant="primary" icon={IconPlusLarge}>
{__("New snapshot")}
@@ -142,7 +140,6 @@ type SnapshotRowProps = {
function SnapshotRow(props: SnapshotRowProps) {
const { __ } = useTranslate();
const deleteSnapshot = useDeleteSnapshot(props.snapshot, props.connectionId);
const { isAuthorized } = use(PermissionsContext);
const typePath = getSnapshotTypeUrlPath(props.snapshot.type);
return (
@@ -164,7 +161,7 @@ function SnapshotRow(props: SnapshotRowProps) {
{props.hasAnyAction && (
<Td noLink width={50} className="text-end">
<ActionDropdown>
{isAuthorized("Snapshot", "deleteSnapshot") && (
{props.snapshot.canDelete && (
<DropdownItem
onClick={deleteSnapshot}
variant="danger"

View File

@@ -34,6 +34,7 @@ const snapshotCreateMutation = graphql`
description
type
createdAt
canDelete: permission(action: "core:snapshot:delete")
}
}
}
@@ -60,14 +61,19 @@ export default function SnapshotFormDialog(props: Props) {
errorMessage: __("Failed to create snapshot"),
});
const { handleSubmit, register, reset, control, formState: { errors } } =
useFormWithSchema(snapshotSchema, {
defaultValues: {
name: "",
description: "",
type: "DATA",
},
});
const {
handleSubmit,
register,
reset,
control,
formState: { errors },
} = useFormWithSchema(snapshotSchema, {
defaultValues: {
name: "",
description: "",
type: "DATA",
},
});
const onSubmit = handleSubmit(async (data) => {
await mutate({
@@ -89,14 +95,7 @@ export default function SnapshotFormDialog(props: Props) {
<Dialog
ref={dialogRef}
trigger={props.children}
title={
<Breadcrumb
items={[
__("Snapshots"),
__("New Snapshot"),
]}
/>
}
title={<Breadcrumb items={[__("Snapshots"), __("New Snapshot")]} />}
>
<form onSubmit={onSubmit}>
<DialogContent className="grid grid-cols-[1fr_420px]">
@@ -125,20 +124,14 @@ export default function SnapshotFormDialog(props: Props) {
label={__("Type")}
error={errors.type?.message}
>
<ControlledField
control={control}
name="type"
type="select"
>
<ControlledField control={control} name="type" type="select">
<SnapshotTypeOptions />
</ControlledField>
</PropertyRow>
</div>
</DialogContent>
<DialogFooter>
<Button type="submit">
{__("Create snapshot")}
</Button>
<Button type="submit">{__("Create snapshot")}</Button>
</DialogFooter>
</form>
</Dialog>