DataMenu
A container component that renders a searchable, filterable data table for various entity types (buildings, sites, infrastructure, files, users). Supports row selection for comparison, inline navigation to detail views, and CRUD operations through child detail components.
Usage
import { DataMenu } from '@collabdt/core/components/menus/DataMenu';
import { ViewerNames } from '@collabdt/core/types';
<DataMenu
currentViewer={ViewerNames.buildings}
height="h-[600px]"
/>
// Minimal variant without frame styling
<DataMenu
currentViewer={ViewerNames.users}
hideFrame
hideTitle
hideActions
/>
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
currentViewer | ViewerNames | Yes | — | Determines which entity type to display: buildings, sites, infrastructure, files, or users. |
height | string | No | 'h-full' | Tailwind height class for the container. |
hideFrame | boolean | No | false | Removes background, padding, and shadow styling when true. |
hideTitle | boolean | No | false | Hides the header title row with icon. |
hideActions | boolean | No | false |
Behaviour
Table View
- Displays a
DataTablepopulated with data from the relevant SWR hook (useBuildings,useSites, etc.) - Search input filters rows by name/address fields
FilterButtonsapplies advanced filters;HeaderButtonsprovides compare mode toggle and entity creation- Clicking a row navigates to the detail view for that entity
- In compare mode, clicking a row toggles selection (max 3 items); checkboxes appear in leading cells
Detail View
- Shows the appropriate detail component (
BuildingDetails,SiteDetails, etc.) based oncurrentViewer - Breadcrumb updates to show the selected entity name
DetailActionscontrols edit/save/cancel flow- Save triggers
saveChanges()on the detail component ref; success/failure toasts display viasonner - Back navigation clears selection and returns to table view
Loading & Errors
- While data loads,
isLoadingis passed toDataTablefor skeleton rendering - API errors are handled through
handleApiError, which displays error toasts
State Reset
- Switching
currentViewerresets compare mode and clears selected items - Switching selected item ID resets the active tab in detail views
Design Decisions
DataMenu is intentionally an orchestration-only component — it manages state, wires context, and handles layout, but delegates all entity-specific logic to focused sub-components and utilities. This makes it easier to extend: adding a new viewer type only requires touching the relevant utility or sub-component rather than editing the core file.
viewerConfig.ts— viewer-specific metadata (icon, i18n title key, DataTypes value) lives in a static config map. Adding a new viewer means adding one entry here.useViewerData— all per-viewer data selection, search, and filter logic is encapsulated in this hook, keeping DataMenu agnostic to how each viewer's data is shaped.DetailHeader— entity title rendering is isolated here. Each entity type follows the samename || fallbackpattern, and new entities add one small sub-component.DetailActions— button logic, label resolution, and all CASL permission checks live here. DataMenu passes behaviour via callbacks and keeps state ownership to itself. The key tradeoff:DetailActionshas a wide props interface because it needs both selected items (for labels and MoreOptions) and callbacks (to trigger upstream state changes). Lifting this state into context was considered but rejected to keep the permissions and edit flow easy to trace.
Permissions
DataMenu itself does not gate rendering on any CASL ability check — it always renders for any authenticated user. Permission enforcement happens at the action level inside child components:
| Action | Subject | Where enforced |
|---|---|---|
create | Building | HeaderButtons → Add Building button |
create | User | HeaderButtons → Add User button |
read | Building | HeaderButtons → View All on Map, Compare |
read | Site | HeaderButtons → View All on Map, Compare |
update | Building | DetailActions → Edit Details button |
update | Site | DetailActions → Edit Details button |
update | Infrastructure | DetailActions → Edit Details button |
update | File | DetailActions → Edit Details button |
update | Role | DetailActions → Edit/Save buttons (users) |
delete | User | DetailActions → via MoreOptions |
update | Site | MoreOptions → Delete Site |
If you are adding a new viewer with edit/create actions, the pattern is: add the ability.can() check inside DetailActions for the edit/save buttons, and inside HeaderButtons for any creation entry point.