5.3 KiB
Module Generator Frontend
The generator UI collects module metadata, selected assets, form layout, and datatable configuration, converts it into TypeScript/TSX source strings, and sends them to the backend generator.
| Responsibility | Source (under apps/admin/src/devtools/) |
|---|---|
| Page submission, notifications, and mutation callbacks | pages/ModuleGeneratorPage/index.tsx |
| Payload assembly | pages/ModuleGeneratorPage/lib/buildGenerateModulePayload.ts |
| Form state, initial values, and sections | view/forms/ModuleGeneratorForm/ |
| Payload DTOs and HTTP client | data/api/ |
| React Query hooks | data/queries/ |
| Source-code builders | data/builders/ |
The page submits through useGenerateModule; success resets the form and shows an alert, errors go through the shared React Query error helpers.
Metadata and Assets
Required metadata: name (frontend folder, backend module identity, route segment, permission-slug base), table (existing PostgreSQL table), generate (selected assets). Backend assets are all selected by default; form and datatable are opt-in.
| Asset | Workspace | Output |
|---|---|---|
model |
Backend | Lucid model |
controller |
Backend | Authenticated resource controller and test |
routes |
Backend | Resource route registration |
validator |
Backend | Create and update Vine validators |
policy |
Backend | Bouncer policy and permission configuration |
api |
Backend | API controller, validators, routes, and test |
form |
Frontend | Form definition, component, and modal/sheet trigger |
datatable |
Frontend | List page table and menu entry |
Before generation the UI reads GET /makeModule/tables (table selector) and GET /makeModule/columns/:table (field choices) — cached via React Query, columns disabled until a table is selected.
Payload Builders
buildGenerateModulePayload delegates to focused builders:
| Builder | Payload field | Generated destination |
|---|---|---|
FormSourceBuilder.buildComponent |
form |
view/forms/MainForm/Component.tsx |
FormSourceBuilder.buildDefinition |
formDefinition |
view/forms/MainForm/form.ts |
ManageTriggerSourceBuilder |
formDialog |
view/widgets/ManageTrigger.tsx |
DataTableSourceBuilder |
dataTable |
view/widgets/DataTable.tsx |
ListPageSourceBuilder |
list |
pages/ListPage/index.tsx |
MenuSourceBuilder |
menu |
config/menu.ts |
ModuleConfigSourceBuilder |
module |
config/module.ts |
Form disabled → form, formDefinition, formDialog are null. Datatable disabled → dataTable and menu are null, and the list-page builder emits a page without a table.
Generated Frontend Architecture
apps/admin/src/modules/<name>/
├── api/ # create.ts, delete.ts, detailed.ts, keys.ts, list.ts, update.ts
├── config/ # translation/, menu.ts, messages.ts, meta.ts, module.ts, routing.tsx
├── entities/ # Entity.ts (from database columns)
├── pages/ListPage/
└── view/
├── forms/MainForm/ # Component.tsx, constants.ts, form.ts, index.ts, submit.ts
├── layouts/Layout.tsx
└── widgets/ # DataTable.tsx, DeleteTrigger.tsx, ManageTrigger.tsx
api/ deliberately has no barrel file — each CRUD operation is its own file, imported directly (import { useCreate } from "../../../api/create"); keys.ts owns query key builders, list.ts/detailed.ts their invalidation helpers.
Layer ownership: entities/Entity.ts is shared by API hooks, forms, and widgets; api/ owns Axios calls, hooks, keys, and notifications; pages/ owns route composition and permission gates; view/forms/ owns schema, values, UI, and submission; view/widgets/ owns stateful interactions; config/ integrates routes, menu, translations, and permissions with the module registry.
Extending
To add a generated frontend artifact: add its configuration type under entities/, UI controls to ModuleGeneratorForm, a focused builder under data/builders/ (for dynamic source), the payload field to GenerateModulePayload + buildGenerateModulePayload, accept and write it in module_controller.ts, and add static structure to _template/ when every module needs it. Verify generation with and without the asset selected.