add permissions and fix issues

This commit is contained in:
Marshal
2026-07-23 20:24:20 +00:00
parent 40f16f3cec
commit 668b5e1c9d
40 changed files with 18634 additions and 342 deletions

View File

@@ -114,7 +114,9 @@ const CargoTypesPage = () => {
const config = getRuleEngineResource(CARGO_SLUG);
const canView = canAccessRuleEngineResource(user, CARGO_SLUG, "view");
const canManage = canAccessRuleEngineResource(user, CARGO_SLUG, "manage");
const canCreate = canAccessRuleEngineResource(user, CARGO_SLUG, "create");
const canUpdate = canAccessRuleEngineResource(user, CARGO_SLUG, "update");
const canDelete = canAccessRuleEngineResource(user, CARGO_SLUG, "delete");
// One fetch of the whole (small) set — page-walked because the API caps
// pageSize at 100; the tree, ancestry and each level are derived client-side
@@ -128,7 +130,7 @@ const CargoTypesPage = () => {
const { create, update, remove } = useRuleEngineMutations(CARGO_SLUG);
// Wagon-type options for the "Wagon types" picker (bulk cargo → allowed list).
const { data: wagonTypeOptions } = useWagonTypeOptions(canManage);
const { data: wagonTypeOptions } = useWagonTypeOptions(canCreate || canUpdate);
const formFields = useMemo<FormFieldDef[]>(
() =>
FORM_FIELDS.map((field) =>
@@ -291,7 +293,7 @@ const CargoTypesPage = () => {
leftSection={<Search size={16} />}
w={240}
/>
{canManage && (
{canCreate && (
<Button
color="teal"
leftSection={<Plus size={16} />}
@@ -335,7 +337,7 @@ const CargoTypesPage = () => {
? "No cargo categories yet"
: `No cargo types under “${str(current?.cargoTypeName)}” yet`}
</Text>
{!term && canManage && (
{!term && canCreate && (
<Button
variant="light"
color="teal"
@@ -354,7 +356,8 @@ const CargoTypesPage = () => {
node={node}
childCount={(childrenOf.get(node.id) ?? []).length}
topBorder={i > 0}
canManage={canManage}
canUpdate={canUpdate}
canDelete={canDelete}
onOpen={() => navigate(`${BASE_PATH}/${node.id}`)}
onEdit={() => setFormMode({ kind: "edit", record: node })}
onDelete={() => setDeleteTarget(node)}
@@ -444,7 +447,8 @@ interface CargoRowProps {
node: CargoNode;
childCount: number;
topBorder: boolean;
canManage: boolean;
canUpdate: boolean;
canDelete: boolean;
onOpen: () => void;
onEdit: () => void;
onDelete: () => void;
@@ -454,7 +458,8 @@ function CargoRow({
node,
childCount,
topBorder,
canManage,
canUpdate,
canDelete,
onOpen,
onEdit,
onDelete,
@@ -529,19 +534,19 @@ function CargoRow({
</UnstyledButton>
<Group gap={4} wrap="nowrap">
{canManage && (
<>
<Tooltip label="Edit" withArrow>
<Button size="compact-sm" variant="subtle" color="gray" onClick={onEdit} px={8}>
<Pencil size={15} />
</Button>
</Tooltip>
<Tooltip label="Delete" withArrow>
<Button size="compact-sm" variant="subtle" color="red" onClick={onDelete} px={8}>
<Trash2 size={15} />
</Button>
</Tooltip>
</>
{canUpdate && (
<Tooltip label="Edit" withArrow>
<Button size="compact-sm" variant="subtle" color="gray" onClick={onEdit} px={8}>
<Pencil size={15} />
</Button>
</Tooltip>
)}
{canDelete && (
<Tooltip label="Delete" withArrow>
<Button size="compact-sm" variant="subtle" color="red" onClick={onDelete} px={8}>
<Trash2 size={15} />
</Button>
</Tooltip>
)}
<Tooltip label="Open" withArrow>
<Button size="compact-sm" variant="subtle" color="teal" onClick={onOpen} px={8}>

View File

@@ -150,9 +150,20 @@ const RuleEngineResourcePage = () => {
const canView = Boolean(
config && canAccessRuleEngineResource(user, config.slug, "view"),
);
const canManage = Boolean(
config && canAccessRuleEngineResource(user, config.slug, "manage"),
// Per-action gates replace the retired coarse "manage": Add shows only with
// create, row Edit with update, row Delete with delete.
const canCreate = Boolean(
config && canAccessRuleEngineResource(user, config.slug, "create"),
);
const canUpdate = Boolean(
config && canAccessRuleEngineResource(user, config.slug, "update"),
);
const canDelete = Boolean(
config && canAccessRuleEngineResource(user, config.slug, "delete"),
);
// Update-class controls (reorder, rate submit/approve, approval-rule decide)
// all map to the update permission — the matching endpoints now require it.
const canUpdateControls = canUpdate;
const listParams = useMemo(
() => ({
@@ -480,7 +491,7 @@ const RuleEngineResourcePage = () => {
cell: ({ row }) => (
<div onClick={(e) => e.stopPropagation()} data-stop-row-click>
<Group gap="xs" wrap="nowrap" justify="flex-end">
{config.orderConfig && canManage ? (
{config.orderConfig && canUpdateControls ? (
<RuleEngineOrderControls
record={row.original}
orderConfig={config.orderConfig}
@@ -493,7 +504,7 @@ const RuleEngineResourcePage = () => {
record={row.original}
config={config}
layout="row"
readOnly={!canManage}
readOnly={!canUpdateControls}
onEdit={(record) => {
setEditing(record);
setFormOpen(true);
@@ -504,8 +515,8 @@ const RuleEngineResourcePage = () => {
? () => setChainOpen(true)
: undefined
}
onSubmitRate={canManage ? (id) => submit.mutate(id) : undefined}
onApproveRate={canManage ? handleApproveRate : undefined}
onSubmitRate={canUpdateControls ? (id) => submit.mutate(id) : undefined}
onApproveRate={canUpdateControls ? handleApproveRate : undefined}
/>
</Group>
</div>
@@ -514,7 +525,7 @@ const RuleEngineResourcePage = () => {
return base;
}, [
canManage,
canUpdateControls,
config,
isRates,
pendingByRateId,
@@ -642,7 +653,7 @@ const RuleEngineResourcePage = () => {
title={config.label}
subtitle={config.subtitle}
action={
canManage && config.slug !== "container-types" ? (
canCreate && config.slug !== "container-types" ? (
<Button leftSection={<Plus size={18} />} onClick={openCreate}>
{addLabel}
</Button>
@@ -653,7 +664,7 @@ const RuleEngineResourcePage = () => {
{isPriorityRules ? (
<PriorityRuleApprovalsSection
requests={priorityWorkflow.pending.data ?? []}
canDecide={canManage}
canDecide={canUpdateControls}
approve={priorityWorkflow.approve}
reject={priorityWorkflow.reject}
/>
@@ -742,7 +753,7 @@ const RuleEngineResourcePage = () => {
showSearch={Boolean(config.supportsSearch)}
searchPlaceholder={config.searchPlaceholder}
onManageOrder={
canManage && config.orderConfig
canUpdateControls && config.orderConfig
? () => setOrderDialogOpen(true)
: undefined
}
@@ -806,16 +817,16 @@ const RuleEngineResourcePage = () => {
pageCount={pageCount}
totalCount={totalCount}
onPaginationChange={setPagination}
readOnly={!canManage}
onEdit={canManage ? openEdit : undefined}
onDelete={canManage ? setDeleteTarget : undefined}
readOnly={!canUpdate && !canDelete}
onEdit={canUpdate ? openEdit : undefined}
onDelete={canDelete ? setDeleteTarget : undefined}
onViewChain={
config.slug === "approval-rules"
? () => setChainOpen(true)
: undefined
}
onSubmitRate={canManage ? (id) => submit.mutate(id) : undefined}
onApproveRate={canManage ? handleApproveRate : undefined}
onSubmitRate={canUpdateControls ? (id) => submit.mutate(id) : undefined}
onApproveRate={canUpdateControls ? handleApproveRate : undefined}
/>
)}
</Stack>