mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
feat(overview): serve GET /overview/layouts filtered by permission
New catalog endpoint, same shape as GET /reports: returns the overview layouts (key + label) the caller holds the matching edr_freight_app:overview:<layout>:view permission for, in priority order. Backend enforcement to go with the permission-based frontend resolver (next commit) — a caller can no longer land on a layout their JWT doesn't actually carry the permission for.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
import type { OverviewLayoutKey } from '../../../seed/freight-permissions.registry';
|
||||
|
||||
/**
|
||||
* One entry per `GET /overview/layouts` item: a layout the caller holds the
|
||||
* `edr_freight_app:overview:<key>:view` permission for. Mirrors the reports
|
||||
* module's catalog entry (`ReportCatalogEntry`) — same "server filters by
|
||||
* permission, frontend just renders what comes back" shape.
|
||||
*/
|
||||
export class OverviewLayoutDto {
|
||||
@ApiProperty({
|
||||
enum: ['clearance', 'occ', 'operation', 'marketer', 'finance', 'executive'],
|
||||
})
|
||||
key!: OverviewLayoutKey;
|
||||
|
||||
@ApiProperty()
|
||||
label!: string;
|
||||
}
|
||||
@@ -9,7 +9,13 @@ import { CurrentUser } from '@edr/api-common';
|
||||
import type { TCurrentUser } from '@tria-plc/api-common/modules/auth/types/current-user.type';
|
||||
|
||||
import { BookingStaff } from '../../common/booking-guards';
|
||||
import { FREIGHT_PERMS } from '../../seed/freight-permissions.registry';
|
||||
import { hasFreightPermission } from '../../common/freight-permission.util';
|
||||
import {
|
||||
FREIGHT_PERMS,
|
||||
OVERVIEW_LAYOUT_KEYS,
|
||||
OVERVIEW_LAYOUT_LABELS,
|
||||
} from '../../seed/freight-permissions.registry';
|
||||
import { OverviewLayoutDto } from './dto/overview-layout.dto';
|
||||
import { OverviewQueryDto } from './dto/overview-query.dto';
|
||||
import { OverviewResponseDto } from './dto/overview-response.dto';
|
||||
import {
|
||||
@@ -34,6 +40,22 @@ export class OverviewController {
|
||||
private readonly userTradeAccessService: UserTradeAccessService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Layouts the caller has permission to render, in priority order — exactly
|
||||
* the same "server filters by permission, frontend just renders what comes
|
||||
* back" shape as GET /reports. A caller lands on exactly one layout, so the
|
||||
* frontend picks the first entry here rather than rendering the whole list.
|
||||
*/
|
||||
@Get('layouts')
|
||||
@BookingStaff(FREIGHT_PERMS.overview.view)
|
||||
@ApiOperation({ summary: 'Overview dashboard layouts the caller has permission to render' })
|
||||
@ApiOkResponse({ type: OverviewLayoutDto, isArray: true })
|
||||
getLayouts(@CurrentUser() user: TCurrentUser): OverviewLayoutDto[] {
|
||||
return OVERVIEW_LAYOUT_KEYS.filter((key) =>
|
||||
hasFreightPermission(user, FREIGHT_PERMS.overview.layout(key)),
|
||||
).map((key) => ({ key, label: OVERVIEW_LAYOUT_LABELS[key] }));
|
||||
}
|
||||
|
||||
@Get()
|
||||
@BookingStaff(FREIGHT_PERMS.overview.view)
|
||||
@ApiOperation({ summary: 'Aggregated dashboard summary for backoffice overview' })
|
||||
|
||||
Reference in New Issue
Block a user