feat: introduce index layout skill for FULL_PAGE index/list tables
- Added a new skill for managing index and list table layouts in the ERP project, detailing layout and data contracts. - Updated project guidelines to reference the new index layout skill. - Introduced rules for page composition, column definitions, audit fields, action column width, and toolbar functionality. - Created utility functions for computing action column width and formatting audit fields, along with corresponding unit tests to ensure reliability. These changes enhance the application by providing a structured approach to index layouts, improving consistency and usability across the ERP project.
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
---
|
||||
name: index-layout
|
||||
description: Use whenever building or editing a FULL_PAGE index / list table in the ERP project (master-data lists, transaction lists, system users/privileges, any EnterpriseDataTable index). Governs LAYOUT and table contracts ONLY — page chrome, module columnDefs vs shared prefix/postfix columns, action-column width, audit field names, and the search/filter/reload toolbar. Does not govern colors, fonts, border-radius, or other visual styling. Trigger this any time an index page, list table, row-action column, audit columns, or index toolbar is added or restructured — including when the user says "build a list page", "index table", or "add a refresh button".
|
||||
---
|
||||
|
||||
# Index Layout
|
||||
|
||||
Layout and data contracts for **FULL_PAGE index / list tables**. Visual style (color, weight, radius, shadows) belongs to `@repo/ui`, not this skill.
|
||||
|
||||
Walk these rules in order whenever you add or change an index table.
|
||||
|
||||
## Project chrome (do not rebuild)
|
||||
|
||||
Index routes already render inside `EnterpriseIndexPageProvider` → `EnterpriseDataTable`. That chrome owns:
|
||||
|
||||
- Page header (title, description, breadcrumbs, Create)
|
||||
- Toolbar: search, filter, **reload**
|
||||
- Prefix columns: selection, row actions, status
|
||||
- Postfix columns: Created by, Created at, Updated by, Updated at
|
||||
- Pagination / server-side row model
|
||||
|
||||
**Do not** re-implement the toolbar, action column, status column, or audit columns in a module page. This skill governs the **`columnDefs` you pass in** and the **entity/transformer field names** the shared table reads.
|
||||
|
||||
## 1. Page composition
|
||||
|
||||
```tsx
|
||||
<EnterpriseIndexPageProvider pageHeaderProps={{ title, description, icon, breadcrumbs }}>
|
||||
<EnterpriseDataTable columnDefs={columnDefs} filterConfig={filterConfig} />
|
||||
</EnterpriseIndexPageProvider>
|
||||
```
|
||||
|
||||
Copy `example/full-page`. Do not invent a third index layout.
|
||||
|
||||
## 2. Module `columnDefs` = business fields only
|
||||
|
||||
Module index pages declare **business columns only** (code, name, relations, flags).
|
||||
|
||||
Do **not** redeclare:
|
||||
|
||||
- `action_column` / row actions
|
||||
- `status` (the shared status badge column)
|
||||
- `createdBy` / `createdAt` / `updatedBy` / `updatedAt`
|
||||
|
||||
```tsx
|
||||
// GOOD
|
||||
const columnDefs = [
|
||||
{ field: 'username', headerName: t('common:fields.username'), minWidth: 160 },
|
||||
{ field: 'privilege', headerName: t('common:fields.privilege'), valueGetter: ({ data }) => relationLabel(data?.privilege) },
|
||||
];
|
||||
|
||||
// BAD — duplicates shared chrome
|
||||
const columnDefs = [
|
||||
{ colId: 'action_column', width: 180 },
|
||||
{ field: 'created_at', headerName: 'Created at' },
|
||||
];
|
||||
```
|
||||
|
||||
## 3. Audit fields are camelCase
|
||||
|
||||
API and transformers map:
|
||||
|
||||
| Entity field | Meaning |
|
||||
|---|---|
|
||||
| `createdBy` | actor string, `{ username }`, or uuid |
|
||||
| `createdAt` | unix ms |
|
||||
| `updatedBy` | actor string, `{ username }`, or uuid |
|
||||
| `updatedAt` | unix ms |
|
||||
|
||||
`EnterpriseDataTable` postfix columns bind those names and fall back to legacy snake_case (`creator_name`, `created_at`, `editor_name`, `updated_at`) for leftover local/Pouch rows.
|
||||
|
||||
Empty values render as `-`. Nested actors display `username` || `name` || `id`.
|
||||
|
||||
Do not alias audit fields to snake_case in TrackGo transformers.
|
||||
|
||||
## 4. Action column width is shared
|
||||
|
||||
Row actions stay a single nowrap icon row (`RowActions` with `responsiveView={false}`). Width is computed in `EnterpriseDataTable` from privileges + `moduleType` (`View` always, then Edit / Duplicate / Activate-or-Deactivate or transaction flags / Delete). `flex: 0` so the column does not shrink.
|
||||
|
||||
Do **not** override action column `width` / `minWidth` in module `columnDefs` or `customPrefixColumn` unless the module adds extra custom row actions **and** you widen via `customPrefixColumn` to fit them.
|
||||
|
||||
## 5. Toolbar always includes reload
|
||||
|
||||
The index toolbar is search + filter + reload. Reload must call `gridApi.refreshServerSide({ purge: true })` (same as search/filter) — **not** `window.location.reload()`.
|
||||
|
||||
Label: `common:actions.reload` (“Reload” / “Muat Ulang”). Icon: `RefreshCw`.
|
||||
|
||||
Do not add a second module-level refresh control that duplicates this.
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Index page uses `EnterpriseIndexPageProvider` + `EnterpriseDataTable` (no custom table chrome)
|
||||
- [ ] `columnDefs` are business fields only
|
||||
- [ ] Transformer maps `createdAt` / `createdBy` / `updatedAt` / `updatedBy`
|
||||
- [ ] Action column width left to the shared table
|
||||
- [ ] Reload is the shared toolbar button, not a full browser refresh
|
||||
Reference in New Issue
Block a user