138 lines
7.2 KiB
Markdown
138 lines
7.2 KiB
Markdown
# Module Generator Frontend
|
|
|
|
The frontend generator UI collects module metadata, selected assets, form layout, and datatable configuration. It converts the configuration into TypeScript/TSX source strings and sends them to the backend generator.
|
|
|
|
## Main Flow
|
|
|
|
| Responsibility | Source |
|
|
| ------------------------------------------------------ | ------------------------------------------------------------------------------------- |
|
|
| Page submission, notifications, and mutation callbacks | `apps/admin/src/devtools/pages/ModuleGeneratorPage/index.tsx` |
|
|
| Payload assembly | `apps/admin/src/devtools/pages/ModuleGeneratorPage/lib/buildGenerateModulePayload.ts` |
|
|
| Form state and initial values | `apps/admin/src/devtools/view/forms/ModuleGeneratorForm/form.ts` |
|
|
| Metadata, form, and datatable sections | `apps/admin/src/devtools/view/forms/ModuleGeneratorForm/sections/` |
|
|
| Payload DTOs | `apps/admin/src/devtools/data/api/dto.ts` |
|
|
| HTTP client | `apps/admin/src/devtools/data/api/index.ts` |
|
|
| React Query hooks | `apps/admin/src/devtools/data/queries/` |
|
|
| Source-code builders | `apps/admin/src/devtools/data/builders/` |
|
|
|
|
The page submits through `useGenerateModule`. On success it resets the form and shows a success alert; backend or network errors are normalized through the shared React Query error helpers.
|
|
|
|
## Metadata and Assets
|
|
|
|
The required metadata is:
|
|
|
|
- `name`: frontend folder name, backend module identity, route segment, and permission-slug base.
|
|
- `table`: existing PostgreSQL source table.
|
|
- `generate`: selected backend and frontend assets.
|
|
|
|
Supported asset values are defined by `ModuleAsset`:
|
|
|
|
| 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 |
|
|
|
|
The default selection includes all backend assets. Form and datatable generation are opt-in.
|
|
|
|
## Schema Queries
|
|
|
|
The frontend uses two authenticated read endpoints before generation:
|
|
|
|
- `GET /makeModule/tables` populates the table selector.
|
|
- `GET /makeModule/columns/:table` populates form and datatable field choices.
|
|
|
|
Table and column requests are cached through React Query. Column queries remain disabled until a table is selected.
|
|
|
|
## Payload Builders
|
|
|
|
`buildGenerateModulePayload` delegates source generation to focused builders:
|
|
|
|
| Builder | Payload field | Generated destination |
|
|
| ------------------------------------- | ---------------- | ----------------------------------- |
|
|
| `FormTemplateBuilder.buildComponent` | `form` | `view/forms/MainForm/Component.tsx` |
|
|
| `FormTemplateBuilder.buildDefinition` | `formDefinition` | `view/forms/MainForm/form.ts` |
|
|
| `FormDialogTemplateBuilder` | `formDialog` | `view/widgets/ManageTrigger.tsx` |
|
|
| `DataTableTemplateBuilder` | `dataTable` | `view/widgets/DataTable.tsx` |
|
|
| `ListPageTemplateBuilder` | `list` | `pages/ListPage/index.tsx` |
|
|
| `MenuTemplateBuilder` | `menu` | `config/menu.ts` |
|
|
| `ModuleTemplateBuilder` | `module` | `config/module.ts` |
|
|
|
|
If form generation is disabled, `form`, `formDefinition`, and `formDialog` are `null`. If datatable generation is disabled, `dataTable` and `menu` are `null`, while the list-page builder emits a page without a table.
|
|
|
|
## Generated Frontend Architecture
|
|
|
|
```txt
|
|
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
|
|
├── pages/
|
|
│ └── ListPage/
|
|
│ └── index.tsx
|
|
└── view/
|
|
├── forms/
|
|
│ └── MainForm/
|
|
│ ├── Component.tsx
|
|
│ ├── constants.ts
|
|
│ ├── form.ts
|
|
│ ├── index.ts
|
|
│ └── submit.ts
|
|
├── layouts/
|
|
│ └── Layout.tsx
|
|
└── widgets/
|
|
├── DataTable.tsx
|
|
├── DeleteTrigger.tsx
|
|
└── ManageTrigger.tsx
|
|
```
|
|
|
|
The `api` directory intentionally has no barrel file. Consumers import each operation directly, for example:
|
|
|
|
```ts
|
|
import { useCreate } from "../../../api/create";
|
|
import { invalidateDetailed } from "../../../api/detailed";
|
|
import { invalidateList } from "../../../api/list";
|
|
import { useUpdate } from "../../../api/update";
|
|
```
|
|
|
|
Each CRUD operation remains isolated in its own file. `keys.ts` owns React Query key builders, while `list.ts` and `detailed.ts` own their cache invalidation helpers.
|
|
|
|
## Layer Responsibilities
|
|
|
|
- `entities/Entity.ts` is generated from database columns and is shared by API hooks, forms, and widgets.
|
|
- `api/` owns Axios calls, React Query hooks, cache keys, and mutation notifications.
|
|
- `pages/` owns route-level composition and permission page gates.
|
|
- `view/forms/` owns schema, form values, UI integration, and submission orchestration.
|
|
- `view/widgets/` owns stateful table, delete, and manage interactions.
|
|
- `config/` integrates routes, menu, translations, metadata, and permissions with the app module registry.
|
|
|
|
## Extending the Frontend Generator
|
|
|
|
When adding a new generated frontend artifact:
|
|
|
|
1. Add its configuration type under `apps/admin/src/devtools/entities/`.
|
|
2. Add UI controls to `ModuleGeneratorForm`.
|
|
3. Add a focused builder under `data/builders/` if the artifact contains dynamic source.
|
|
4. Add the payload field to `GenerateModulePayload` and `buildGenerateModulePayload`.
|
|
5. Accept and write the field in `backend/app/controllers/module_controller.ts`.
|
|
6. Add the static structure to `apps/admin/src/modules/_template/` when every module needs it.
|
|
7. Verify generation with and without the new asset selected.
|