mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 08:48:11 +00:00
feat(iam): add per-layout overview permissions
Adds edr_freight_app:overview:<layout>:view for each of the 6 overview dashboard layouts (clearance, occ, operation, marketer, finance, executive), seeded via OVERVIEW_LAYOUT_PERMISSIONS alongside the existing report permissions. Granted 1:1 to match today's role-dashboards.config.ts ROLE_LAYOUTS key table, appended only at the terminal EDR_FREIGHT_ROLES / EDR_FREIGHT_POSITIONS assembly points (never inside the reusable ROLE_PERMISSION_PRESETS/POSITION_PERMISSION_PRESETS builders) so composite positions like chief don't leak multiple layout grants from the role arrays they spread. The ~20 ad-hoc edr_freight_app/xxx department sub-positions are not backfilled here and will fall back to the executive layout until granted manually via the IAM positions admin screen. Part of switching overview layout resolution from role/position-key matching to permission checks, mirroring how reports already work.
This commit is contained in:
@@ -2,10 +2,15 @@ import {
|
|||||||
BOOKING_RULE_ENGINE_PERMISSIONS,
|
BOOKING_RULE_ENGINE_PERMISSIONS,
|
||||||
BOOKING_RULE_ENGINE_PERMISSION_KEYS,
|
BOOKING_RULE_ENGINE_PERMISSION_KEYS,
|
||||||
deriveReadPermissions,
|
deriveReadPermissions,
|
||||||
|
FREIGHT_PERMS,
|
||||||
POSITION_PERMISSION_PRESETS,
|
POSITION_PERMISSION_PRESETS,
|
||||||
ROLE_PERMISSION_PRESETS,
|
ROLE_PERMISSION_PRESETS,
|
||||||
} from './freight-permissions.registry';
|
} from './freight-permissions.registry';
|
||||||
|
|
||||||
|
/** Shorthand for the one overview-layout permission a role/position preset gets. */
|
||||||
|
const overviewLayout = (key: Parameters<typeof FREIGHT_PERMS.overview.layout>[0]): string =>
|
||||||
|
FREIGHT_PERMS.overview.layout(key);
|
||||||
|
|
||||||
export type FreightSeedRole = {
|
export type FreightSeedRole = {
|
||||||
key: string;
|
key: string;
|
||||||
name: { en: string };
|
name: { en: string };
|
||||||
@@ -248,48 +253,55 @@ export const EDR_FREIGHT_ROLES: FreightSeedRole[] = [
|
|||||||
{
|
{
|
||||||
key: "edr_line_staff",
|
key: "edr_line_staff",
|
||||||
name: { en: "EDR Line Staff" },
|
name: { en: "EDR Line Staff" },
|
||||||
permissionKeys: [...ROLE_PERMISSION_PRESETS.lineStaff],
|
// OCC: the legacy role form of the control-centre desk (no position preset
|
||||||
|
// grants this layout — see EDR_FREIGHT_POSITIONS).
|
||||||
|
permissionKeys: [...ROLE_PERMISSION_PRESETS.lineStaff, overviewLayout("occ")],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "edr_operations_officer",
|
key: "edr_operations_officer",
|
||||||
name: { en: "EDR Operations Officer" },
|
name: { en: "EDR Operations Officer" },
|
||||||
permissionKeys: [...ROLE_PERMISSION_PRESETS.operationsOfficer],
|
permissionKeys: [
|
||||||
|
...ROLE_PERMISSION_PRESETS.operationsOfficer,
|
||||||
|
overviewLayout("operation"),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "edr_director",
|
key: "edr_director",
|
||||||
name: { en: "EDR Director" },
|
name: { en: "EDR Director" },
|
||||||
permissionKeys: [...ROLE_PERMISSION_PRESETS.director],
|
permissionKeys: [...ROLE_PERMISSION_PRESETS.director, overviewLayout("executive")],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "edr_ceo",
|
key: "edr_ceo",
|
||||||
name: { en: "EDR CEO" },
|
name: { en: "EDR CEO" },
|
||||||
permissionKeys: [...ROLE_PERMISSION_PRESETS.ceo],
|
permissionKeys: [...ROLE_PERMISSION_PRESETS.ceo, overviewLayout("executive")],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "edr_finance",
|
key: "edr_finance",
|
||||||
name: { en: "EDR Finance" },
|
name: { en: "EDR Finance" },
|
||||||
permissionKeys: [...ROLE_PERMISSION_PRESETS.finance],
|
// No position preset grants this layout — Finance only exists as a Role.
|
||||||
|
permissionKeys: [...ROLE_PERMISSION_PRESETS.finance, overviewLayout("finance")],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "edr_marketing",
|
key: "edr_marketing",
|
||||||
name: { en: "EDR Marketing" },
|
name: { en: "EDR Marketing" },
|
||||||
permissionKeys: [...ROLE_PERMISSION_PRESETS.marketing],
|
permissionKeys: [...ROLE_PERMISSION_PRESETS.marketing, overviewLayout("marketer")],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "edr_gl_ethiopia",
|
key: "edr_gl_ethiopia",
|
||||||
name: { en: "EDR Global Logistics — Ethiopia" },
|
name: { en: "EDR Global Logistics — Ethiopia" },
|
||||||
permissionKeys: [...ROLE_PERMISSION_PRESETS.glEthiopia],
|
permissionKeys: [...ROLE_PERMISSION_PRESETS.glEthiopia, overviewLayout("clearance")],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "edr_gl_djibouti",
|
key: "edr_gl_djibouti",
|
||||||
name: { en: "EDR Global Logistics — Djibouti" },
|
name: { en: "EDR Global Logistics — Djibouti" },
|
||||||
permissionKeys: [...ROLE_PERMISSION_PRESETS.glDjibouti],
|
permissionKeys: [...ROLE_PERMISSION_PRESETS.glDjibouti, overviewLayout("clearance")],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "edr_org_manager",
|
key: "edr_org_manager",
|
||||||
name: { en: "EDR Org Manager" },
|
name: { en: "EDR Org Manager" },
|
||||||
permissionKeys: [
|
permissionKeys: [
|
||||||
...BOOKING_RULE_ENGINE_PERMISSION_KEYS,
|
...BOOKING_RULE_ENGINE_PERMISSION_KEYS,
|
||||||
|
overviewLayout("executive"),
|
||||||
...EMPLOYEE_REGISTRATION_PERMISSIONS.map((p) => p.key),
|
...EMPLOYEE_REGISTRATION_PERMISSIONS.map((p) => p.key),
|
||||||
...ROLE_ASSIGNMENT_PERMISSIONS.map((p) => p.key),
|
...ROLE_ASSIGNMENT_PERMISSIONS.map((p) => p.key),
|
||||||
...HIERARCHY_UNIT_PERMISSIONS.map((p) => p.key),
|
...HIERARCHY_UNIT_PERMISSIONS.map((p) => p.key),
|
||||||
@@ -326,15 +338,17 @@ export const EDR_FREIGHT_ROLES: FreightSeedRole[] = [
|
|||||||
* PositionPermission rows (NOT Role/RolePermission). Users get their access by
|
* PositionPermission rows (NOT Role/RolePermission). Users get their access by
|
||||||
* being assigned to a Position via EmployeePosition.
|
* being assigned to a Position via EmployeePosition.
|
||||||
*/
|
*/
|
||||||
|
// No position preset grants the "occ" or "finance" overview layouts today —
|
||||||
|
// see the comments on edr_line_staff / edr_finance above.
|
||||||
export const EDR_FREIGHT_POSITIONS: FreightSeedPosition[] = [
|
export const EDR_FREIGHT_POSITIONS: FreightSeedPosition[] = [
|
||||||
{ key: "chief", name: { en: "Chief" }, rank: 1, permissionKeys: [...POSITION_PERMISSION_PRESETS.chief] },
|
{ key: "chief", name: { en: "Chief" }, rank: 1, permissionKeys: [...POSITION_PERMISSION_PRESETS.chief, overviewLayout("executive")] },
|
||||||
{ key: "director", name: { en: "Director" }, rank: 2, permissionKeys: [...POSITION_PERMISSION_PRESETS.director] },
|
{ key: "director", name: { en: "Director" }, rank: 2, permissionKeys: [...POSITION_PERMISSION_PRESETS.director, overviewLayout("executive")] },
|
||||||
{ key: "ceo", name: { en: "CEO" }, rank: 1, permissionKeys: [...POSITION_PERMISSION_PRESETS.ceo] },
|
{ key: "ceo", name: { en: "CEO" }, rank: 1, permissionKeys: [...POSITION_PERMISSION_PRESETS.ceo, overviewLayout("executive")] },
|
||||||
{ key: "ethiopian_gl", name: { en: "Ethiopian GL" }, rank: 3, permissionKeys: [...POSITION_PERMISSION_PRESETS.ethiopianGl] },
|
{ key: "ethiopian_gl", name: { en: "Ethiopian GL" }, rank: 3, permissionKeys: [...POSITION_PERMISSION_PRESETS.ethiopianGl, overviewLayout("clearance")] },
|
||||||
{ key: "djibouti_gl", name: { en: "Djibouti GL" }, rank: 3, permissionKeys: [...POSITION_PERMISSION_PRESETS.djiboutiGl] },
|
{ key: "djibouti_gl", name: { en: "Djibouti GL" }, rank: 3, permissionKeys: [...POSITION_PERMISSION_PRESETS.djiboutiGl, overviewLayout("clearance")] },
|
||||||
{ key: "marketer", name: { en: "Marketer" }, rank: 4, permissionKeys: [...POSITION_PERMISSION_PRESETS.marketer] },
|
{ key: "marketer", name: { en: "Marketer" }, rank: 4, permissionKeys: [...POSITION_PERMISSION_PRESETS.marketer, overviewLayout("marketer")] },
|
||||||
{ key: "operation", name: { en: "Operation" }, rank: 4, permissionKeys: [...POSITION_PERMISSION_PRESETS.operation] },
|
{ key: "operation", name: { en: "Operation" }, rank: 4, permissionKeys: [...POSITION_PERMISSION_PRESETS.operation, overviewLayout("operation")] },
|
||||||
{ key: "operations_chief", name: { en: "Operations Chief" }, rank: 2, permissionKeys: [...POSITION_PERMISSION_PRESETS.operationsChief] },
|
{ key: "operations_chief", name: { en: "Operations Chief" }, rank: 2, permissionKeys: [...POSITION_PERMISSION_PRESETS.operationsChief, overviewLayout("operation")] },
|
||||||
{ key: "dispatcher", name: { en: "Dispatcher" }, rank: 4, permissionKeys: [...POSITION_PERMISSION_PRESETS.dispatcher] },
|
{ key: "dispatcher", name: { en: "Dispatcher" }, rank: 4, permissionKeys: [...POSITION_PERMISSION_PRESETS.dispatcher, overviewLayout("operation")] },
|
||||||
{ key: "truck_machinery_chief", name: { en: "Truck & Machinery Chief" }, rank: 2, permissionKeys: [...POSITION_PERMISSION_PRESETS.truckMachineryChief] },
|
{ key: "truck_machinery_chief", name: { en: "Truck & Machinery Chief" }, rank: 2, permissionKeys: [...POSITION_PERMISSION_PRESETS.truckMachineryChief, overviewLayout("operation")] },
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -148,6 +148,52 @@ export const REPORT_PERMISSIONS: FreightPermissionSeed[] =
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overview dashboard layouts (see the backoffice's role-dashboards.config.ts,
|
||||||
|
* where `LAYOUTS` renders one composition per key). Unlike reports, a caller
|
||||||
|
* lands on exactly ONE layout, so `OVERVIEW_LAYOUT_KEYS` is also the priority
|
||||||
|
* order: whoever resolves the permission set picks the FIRST key here the
|
||||||
|
* caller holds — the specific operational view wins over the broad executive
|
||||||
|
* one, same rule the old role/position-key table encoded.
|
||||||
|
*
|
||||||
|
* NEVER reorder — GET /overview/layouts and the frontend both walk this array
|
||||||
|
* to break ties, so reordering silently changes who gets which dashboard.
|
||||||
|
*/
|
||||||
|
export const OVERVIEW_LAYOUT_KEYS = [
|
||||||
|
"clearance",
|
||||||
|
"occ",
|
||||||
|
"operation",
|
||||||
|
"marketer",
|
||||||
|
"finance",
|
||||||
|
"executive",
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export type OverviewLayoutKey = (typeof OVERVIEW_LAYOUT_KEYS)[number];
|
||||||
|
|
||||||
|
export const OVERVIEW_LAYOUT_LABELS: Record<OverviewLayoutKey, string> = {
|
||||||
|
clearance: "Clearance & logistics dashboard",
|
||||||
|
occ: "Control centre dashboard",
|
||||||
|
operation: "Operations dashboard",
|
||||||
|
marketer: "Marketing dashboard",
|
||||||
|
finance: "Finance dashboard",
|
||||||
|
executive: "Executive dashboard",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const overviewLayoutPermissionKey = (key: string): string =>
|
||||||
|
`edr_freight_app:overview:${key}:view`;
|
||||||
|
|
||||||
|
const overviewLayoutPermId = (index: number): string =>
|
||||||
|
`a4f00003-0001-4000-8000-${(index + 1).toString(16).padStart(12, "0")}`;
|
||||||
|
|
||||||
|
export const OVERVIEW_LAYOUT_PERMISSIONS: FreightPermissionSeed[] =
|
||||||
|
OVERVIEW_LAYOUT_KEYS.map((key, index) =>
|
||||||
|
perm(
|
||||||
|
overviewLayoutPermId(index),
|
||||||
|
overviewLayoutPermissionKey(key),
|
||||||
|
`Overview layout: ${OVERVIEW_LAYOUT_LABELS[key]}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
export const BOOKING_PERMISSIONS: FreightPermissionSeed[] = [
|
export const BOOKING_PERMISSIONS: FreightPermissionSeed[] = [
|
||||||
perm(
|
perm(
|
||||||
"a1000001-0001-4000-8000-000000000001",
|
"a1000001-0001-4000-8000-000000000001",
|
||||||
@@ -1759,6 +1805,7 @@ export const NOTIFICATION_PERMISSIONS: FreightPermissionSeed[] = [
|
|||||||
|
|
||||||
export const ADVANCED_BACKOFFICE_PERMISSIONS: FreightPermissionSeed[] = [
|
export const ADVANCED_BACKOFFICE_PERMISSIONS: FreightPermissionSeed[] = [
|
||||||
...REPORT_PERMISSIONS,
|
...REPORT_PERMISSIONS,
|
||||||
|
...OVERVIEW_LAYOUT_PERMISSIONS,
|
||||||
...CUSTOMER_PERMISSIONS,
|
...CUSTOMER_PERMISSIONS,
|
||||||
...SHIPPING_LINE_PERMISSIONS,
|
...SHIPPING_LINE_PERMISSIONS,
|
||||||
...CHAT_PERMISSIONS,
|
...CHAT_PERMISSIONS,
|
||||||
@@ -2295,6 +2342,7 @@ export const FREIGHT_PERMS = {
|
|||||||
},
|
},
|
||||||
overview: {
|
overview: {
|
||||||
view: "edr_freight_app:overview:view",
|
view: "edr_freight_app:overview:view",
|
||||||
|
layout: (key: OverviewLayoutKey): string => overviewLayoutPermissionKey(key),
|
||||||
},
|
},
|
||||||
reports: {
|
reports: {
|
||||||
view: "edr_freight_app:reports:view",
|
view: "edr_freight_app:reports:view",
|
||||||
|
|||||||
Reference in New Issue
Block a user