Fix data pages permissions handling

Signed-off-by: Émile Ré <nemile.re@gmail.com>
This commit is contained in:
Émile Ré
2025-12-31 16:31:33 +01:00
committed by Bryan Frimin
parent 5b0627b05a
commit f3e23850ff
12 changed files with 333 additions and 60 deletions

View File

@@ -35,8 +35,6 @@ import type {
import type { DataListQuery } from "/__generated__/core/DataListQuery.graphql";
import { SortableTable } from "/components/SortableTable";
import { SnapshotBanner } from "/components/SnapshotBanner";
import { use } from "react";
import { PermissionsContext } from "/providers/PermissionsContext";
const paginatedDataFragment = graphql`
fragment DataPageFragment on Organization
@@ -76,6 +74,8 @@ const paginatedDataFragment = graphql`
}
}
createdAt
canUpdate: permission(action: "core:datum:update")
canDelete: permission(action: "core:datum:delete")
}
}
}
@@ -93,15 +93,12 @@ export default function DataPage(props: Props) {
const organizationId = useOrganizationId();
const { snapshotId } = useParams<{ snapshotId?: string }>();
const isSnapshotMode = Boolean(snapshotId);
const { isAuthorized } = use(PermissionsContext);
const queryData = usePreloadedQuery<DatumGraphListQuery>(
const { node: data } = usePreloadedQuery<DatumGraphListQuery>(
dataQuery,
props.queryRef,
);
const data = queryData.node;
const pagination = usePaginationFragment<DataListQuery, DataPageFragment$key>(
paginatedDataFragment,
data,
@@ -128,8 +125,7 @@ export default function DataPage(props: Props) {
const hasAnyAction =
!isSnapshotMode &&
(isAuthorized("Datum", "updateDatum") ||
isAuthorized("Datum", "deleteDatum"));
dataEntries.some(({ canDelete, canUpdate }) => canUpdate || canDelete);
return (
<div className="space-y-6">
@@ -142,7 +138,7 @@ export default function DataPage(props: Props) {
"Manage your organization's data assets and their classifications.",
)}
>
{!snapshotId && isAuthorized("Organization", "createDatum") && (
{!snapshotId && data.canCreateDatum && (
<CreateDatumDialog
connection={connectionId}
organizationId={organizationId}
@@ -193,7 +189,6 @@ function DataRow({
const { __ } = useTranslate();
const deleteDatum = useDeleteDatum(entry, connectionId);
const vendors = entry.vendors?.edges.map((edge) => edge.node) ?? [];
const { isAuthorized } = use(PermissionsContext);
const detailUrl = snapshotId
? `/organizations/${organizationId}/snapshots/${snapshotId}/data/${entry.id}`
: `/organizations/${organizationId}/data/${entry.id}`;
@@ -235,7 +230,7 @@ function DataRow({
{hasAnyAction && (
<Td noLink width={50} className="text-end">
<ActionDropdown>
{isAuthorized("Datum", "deleteDatum") && (
{entry.canDelete && (
<DropdownItem
onClick={deleteDatum}
variant="danger"

View File

@@ -29,8 +29,6 @@ import z from "zod";
import { SnapshotBanner } from "/components/SnapshotBanner";
import { validateSnapshotConsistency } from "@probo/helpers";
import type { DatumGraphNodeQuery } from "/__generated__/core/DatumGraphNodeQuery.graphql";
import { use } from "react";
import { PermissionsContext } from "/providers/PermissionsContext";
const updateDatumSchema = z.object({
name: z.string().min(1, "Name is required"),
@@ -58,7 +56,6 @@ export default function DatumDetailsPage(props: Props) {
const { __ } = useTranslate();
const organizationId = useOrganizationId();
const { isAuthorized } = use(PermissionsContext);
const deleteDatum = useDeleteDatum(
datumEntry,
@@ -112,6 +109,8 @@ export default function DatumDetailsPage(props: Props) {
},
];
const disabled = !isSnapshotMode && datumEntry.canUpdate;
return (
<div className="space-y-6">
{isSnapshotMode && snapshotId && (
@@ -124,7 +123,7 @@ export default function DatumDetailsPage(props: Props) {
<div className="text-2xl">{datumEntry?.name}</div>
<Badge variant="info">{datumEntry?.dataClassification}</Badge>
</div>
{!isSnapshotMode && isAuthorized("Datum", "deleteDatum") && (
{!isSnapshotMode && datumEntry.canDelete && (
<ActionDropdown variant="secondary">
<DropdownItem
variant="danger"
@@ -142,7 +141,7 @@ export default function DatumDetailsPage(props: Props) {
label={__("Name")}
{...register("name")}
type="text"
disabled={isSnapshotMode}
disabled={!disabled}
/>
<ControlledField
@@ -150,7 +149,7 @@ export default function DatumDetailsPage(props: Props) {
name="dataClassification"
type="select"
label={__("Classification")}
disabled={isSnapshotMode}
disabled={!disabled}
>
<Option value="PUBLIC">{__("Public")}</Option>
<Option value="INTERNAL">{__("Internal")}</Option>
@@ -163,7 +162,7 @@ export default function DatumDetailsPage(props: Props) {
control={control}
name="ownerId"
label={__("Owner")}
disabled={isSnapshotMode}
disabled={!disabled}
/>
<VendorsMultiSelectField
@@ -171,13 +170,13 @@ export default function DatumDetailsPage(props: Props) {
control={control}
name="vendorIds"
label={__("Vendors")}
disabled={isSnapshotMode}
disabled={!disabled}
selectedVendors={vendors}
/>
{!isSnapshotMode && (
<div className="flex justify-end">
{formState.isDirty && isAuthorized("Datum", "updateDatum") && (
{formState.isDirty && datumEntry.canUpdate && (
<Button type="submit" disabled={formState.isSubmitting}>
{formState.isSubmitting ? __("Updating...") : __("Update")}
</Button>