mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 12:18:11 +00:00
implement freight permissions for trains, wagons, and routes
This commit is contained in:
@@ -3,6 +3,8 @@ import { Box, Button, Card, Container, Group, Modal, Select, Stack, Text, Title
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { api } from "@/services/api";
|
||||
import { useAuth } from "@/auth/useAuth";
|
||||
import { canFleetAction } from "@/lib/permissions";
|
||||
import Breadcrumbs from "@/components/ui/Breadcrumbs";
|
||||
import { Inbox, Plus, Warehouse } from "lucide-react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
@@ -37,6 +39,10 @@ const FleetResourcePage = () => {
|
||||
const slug = getFleetSlugFromPath(location.pathname) ?? DEFAULT_SLUG;
|
||||
const config = getFleetResource(slug);
|
||||
const { toast } = useToast();
|
||||
const { user } = useAuth();
|
||||
const canCreate = canFleetAction(user, slug, "create");
|
||||
const canUpdate = canFleetAction(user, slug, "update");
|
||||
const canDelete = canFleetAction(user, slug, "delete");
|
||||
|
||||
const { pagination, setPagination } = usePagination({ pageSize: 10 });
|
||||
const [search, setSearch] = useState("");
|
||||
@@ -278,12 +284,16 @@ const FleetResourcePage = () => {
|
||||
record={row.original}
|
||||
config={config}
|
||||
layout="compact"
|
||||
onEdit={(record) => {
|
||||
setEditing(record);
|
||||
setFormOpen(true);
|
||||
}}
|
||||
onRemove={setRemoveTarget}
|
||||
onAssignDriver={setAssigningDriver}
|
||||
onEdit={
|
||||
canUpdate
|
||||
? (record) => {
|
||||
setEditing(record);
|
||||
setFormOpen(true);
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onRemove={canDelete ? setRemoveTarget : undefined}
|
||||
onAssignDriver={canUpdate ? setAssigningDriver : undefined}
|
||||
onHistory={setHistoryTarget}
|
||||
/>
|
||||
</div>
|
||||
@@ -291,7 +301,7 @@ const FleetResourcePage = () => {
|
||||
});
|
||||
|
||||
return base;
|
||||
}, [config, dynamicOptions.yards]);
|
||||
}, [config, dynamicOptions.yards, canUpdate, canDelete]);
|
||||
|
||||
const tableStatus = isLoading ? "loading" : isError ? "error" : "success";
|
||||
|
||||
@@ -390,15 +400,17 @@ const FleetResourcePage = () => {
|
||||
<Group gap="sm">
|
||||
{slug === "wagons" ? (
|
||||
<>
|
||||
<Button
|
||||
variant="light"
|
||||
color="edr-green"
|
||||
leftSection={<Warehouse size={16} />}
|
||||
styles={{ label: { fontWeight: 500 } }}
|
||||
onClick={() => setWagonWorkspaceOpen(true)}
|
||||
>
|
||||
Yard Workspace
|
||||
</Button>
|
||||
{canUpdate ? (
|
||||
<Button
|
||||
variant="light"
|
||||
color="edr-green"
|
||||
leftSection={<Warehouse size={16} />}
|
||||
styles={{ label: { fontWeight: 500 } }}
|
||||
onClick={() => setWagonWorkspaceOpen(true)}
|
||||
>
|
||||
Yard Workspace
|
||||
</Button>
|
||||
) : null}
|
||||
<Button
|
||||
variant="light"
|
||||
color="grape"
|
||||
@@ -410,12 +422,14 @@ const FleetResourcePage = () => {
|
||||
</Button>
|
||||
</>
|
||||
) : null}
|
||||
<Button leftSection={<Plus size={16} />} styles={{ label: { fontWeight: 500 } }} onClick={() => {
|
||||
setEditing(null);
|
||||
setFormOpen(true);
|
||||
}}>
|
||||
{config.addLabel}
|
||||
</Button>
|
||||
{canCreate ? (
|
||||
<Button leftSection={<Plus size={16} />} styles={{ label: { fontWeight: 500 } }} onClick={() => {
|
||||
setEditing(null);
|
||||
setFormOpen(true);
|
||||
}}>
|
||||
{config.addLabel}
|
||||
</Button>
|
||||
) : null}
|
||||
</Group>
|
||||
</Group>
|
||||
|
||||
@@ -529,11 +543,15 @@ const FleetResourcePage = () => {
|
||||
pageCount={pageCount}
|
||||
totalCount={filteredRows.length}
|
||||
onPaginationChange={setPagination}
|
||||
onEdit={(record) => {
|
||||
setEditing(record);
|
||||
setFormOpen(true);
|
||||
}}
|
||||
onRemove={setRemoveTarget}
|
||||
onEdit={
|
||||
canUpdate
|
||||
? (record) => {
|
||||
setEditing(record);
|
||||
setFormOpen(true);
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onRemove={canDelete ? setRemoveTarget : undefined}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
@@ -36,6 +36,8 @@ import RuleEngineListFooter from "@/components/ruleEngine/RuleEngineListFooter";
|
||||
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
|
||||
import { api } from "@/services/api";
|
||||
import { ruleEngineService } from "@/services/ruleEngine/ruleEngine.service";
|
||||
import { useAuth } from "@/auth/useAuth";
|
||||
import { canFleetAction } from "@/lib/permissions";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import {
|
||||
formatRouteLabel,
|
||||
@@ -160,6 +162,10 @@ export default function RoutesPage() {
|
||||
const { viewMode, setViewMode } = useFleetViewMode("routes");
|
||||
const { pagination, setPagination } = usePagination({ pageSize: 10 });
|
||||
const { toast } = useToast();
|
||||
const { user } = useAuth();
|
||||
const canCreate = canFleetAction(user, "routes", "create");
|
||||
const canUpdate = canFleetAction(user, "routes", "update");
|
||||
const canDelete = canFleetAction(user, "routes", "delete");
|
||||
|
||||
const routesQuery = useQuery(api.routes.list.queryOptions());
|
||||
const yardsQuery = useQuery(api.routes.yards.queryOptions());
|
||||
@@ -441,26 +447,30 @@ export default function RoutesPage() {
|
||||
<Eye size={16} />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
<Tooltip label="Edit">
|
||||
<ActionIcon variant="subtle" color="gray" onClick={() => openEdit(row.original)}>
|
||||
<Edit size={16} />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
<Tooltip label="Mark stop working">
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
color="red"
|
||||
disabled={row.original.status === "STOP_WORKING" || deactivateMutation.isPending}
|
||||
onClick={() => handleDeactivate(row.original)}
|
||||
>
|
||||
<Trash2 size={16} />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
{canUpdate ? (
|
||||
<Tooltip label="Edit">
|
||||
<ActionIcon variant="subtle" color="gray" onClick={() => openEdit(row.original)}>
|
||||
<Edit size={16} />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{canDelete ? (
|
||||
<Tooltip label="Mark stop working">
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
color="red"
|
||||
disabled={row.original.status === "STOP_WORKING" || deactivateMutation.isPending}
|
||||
onClick={() => handleDeactivate(row.original)}
|
||||
>
|
||||
<Trash2 size={16} />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</Group>
|
||||
),
|
||||
},
|
||||
];
|
||||
}, [deactivateMutation.isPending]);
|
||||
}, [deactivateMutation.isPending, canUpdate, canDelete]);
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
@@ -468,9 +478,11 @@ export default function RoutesPage() {
|
||||
title="Routes"
|
||||
subtitle="Define rail corridors, segment distances, and operational status for train scheduling."
|
||||
action={
|
||||
<Button leftSection={<Plus size={18} />} onClick={openCreate}>
|
||||
Add route
|
||||
</Button>
|
||||
canCreate ? (
|
||||
<Button leftSection={<Plus size={18} />} onClick={openCreate}>
|
||||
Add route
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -555,9 +567,11 @@ export default function RoutesPage() {
|
||||
<Button variant="light" size="compact-sm" onClick={() => setViewing(route)}>
|
||||
View
|
||||
</Button>
|
||||
<Button variant="light" size="compact-sm" onClick={() => openEdit(route)}>
|
||||
Edit
|
||||
</Button>
|
||||
{canUpdate ? (
|
||||
<Button variant="light" size="compact-sm" onClick={() => openEdit(route)}>
|
||||
Edit
|
||||
</Button>
|
||||
) : null}
|
||||
</Group>
|
||||
</Stack>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user