drf-react-by-schema 0.28.26 → 0.28.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/components/DataGridBySchemaEditable/DataGridDesktop.d.ts +3 -0
- package/dist/components/DataGridBySchemaEditable/DataGridDesktop.d.ts.map +1 -1
- package/dist/components/DataGridBySchemaEditable/DataGridDesktop.js +22 -4
- package/dist/components/forms/Form.d.ts +2 -0
- package/dist/components/forms/Form.d.ts.map +1 -1
- package/docs/API_REFERENCE.md +665 -0
- package/docs/FIELD_TYPES.md +145 -0
- package/docs/localization.md +173 -0
- package/docs/password-reset-and-email.md +145 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -34,6 +34,16 @@ On the React side, `drf-react-by-schema-react` offers a range of powerful compon
|
|
|
34
34
|
|
|
35
35
|
The _DRF and React By Schema_ Suite is available for React at https://www.npmjs.com/package/drf-react-by-schema and for Django at https://pypi.org/project/drf-react-by-schema/.
|
|
36
36
|
|
|
37
|
+
## API reference
|
|
38
|
+
|
|
39
|
+
Every exported component (purpose and props), the full `useAPIWrapper()` API (data,
|
|
40
|
+
auth, form state, dialogs, feedback), the shared prop building blocks
|
|
41
|
+
(`fieldsLayout`, `fieldsProps`, `sumRows`, actions, …) and the utility functions are
|
|
42
|
+
documented in **[`docs/API_REFERENCE.md`](docs/API_REFERENCE.md)**.
|
|
43
|
+
|
|
44
|
+
Consuming apps must use `useAPIWrapper()`. The lower-level `useDRFReactBySchema()` is
|
|
45
|
+
internal, is not exported from the package entry and must not be used by app code.
|
|
46
|
+
|
|
37
47
|
## Field types & widgets
|
|
38
48
|
|
|
39
49
|
Every schema field `type` maps to a specific widget. This includes the standard
|
|
@@ -5,6 +5,9 @@ import { AnySchema } from 'yup';
|
|
|
5
5
|
import { CustomToolbarProps } from './CustomToolbar';
|
|
6
6
|
declare module '@mui/x-data-grid' {
|
|
7
7
|
interface ToolbarPropsOverrides extends CustomToolbarProps {
|
|
8
|
+
isEditableToolbar?: boolean;
|
|
9
|
+
hideToolbarComponent?: boolean;
|
|
10
|
+
watchEditingRowValues?: WatchEditingRowValues;
|
|
8
11
|
}
|
|
9
12
|
}
|
|
10
13
|
import { SxProps, Theme } from '@mui/material/styles';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataGridDesktop.d.ts","sourceRoot":"","sources":["../../../src/components/DataGridBySchemaEditable/DataGridDesktop.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAA0C,SAAS,EAAE,MAAM,OAAO,CAAC;AACjF,OAAO,EAEL,SAAS,EACT,oBAAoB,EACpB,yBAAyB,EAI1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AAOhF,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAGrD,OAAO,QAAQ,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"DataGridDesktop.d.ts","sourceRoot":"","sources":["../../../src/components/DataGridBySchemaEditable/DataGridDesktop.tsx"],"names":[],"mappings":"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"}
|
|
@@ -32,6 +32,17 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
36
|
+
var t = {};
|
|
37
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
38
|
+
t[p] = s[p];
|
|
39
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
40
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
41
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
42
|
+
t[p[i]] = s[p[i]];
|
|
43
|
+
}
|
|
44
|
+
return t;
|
|
45
|
+
};
|
|
35
46
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
47
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
48
|
};
|
|
@@ -59,6 +70,13 @@ const usePreparedColumns_1 = require("./hooks/usePreparedColumns");
|
|
|
59
70
|
const useDataGridActions_1 = require("./hooks/useDataGridActions");
|
|
60
71
|
const useProcessRowUpdate_1 = require("./hooks/useProcessRowUpdate");
|
|
61
72
|
const RowEditingWatcher_1 = __importDefault(require("./RowEditingWatcher"));
|
|
73
|
+
// Module-level so the slot type stays stable across renders; an inline slot component remounts the toolbar and its quick filter input.
|
|
74
|
+
const InternalToolbar = (_a) => {
|
|
75
|
+
var { isEditableToolbar, hideToolbarComponent, watchEditingRowValues } = _a, props = __rest(_a, ["isEditableToolbar", "hideToolbarComponent", "watchEditingRowValues"]);
|
|
76
|
+
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
77
|
+
isEditableToolbar && watchEditingRowValues && (react_1.default.createElement(RowEditingWatcher_1.default, { watchEditingRowValues: watchEditingRowValues })),
|
|
78
|
+
!hideToolbarComponent && react_1.default.createElement(CustomToolbar_1.CustomToolbar, Object.assign({}, props))));
|
|
79
|
+
};
|
|
62
80
|
function DataGridDesktop({ schema, apiRef, dataGridRows, setDataGridRows, rowCount = 0, columns, columnVisibilityModel, model, name = Math.floor(Math.random() * 1000000).toString(), indexField = 'nome', addExistingModel, indexFieldMinWidth = 350, indexFieldBasePath = '', indexFieldViewBasePath, stateToLink = {}, minWidth = 80, loading, modelParent, modelParentId, customColumnOperations, customFieldFormLayouts, customLinkDestination, LinkComponent, onProcessRow, watchEditingRowValues, onEditModel, isEditable = false, nonEditableActions, hasBulkSelect, onSelectActions, sx: sxProp, isAutoHeight, defaultValues, hideFooterPagination, setVisibleRows, paginationModel, setPaginationModel, hideFooterComponent, hideToolbarComponent, tableAutoHeight, actions = ['editInline', 'remove'], customActions, hideColumnsButton, hideFilterButton, hideDensityButton, hideExportButton, hideQuickFilterBar, optionsAC: optionsACExternal, extraValidators, emptyItem, handleDeleteClick, setSnackBar, yupValidationSchema, }) {
|
|
63
81
|
var _a;
|
|
64
82
|
const [dataGridLoading, setDataGridLoading] = (0, react_1.useState)(false);
|
|
@@ -365,10 +383,7 @@ function DataGridDesktop({ schema, apiRef, dataGridRows, setDataGridRows, rowCou
|
|
|
365
383
|
});
|
|
366
384
|
console.log(e);
|
|
367
385
|
}, slots: {
|
|
368
|
-
|
|
369
|
-
toolbar: (props) => (react_1.default.createElement(react_1.default.Fragment, null,
|
|
370
|
-
isEditable && watchEditingRowValues && (react_1.default.createElement(RowEditingWatcher_1.default, { watchEditingRowValues: watchEditingRowValues })),
|
|
371
|
-
!hideToolbarComponent && react_1.default.createElement(CustomToolbar_1.CustomToolbar, Object.assign({}, props)))),
|
|
386
|
+
toolbar: InternalToolbar,
|
|
372
387
|
footer: hideFooterComponent ? () => react_1.default.createElement(react_1.default.Fragment, null) : InternalFooter,
|
|
373
388
|
}, slotProps: {
|
|
374
389
|
toolbar: {
|
|
@@ -384,6 +399,9 @@ function DataGridDesktop({ schema, apiRef, dataGridRows, setDataGridRows, rowCou
|
|
|
384
399
|
hideDensityButton,
|
|
385
400
|
hideExportButton,
|
|
386
401
|
hideQuickFilterBar,
|
|
402
|
+
hideToolbarComponent,
|
|
403
|
+
isEditableToolbar: isEditable,
|
|
404
|
+
watchEditingRowValues,
|
|
387
405
|
showQuickFilter: true,
|
|
388
406
|
quickFilterProps: { debounceMs: 500 },
|
|
389
407
|
handleExportExcel: paginationModel
|
|
@@ -52,7 +52,9 @@ interface FormProps<T extends TField = void> extends Omit<CommonFieldProps<T>, '
|
|
|
52
52
|
elevation?: number;
|
|
53
53
|
CustomFormActions?: (props: FormActionsProps) => React.JSX.Element;
|
|
54
54
|
extraValidators?: ExtraValidators<T>;
|
|
55
|
+
/** Field names monitored on change; requires `onWatchChange`. */
|
|
55
56
|
watchValues?: FieldList<T>;
|
|
57
|
+
/** Called with `{ [field]: value }` when a watched value changes. */
|
|
56
58
|
onWatchChange?: (values: FormWatchObject<T>) => void;
|
|
57
59
|
reloadStateStamp?: number | string;
|
|
58
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Form.d.ts","sourceRoot":"","sources":["../../../src/components/forms/Form.tsx"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Form.d.ts","sourceRoot":"","sources":["../../../src/components/forms/Form.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
# API reference — `drf-react-by-schema` (React)
|
|
2
|
+
|
|
3
|
+
Canonical reference for everything the package exposes to **consuming apps**: the
|
|
4
|
+
provider, `useAPIWrapper()`, the components, their props and the utility functions.
|
|
5
|
+
|
|
6
|
+
The public surface is exactly what `src/index.ts` exports. If a symbol is not
|
|
7
|
+
re-exported there, it is internal — do not import it from a deep path
|
|
8
|
+
(`drf-react-by-schema/dist/...`), because its signature may change without notice.
|
|
9
|
+
|
|
10
|
+
Related docs:
|
|
11
|
+
|
|
12
|
+
- [`FIELD_TYPES.md`](FIELD_TYPES.md) — schema `type` → widget table.
|
|
13
|
+
- [`localization.md`](localization.md) — `theme.texts`, MUI locale setup.
|
|
14
|
+
- [`password-reset-and-email.md`](password-reset-and-email.md) — forgot/change password flow.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 0. Golden rules for consuming apps
|
|
19
|
+
|
|
20
|
+
1. **Wrap the app with `DRFReactBySchemaProvider`.** It installs the MUI theme,
|
|
21
|
+
`CssBaseline`, the context and the built-in overlays (dialog, snackbar, loading
|
|
22
|
+
backdrop).
|
|
23
|
+
2. **Use `useAPIWrapper()` for every data/auth action.** It is the only public data
|
|
24
|
+
hook.
|
|
25
|
+
3. **Never call `useDRFReactBySchema()`.** It exists as an internal building block of
|
|
26
|
+
this package, is **not exported** from the package entry, and only returns raw
|
|
27
|
+
context (`serverEndPoint`, `theme`, `isInBatches`, `firstBatchLength`, `schemas`,
|
|
28
|
+
`pagination`). It has no data, auth or form helpers and is not a supported app API.
|
|
29
|
+
4. **Fetch helpers return `Item | AxiosError`.** Always check
|
|
30
|
+
`axios.isAxiosError(result)` before using the value.
|
|
31
|
+
5. **Schemas come from the Django pair** (`drf-react-by-schema-django`) through
|
|
32
|
+
`OPTIONS` or the `sync_react` snapshots passed to the provider. Never hand-write
|
|
33
|
+
field metadata for a model that the backend already describes.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 1. `DRFReactBySchemaProvider`
|
|
38
|
+
|
|
39
|
+
`src/context/DRFReactBySchemaProvider.tsx`
|
|
40
|
+
|
|
41
|
+
Wraps the app. Props (`DRFReactBySchemaProviderProps`):
|
|
42
|
+
|
|
43
|
+
| Prop | Type | Default | Purpose |
|
|
44
|
+
| --- | --- | --- | --- |
|
|
45
|
+
| `serverEndPoint` | `ServerEndPoint \| null` | `null` | Django URLs. See below. |
|
|
46
|
+
| `theme` | `Theme` | package default | Deep-merged over the default theme. Localize through `theme.texts`. |
|
|
47
|
+
| `isInBatches` | `boolean` | `true` | Lists fetch in two batches (schema+first page, then the rest) to render faster. |
|
|
48
|
+
| `firstBatchLength` | `number` | `100` | Batch size used when `isInBatches` is on. |
|
|
49
|
+
| `schemas` | `SchemasType` | `undefined` | `sync_react` output. Avoids `OPTIONS` round-trips. Values may be inline `SchemaOptionsType` objects or `() => import(...)` loaders. |
|
|
50
|
+
| `pagination` | `PaginationConfig` | `{ perPage: 50, pageSizeOptions: [5,10,25,50,100,200], maxPageSize: 500 }` | Defaults for server-side lists. |
|
|
51
|
+
| `children` | `ReactNode` | — | App tree. |
|
|
52
|
+
|
|
53
|
+
`ServerEndPoint`:
|
|
54
|
+
|
|
55
|
+
| Key | Default derived by the provider |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| `url` | required |
|
|
58
|
+
| `apiTokenUrl` | required (JWT token endpoint) |
|
|
59
|
+
| `api` | `${url}/api` |
|
|
60
|
+
| `autocomplete` | `${url}/autocomplete` |
|
|
61
|
+
| `getToken` | `apiTokenUrl` |
|
|
62
|
+
| `refreshToken` | `${apiTokenUrl}refresh/` |
|
|
63
|
+
| `verifyToken` | `${apiTokenUrl}verify/` |
|
|
64
|
+
| `media` | `${url}/media` |
|
|
65
|
+
| `signUp` | **no default** — set it explicitly to enable sign-up |
|
|
66
|
+
| `requestPasswordReset` | `${api}/password_reset/request/` |
|
|
67
|
+
| `validatePasswordReset` | `${api}/password_reset/validate/` |
|
|
68
|
+
| `confirmPasswordReset` | `${api}/password_reset/confirm/` |
|
|
69
|
+
| `changePassword` | `${api}/my_account/change_password/` |
|
|
70
|
+
|
|
71
|
+
The provider also renders the package overlays, so `setDialog`,
|
|
72
|
+
`onTriggerSnackBar` and the loading backdrop work anywhere below it.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 2. `useAPIWrapper()`
|
|
77
|
+
|
|
78
|
+
`src/context/APIWrapperContext.tsx`
|
|
79
|
+
|
|
80
|
+
The single hook for data, auth, form state and feedback. It returns
|
|
81
|
+
`APIWrapperContextType<T>` (generic `T` is your generated model type; omit it for
|
|
82
|
+
`Record<string, any>`).
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
const {
|
|
86
|
+
usuaria, isLoggedIn, signOut,
|
|
87
|
+
getGenericModelList, getGenericModel, onDeleteModel,
|
|
88
|
+
onTriggerSnackBar, setDialog, isMobile,
|
|
89
|
+
} = useAPIWrapper();
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 2.1 Session and current user
|
|
93
|
+
|
|
94
|
+
| Member | Signature | Notes |
|
|
95
|
+
| --- | --- | --- |
|
|
96
|
+
| `usuaria` | `Item \| null` | Current user from `GET /api/my_account/`. `null` before load/sign-out. |
|
|
97
|
+
| `updateUsuaria` | `() => void` | Re-fetches `my_account`. On failure stores `{ erro: 'token inválido' }`. |
|
|
98
|
+
| `isLoggedIn` | `() => Promise<false \| Item>` | Validates the stored JWT and returns the user (or `false`). Does not write `usuaria`. |
|
|
99
|
+
| `loginByPayload` | `(payload: Item) => Promise<boolean \| AxiosError>` | `POST` to `getToken`; stores access/refresh tokens. Returns `false` on bad credentials. |
|
|
100
|
+
| `signOut` | `() => void` | Clears tokens, `usuaria`, `optionsAC`, `pageForm` and `editModel`. |
|
|
101
|
+
| `getSignUpOptions` | `() => Promise<SchemaType \| AxiosError>` | Schema of the sign-up form. |
|
|
102
|
+
| `signUp` | `<U>(data: Item<U>) => Promise<Item<U> \| AxiosError>` | `POST` to `serverEndPoint.signUp`. |
|
|
103
|
+
| `isMobile` | `boolean` | `theme.breakpoints.down('md')`. |
|
|
104
|
+
|
|
105
|
+
Password management (see [`password-reset-and-email.md`](password-reset-and-email.md)):
|
|
106
|
+
|
|
107
|
+
| Member | Signature |
|
|
108
|
+
| --- | --- |
|
|
109
|
+
| `requestPasswordReset` | `(email: string) => Promise<Item \| AxiosError>` |
|
|
110
|
+
| `validatePasswordReset` | `(data: Item) => Promise<Item \| AxiosError>` |
|
|
111
|
+
| `confirmPasswordReset` | `(data: Item) => Promise<Item \| AxiosError>` |
|
|
112
|
+
| `changePassword` | `(data: Item) => Promise<Item \| AxiosError>` |
|
|
113
|
+
|
|
114
|
+
### 2.2 Reading data
|
|
115
|
+
|
|
116
|
+
| Member | Signature | Notes |
|
|
117
|
+
| --- | --- | --- |
|
|
118
|
+
| `getGenericModel` | `({ model, id?, relatedModel?, relatedModelId? }) => Promise<{ data, schema, columns, modelOptions } \| AxiosError>` | One record + its schema/columns. With no `id` it returns the schema and an empty record; create forms should use `loadSinglePageData`/`<Form>`, which map tmp ids to no id. |
|
|
119
|
+
| `getGenericModelList` | `GetGenericModelListPropsLocal<T> => Promise<DataSchemaColumnsType<T> \| AxiosError>` | List with server filter/sort/paginate/totals. Params: `model`, `id`, `relatedModel`, `relatedModelId`, `columnFields`, `creatableFields`, `disabledFields`, `isInBatches`, `loadedSchema`, `loadedModelOptions`, `page`, `pageSize`, `filter`, `queryParams`, `sort`, `sumRows`. Returns `{ data, schema, columns, modelOptions, rowCount, sumRowsTotals, facets }`. |
|
|
120
|
+
| `getAutoComplete` | `(model: string, queryParams?: string[]) => Promise<AutocompleteItem[] \| AxiosError>` | Options for relation fields. Duplicate labels get a `(n)` suffix. |
|
|
121
|
+
| `getRawData` | `<U = void>(route: string) => Promise<U \| AxiosError>` | Authenticated `GET` against `${api}/${route}`. Handles 401 by refreshing the token. |
|
|
122
|
+
| `getAllModels` | `() => Promise<Item[]>` | Model list used by admin-like screens. Returns `[]` on error. |
|
|
123
|
+
| `getModelMeta` | `(model: string) => Promise<{ verboseName, verboseNamePlural }>` | From the loaded schemas; falls back to the model slug. Does not hit the network when `schemas` is provided. |
|
|
124
|
+
|
|
125
|
+
Server query grammar produced by `getGenericModelList` (Django side):
|
|
126
|
+
|
|
127
|
+
- quick filter → `search=<value>`
|
|
128
|
+
- filter item → `field=<field>&operator=<op>&value=<value>`
|
|
129
|
+
- sort → `ordering=field,-other`
|
|
130
|
+
- pagination → `page=<1-based>&page_size=<n>`
|
|
131
|
+
- totals → `sum_rows=<field>[|<facet>...][|<limit>],...`
|
|
132
|
+
- batching → `is_first_batch=1` / `is_last_batch=1`
|
|
133
|
+
|
|
134
|
+
### 2.3 Writing data
|
|
135
|
+
|
|
136
|
+
| Member | Signature | Notes |
|
|
137
|
+
| --- | --- | --- |
|
|
138
|
+
| `onSubmit` | `(model, id, data, event?) => Promise<Id \| AxiosError>` | Validates/normalizes `data` with the current `pageForm.schema`, then `POST` when `id` is tmp/empty or `PUT` otherwise. Shows snackbars and refreshes `optionsAC`. Requires a loaded `pageForm` (normally provided by `<Form>`/`loadSinglePageData`). Returns the new id. |
|
|
139
|
+
| `postData` | `({ path, data, contentType? }) => Promise<Item \| AxiosError>` | Raw `POST` (no schema normalization). |
|
|
140
|
+
| `updateModel` | `({ path, id, data, contentType? }) => Promise<Item \| AxiosError>` | Raw `PUT`. |
|
|
141
|
+
| `rawUpdateDataBySchema` | `(props: UpdateDataBySchema) => Promise<Item \| AxiosError>` | `POST` (tmp/missing id) or `PUT` after `prepareDataBySchema` normalization. `props`: `{ model, modelObjectId, data, schema, path? }`. |
|
|
142
|
+
| `rawDeleteData` | `(model: string, id: Id) => Promise<true \| AxiosError>` | Raw `DELETE`, no dialog/snackbar. |
|
|
143
|
+
| `onEditModelDataGridSave` | `({ model, newRow, schema }) => Promise<Item \| AxiosError>` | Inline grid save; uses the row id and `path = model`. |
|
|
144
|
+
| `onEditRelatedModelSave` | `({ model, id, relatedModel, newRow, schema, onlyAddExisting? }) => Promise<Item \| ItemSchemaColumnsType \| AxiosError>` | Nested create/update (`onlyAddExisting` links an existing record via `id_to_add`). |
|
|
145
|
+
| `onDeleteRelatedModel` | `({ model, id, relatedModel, relatedModelId }) => Promise<true \| AxiosError>` | Nested `DELETE`, no confirmation dialog. |
|
|
146
|
+
| `exportExcelData` | `({ model, modelParent?, modelParentId?, paginationModel }) => Promise<true \| AxiosError>` | Downloads the current list as an Excel file. |
|
|
147
|
+
|
|
148
|
+
### 2.4 Dialog-driven CRUD
|
|
149
|
+
|
|
150
|
+
| Member | Signature | Notes |
|
|
151
|
+
| --- | --- | --- |
|
|
152
|
+
| `onEditModel` | `(p: OnEditModelType) => void` | Opens the built-in dialog and loads the record. `p`: `{ model, id, labelKey, fieldKey?, index?, setValue?, getValues?, fieldsLayout?, initialValuesPartial? }`. It updates the parent form value and `optionsAC` after save when `setValue`/`getValues` are given. |
|
|
153
|
+
| `onEditModelSave` | `(data: Item) => Promise<boolean \| AxiosError>` | Closes the dialog and saves the model currently held in `editModel.current` (set by `onEditModel`). |
|
|
154
|
+
| `onDeleteModel` | `(model, id, onSuccess?) => void` | Opens a confirmation dialog and deletes on confirm. Returns immediately — no promise. For nested rows use `onDeleteRelatedModel`. |
|
|
155
|
+
| `editModel` | `RefObject<Item>` | The record being edited in the dialog. Read-only for app code. |
|
|
156
|
+
|
|
157
|
+
### 2.5 Page form state
|
|
158
|
+
|
|
159
|
+
`<Form>` stores its state here; custom screens can reuse the same machinery.
|
|
160
|
+
|
|
161
|
+
| Member | Signature | Notes |
|
|
162
|
+
| --- | --- | --- |
|
|
163
|
+
| `loadSinglePageData` | `(p: LoadSinglePageDataProps) => Promise<Item \| AxiosError>` | Loads record + schema, builds initial values and the yup validation schema, and populates `pageForm`. `p`: `{ model, objId?, objTitleField?, optionsACModels?, defaults?, extraValidators?, fieldsLayout? }`. |
|
|
164
|
+
| `pageForm` | `PageFormType \| null` | `{ id, model, modelVerboseName, modelVerboseNamePlural, schema, columns, initialValues, validationSchema, objTitleField }`. |
|
|
165
|
+
| `resetPageForm` | `() => void` | Clears `pageForm`. |
|
|
166
|
+
| `formTools` | `FormTools \| undefined` | React-hook-form handles of the mounted `<Form>`: `{ errors, reset, getValues, setValue, isDirty }`. |
|
|
167
|
+
| `optionsAC` | `OptionsAC \| null` | Cache of autocomplete options, keyed by model. |
|
|
168
|
+
| `setOptionsAC` | `(x: Partial<OptionsAC>) => void` | Merges into the cache. |
|
|
169
|
+
| `populateOptionsAC` | `(models: string[]) => void` | Fetches and caches options for the given models. |
|
|
170
|
+
| `handleLoading` | `(p: boolean) => void` | Shows/hides the global loading backdrop. |
|
|
171
|
+
|
|
172
|
+
### 2.6 Feedback
|
|
173
|
+
|
|
174
|
+
| Member | Signature | Notes |
|
|
175
|
+
| --- | --- | --- |
|
|
176
|
+
| `onTriggerSnackBar` | `({ msg, severity? }) => void` | `severity` is a MUI `AlertColor` (`'info'` default). |
|
|
177
|
+
| `setDialog` | `(state: Partial<DialogType> \| null) => void` | Opens/updates/closes the global dialog. `{ open, loading?, title?, Body?, Actions?, isCancelDisabled?, size? }`. Pass `null` to reset. |
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 3. Components
|
|
182
|
+
|
|
183
|
+
All components below are exported from the package root. Generic components accept an
|
|
184
|
+
optional `T` (`TField`) generated by `sync_react`.
|
|
185
|
+
|
|
186
|
+
### 3.1 Forms
|
|
187
|
+
|
|
188
|
+
#### `<Form />` — full create/edit page
|
|
189
|
+
|
|
190
|
+
`src/components/forms/Form.tsx`
|
|
191
|
+
|
|
192
|
+
Loads schema + record, builds fields and validation, renders top/bottom action bars, and
|
|
193
|
+
navigates after save.
|
|
194
|
+
|
|
195
|
+
| Prop | Type | Purpose |
|
|
196
|
+
| --- | --- | --- |
|
|
197
|
+
| `model` | `string` | Model slug (e.g. `"comunidade"`). |
|
|
198
|
+
| `objId` | `Id` | Record id. Omit/`'novo'`/`tmp*` for create. |
|
|
199
|
+
| `defaults` | `PartialItem<T>` | Initial values for a create form. |
|
|
200
|
+
| `objTitleField` | `FieldKey<T>` | Field used as the record title. |
|
|
201
|
+
| `onSave` | `(currentId, newIdOrError, buttonType: FormSaveActions) => void` | After a save attempt. `buttonType` tells which button was used. |
|
|
202
|
+
| `onDelete` | `(removedId: Id) => void` | After a delete. |
|
|
203
|
+
| `onCancel` | `MouseEventHandler` | Runs before navigating away from cancel. |
|
|
204
|
+
| `navigate` | `(to: string) => void; (delta: number) => void` | Router adapter. Without it, `window.location.href` / `history.back()` are used. |
|
|
205
|
+
| `exit` | `(newId?: Id) => void` | Custom exit. Takes precedence over `exitPath`. |
|
|
206
|
+
| `exitPath` | `string` | Path to go after save/cancel; `{ID}` is replaced by the record id. |
|
|
207
|
+
| `editPath` | `string` | Path of the edit page; `{ID}` marks where the id goes. Defaults to the current directory + id. |
|
|
208
|
+
| `saveAndContinue` | `boolean` | Shows the "save and continue" button. |
|
|
209
|
+
| `title` | `string` | Header title. |
|
|
210
|
+
| `labelSave` / `labelSaveAndContinue` / `labelSaveAndCreateNew` / `labelCancel` / `labelRemove` | `string` | Override button labels (defaults come from `theme.texts.forms`). |
|
|
211
|
+
| `fieldsLayout` | `FormFieldLayout<T>[]` | Sections/rows/custom elements. See §4.1. |
|
|
212
|
+
| `customFieldFormLayouts` | `CustomFormFieldLayouts<T>` | Per-relation-field layouts for nested/editable relations. |
|
|
213
|
+
| `hiddenFields` | `FieldList<T>` | Fields not rendered; their values are preserved as hidden inputs on save. |
|
|
214
|
+
| `fieldsProps` | `FieldsProps<T>` | Per-field widget overrides (see §4.3). |
|
|
215
|
+
| `optionsAC` / `setOptionsAC` | `OptionsAC<T>` / setter | External autocomplete cache. Usually unnecessary inside a page. |
|
|
216
|
+
| `isolatedGetAutoComplete` | `(model) => Promise<AutocompleteItem[] \| AxiosError>` | Replace the autocomplete loader for this form only. |
|
|
217
|
+
| `relatedEditable` | `boolean` | `false` disables the inline edit dialogs for relation fields. |
|
|
218
|
+
| `autoFocusField` | `FieldKey<T>` | Focus this field on mount. |
|
|
219
|
+
| `elevation` | `number` | Card elevation. |
|
|
220
|
+
| `extraValidators` | `ExtraValidators<T>` | Replace the yup validator for individual fields. |
|
|
221
|
+
| `watchValues` | `FieldList<T>` | Fields monitored by `FormWatcher`. Requires `onWatchChange`. |
|
|
222
|
+
| `onWatchChange` | `(values: FormWatchObject<T>) => void` | Called with `{ [field]: value }` whenever a watched value changes (deep-equality guarded). |
|
|
223
|
+
| `reloadStateStamp` | `number \| string` | Change it to force a reload of the record/schema. |
|
|
224
|
+
| `CustomFormActions` | `(props: FormActionsProps) => JSX.Element` | Replace the default action bar. |
|
|
225
|
+
| `multiline`, `fieldKey`, `labelKey`, `optionsModel`, `getOptionLabel`, `renderOption`, `onEditModel`, `options`, `isSemaphoric`, `label`, `decimalScale` | — | Shared field props forwarded to the schema renderer (only these are forwarded). |
|
|
226
|
+
| `sxSection`, `sxSectionTitle`, `sxRow`, `sxRowMultiple` | `SxProps<Theme>` | Layout styling. |
|
|
227
|
+
|
|
228
|
+
Behavior worth knowing:
|
|
229
|
+
|
|
230
|
+
- It renders an empty fragment until the schema for `model` is in `pageForm`.
|
|
231
|
+
- Navigation precedence on exit: `exit` → `exitPath` → `history.back()`.
|
|
232
|
+
- A dirty form installs a `beforeunload` guard.
|
|
233
|
+
- DRF field errors returned by a serializer `validate()` are mapped onto the form fields.
|
|
234
|
+
- On unmount it resets `pageForm`.
|
|
235
|
+
|
|
236
|
+
#### `<FormBySchema />` — form body (no page chrome)
|
|
237
|
+
|
|
238
|
+
`src/components/forms/FormBySchema.tsx`
|
|
239
|
+
|
|
240
|
+
Renders a schema-driven form body. It does **not** create the react-hook-form context, so
|
|
241
|
+
you pass `schema`, `control`, `errors` and (usually) `getValues`/`setValue`.
|
|
242
|
+
|
|
243
|
+
Additional props beyond the shared field props (§4.2):
|
|
244
|
+
|
|
245
|
+
| Prop | Type | Purpose |
|
|
246
|
+
| --- | --- | --- |
|
|
247
|
+
| `schema` | `SchemaType<T>` | Required. |
|
|
248
|
+
| `control` | `Control<Item<T>>` | Required. |
|
|
249
|
+
| `errors` | `FieldErrors<Item<T>>` | Required. |
|
|
250
|
+
| `fieldsLayout` | `FormFieldLayout<T>[]` | Sections/rows/custom elements. |
|
|
251
|
+
| `customFieldFormLayouts` | `CustomFormFieldLayouts<T>` | Per-relation layouts. |
|
|
252
|
+
| `hiddenFields` | `FieldList<T>` | Fields not rendered. |
|
|
253
|
+
| `fieldsProps` | `FieldsProps<T>` | Per-field overrides. |
|
|
254
|
+
| `setOptionsAC` | `(x: OptionsAC<T>) => void` | Cache setter when you own the options. |
|
|
255
|
+
| `isolatedGetAutoComplete` | loader | Replace the autocomplete loader. |
|
|
256
|
+
| `relatedEditable` | `boolean` | Disable inline relation dialogs. |
|
|
257
|
+
| `autoFocusField` | `FieldKey<T>` | Initial focus. |
|
|
258
|
+
| `elevation` | `number` | Card elevation. |
|
|
259
|
+
| `conditionalVisible` / `watchedValues` | internal | Usually supplied by `<Form>`/`DialogFormBySchema`; do not set by hand. |
|
|
260
|
+
| `sxSection`, `sxSectionTitle`, `sxRow`, `sxRowMultiple` | `SxProps<Theme>` | Layout styling. |
|
|
261
|
+
|
|
262
|
+
#### `<DialogFormBySchema />` — schema-driven dialog form
|
|
263
|
+
|
|
264
|
+
`src/components/forms/DialogFormBySchema.tsx`
|
|
265
|
+
|
|
266
|
+
| Prop | Type | Purpose |
|
|
267
|
+
| --- | --- | --- |
|
|
268
|
+
| `schema` | `SchemaType<T>` | Required. |
|
|
269
|
+
| `validationSchema` | `AnyObjectSchema` | Required yup schema. |
|
|
270
|
+
| `initialValues` | `Item<T>` | Required. |
|
|
271
|
+
| `onEditModelSave` | `(data: Item<T>) => Promise<boolean \| AxiosError>` | Save callback. |
|
|
272
|
+
| `setDialog` | `(x: Partial<DialogType>) => void` | Close/update the dialog. |
|
|
273
|
+
| `getAutoComplete` | loader | Autocomplete loader. |
|
|
274
|
+
| `optionsAC` / `hiddenFields` / `fieldsLayout` | — | Options cache, hidden fields, layout. |
|
|
275
|
+
| `setOptionsAC` | `(x: Partial<OptionsAC<T>>) => void` | Required by the prop type, but currently unused (pass the cache through `optionsAC`). |
|
|
276
|
+
| `isCancelDisabled` | `boolean` | Disable cancel (e.g. while saving). |
|
|
277
|
+
| `forceSaveEnabled` | `boolean` | Keep the save button enabled even when the form is not dirty. |
|
|
278
|
+
|
|
279
|
+
#### `<FormWatcher />` — invisible watcher
|
|
280
|
+
|
|
281
|
+
`src/components/forms/FormWatcher.tsx`
|
|
282
|
+
|
|
283
|
+
| Prop | Type | Purpose |
|
|
284
|
+
| --- | --- | --- |
|
|
285
|
+
| `control` | `Control<GenericValue>` | Required form control. |
|
|
286
|
+
| `watch` | `FieldList<T>` | Required list of field names. |
|
|
287
|
+
| `onChange` | `(values: FormWatchObject<T>) => void` | Called on change (deep-equality guarded). |
|
|
288
|
+
|
|
289
|
+
`<Form>` wraps it for you through `watchValues` + `onWatchChange`; use it directly only
|
|
290
|
+
inside a custom `FormProvider`.
|
|
291
|
+
|
|
292
|
+
#### `<FieldBySchema />` — one field
|
|
293
|
+
|
|
294
|
+
`src/components/forms/FieldBySchema.tsx` — routes the schema `type` to the right widget.
|
|
295
|
+
|
|
296
|
+
| Prop | Type | Purpose |
|
|
297
|
+
| --- | --- | --- |
|
|
298
|
+
| `name` | `FieldKey<T>` | Required field name. |
|
|
299
|
+
| `schema` | `SchemaType<T>` | Required full schema. |
|
|
300
|
+
| `control` | `Control<Item<T>>` | Required. |
|
|
301
|
+
| `errors` | `FieldErrors<Item<T>>` | Required. |
|
|
302
|
+
| `autoFocus` | `boolean` | Initial focus. |
|
|
303
|
+
| plus | `CommonFieldProps<T>` | `fieldKey`, `labelKey`, `index`, `optionsAC`, `optionsModel`, `getOptionLabel`, `renderOption`, `onEditModel`, `fieldsLayout`, `options`, `multiline`, `isSemaphoric`, `label`, `onValueChange`, `decimalScale`, `type`, `autoComplete`, `minRows`, `optionIdKey`, `optionLabelKey`, `disabled`, `sx`. |
|
|
304
|
+
|
|
305
|
+
#### Password forms
|
|
306
|
+
|
|
307
|
+
| Component | Props | Purpose |
|
|
308
|
+
| --- | --- | --- |
|
|
309
|
+
| `ChangePasswordForm` | `onSuccess?: () => void`, `submitLabel?: string` | Current/new/confirm password; calls `changePassword`. |
|
|
310
|
+
| `ForgotPasswordForm` | `token?: string`, `uid?: string`, `onSuccess?: () => void`, `onBack?: () => void` | With `token`+`uid` it shows the "set new password" step; without them it requests the reset e-mail. |
|
|
311
|
+
|
|
312
|
+
### 3.2 Lists and grids
|
|
313
|
+
|
|
314
|
+
#### `<GenericModelList />` — main list page
|
|
315
|
+
|
|
316
|
+
`src/components/GenericModelList.tsx`
|
|
317
|
+
|
|
318
|
+
| Prop | Type | Purpose |
|
|
319
|
+
| --- | --- | --- |
|
|
320
|
+
| `model` | `string` | Required. |
|
|
321
|
+
| `paginationMode` | `'server' \| 'client'` | Required. `client`: fetch all (batched); `server`: filter/sort/paginate/totals on the server. |
|
|
322
|
+
| `columnFields` | `FieldList<T>` | Columns to show, in order. Defaults to every schema field. |
|
|
323
|
+
| `hiddenFields` | `FieldList<T>` | Columns hidden by default. |
|
|
324
|
+
| `creatableFields` | `FieldList<T>` | Fields editable when adding a row. |
|
|
325
|
+
| `disabledFields` | `FieldList<T>` | Fields never editable. |
|
|
326
|
+
| `minWidthFields` | `MinWidthFields<T>` | Per-column min width. |
|
|
327
|
+
| `indexField` | `FieldKey<T>` | Main/link column. |
|
|
328
|
+
| `indexFieldBasePath` / `indexFieldViewBasePath` | `string` | Paths used by the index link. |
|
|
329
|
+
| `addExistingModel` | `string` | Enables "add existing" for a relation list. |
|
|
330
|
+
| `isEditable` | `boolean` | Inline editing. |
|
|
331
|
+
| `hasBulkSelect`, `onSelectActions` | `boolean`, `OnSelectActions[]` | Selection + bulk actions (`'bulkDelete'`, `'bulkCreate'`, or a custom function). |
|
|
332
|
+
| `actions` | `RowAction<T>[]` | Row actions; default `['editInline', 'remove']`. |
|
|
333
|
+
| `nonEditableActions` | `NonEditableRowAction<T>[]` | Read-only row actions (`'edit'`, `'view'`, custom). |
|
|
334
|
+
| `customActions` | `CustomAction[]` | Extra toolbar/grid actions (`{ key, icon, label, handleClick }`). |
|
|
335
|
+
| `customColumnOperations` | `(column) => column \| Promise<column>` | Last-chance column mutation. |
|
|
336
|
+
| `customLinkDestination` | `(params: GridRenderCellParams) => string` | Custom href for cells. |
|
|
337
|
+
| `customFieldFormLayouts` | `CustomFormFieldLayouts<T>` | Nested relation layouts. |
|
|
338
|
+
| `sumRows` | `SumRowsType<T>` | Totals; in `server` mode also sends `sum_rows` and renders facets. |
|
|
339
|
+
| `defaultFilter` | `GridFilterModel` | Initial filter, merged with the toolbar filter in server mode. |
|
|
340
|
+
| `queryParams` | `string[]` | Extra raw query params appended to every request. |
|
|
341
|
+
| `defaultValues` | `PartialItem<T>` | Defaults for new inline rows. |
|
|
342
|
+
| `optionsAC` | `OptionsAC<T>` | External options cache. |
|
|
343
|
+
| `extraValidators` | `ExtraValidators<T>` | Per-field yup overrides for inline editing. |
|
|
344
|
+
| `onProcessRow` | `(row?: Item<T>) => void` | After an inline save (row) or delete. |
|
|
345
|
+
| `onDataChange` | `(rows: Item<T>[]) => void` | After any grid data change. |
|
|
346
|
+
| `watchEditingRowValues` | `WatchEditingRowValues<T>` | Observe the row being edited; receives `{ rowEditingValues, setRowEditingValues }`. |
|
|
347
|
+
| `reloadStateStamp` | `number \| string` | Change to reload the list. |
|
|
348
|
+
| `isAutoHeight` | `boolean` | Default `true`. |
|
|
349
|
+
| `tableAutoHeight` | `boolean` | Fill the parent instead of fixed grid height. |
|
|
350
|
+
| `cardsViewOnly` | `boolean` | Force the mobile card layout. |
|
|
351
|
+
| `hasHeader` | `boolean` | Show the model plural name + add link. |
|
|
352
|
+
| `LinkComponent` | `LinkComponentType \| null` | Router link adapter (`{ to, href?, state?, ... }`). |
|
|
353
|
+
| `MobileListRenderItem` | `(info) => ReactElement \| null` | Custom mobile card renderer. `info`: `{ item, index, id }` where `item` is formatted. |
|
|
354
|
+
| `MobileRenderNoResults` | `() => ReactElement \| null` | Empty state for mobile. |
|
|
355
|
+
| `disableScreenLoading` | `boolean` | Skip the global loading backdrop. |
|
|
356
|
+
| `hideFooterComponent`, `hideToolbarComponent`, `hideColumnsButton`, `hideFilterButton`, `hideDensityButton`, `hideExportButton`, `hideQuickFilterBar` | `boolean` | UI toggles. |
|
|
357
|
+
|
|
358
|
+
#### `<GenericRelatedModelList />` — nested collection
|
|
359
|
+
|
|
360
|
+
`src/components/GenericRelatedModelList.tsx`
|
|
361
|
+
|
|
362
|
+
Most of the same grid props (minus `disableScreenLoading`, `hasHeader` and
|
|
363
|
+
`customLinkDestination`), plus:
|
|
364
|
+
|
|
365
|
+
| Prop | Type | Purpose |
|
|
366
|
+
| --- | --- | --- |
|
|
367
|
+
| `model` | `string` | Parent model. |
|
|
368
|
+
| `id` | `Id` | Parent id. |
|
|
369
|
+
| `relatedModel` | `string` | Related model slug (the nested route segment). |
|
|
370
|
+
| `label` | `string` | Card/table title. |
|
|
371
|
+
| `paginationMode` | `'server' \| 'client'` | Required. |
|
|
372
|
+
| `usuaria` | `Item \| null` | Kept for compatibility; not used by the component. |
|
|
373
|
+
| `isInBatches` | `boolean` | Default `true`. |
|
|
374
|
+
| `noCardWrapper` | `boolean` | Render without the surrounding `Card`. |
|
|
375
|
+
| `hiddenFields` | `FieldList<T>` | Default `['id']`. |
|
|
376
|
+
| `isEditable` | `boolean` | Default `true`. |
|
|
377
|
+
|
|
378
|
+
It requests `/<model>/<id>/<relatedModel>/` and offers add/edit/remove for those rows.
|
|
379
|
+
|
|
380
|
+
#### `<DataGridBySchemaEditable />` — lower-level grid
|
|
381
|
+
|
|
382
|
+
`src/components/DataGridBySchemaEditable.tsx`
|
|
383
|
+
|
|
384
|
+
Desktop DataGrid + mobile cards. Use it for fully custom grids; the list components above
|
|
385
|
+
wrap it. Required: `schema`, `data`, `columns`, `model`, `onEditModel`.
|
|
386
|
+
|
|
387
|
+
Other props: `rowCount`, `columnVisibilityModel`, `fieldKey`, `labelKey`, `index`,
|
|
388
|
+
`name`, `indexField` (default `'nome'`), `addExistingModel`, `indexFieldMinWidth`,
|
|
389
|
+
`indexFieldBasePath`, `indexFieldViewBasePath`, `stateToLink`, `minWidth`, `loading`,
|
|
390
|
+
`modelParent`, `modelParentId`, `customColumnOperations`, `customFieldFormLayouts`,
|
|
391
|
+
`customLinkDestination`, `LinkComponent`, `onProcessRow`, `onDataChange`,
|
|
392
|
+
`watchEditingRowValues`, `isEditable` (default `false`), `nonEditableActions`,
|
|
393
|
+
`hasBulkSelect`, `cardsViewOnly`, `onSelectActions`, `sx`, `isAutoHeight`,
|
|
394
|
+
`defaultValues`, `hideFooterPagination`, `setVisibleRows`, `paginationModel`,
|
|
395
|
+
`setPaginationModel`, `hideFooterComponent`, `hideToolbarComponent`, `tableAutoHeight`,
|
|
396
|
+
`actions` (default `['editInline', 'remove']`), `customActions`, `hideColumnsButton`,
|
|
397
|
+
`hideFilterButton`, `hideDensityButton`, `hideExportButton`, `hideQuickFilterBar`,
|
|
398
|
+
`optionsAC`, `extraValidators`, `MobileListRenderItem`, `MobileRenderNoResults`.
|
|
399
|
+
|
|
400
|
+
#### `<DataTotals />` — client-side totals
|
|
401
|
+
|
|
402
|
+
`src/components/DataTotals.tsx`
|
|
403
|
+
|
|
404
|
+
| Prop | Type |
|
|
405
|
+
| --- | --- |
|
|
406
|
+
| `schema` | `SchemaType` |
|
|
407
|
+
| `data` | `Item[]` |
|
|
408
|
+
| `sumRows` | `SumRowsType` (required to render) |
|
|
409
|
+
| `visibleRows` | `GridRowId[]` (optional; sum only visible rows) |
|
|
410
|
+
|
|
411
|
+
There is no public `DataTotalsServer`: server totals/facets are rendered internally by
|
|
412
|
+
`GenericModelList`. (This is a correction to older docs that listed it as exported.)
|
|
413
|
+
|
|
414
|
+
### 3.3 Detail views
|
|
415
|
+
|
|
416
|
+
#### `<DetailBySchema />` — read-only detail body
|
|
417
|
+
|
|
418
|
+
`src/components/details/DetailBySchema.tsx`
|
|
419
|
+
|
|
420
|
+
| Prop | Type | Purpose |
|
|
421
|
+
| --- | --- | --- |
|
|
422
|
+
| `values` | `Item<T>` | Required record. |
|
|
423
|
+
| `schema` | `SchemaType<T>` | Required. |
|
|
424
|
+
| `columns` | `GridEnrichedBySchemaColDef<T>[]` | Required; drives field order/labels. |
|
|
425
|
+
| `loading` | `boolean` | Loading state. |
|
|
426
|
+
| `editLink` / `editLabel` | `string` | Optional edit button. |
|
|
427
|
+
| `fieldsLayout` | `DetailFieldLayout<T>[]` | Sections/accordions. See §4.6. |
|
|
428
|
+
| `hiddenFields` | `FieldList<T>` | Default `['id']`. |
|
|
429
|
+
| `fieldsProps` | `DetailFieldsProps<T>` | Per-field overrides/formatters. |
|
|
430
|
+
| `elevation` | `number` | Card elevation. |
|
|
431
|
+
| `sxSection`, `sxSectionTitle`, `sxRow`, `sxRowMultiple`, `sxField`, `sxLabel`, `sxValue`, `sxValueList`, `sxValueListItem`, `sxValueListItemText` | `SxProps<Theme>` | Styling. |
|
|
432
|
+
|
|
433
|
+
#### `<DetailFieldBySchema />` — one read-only field
|
|
434
|
+
|
|
435
|
+
| Prop | Type | Purpose |
|
|
436
|
+
| --- | --- | --- |
|
|
437
|
+
| `fieldKey` | `FieldKey` | Required label/fallback. |
|
|
438
|
+
| `fieldSchema` | `Field` | Metadata; without it the component logs an error and renders nothing. |
|
|
439
|
+
| `value` | `FormattedItemValue` (`{ title, valueStr, value }`) | The formatted value. |
|
|
440
|
+
| `item` | `Item<T>` | Raw record, passed to formatters. |
|
|
441
|
+
| `valueFormatter` | `(value, item, fieldSchema?) => any` | Format before display. |
|
|
442
|
+
| `renderValue` | `({ value, item, fieldSchema, label }) => ReactNode` | Replace the value node. |
|
|
443
|
+
| `emptyValue` | `ReactNode` | Default `-`. |
|
|
444
|
+
| `hideIfEmpty` | `boolean` | Render nothing when empty. |
|
|
445
|
+
| `optionIdKey` / `optionLabelKey` | `string` | Choice/relation keys. |
|
|
446
|
+
| `sxField`, `sxLabel`, `sxValue`, `sxValueList`, `sxValueListItem`, `sxValueListItemText` | `SxProps<Theme>` | Styling. |
|
|
447
|
+
|
|
448
|
+
#### `<DetailPage />` — full detail page
|
|
449
|
+
|
|
450
|
+
`src/components/details/DetailPage.tsx` — header (back/title/edit), optional hero and
|
|
451
|
+
tabs; no router dependency.
|
|
452
|
+
|
|
453
|
+
Props: `model`, `objId`, `titleField`, `title`, `backLink`, `backLabel` (default
|
|
454
|
+
`'Back'`), `onBack` (takes precedence over `backLink`), `editLink`, `editLabel`,
|
|
455
|
+
`hero`, `tabs` (`DetailTabConfig[]`: `{ key, label, sections?, render?, count?,
|
|
456
|
+
hidden?, icon? }`), `sections`, `fieldsLayout` (alias of `sections`), `hiddenFields`,
|
|
457
|
+
`fieldsProps`, `elevation` (default `0`), `renderHeader`, `renderShell`, `emptyLabel`,
|
|
458
|
+
`errorLabel`, `retryLabel`, plus the shared `sx*` props.
|
|
459
|
+
|
|
460
|
+
#### `useDetailData()` — detail data loader
|
|
461
|
+
|
|
462
|
+
`src/hooks/useDetailData.ts`
|
|
463
|
+
|
|
464
|
+
```ts
|
|
465
|
+
const { values, schema, columns, loading, error, reload } = useDetailData({ model, objId });
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
`UseDetailDataResult`: `{ values, schema, columns, loading, error, reload }`.
|
|
469
|
+
`UseDetailDataProps` also declares `titleField`, but the hook currently only uses
|
|
470
|
+
`model` and `objId`.
|
|
471
|
+
|
|
472
|
+
### 3.4 Small shared components
|
|
473
|
+
|
|
474
|
+
| Component | Props | Purpose |
|
|
475
|
+
| --- | --- | --- |
|
|
476
|
+
| `HtmlContent` | `{ html?: string \| null; sx?: SxProps<Theme> }` | Sanitized read-only HTML. Uses `dompurify` when installed, otherwise strips tags. |
|
|
477
|
+
| `FileTypeIcon` | `{ name?: string }` | Icon for a file name/URL extension. Exports `FILE_TYPE_ICONS` and `DEFAULT_FILE_ICON` from the same module (not from the package root). |
|
|
478
|
+
| `DialogActions` | `{ setDialog, handleSave?, btnCancel?, btnConfirm? }` | Cancel/confirm buttons for a `setDialog` body. |
|
|
479
|
+
|
|
480
|
+
### 3.5 Field widgets and grid cells
|
|
481
|
+
|
|
482
|
+
These are exported for composition inside custom layouts. All form widgets accept
|
|
483
|
+
`FieldBySchemaProps<T>` (`name`, `schema`, `control`, `errors`, plus `CommonFieldProps`):
|
|
484
|
+
|
|
485
|
+
`TextFieldBySchema`, `HtmlFieldBySchema`, `BooleanFieldBySchema`,
|
|
486
|
+
`DesktopDatePickerBySchema`, `DesktopDateTimePickerBySchema`,
|
|
487
|
+
`AutocompleteFieldBySchema`, `EditableAutocompleteFieldBySchema`, `FloatFieldBySchema`.
|
|
488
|
+
|
|
489
|
+
Grid editing primitives (they rely on the DataGrid edit context, not on
|
|
490
|
+
react-hook-form): `SelectEditInputCell`, `GridDateInput`, `GridDecimalInput`,
|
|
491
|
+
`GridPatternInput`, `BooleanInputCell`.
|
|
492
|
+
|
|
493
|
+
Leaflet helpers: `applyDefaultLeafletIcon`, `applyThemeMarkerIcon`,
|
|
494
|
+
`DRF_REACT_BY_SCHEMA_MARKER_ICON`, `DEFAULT_LAYERS`; text lookup: `getThemeTexts`.
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## 4. Shared prop building blocks
|
|
499
|
+
|
|
500
|
+
These types are exported from `@types` and reused by the components above.
|
|
501
|
+
|
|
502
|
+
### 4.1 `fieldsLayout` (forms)
|
|
503
|
+
|
|
504
|
+
`FormFieldLayout<T>` = `{ title?, rows?, customLabels?, CustomElement? }` per section.
|
|
505
|
+
|
|
506
|
+
- `rows` is an array of: a field name, an array of fields (same row), or a
|
|
507
|
+
`CustomFormField` (`{ key, CustomElement }`).
|
|
508
|
+
- `customLabels` overrides specific labels in that section.
|
|
509
|
+
- `CustomElement` replaces the whole section body.
|
|
510
|
+
|
|
511
|
+
### 4.2 `CommonFieldProps` (shared by field widgets/forms)
|
|
512
|
+
|
|
513
|
+
`value`, `multiline`, `setValue`, `getValues`, `fieldKey`, `labelKey`, `index`,
|
|
514
|
+
`optionsAC`, `optionsModel`, `getOptionLabel`, `renderOption`, `onEditModel`,
|
|
515
|
+
`fieldsLayout`, `multiple`, `sx`, `options`, `isSemaphoric`, `label`, `onValueChange`,
|
|
516
|
+
`decimalScale`, `type`, `autoComplete`, `minRows`, `optionIdKey`, `optionLabelKey`,
|
|
517
|
+
`disabled`.
|
|
518
|
+
|
|
519
|
+
### 4.3 `fieldsProps`
|
|
520
|
+
|
|
521
|
+
`Record<fieldName, CommonFieldProps>` — per-field widget overrides, e.g.
|
|
522
|
+
`fieldsProps={{ observacao: { minRows: 5 }, comunidade: { disabled: true } }}`.
|
|
523
|
+
|
|
524
|
+
### 4.4 `hiddenFields`, `columnFields`, `creatableFields`, `disabledFields`
|
|
525
|
+
|
|
526
|
+
`FieldList<T>` (array of field names). They filter columns/fields; in forms,
|
|
527
|
+
`hiddenFields` values are preserved as hidden inputs on save.
|
|
528
|
+
|
|
529
|
+
### 4.5 `sumRows`
|
|
530
|
+
|
|
531
|
+
`SumRowsType<T>` = `{ rows: SumRowsItem<T>[]; severity?: AlertColor }`, where a row is
|
|
532
|
+
`{ field, prefix?, suffix?, isCount?, facetBy?, facetLimit? }`.
|
|
533
|
+
|
|
534
|
+
- In `client` mode `DataTotals` sums the loaded rows (optionally only `visibleRows`).
|
|
535
|
+
- In `server` mode the same rows become the `sum_rows` query and `DataTotalsServer`
|
|
536
|
+
(internal) renders `sumRowsTotals` + `facets`.
|
|
537
|
+
- `facetBy` accepts field keys or nested forward relations (`'comunidade__municipio'`).
|
|
538
|
+
|
|
539
|
+
### 4.6 `fieldsLayout` (details)
|
|
540
|
+
|
|
541
|
+
`DetailFieldLayout<T>` = `{ title?, rows?, CustomElement?, isAccordion?, isAccordionOpen?,
|
|
542
|
+
hidden?, hideIfEmpty? }`.
|
|
543
|
+
|
|
544
|
+
- `rows` accepts field paths, arrays (same row), or `CustomDetailField`
|
|
545
|
+
(`{ key, CustomElement }`).
|
|
546
|
+
- Dotted paths (`'contratacao.valor'`) resolve nested values/metadata.
|
|
547
|
+
- `hidden(values)` omits the section; `hideIfEmpty` omits it when every field is empty.
|
|
548
|
+
|
|
549
|
+
### 4.7 `fieldsProps` (details)
|
|
550
|
+
|
|
551
|
+
`DetailFieldsProps<T>` — per-field `DetailCommonFieldProps`: `valueFormatter`,
|
|
552
|
+
`renderValue`, `emptyValue`, `hideIfEmpty`, `item`, `fieldSchema`, plus `sx*` overrides
|
|
553
|
+
and the shared `CommonFieldProps`.
|
|
554
|
+
|
|
555
|
+
### 4.8 Actions
|
|
556
|
+
|
|
557
|
+
- `ActionType`: `'editInline' | 'remove' | 'edit' | 'view'`.
|
|
558
|
+
- `RowAction<T>`: an `ActionType` or `CustomRowAction` (`{ icon, label?, handleClick(item) }`).
|
|
559
|
+
- `NonEditableRowAction<T>`: `'edit' | 'view' | CustomRowAction`.
|
|
560
|
+
- `CustomAction<T>`: `{ key, icon, label, handleClick(item) }` — extra toolbar action.
|
|
561
|
+
- `OnSelectActions`: `{ title, action: 'bulkDelete' | 'bulkCreate' | custom(selectedData, bulkUpdateData) }`.
|
|
562
|
+
|
|
563
|
+
### 4.9 `optionsAC` and relation loading
|
|
564
|
+
|
|
565
|
+
`OptionsAC<T>` is `Record<model, OptionsACItem[]>` (usually
|
|
566
|
+
`AutocompleteItem = { id, label }`, choice items are also accepted). It is populated
|
|
567
|
+
automatically for relation fields; pass it only when you need to preload/override
|
|
568
|
+
options.
|
|
569
|
+
|
|
570
|
+
### 4.10 `extraValidators`
|
|
571
|
+
|
|
572
|
+
`Record<fieldName, YupSchema>` replacing the generated validator for those fields.
|
|
573
|
+
Useful for cross-field rules, e.g.
|
|
574
|
+
`{ fim: yup.date().min(yup.ref('inicio'), '...') }` (resolve the ref against the form
|
|
575
|
+
values).
|
|
576
|
+
|
|
577
|
+
### 4.11 `LinkComponent`
|
|
578
|
+
|
|
579
|
+
`React.ComponentType<{ to: string | object; href?; state?; className?; style?; children? }>`
|
|
580
|
+
— lets the package navigate with react-router (or any router) instead of plain anchors.
|
|
581
|
+
|
|
582
|
+
### 4.12 `FormSaveActions`
|
|
583
|
+
|
|
584
|
+
Enum passed to `Form.onSave` as `buttonType`:
|
|
585
|
+
`EXIT_ON_SAVE = 'exitOnSave'`, `SAVE_AND_CONTINUE = 'saveAndContinue'`,
|
|
586
|
+
`SAVE_AND_CREATE_NEW = 'saveAndCreateNew'`.
|
|
587
|
+
|
|
588
|
+
### 4.13 `reloadStateStamp`
|
|
589
|
+
|
|
590
|
+
Any `number | string`. When it changes, `<Form>`, `<GenericModelList>` and
|
|
591
|
+
`<GenericRelatedModelList>` reload their data. Useful after an external mutation.
|
|
592
|
+
|
|
593
|
+
### 4.14 `conditional_visible`
|
|
594
|
+
|
|
595
|
+
Schema key (produced by Django) that hides fields until a condition holds. Hidden
|
|
596
|
+
fields are cleared on save. Shapes accepted: a `[field, value]` pair, an array of
|
|
597
|
+
conditions (OR, legacy), or `{ operator: 'AND' | 'OR', conditions: [...] }` (nestable).
|
|
598
|
+
`ui_required` fields are required only while visible. See the README section for a
|
|
599
|
+
worked example.
|
|
600
|
+
|
|
601
|
+
---
|
|
602
|
+
|
|
603
|
+
## 5. Utility functions
|
|
604
|
+
|
|
605
|
+
Exported from the package root.
|
|
606
|
+
|
|
607
|
+
| Function | Signature | Purpose |
|
|
608
|
+
| --- | --- | --- |
|
|
609
|
+
| `setAuthToken` | `(token: string \| null) => void` | Stores the access token in `localStorage` and sets/clears the axios `Authorization` header. `null` also removes the refresh token. |
|
|
610
|
+
| `hasJWT` | `() => boolean` | Whether an access token is stored. |
|
|
611
|
+
| `clearJWT` | `() => false` | Removes the access token (and returns `false`). |
|
|
612
|
+
| `AUTH_EXPIRED_EVENT` | `string` constant | Dispatched on `window` when the token refresh fails. Listen to it to sign the user out. |
|
|
613
|
+
| `emptyByType` | `(field: Field, forDatabase = false) => any` | Empty value for a field type (`''`, `[]`, `false`, `0`, `null`, …). `forDatabase` fixes nested-object/`field` edge cases. |
|
|
614
|
+
| `populateValues` | `({ data, schema }) => Item` | Fills missing values with `emptyByType` and normalizes choices/relations for the forms. |
|
|
615
|
+
| `enrichChoices` | `(rawData, schema) => Item<T>` | Shapes raw choice values into `{ value, display_name }` (and lists into arrays of them). |
|
|
616
|
+
| `getChoiceByValue` | `(value, choices?) => string \| null \| undefined` | Choice `display_name` for a raw value. |
|
|
617
|
+
| `buildGenericYupValidationSchema` | `({ data, schema, many?, skipFields?, extraValidators?, uiFields? }) => ObjectSchema` | Builds the yup schema used by forms/grids from field metadata. |
|
|
618
|
+
| `getDataGridColumns` | `(schema, columnFields?, creatableFields?, disabledFields?) => GridEnrichedBySchemaColDef[] \| false` | Derives grid columns from a schema. |
|
|
619
|
+
| `errorProps` | `({ errors, fieldKey, fieldKeyProp, index? }) => { error, helperText }` | Maps react-hook-form errors to MUI `TextField`/grid props. |
|
|
620
|
+
| `getFieldErrorsFromResponse` | `(response, schema?) => Record<field, { type, message }>` | Normalizes DRF validation errors for `setError` (skips unknown keys and `non_field_errors`). |
|
|
621
|
+
| `getTmpId` | `() => string` | Generates a `tmp<n>` id for unsaved rows. |
|
|
622
|
+
| `isTmpId` | `(id) => boolean` | `true` for empty/`'novo'`/`tmp*` ids. |
|
|
623
|
+
| `isReadOnlyField` | `(field?) => boolean` | Read-only derived field (relations are not considered read-only here). |
|
|
624
|
+
| `isRelationField` | `(field?) => boolean` | `type` is `'field'` or `'nested object'`. |
|
|
625
|
+
| `getPatternFormat` | `(type: string) => string` | Input mask for known field types (`telefone`, `cpf`, `cnpj`, …). |
|
|
626
|
+
| `slugToCamelCase` | `(str, includeFirst = false) => string` | Converts slugs to camelCase (`my_model` → `myModel`); `includeFirst` capitalizes the first letter (`MyModel`). |
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
630
|
+
## 6. Error handling contract
|
|
631
|
+
|
|
632
|
+
- Every fetch/write helper resolves to the value **or** an `AxiosError`-shaped object
|
|
633
|
+
(`axios.isAxiosError(result) === true`). Check before use.
|
|
634
|
+
- A `401` triggers a single token refresh; if that fails the package dispatches
|
|
635
|
+
`AUTH_EXPIRED_EVENT` and returns an error.
|
|
636
|
+
- The high-level write helpers (`onSubmit`, `onEditModelSave`, `onDeleteModel`, …) also
|
|
637
|
+
show a snackbar and close dialogs as documented above; the raw helpers (`postData`,
|
|
638
|
+
`updateModel`, `rawDeleteData`) do not.
|
|
639
|
+
- `<Form>` maps per-field DRF errors onto the corresponding form fields; unknown keys
|
|
640
|
+
and `non_field_errors` stay in the generic snackbar message.
|
|
641
|
+
|
|
642
|
+
---
|
|
643
|
+
|
|
644
|
+
## 7. Agent notes and gotchas
|
|
645
|
+
|
|
646
|
+
- `watchValues`/`onWatchChange` only run when **both** are provided. `onWatchChange`
|
|
647
|
+
receives an object keyed by the listed field names, and is only called when the
|
|
648
|
+
watched values actually change (deep equality).
|
|
649
|
+
- `GenericModelList` has no `paginationModel` or `title` prop; the pagination model is
|
|
650
|
+
internal and the header title is the model's `verbose_name_plural`. `fieldsLayout`
|
|
651
|
+
belongs to `<Form>`; lists use `customFieldFormLayouts` for nested forms.
|
|
652
|
+
- `onDeleteModel` is fire-and-forget (confirmation dialog), while
|
|
653
|
+
`onDeleteRelatedModel` returns a promise.
|
|
654
|
+
- `getRawData` prefixes `${serverEndPoint.api}/`; do not pass a leading `/api`.
|
|
655
|
+
- `FormBySchema` needs the react-hook-form `control`/`errors`; it does not create a form.
|
|
656
|
+
- `Form` accepts a `register` prop in its type but ignores it — the component owns the
|
|
657
|
+
react-hook-form instance and passes its own `register` down.
|
|
658
|
+
- `FieldBySchema`/`DetailFieldBySchema` silently skip fields with no schema entry
|
|
659
|
+
(`DetailFieldBySchema` logs an error); always pass the matching schema.
|
|
660
|
+
- `conditional_visible` values are cleared on save; do not rely on stale hidden values.
|
|
661
|
+
- `ui_required` is enforced only for fields present in the rendered layout.
|
|
662
|
+
- Mobile: forms/grids switch to cards below the `md` breakpoint; `cardsViewOnly` forces
|
|
663
|
+
cards on desktop. Always check layouts on mobile.
|
|
664
|
+
- The two `*.md` files next to `DataGridBySchemaEditable` and
|
|
665
|
+
`DRFReactBySchemaProvider` are legacy snippets, not references — use this document.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Field types & widgets
|
|
2
|
+
|
|
3
|
+
`drf-react-by-schema` derives every form widget, validation rule and DataGrid column
|
|
4
|
+
directly from the schema generated by `drf-react-by-schema-django` (via the model
|
|
5
|
+
serializers + `OPTIONS`/`sync_react`). This page documents each schema field `type`
|
|
6
|
+
and the matching widget it renders.
|
|
7
|
+
|
|
8
|
+
## Quick reference
|
|
9
|
+
|
|
10
|
+
The `type` value comes from the schema that Django exposes for each model field.
|
|
11
|
+
The table below maps every type to its **form widget** and its **DataGrid** behavior.
|
|
12
|
+
|
|
13
|
+
| Schema type | Form widget | DataGrid read (cell) | DataGrid edit | Notes |
|
|
14
|
+
| --- | --- | --- | --- | --- |
|
|
15
|
+
| `string` | `TextField` (single line) | text | text input (mask if `pattern_format`) | |
|
|
16
|
+
| `string` + `model_html` | **Tiptap WYSIWYG** (`HtmlFieldBySchema`) | sanitized **HTML** | text input | optional peers; falls back to multiline `TextField` |
|
|
17
|
+
| `email` | `TextField` (email) | text | text input | |
|
|
18
|
+
| `password` | `TextField` (`type="password"`) | text (hidden) | text input | |
|
|
19
|
+
| `number`, `integer` | `TextField` (numeric) | number (pt-BR formatted) | numeric input | `min`/`max` from validators |
|
|
20
|
+
| `decimal`, `float` | `FloatFieldBySchema` (decimal input) | number (pt-BR, `decimal_places`) | `GridDecimalInput` | honors `decimal_places`, `is_currency` |
|
|
21
|
+
| `date` | `DesktopDatePickerBySchema` (MUI date picker) | date (`date_views` format) | `GridDateInput` | |
|
|
22
|
+
| `datetime` | `DesktopDateTimePickerBySchema` (MUI date-time picker) | date-time (`DD/MM/YYYY HH:mm`) | `GridDateTimeInput` | |
|
|
23
|
+
| `boolean` | `BooleanFieldBySchema` (switch) | `Sim` / `Não` | `BooleanInputCell` | |
|
|
24
|
+
| `choice` | `AutocompleteFieldBySchema` (single select) | label (join) | `SelectEditInputCell` | `choices` provide options |
|
|
25
|
+
| `list` / `multiple choice` | `AutocompleteFieldBySchema` (multi-select) | label (comma-joined) | `SelectEditInputCell` (`multiple`) | `many: true`; child `choices` |
|
|
26
|
+
| `field` / `nested object` | `EditableAutocompleteFieldBySchema` (related) | related label | `SelectEditInputCell` | `related_editable` enables editing via dialog |
|
|
27
|
+
| `file` / `file upload` | `FileFieldBySchema` (upload) | file name | `FileInputCell` | `allowed_mime_types` |
|
|
28
|
+
| `image` / `image upload` | `FileFieldBySchema` (image upload) | thumbnail preview | `FileInputCell` | `allowed_mime_types` |
|
|
29
|
+
| `array` | `TextField` (default fallback) | text | text input | |
|
|
30
|
+
| `slug` | `TextField` | text | text input | forced `read_only` |
|
|
31
|
+
| `point` | Leaflet **point picker** (see Geometry below) | **thumb map** | **modal** point picker | requires PostGIS + leaflet |
|
|
32
|
+
| `polygon` | Leaflet **polygon draw** (see Geometry below) | **thumb map** | **modal** polygon draw | requires PostGIS + leaflet |
|
|
33
|
+
| `multipoint` | Leaflet **multi-point picker** (see Geometry below) | **thumb map** | **modal** multi-point picker | requires PostGIS + leaflet |
|
|
34
|
+
| `multipolygon` | Leaflet **multi-polygon draw** (see Geometry below) | **thumb map** | **modal** multi-polygon draw | requires PostGIS + leaflet |
|
|
35
|
+
| `geometrycollection` | Leaflet **points + polygons draw** (see Geometry below) | **thumb map** | **modal** geometry draw | requires PostGIS + leaflet |
|
|
36
|
+
|
|
37
|
+
## Rich text fields (`model_html`)
|
|
38
|
+
|
|
39
|
+
A Django `TextField(rich_text=True)` (from `drf_react_by_schema.fields`) keeps its plain
|
|
40
|
+
`string` type but adds `model_html: true` to the schema. The value **is HTML** — the same
|
|
41
|
+
format the Django admin's Summernote widgets store — so no conversion or migration is
|
|
42
|
+
needed for existing admin-authored content.
|
|
43
|
+
|
|
44
|
+
### Requirements
|
|
45
|
+
|
|
46
|
+
The editor is optional, like the map widgets. Install Tiptap in the **consuming app**:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install @tiptap/react @tiptap/starter-kit
|
|
50
|
+
# optional: sanitizes rich text in detail views
|
|
51
|
+
npm install dompurify
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Without Tiptap the field falls back to the multiline text field (raw HTML editable as
|
|
55
|
+
text), and the form keeps working. Without `dompurify` the detail view renders the value
|
|
56
|
+
as plain text (tags stripped) instead of injecting HTML.
|
|
57
|
+
|
|
58
|
+
### Widgets and behaviour
|
|
59
|
+
|
|
60
|
+
- **Form** (`HtmlFieldBySchema` → `RichTextEditorInput`): a Tiptap editor with an MUI
|
|
61
|
+
toolbar — paragraph/H1–H3, bold, italic, underline, strikethrough, bullet and ordered
|
|
62
|
+
lists, quote, code block, horizontal rule, link (dialog), clear formatting, undo/redo.
|
|
63
|
+
The form value is the editor's HTML (`getHTML()`), empty content is saved as `''`.
|
|
64
|
+
- **Detail** (`DetailFieldBySchema` → `HtmlContent`): the HTML is sanitized with
|
|
65
|
+
DOMPurify against an allow-list of tags/attributes, then rendered read-only with the
|
|
66
|
+
package's typography scale.
|
|
67
|
+
- **Grid**: the cell shows the stored HTML as text (no rendering); the toolbar strings are
|
|
68
|
+
localized through `theme.texts.richText` (see `docs/localization.md`).
|
|
69
|
+
|
|
70
|
+
Sanitization happens on **render**, not on save: the API keeps the HTML verbatim, so any
|
|
71
|
+
other client of the same column must sanitize it too.
|
|
72
|
+
|
|
73
|
+
## Geometry fields (PostGIS)
|
|
74
|
+
|
|
75
|
+
Geometry field types map to Django's GeoDjango model fields (`PointField`,
|
|
76
|
+
`PolygonField`, `MultiPointField`, `MultiPolygonField`, `GeometryCollectionField`)
|
|
77
|
+
serialized as **GeoJSON**. They are only emitted when the database engine is PostGIS.
|
|
78
|
+
|
|
79
|
+
### Requirements
|
|
80
|
+
|
|
81
|
+
The map widgets are optional. They require the following packages to be installed in
|
|
82
|
+
the **consuming app** (they are declared as *optional* peer dependencies of
|
|
83
|
+
`drf-react-by-schema`):
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm install leaflet react-leaflet leaflet-draw
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If any of them is missing, the field falls back to a plain widget so the app keeps
|
|
90
|
+
working:
|
|
91
|
+
|
|
92
|
+
- **`point`** → a single-line text input.
|
|
93
|
+
- **`polygon`, `multipoint`, `multipolygon`, `geometrycollection`** → a multiline text area.
|
|
94
|
+
|
|
95
|
+
In both cases the value stays a GeoJSON string.
|
|
96
|
+
|
|
97
|
+
### Widgets and behaviour
|
|
98
|
+
|
|
99
|
+
All geometry widgets share the same map + text editing UI:
|
|
100
|
+
|
|
101
|
+
- The **map** shows and edits the geometry over an OpenStreetMap base layer.
|
|
102
|
+
- A **text field** below the map is **always synchronized in both directions**:
|
|
103
|
+
- paste/edit a GeoJSON string → it renders immediately on the map;
|
|
104
|
+
- draw/move on the map → the text field updates to the generated GeoJSON.
|
|
105
|
+
- **Malformed (or wrong-type) GeoJSON** text is flagged as an **input error** — the
|
|
106
|
+
message shows `Dados malformados, corrija o GeoJSON para refletir no mapa.` and the
|
|
107
|
+
previously drawn features are kept on the map (they are not wiped).
|
|
108
|
+
- The read-only **grid cell** renders a **thumb map**: a static mini-map fitted to the
|
|
109
|
+
geometry with padding + a zoom cap, so the shape is shown with some surrounding
|
|
110
|
+
context.
|
|
111
|
+
- The **grid edit cell** is a button that opens a **modal** with the picker/drawer + the
|
|
112
|
+
synced GeoJSON text field.
|
|
113
|
+
|
|
114
|
+
Behaviour per type:
|
|
115
|
+
|
|
116
|
+
| `type` | Can add | Move existing | Remove existing | Single instance? |
|
|
117
|
+
| --- | --- | --- | --- | --- |
|
|
118
|
+
| `point` | add **one** marker | drag marker | via grid edit delete | **yes** |
|
|
119
|
+
| `polygon` | draw **one** polygon | draw-edit (drag/reshape) | via edit delete | **yes** |
|
|
120
|
+
| `multipoint` | add **many** markers | drag each marker | via edit delete | no |
|
|
121
|
+
| `multipolygon` | add **many** polygons | draw-edit each | via edit delete | no |
|
|
122
|
+
| `geometrycollection` | **many** points **and** polygons | both | both | no |
|
|
123
|
+
|
|
124
|
+
- For the **single-instance** types (`point`, `polygon`), once one shape exists the
|
|
125
|
+
corresponding "add" tool is hidden from the toolbar — the shape can be **moved** and
|
|
126
|
+
**removed**, and removing it re-enables adding.
|
|
127
|
+
- Points (`point`, `multipoint`, and the points in `geometrycollection`) are **draggable**
|
|
128
|
+
markers: drag to move, and the new coordinates are written back immediately.
|
|
129
|
+
- Polygons (and the polygon parts of `multipolygon` / `geometrycollection`) use
|
|
130
|
+
Leaflet-Draw's edit control to **move/resize** and its delete tool to remove.
|
|
131
|
+
|
|
132
|
+
### Server side
|
|
133
|
+
|
|
134
|
+
| Model field (drf-react-by-schema) | Schema `type` | GeoJSON |
|
|
135
|
+
| --- | --- | --- |
|
|
136
|
+
| `fields.PointField` | `point` | `Point` |
|
|
137
|
+
| `fields.PolygonField` | `polygon` | `Polygon` |
|
|
138
|
+
| `fields.MultiPointField` | `multipoint` | `MultiPoint` |
|
|
139
|
+
| `fields.MultiPolygonField` | `multipolygon` | `MultiPolygon` |
|
|
140
|
+
| `fields.GeometryCollectionField` | `geometrycollection` | `GeometryCollection` |
|
|
141
|
+
|
|
142
|
+
> Tip: after adding/editing these model fields, run Django's `manage.py sync_react` to
|
|
143
|
+
> regenerate the TypeScript types — geometry fields map to the corresponding GeoJSON
|
|
144
|
+
> types (`Point`, `Polygon`, `MultiPoint`, `MultiPolygon`, `GeometryCollection`) rather
|
|
145
|
+
> than `any`.
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# Localization & theming
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`drf-react-by-schema` exposes its user-facing strings through the **MUI theme**, so a
|
|
6
|
+
consuming app can localize (translate) every widget in **one place** — its own theme.
|
|
7
|
+
This follows MUI's own approach (MUI components take `localeText`/`locale` props and the
|
|
8
|
+
DataGrid locale lives on the theme), keeps the strings out of `DRFReactBySchemaProvider`,
|
|
9
|
+
and works out of the box with sensible defaults.
|
|
10
|
+
|
|
11
|
+
## How it works
|
|
12
|
+
|
|
13
|
+
- The package **augments the MUI theme** (`@mui/material/styles`) with a typed `texts`
|
|
14
|
+
field (`Theme.texts` / `ThemeOptions.texts`).
|
|
15
|
+
- Package **defaults** (English) are baked into the package's **default theme**; apps
|
|
16
|
+
override any namespace they want in their own theme.
|
|
17
|
+
- `DRFReactBySchemaProvider` **deepmerges** the app's `theme` onto that default theme
|
|
18
|
+
(`deepmerge(defaultTheme, theme)`), so an app only sets the keys it wants.
|
|
19
|
+
- Widgets read the texts through `useTheme()` plus the exported `getThemeTexts(theme)`
|
|
20
|
+
helper, falling back to the built-in defaults when `theme.texts` is absent.
|
|
21
|
+
|
|
22
|
+
Because everything lives in the theme, it works under `DRFReactBySchemaProvider` **and**
|
|
23
|
+
under any plain `ThemeProvider` (texts simply fall back to the package defaults).
|
|
24
|
+
|
|
25
|
+
## Available texts (namespaces)
|
|
26
|
+
|
|
27
|
+
The `texts` shape is extensible — add new namespaces over time. Currently:
|
|
28
|
+
|
|
29
|
+
| Namespace | Used by | Keys |
|
|
30
|
+
| --------- | ------- | ---- |
|
|
31
|
+
| `texts.geometry` | geometry picker (`MapGeometryPicker`) and grid edit/thumb cells (`GeoEditCell`) | `labelPoint`, `labelOther`, `malformed`, `synced`, `edit`, `define`, `drawSelectTitle`, `close` |
|
|
32
|
+
| `texts.forms` | form action buttons (`FormActions`, `DialogFormBySchema`) and dialogs (`DialogActions`) | `save`, `saveAndContinue`, `saveAndCreateNew`, `cancel`, `remove`, `dialogCancel`, `dialogSave` |
|
|
33
|
+
| `texts.richText` | rich-text toolbar (`RichTextEditorInput`) and link dialog | `paragraph`, `heading1`–`heading3`, `bold`, `italic`, `underline`, `strike`, `bulletList`, `orderedList`, `blockquote`, `codeBlock`, `horizontalRule`, `link`, `linkTitle`, `linkUrl`, `linkApply`, `linkRemove`, `linkCancel`, `clearFormatting`, `undo`, `redo` |
|
|
34
|
+
|
|
35
|
+
## Setting texts in your app
|
|
36
|
+
|
|
37
|
+
Add a `texts` key to the `theme` you pass to `DRFReactBySchemaProvider` (or to your own
|
|
38
|
+
`ThemeProvider`). The provider deepmerges it, so you can provide only the keys you want
|
|
39
|
+
to change.
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
// theme.ts
|
|
43
|
+
import { createTheme } from '@mui/material/styles'
|
|
44
|
+
|
|
45
|
+
export const theme = createTheme({
|
|
46
|
+
// ...palette, typography, etc.
|
|
47
|
+
texts: {
|
|
48
|
+
geometry: {
|
|
49
|
+
labelPoint: 'Coordenadas (GeoJSON)',
|
|
50
|
+
labelOther: 'GeoJSON (cole aqui)',
|
|
51
|
+
malformed: 'Dados malformados, corrija o GeoJSON para refletir no mapa.',
|
|
52
|
+
synced: 'O GeoJSON abaixo é sincronizado com o mapa.',
|
|
53
|
+
edit: 'Editar geometria',
|
|
54
|
+
define: 'Definir geometria',
|
|
55
|
+
drawSelectTitle: 'Desenhar / selecionar geometria',
|
|
56
|
+
close: 'Fechar',
|
|
57
|
+
},
|
|
58
|
+
forms: {
|
|
59
|
+
save: 'Salvar',
|
|
60
|
+
saveAndContinue: 'Salvar e continuar',
|
|
61
|
+
saveAndCreateNew: 'Salvar e criar novo',
|
|
62
|
+
cancel: 'Cancelar',
|
|
63
|
+
remove: 'Apagar',
|
|
64
|
+
dialogCancel: 'Cancelar',
|
|
65
|
+
dialogSave: 'Salvar',
|
|
66
|
+
},
|
|
67
|
+
richText: {
|
|
68
|
+
paragraph: 'Parágrafo',
|
|
69
|
+
heading1: 'Título 1',
|
|
70
|
+
heading2: 'Título 2',
|
|
71
|
+
heading3: 'Título 3',
|
|
72
|
+
bold: 'Negrito',
|
|
73
|
+
italic: 'Itálico',
|
|
74
|
+
underline: 'Sublinhado',
|
|
75
|
+
strike: 'Riscado',
|
|
76
|
+
bulletList: 'Lista com marcadores',
|
|
77
|
+
orderedList: 'Lista numerada',
|
|
78
|
+
blockquote: 'Citação',
|
|
79
|
+
codeBlock: 'Bloco de código',
|
|
80
|
+
horizontalRule: 'Linha horizontal',
|
|
81
|
+
link: 'Link',
|
|
82
|
+
linkTitle: 'Inserir link',
|
|
83
|
+
linkUrl: 'URL',
|
|
84
|
+
linkApply: 'Aplicar',
|
|
85
|
+
linkRemove: 'Remover link',
|
|
86
|
+
linkCancel: 'Cancelar',
|
|
87
|
+
clearFormatting: 'Limpar formatação',
|
|
88
|
+
undo: 'Desfazer',
|
|
89
|
+
redo: 'Refazer',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
// App.js
|
|
95
|
+
import { DRFReactBySchemaProvider } from 'drf-react-by-schema'
|
|
96
|
+
import { theme } from './theme'
|
|
97
|
+
|
|
98
|
+
<DRFReactBySchemaProvider serverEndPoint={...} schema={...} theme={theme}>
|
|
99
|
+
<YourWonderfulApp />
|
|
100
|
+
</DRFReactBySchemaProvider>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
TypeScript picks up the `texts` keys automatically from the theme augmentation; you can
|
|
104
|
+
also import and reuse the text types (`DRFReactBySchemaTexts`, `GeometryTexts`,
|
|
105
|
+
`FormTexts`) from `drf-react-by-schema` for reference.
|
|
106
|
+
|
|
107
|
+
## Precedence
|
|
108
|
+
|
|
109
|
+
Strings resolve in this order, so the most specific wins:
|
|
110
|
+
|
|
111
|
+
1. **Explicit component prop** — e.g. `FormActions` has `labelSave`/`labelCancel`/
|
|
112
|
+
`labelRemove`/`labelSaveAndContinue`/`labelSaveAndCreateNew`; `DialogActions` has
|
|
113
|
+
`btnCancel`/`btnConfirm`; `MapGeometryPicker` has `label`/`helperText`.
|
|
114
|
+
2. **`theme.texts.<namespace>`** — set app-wide in your theme.
|
|
115
|
+
3. **Package `DEFAULT_TEXTS`** — the built-in fallback.
|
|
116
|
+
|
|
117
|
+
Since the explicit props still exist, both strategies can coexist: pass per-component
|
|
118
|
+
strings for a one-off button, or set theme texts for whole-app localization.
|
|
119
|
+
|
|
120
|
+
## MUI component localization
|
|
121
|
+
|
|
122
|
+
The package's default theme already localizes the MUI components it renders to
|
|
123
|
+
**pt-BR** by composing MUI's official locale packages:
|
|
124
|
+
|
|
125
|
+
- `@mui/material/locale` (core components)
|
|
126
|
+
- `@mui/x-data-grid/locales` (DataGrid), plus DataGrid `localeText` overrides for the
|
|
127
|
+
package's custom toolbar strings (`Buscar...`, `Limpar busca`, …)
|
|
128
|
+
- `@mui/x-date-pickers/locales` (date pickers)
|
|
129
|
+
|
|
130
|
+
Date/time inputs additionally wrap each field in
|
|
131
|
+
`<LocalizationProvider adapterLocale="pt-br">`. To switch to another language, set the
|
|
132
|
+
corresponding MUI locale + DataGrid `localeText` in your theme and the desired
|
|
133
|
+
`adapterLocale` on the picker inputs.
|
|
134
|
+
|
|
135
|
+
## Markers (geometry)
|
|
136
|
+
|
|
137
|
+
By default the geometry widgets render points with a **built-in inline-SVG marker
|
|
138
|
+
icon** (a data-URI), so markers appear out of the box under any bundler — Leaflet's
|
|
139
|
+
stock page-relative PNGs 404 inside an SPA. To use a custom marker, call the imperative
|
|
140
|
+
helper once at app startup (it always applies/overrides):
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import { applyDefaultLeafletIcon } from 'drf-react-by-schema'
|
|
144
|
+
|
|
145
|
+
applyDefaultLeafletIcon({
|
|
146
|
+
iconUrl: '/assets/my-marker.png',
|
|
147
|
+
iconSize: [30, 42],
|
|
148
|
+
iconAnchor: [15, 42],
|
|
149
|
+
})
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
If you don't call it, the package's widgets apply the built-in default the first time it
|
|
153
|
+
is needed (and never override an icon you already placed on `L.Icon.Default`). Because
|
|
154
|
+
the application is one-shot, call it before rendering your maps; subsequent calls without
|
|
155
|
+
arguments are no-ops.
|
|
156
|
+
|
|
157
|
+
## Reading texts in custom components
|
|
158
|
+
|
|
159
|
+
If you build custom widgets that should share the same themed strings, use the exported
|
|
160
|
+
`getThemeTexts(theme)` helper (returns theme texts merged over the package defaults):
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
import { useTheme } from '@mui/material/styles'
|
|
164
|
+
import { getThemeTexts } from 'drf-react-by-schema'
|
|
165
|
+
|
|
166
|
+
function MyActions() {
|
|
167
|
+
const formTexts = getThemeTexts(useTheme()).forms
|
|
168
|
+
return <button>{formTexts.save}</button>
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The text types (`DRFReactBySchemaTexts`, `GeometryTexts`, `FormTexts`) are exported from
|
|
173
|
+
`drf-react-by-schema` too, so you can type helper objects separately.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Password reset, change password & e-mail setup
|
|
2
|
+
|
|
3
|
+
End-to-end guide for the **forgot-password / change-password** flow on a
|
|
4
|
+
Django + DRF + simplejwt backend with this React package.
|
|
5
|
+
|
|
6
|
+
The **React** side ships:
|
|
7
|
+
|
|
8
|
+
- `ForgotPasswordForm` — works in two modes:
|
|
9
|
+
- *request*: asks for the e-mail and calls `requestPasswordReset`.
|
|
10
|
+
- *confirm*: given `uid` + `token` (from the e-mail link), sets a new password
|
|
11
|
+
via `confirmPasswordReset`.
|
|
12
|
+
- `ChangePasswordForm` — for an already signed-in user (current password + new
|
|
13
|
+
password), backed by `changePassword`.
|
|
14
|
+
- `useAPIWrapper()` exposes: `requestPasswordReset(email)`,
|
|
15
|
+
`validatePasswordReset({ uid, token })`,
|
|
16
|
+
`confirmPasswordReset({ uid, token, new_password })`, `changePassword({ old_password, new_password })`.
|
|
17
|
+
`validatePasswordReset` resolves the account behind a reset link (name +
|
|
18
|
+
`has_usable_password`) without changing anything, so the page can greet the user
|
|
19
|
+
by name and tell a first-time invite (no usable password yet) from a reset.
|
|
20
|
+
|
|
21
|
+
Everything is mobile-friendly (the forms use `fullWidth` fields) and lives under
|
|
22
|
+
`DRFReactBySchemaProvider`, so the helpers are typed through `useAPIWrapper()`.
|
|
23
|
+
|
|
24
|
+
## 1. Server contract (provided by drf-react-by-schema-django)
|
|
25
|
+
|
|
26
|
+
The Django package exposes these endpoints (auto-registered):
|
|
27
|
+
|
|
28
|
+
| Method | Endpoint | Auth | Body |
|
|
29
|
+
|---|---|---|---|
|
|
30
|
+
| POST | `password_reset/request/` | none | `{ email }` |
|
|
31
|
+
| POST | `password_reset/validate/` | none | `{ uid, token }` |
|
|
32
|
+
| POST | `password_reset/confirm/` | none | `{ uid, token, new_password }` |
|
|
33
|
+
| POST | `my_account/change_password/` | JWT | `{ old_password, new_password }` |
|
|
34
|
+
|
|
35
|
+
It reuses `django.contrib.auth` for token generation and password hashing, so no
|
|
36
|
+
extra package (allauth / dj-rest-auth) is required. See the Django package README
|
|
37
|
+
for the full details of the pluggable delivery callback.
|
|
38
|
+
|
|
39
|
+
## 2. Frontend wiring (no extra config needed)
|
|
40
|
+
|
|
41
|
+
`DRFReactBySchemaProvider` derives `requestPasswordReset`, `validatePasswordReset`,
|
|
42
|
+
`confirmPasswordReset` and `changePassword` from your `serverEndPoint` automatically
|
|
43
|
+
(`{api}/password_reset/…`, `{api}/my_account/change_password/`). You only need the
|
|
44
|
+
usual `url`/`apiTokenUrl`, e.g.:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
const serverEndPoint = {
|
|
48
|
+
url: 'http://localhost:8000',
|
|
49
|
+
apiTokenUrl: 'http://localhost:8000/api/token/',
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Example — a public reset page reached both from the login screen and from the
|
|
54
|
+
e-mail link (`/esqueci-senha?uid=..&token=..`):
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { ForgotPasswordForm } from 'drf-react-by-schema'
|
|
58
|
+
|
|
59
|
+
function ForgotPasswordPage() {
|
|
60
|
+
const [params] = useSearchParams()
|
|
61
|
+
const navigate = useNavigate()
|
|
62
|
+
const uid = params.get('uid') ?? undefined
|
|
63
|
+
const token = params.get('token') ?? undefined
|
|
64
|
+
return (
|
|
65
|
+
<ForgotPasswordForm
|
|
66
|
+
uid={uid} // present -> confirm mode
|
|
67
|
+
token={token}
|
|
68
|
+
onBack={() => navigate('/')}
|
|
69
|
+
onSuccess={() => navigate('/')}
|
|
70
|
+
/>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
An authenticated "change my password" screen:
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
import { ChangePasswordForm } from 'drf-react-by-schema'
|
|
79
|
+
// <ChangePasswordForm onSuccess={() => signOut()} />
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 3. Delivering the e-mail (the "e-mail infrastructure")
|
|
83
|
+
|
|
84
|
+
Sending is handled by the **backend** — the React app only composes the reset
|
|
85
|
+
link `{scheme}://{host}\{path}?uid=..&token=..`. Two levels of configuration:
|
|
86
|
+
|
|
87
|
+
**Simple (no code):** configure Django e-mail settings and the reset link path;
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
# settings.py / settings_local.py
|
|
91
|
+
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" # or console in dev
|
|
92
|
+
EMAIL_HOST = "smtp.your-provider.com"
|
|
93
|
+
EMAIL_PORT = 587
|
|
94
|
+
EMAIL_USE_TLS = True
|
|
95
|
+
EMAIL_HOST_USER = "no-reply@your-domain"
|
|
96
|
+
EMAIL_HOST_PASSWORD = "…"
|
|
97
|
+
DEFAULT_FROM_EMAIL = "Your App <no-reply@your-domain>"
|
|
98
|
+
|
|
99
|
+
PASSWORD_RESET_SCHEME = "https"
|
|
100
|
+
PASSWORD_RESET_DOMAIN = "app.your-domain" # avoids trusting request scheme behind a proxy
|
|
101
|
+
PASSWORD_RESET_CONFIRM_PATH = "/esqueci-senha" # your page
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
With that, `drf-react-by-schema-django` sends a plain-text message via Django's
|
|
105
|
+
mail backend.
|
|
106
|
+
|
|
107
|
+
**Customised (still small):** point `DRF_REACT_BY_SCHEMA['PASSWORD_RESET_CALLBACK']`
|
|
108
|
+
at a callable `(request, user, uid, token)`. The library already mints
|
|
109
|
+
`uid`/`token` before invoking it, so the change is a single function (branding,
|
|
110
|
+
HTML, another channel, queueing…):
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
# myapp/auth.py
|
|
114
|
+
def send_reset_email(request, user, uid, token):
|
|
115
|
+
send_mail("Redefina sua senha", f"Link: https://app.suaorg.org/esqueci-senha?uid={uid}&token={token}", None, [user.email])
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
DRF_REACT_BY_SCHEMA = { ...
|
|
120
|
+
"PASSWORD_RESET_CALLBACK": "myapp.auth.send_reset_email",
|
|
121
|
+
"PASSWORD_RESET_CONFIRM_PATH": "/esqueci-senha",
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Dev vs prod
|
|
126
|
+
|
|
127
|
+
- **Dev**: `EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"` prints
|
|
128
|
+
the message to the terminal — great to test the flow without real SMTP.
|
|
129
|
+
- **Prod (Ubuntu/VPS)**: point `EMAIL_BACKEND` to a real SMTP host (transactional
|
|
130
|
+
provider recommended), set `EMAIL_*`, fix `PASSWORD_RESET_DOMAIN`/`SCHEME` and
|
|
131
|
+
list the domain in `ALLOWED_HOSTS`. Keep real credentials out of the repo
|
|
132
|
+
(e.g. in a gitignored `settings_local.py` + a gitignored server guide).
|
|
133
|
+
|
|
134
|
+
## 4. Real-world flow
|
|
135
|
+
|
|
136
|
+
1. User taps "Esqueci minha senha" on the login → goes to the public page.
|
|
137
|
+
2. Page calls `requestPasswordReset(email)` → backend mints `uid`/`token` and
|
|
138
|
+
fires the callback → e-mail with the link.
|
|
139
|
+
3. User opens the link (`…?uid=..&token=..`) → the same page is in *confirm* mode
|
|
140
|
+
→ `confirmPasswordReset({ uid, token, new_password })` sets the password.
|
|
141
|
+
4. (Optional) sign-in and use `ChangePasswordForm` → `changePassword(...)`.
|
|
142
|
+
|
|
143
|
+
Inviting a new user works the same way: create the account with an **unusable
|
|
144
|
+
password** on the backend and fire `requestPasswordReset(email)` so the invited
|
|
145
|
+
person receives a link to set their own password.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drf-react-by-schema",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.28",
|
|
4
4
|
"description": "Components and Tools for building a React App having Django Rest Framework (DRF) as server",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -132,6 +132,7 @@
|
|
|
132
132
|
"not dead"
|
|
133
133
|
],
|
|
134
134
|
"files": [
|
|
135
|
-
"dist"
|
|
135
|
+
"dist",
|
|
136
|
+
"docs"
|
|
136
137
|
]
|
|
137
138
|
}
|