identity-admin 1.28.28 → 1.28.30
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 +148 -148
- package/lib/Dashboard.d.ts +14 -14
- package/lib/Dashboard.js +95 -95
- package/lib/container/helpers/HelperInversify.d.ts +6 -6
- package/lib/container/helpers/HelperInversify.js +10 -10
- package/lib/container/helpers/HelperTypes.d.ts +5 -5
- package/lib/container/helpers/HelperTypes.js +7 -7
- package/lib/container/index.d.ts +1 -1
- package/lib/container/index.js +14 -14
- package/lib/container/repositories/RepositoryInversify.d.ts +4 -4
- package/lib/container/repositories/RepositoryInversify.js +13 -13
- package/lib/container/repositories/RepositoryTypes.d.ts +4 -4
- package/lib/container/repositories/RepositoryTypes.js +6 -6
- package/lib/container/types.d.ts +8 -8
- package/lib/container/types.js +9 -9
- package/lib/controllers/ActionController.d.ts +9 -9
- package/lib/controllers/ActionController.js +141 -141
- package/lib/controllers/AdminNotificationController.d.ts +8 -8
- package/lib/controllers/AdminNotificationController.js +69 -69
- package/lib/controllers/DashboardController.d.ts +45 -45
- package/lib/controllers/DashboardController.js +827 -827
- package/lib/controllers/PermissionController.d.ts +6 -6
- package/lib/controllers/PermissionController.js +52 -52
- package/lib/controllers/ResourceController.d.ts +15 -15
- package/lib/controllers/ResourceController.js +128 -128
- package/lib/helpers/ActionsGenerator.d.ts +11 -11
- package/lib/helpers/ActionsGenerator.js +168 -168
- package/lib/helpers/AdminNotifications/AdminNotificationCreation.d.ts +54 -54
- package/lib/helpers/AdminNotifications/AdminNotificationCreation.js +66 -66
- package/lib/helpers/AdminNotifications/AdminNotificationFetcher.d.ts +63 -63
- package/lib/helpers/AdminNotifications/AdminNotificationFetcher.js +45 -45
- package/lib/helpers/FilterQueryHelper.d.ts +9 -9
- package/lib/helpers/FilterQueryHelper.js +83 -83
- package/lib/helpers/FiltersHelper.d.ts +9 -9
- package/lib/helpers/FiltersHelper.js +126 -126
- package/lib/helpers/JsonRichText/DraftRawToUniversalConverter.d.ts +3 -3
- package/lib/helpers/JsonRichText/DraftRawToUniversalConverter.js +144 -144
- package/lib/helpers/JsonRichText/IDraftRawType.d.ts +18 -18
- package/lib/helpers/JsonRichText/IDraftRawType.js +2 -2
- package/lib/helpers/JsonRichText/IUniversalJsonType.d.ts +24 -24
- package/lib/helpers/JsonRichText/IUniversalJsonType.js +10 -10
- package/lib/helpers/LocalesHelper.d.ts +4 -4
- package/lib/helpers/LocalesHelper.js +73 -73
- package/lib/helpers/LocalizedStringHelper.d.ts +11 -11
- package/lib/helpers/LocalizedStringHelper.js +76 -76
- package/lib/helpers/Permissions/PermissionFetcher.d.ts +8 -8
- package/lib/helpers/Permissions/PermissionFetcher.js +95 -95
- package/lib/helpers/Permissions/PermissionLabel.d.ts +2 -2
- package/lib/helpers/Permissions/PermissionLabel.js +42 -42
- package/lib/helpers/Permissions/PermissionMapper.d.ts +13 -13
- package/lib/helpers/Permissions/PermissionMapper.js +35 -35
- package/lib/helpers/Permissions/PermissionResource.d.ts +6 -6
- package/lib/helpers/Permissions/PermissionResource.js +62 -62
- package/lib/helpers/Permissions/PermissionSavingService.d.ts +13 -13
- package/lib/helpers/Permissions/PermissionSavingService.js +32 -32
- package/lib/helpers/Permissions/SavePermissionGroup.d.ts +6 -6
- package/lib/helpers/Permissions/SavePermissionGroup.js +32 -32
- package/lib/helpers/Permissions/UpdatePermissionGroup.d.ts +6 -6
- package/lib/helpers/Permissions/UpdatePermissionGroup.js +50 -50
- package/lib/helpers/Permissions/types.d.ts +17 -17
- package/lib/helpers/Permissions/types.js +2 -2
- package/lib/helpers/PopulationHelper.d.ts +12 -12
- package/lib/helpers/PopulationHelper.js +50 -50
- package/lib/helpers/RecordsCounter.d.ts +10 -10
- package/lib/helpers/RecordsCounter.js +33 -33
- package/lib/helpers/ReportsGenerator.d.ts +26 -26
- package/lib/helpers/ReportsGenerator.js +163 -162
- package/lib/helpers/ResourceGenerator.d.ts +9 -9
- package/lib/helpers/ResourceGenerator.js +172 -172
- package/lib/helpers/ResourceHelper.d.ts +28 -28
- package/lib/helpers/ResourceHelper.js +397 -397
- package/lib/helpers/RportsGenerator.d.ts +10 -10
- package/lib/helpers/RportsGenerator.js +21 -21
- package/lib/helpers/SchemaGenerator.d.ts +7 -7
- package/lib/helpers/SchemaGenerator.js +137 -137
- package/lib/helpers/SchemaHelper.d.ts +5 -5
- package/lib/helpers/SchemaHelper.js +21 -21
- package/lib/helpers/UserActionsLog/UserActionsLogHelper.d.ts +2 -2
- package/lib/helpers/UserActionsLog/UserActionsLogHelper.js +49 -49
- package/lib/locales/en.json +54 -54
- package/lib/middlewares/cache/decorator.d.ts +3 -3
- package/lib/middlewares/cache/decorator.js +60 -60
- package/lib/middlewares/cache/deletionMethods.d.ts +3 -3
- package/lib/middlewares/cache/deletionMethods.js +23 -23
- package/lib/middlewares/isAuth.d.ts +13 -13
- package/lib/middlewares/isAuth.js +43 -43
- package/lib/models/ModelNames.d.ts +10 -10
- package/lib/models/ModelNames.js +13 -13
- package/lib/models/adminNotification/AdminNotification.d.ts +5 -5
- package/lib/models/adminNotification/AdminNotification.js +70 -70
- package/lib/models/adminNotification/IAdminNotification.d.ts +35 -35
- package/lib/models/adminNotification/IAdminNotification.js +15 -15
- package/lib/models/adminpermission/AdminPermission.d.ts +6 -6
- package/lib/models/adminpermission/AdminPermission.js +27 -27
- package/lib/models/adminpermission/IAdminPermission.d.ts +13 -13
- package/lib/models/adminpermission/IAdminPermission.js +2 -2
- package/lib/models/customPage/CustomPage.d.ts +2 -2
- package/lib/models/customPage/CustomPage.js +38 -38
- package/lib/models/customPage/ICustomPage.d.ts +17 -17
- package/lib/models/customPage/ICustomPage.js +2 -2
- package/lib/models/file/File.d.ts +2 -2
- package/lib/models/file/File.js +23 -23
- package/lib/models/file/IFile.d.ts +15 -15
- package/lib/models/file/IFile.js +2 -2
- package/lib/models/language/ILanguage.d.ts +8 -8
- package/lib/models/language/ILanguage.js +8 -8
- package/lib/models/language/LanguageSchema.d.ts +9 -9
- package/lib/models/language/LanguageSchema.js +17 -17
- package/lib/models/location/ILocation.d.ts +16 -16
- package/lib/models/location/ILocation.js +2 -2
- package/lib/models/location/Location.d.ts +2 -2
- package/lib/models/location/Location.js +29 -29
- package/lib/models/mailLog/IMailLog.d.ts +14 -14
- package/lib/models/mailLog/IMailLog.js +2 -2
- package/lib/models/mailLog/MailLog.d.ts +3 -3
- package/lib/models/mailLog/MailLog.js +23 -23
- package/lib/models/modelConfiguration/IModelConfigurations.d.ts +31 -31
- package/lib/models/modelConfiguration/IModelConfigurations.js +2 -2
- package/lib/models/modelConfiguration/ModelConfiguration.d.ts +13 -13
- package/lib/models/modelConfiguration/ModelConfiguration.js +103 -103
- package/lib/models/permission/IPermission.d.ts +14 -14
- package/lib/models/permission/IPermission.js +2 -2
- package/lib/models/permission/Permission.d.ts +6 -6
- package/lib/models/permission/Permission.js +28 -28
- package/lib/models/permissiongroup/IPermissionGroup.d.ts +15 -15
- package/lib/models/permissiongroup/IPermissionGroup.js +2 -2
- package/lib/models/permissiongroup/PermissionGroup.d.ts +6 -6
- package/lib/models/permissiongroup/PermissionGroup.js +23 -23
- package/lib/models/request-log/IRequestLog.d.ts +22 -22
- package/lib/models/request-log/IRequestLog.js +2 -2
- package/lib/models/request-log/RequestLog.d.ts +3 -3
- package/lib/models/request-log/RequestLog.js +51 -51
- package/lib/models/userActionsLog/IUserActionsLog.d.ts +26 -26
- package/lib/models/userActionsLog/IUserActionsLog.js +11 -11
- package/lib/models/userActionsLog/UserActionsLog.d.ts +3 -3
- package/lib/models/userActionsLog/UserActionsLog.js +41 -41
- package/lib/pdf/ReportTemplate.d.ts +71 -71
- package/lib/pdf/ReportTemplate.js +94 -94
- package/lib/repositories/AdminNotificationRepository.d.ts +7 -7
- package/lib/repositories/AdminNotificationRepository.js +23 -23
- package/lib/repositories/AdminPermissionRepository.d.ts +7 -7
- package/lib/repositories/AdminPermissionRepository.js +23 -23
- package/lib/repositories/DashboardRepository.d.ts +5 -5
- package/lib/repositories/DashboardRepository.js +12 -12
- package/lib/repositories/PermissionGroupRepository.d.ts +7 -7
- package/lib/repositories/PermissionGroupRepository.js +23 -23
- package/lib/repositories/PermissionRepository.d.ts +7 -7
- package/lib/repositories/PermissionRepository.js +23 -23
- package/lib/repositories/Repository.d.ts +68 -68
- package/lib/repositories/Repository.js +215 -215
- package/lib/repositories/RequestLogRepository.d.ts +10 -10
- package/lib/repositories/RequestLogRepository.js +54 -54
- package/lib/repositories/SaveResult.d.ts +14 -14
- package/lib/repositories/SaveResult.js +18 -18
- package/lib/resources/AdminNotificationsResource.d.ts +3 -3
- package/lib/resources/AdminNotificationsResource.js +23 -23
- package/lib/resources/AdminPermissionResource.d.ts +5 -5
- package/lib/resources/AdminPermissionResource.js +36 -36
- package/lib/resources/PermissionGroupResource.d.ts +5 -5
- package/lib/resources/PermissionGroupResource.js +60 -60
- package/lib/resources/PermissionsResource.d.ts +5 -5
- package/lib/resources/PermissionsResource.js +23 -23
- package/lib/resources/parents.d.ts +12 -12
- package/lib/resources/parents.js +15 -15
- package/lib/router/index.d.ts +8 -8
- package/lib/router/index.js +104 -104
- package/lib/seeds/PermissionSeeder.d.ts +4 -4
- package/lib/seeds/PermissionSeeder.js +56 -56
- package/lib/types/DashbordConfig.d.ts +21 -21
- package/lib/types/DashbordConfig.js +2 -2
- package/lib/types/IConfigurationFile.d.ts +14 -14
- package/lib/types/IConfigurationFile.js +2 -2
- package/lib/types/IResourceFile.d.ts +738 -736
- package/lib/types/IResourceFile.js +2 -2
- package/lib/types/IResourceResponse.d.ts +96 -96
- package/lib/types/IResourceResponse.js +2 -2
- package/lib/types/helpers.d.ts +72 -71
- package/lib/types/helpers.js +84 -83
- package/lib/utils/DateUtils.d.ts +7 -7
- package/lib/utils/DateUtils.js +45 -45
- package/lib/utils/ResourceUtils.d.ts +2 -2
- package/lib/utils/ResourceUtils.js +7 -7
- package/lib/utils/ResponseUtils.d.ts +11 -11
- package/lib/utils/ResponseUtils.js +41 -41
- package/lib/utils/StringUtils.d.ts +9 -9
- package/lib/utils/StringUtils.js +46 -46
- package/lib/view/asset-manifest.json +18 -18
- package/lib/view/assets/icons/delete_icon.svg +3 -3
- package/lib/view/assets/icons/flags/ic_flag_cn.svg +9 -9
- package/lib/view/assets/icons/flags/ic_flag_sa.svg +9 -9
- package/lib/view/assets/icons/flags/ic_flag_vn.svg +9 -9
- package/lib/view/assets/icons/info_icon.svg +3 -3
- package/lib/view/assets/icons/navbar/ic_banking.svg +5 -5
- package/lib/view/assets/icons/navbar/ic_invoice.svg +4 -4
- package/lib/view/assets/icons/navbar/ic_kanban.svg +7 -7
- package/lib/view/assets/icons/navbar/ic_menu_item.svg +8 -8
- package/lib/view/assets/icons/small_info_icon.svg +3 -3
- package/lib/view/assets/illustrations/Group 16.svg +4 -4
- package/lib/view/assets/illustrations/logo.svg +5 -5
- package/lib/view/favicon/browserconfig.xml +9 -9
- package/lib/view/favicon/safari-pinned-tab.svg +182 -182
- package/lib/view/favicon/site.webmanifest +19 -19
- package/lib/view/fonts/index.css +18 -18
- package/lib/view/index.html +52 -52
- package/lib/view/manifest.json +20 -20
- package/lib/view/robots.txt +3 -3
- package/lib/view/static/css/main.54de06ef.css +1 -1
- package/lib/view/static/js/574.778b5963.chunk.js +1 -1
- package/lib/view/static/js/678.521704a3.chunk.js +1 -1
- package/lib/view/static/js/798.54856416.chunk.js +1 -1
- package/lib/view/static/js/main.4687f255.js +2 -2
- package/lib/view/static/js/main.4687f255.js.LICENSE.txt +214 -214
- package/package.json +65 -64
- package/skills/identity-admin/SKILL.md +272 -0
- package/skills/identity-admin/resource-file.md +654 -0
|
@@ -0,0 +1,654 @@
|
|
|
1
|
+
# Resource File Reference (`IResourceFile`)
|
|
2
|
+
|
|
3
|
+
This is the companion reference for the **identity-admin** skill. It documents every property of the `IResourceFile` interface that defines how a Mongoose model appears and behaves in the admin dashboard.
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
export interface IResourceFile {
|
|
7
|
+
properties: { /* see below */ };
|
|
8
|
+
listProperties?: string[];
|
|
9
|
+
showProperties?: string[];
|
|
10
|
+
formProperties?: string[];
|
|
11
|
+
filterProperties?: string[];
|
|
12
|
+
quickFilterProperties?: string[];
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Required Properties
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
properties: {
|
|
22
|
+
resource: Model<any, any>; // the compiled Mongoose model
|
|
23
|
+
modelName: string; // database collection name
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- `resource` — The Mongoose model instance (e.g., `User` from `mongoose.model('User', schema)`)
|
|
28
|
+
- `modelName` — The collection name in MongoDB (e.g., `'users'`). Used for API route generation and permission lookups.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Identity & Display
|
|
33
|
+
|
|
34
|
+
| Property | Type | Default | Description |
|
|
35
|
+
|----------|------|---------|-------------|
|
|
36
|
+
| `properties.name` | `string` | `modelName` | Display name in nav bar, page titles, and breadcrumbs |
|
|
37
|
+
| `properties.title` | `string` | Auto-detected | Field used as the clickable record link. Auto-detects `name`, `title`, or `email` on the schema; falls back to `_id`. Also used as the search bar target. |
|
|
38
|
+
| `properties.defaultOrderBy` | `string` | Schema title field | Sort field for the list view |
|
|
39
|
+
| `properties.defaultOrder` | `'asc' \| 'desc'` | `'asc'` | Sort direction |
|
|
40
|
+
| `properties.defaultrowsPerPage` | `number` | `10` | Default pagination size |
|
|
41
|
+
|
|
42
|
+
## Navigation
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
properties: {
|
|
46
|
+
parent?: {
|
|
47
|
+
name: string; // nav group label (e.g., "Content", "Users")
|
|
48
|
+
icon: string; // MUI icon name (e.g., "People", "Settings")
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Resources with the same `parent.name` are grouped under one nav section. Icons come from [Material UI icons](https://mui.com/material-ui/material-icons/).
|
|
54
|
+
|
|
55
|
+
## Visibility & Access Control
|
|
56
|
+
|
|
57
|
+
| Property | Type | Default | Description |
|
|
58
|
+
|----------|------|---------|-------------|
|
|
59
|
+
| `properties.isAllowed` | `(currentUser) => Promise<boolean>` | `true` | Whether the user can access this resource at all |
|
|
60
|
+
| `properties.isVisible` | `(currentUser) => Promise<boolean>` | `true` | Whether the resource appears in the nav bar |
|
|
61
|
+
| `properties.enableLog` | `(currentUser) => Promise<boolean>` | `false` | Whether to log changes to this resource |
|
|
62
|
+
| `properties.hiddenProperties` | `string[]` | `[]` | Fields completely hidden from all pages |
|
|
63
|
+
|
|
64
|
+
## Display Property Arrays
|
|
65
|
+
|
|
66
|
+
Control exactly which fields appear on each view:
|
|
67
|
+
|
|
68
|
+
| Array | Purpose |
|
|
69
|
+
|-------|---------|
|
|
70
|
+
| `listProperties` | Table columns in the list/index view. Shows first 4 by default. |
|
|
71
|
+
| `showProperties` | Read-only fields in the detail view |
|
|
72
|
+
| `formProperties` | Editable fields in create/edit forms |
|
|
73
|
+
| `filterProperties` | Fields available in the advanced filter panel |
|
|
74
|
+
| `quickFilterProperties` | Fields shown as quick filter chips above the table |
|
|
75
|
+
|
|
76
|
+
If not specified, **all schema fields** (`list/show/form/filter`) or **none** (`quickFilter`) are shown.
|
|
77
|
+
|
|
78
|
+
## Field Overrides (`properties.model`)
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
properties: {
|
|
82
|
+
model?: { [fieldName: string]: IFieldValue } | IModel;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Override any schema field's behavior, or add virtual fields. Each key is a field name from the Mongoose schema.
|
|
87
|
+
|
|
88
|
+
### `IFieldValue` Reference
|
|
89
|
+
|
|
90
|
+
| Property | Type | Default | Description |
|
|
91
|
+
|----------|------|---------|-------------|
|
|
92
|
+
| `type` | `FieldTypes` | Same as schema | Override the field type. See enums below. |
|
|
93
|
+
| `required` | `boolean` | Same as schema | Override whether the field is required in forms |
|
|
94
|
+
| `isEditable` | `boolean` | `true` | Whether the field can be edited |
|
|
95
|
+
| `enumValues` | `string[] \| { [key]: { label, color?, labelColor? } }` | Same as schema | Custom enum labels and chip colors |
|
|
96
|
+
| `countryCodes` | `string[]` | — | Allowed country codes for phone number fields (e.g., `['sa', 'eg']`) |
|
|
97
|
+
| `defaultCountryCode` | `string` | First country or `'sa'` | Default selected country for phone fields |
|
|
98
|
+
| `mediaUploader` | `boolean` | — | Enable media upload for reference fields pointing to the Image collection |
|
|
99
|
+
| `fileType` | `FileTypes` | `'IMAGE'` | Restrict media uploader to specific file types |
|
|
100
|
+
| `imageOptimizingCategory` | `ImageOptimizingCategories` | `'NORMAL'` | Image compression level (`'NORMAL'` or `'BANNERS'`) |
|
|
101
|
+
| `disableImageOptimization` | `boolean` | `false` | Skip image optimization |
|
|
102
|
+
| `imageBackgroundHexColor` | `string` | — | Background color for image display |
|
|
103
|
+
| `withTime` | `boolean` | `false` | Show time picker alongside date picker |
|
|
104
|
+
| `apiRoute` | `string` | — | API endpoint for fetching reference options |
|
|
105
|
+
| `valuePath` | `string` | — | Path to the value inside a referenced document |
|
|
106
|
+
| `isClickable` | `boolean` | — | Whether the field value is clickable in the list |
|
|
107
|
+
| `path` | `string` | — | Resource path to navigate to on click |
|
|
108
|
+
| `keys` | `string[]` | — | Keys to show within a nested schema field |
|
|
109
|
+
| `schema` | `IModel \| { [key]: IFieldValue }` | — | Define nested schema structure |
|
|
110
|
+
| `multipleInFilter` | `boolean` | — | Enable multi-value selection for this quick filter |
|
|
111
|
+
| `yupValidationSchema` | `Yup.Schema` | Same as schema | Custom Yup validation |
|
|
112
|
+
| `enableCreateNewButtonOnReference` | `boolean` | `false` | Show "Create New" button inside reference selector |
|
|
113
|
+
| `textArea` | `boolean` | `false` | Render text field as a multi-line textarea |
|
|
114
|
+
| `relatedFields` | `string[]` | — | Show related fields from a referenced document |
|
|
115
|
+
| `minWidth` | `number` | — | Minimum column width in the list view |
|
|
116
|
+
| `filter` | `{ formList?, filterList? }` | — | Filter options for reference selectors (`Record<string, any>`) |
|
|
117
|
+
| `arrayType` | `FieldTypes` | Same as schema | Element type for array fields |
|
|
118
|
+
| `isDraggable` | `boolean` | `true` | Whether array items are reorderable by drag-and-drop |
|
|
119
|
+
|
|
120
|
+
### Virtual Fields (`IModel.virtuals`)
|
|
121
|
+
|
|
122
|
+
Add fields that don't exist in the database but are needed in the UI:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
model?: {
|
|
126
|
+
virtuals?: {
|
|
127
|
+
[virtualName: string]: IVirtualValue;
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### `IVirtualValue` Reference
|
|
133
|
+
|
|
134
|
+
| Property | Type | Description |
|
|
135
|
+
|----------|------|-------------|
|
|
136
|
+
| `type` | `'password' \| 'ref' \| 'Array'` | Virtual field type |
|
|
137
|
+
| `filterBy` | `string` | For `ref` type: the foreign key field for one-to-many relations |
|
|
138
|
+
| `arrayType` | `string` | For `Array` type: the element type |
|
|
139
|
+
| `showIn` | `Virtuals` | Where to display: `'SHOW'`, `'LIST'`, `'FORM'`, or `'FILTER'` |
|
|
140
|
+
| `required` | `boolean` | Whether the virtual is required in forms |
|
|
141
|
+
| `resource` | `Model` | For `ref`/`Array` type: the related Mongoose model |
|
|
142
|
+
| `handler` | `(filterQuery, value) => filterQuery` | Custom filter query logic when used in filters |
|
|
143
|
+
|
|
144
|
+
**Use cases:**
|
|
145
|
+
|
|
146
|
+
- `password` — Add a password field to the creation form without storing it in the model
|
|
147
|
+
- `ref` — Display related child records (e.g., all posts by a user) in the show page
|
|
148
|
+
- `Array` — Display an array of related items
|
|
149
|
+
|
|
150
|
+
## Actions (`properties.actions`)
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
properties: {
|
|
154
|
+
actions?: ActionOptions;
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Control built-in CRUD actions and add custom extra actions:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
interface ActionOptions {
|
|
162
|
+
show?: Action;
|
|
163
|
+
new?: Action;
|
|
164
|
+
edit?: Action;
|
|
165
|
+
delete?: Action;
|
|
166
|
+
import?: Action;
|
|
167
|
+
bulkDelete?: Action;
|
|
168
|
+
duplicate?: Action;
|
|
169
|
+
extras?: ExtraAction[];
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### `Action` Interface (for built-in actions)
|
|
174
|
+
|
|
175
|
+
| Property | Type | Default | Description |
|
|
176
|
+
|----------|------|---------|-------------|
|
|
177
|
+
| `isAccessible` | `boolean` | `true` (except bulkDelete/import: `false`) | Whether the action is available |
|
|
178
|
+
| `reloadAfterAction` | `boolean` | `false` | Reload page after action execution |
|
|
179
|
+
| `isAllowed` | `(currentUser) => boolean` | Same as `isAccessible` | Role-based permission check |
|
|
180
|
+
| `isMainAction` | `boolean` | `true` for show/edit, `false` for others | Whether action appears as a primary button vs. menu item |
|
|
181
|
+
| `isVisible` | `(data: ActionData) => Promise<boolean>` | Same as `isAccessible` | Per-record visibility check |
|
|
182
|
+
|
|
183
|
+
### `ExtraAction` Interface (custom actions)
|
|
184
|
+
|
|
185
|
+
| Property | Type | Default | Description |
|
|
186
|
+
|----------|------|---------|-------------|
|
|
187
|
+
| `key` | `string` | — | Unique identifier within the resource |
|
|
188
|
+
| `name` | `string` | — | Button label |
|
|
189
|
+
| `icon` | `string` | — | MUI icon name |
|
|
190
|
+
| `color` | `string \| ButtonColors` | `'inherit'` (bulk) / `'black'` (record) | Button color |
|
|
191
|
+
| `size` | `ButtonSizes` | `'small'` | Button size (bulk actions only) |
|
|
192
|
+
| `variant` | `ButtonVariants` | `'contained'` | Button variant (bulk actions only) |
|
|
193
|
+
| `actionType` | `'record' \| 'resource'` | — | `'record'` = per-row action, `'resource'` = top-level button |
|
|
194
|
+
| `guardTitle` | `string` | — | Confirmation dialog title |
|
|
195
|
+
| `guard` | `string` | — | Confirmation dialog message |
|
|
196
|
+
| `message` | `string` | `'Action was executed successfully'` | Success alert message |
|
|
197
|
+
| `showAlertMessage` | `boolean` | `true` | Whether to show the success alert |
|
|
198
|
+
| `severity` | `'success' \| 'info' \| 'warning' \| 'error'` | `'success'` | Alert severity/color |
|
|
199
|
+
| `fullScreen` | `boolean` | `false` | Whether the custom component dialog is full screen |
|
|
200
|
+
| `isVisible` | `(data: ActionData) => Promise<boolean>` | Always visible | Per-record visibility |
|
|
201
|
+
| `isMainAction` | `boolean` | `true` for show/edit | Whether it's a primary button vs. menu item |
|
|
202
|
+
| `handler` | `(req, res, data) => Promise<IActionHandlerResponse>` | — | The action logic |
|
|
203
|
+
| `handlerStrategy` | `HandlerStrategy` | — | `'NORMAL'`, `'FILE_DOWNLOAD'`, or `'CUSTOM_COMPONENT'` |
|
|
204
|
+
|
|
205
|
+
### `IActionHandlerResponse`
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
interface IActionHandlerResponse {
|
|
209
|
+
action: ActionNames; // 'SHOW' | 'LIST' | 'NEW' | 'EDIT'
|
|
210
|
+
path: string; // resource.path to redirect to
|
|
211
|
+
recordId?: string; // for SHOW/EDIT redirections
|
|
212
|
+
filePath?: string; // for FILE_DOWNLOAD strategy
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### `ActionData` (passed to `isVisible` and `handler`)
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
interface ActionData {
|
|
220
|
+
record: any; // the document
|
|
221
|
+
currentUser: Document; // authenticated user
|
|
222
|
+
resource: {
|
|
223
|
+
name: string; // modelName
|
|
224
|
+
path: string; // resource route path
|
|
225
|
+
repository: IRepository<Document>; // the repository instance
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Filters (`properties.filters`)
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
properties: {
|
|
234
|
+
filters?: IFilters;
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Scopes
|
|
239
|
+
|
|
240
|
+
Scope filters add tabs above the list view:
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
scopes?: {
|
|
244
|
+
isAccessible: boolean; // default false
|
|
245
|
+
showAll?: boolean; // show "All" tab (default true)
|
|
246
|
+
|
|
247
|
+
// Auto scope — filters by a schema key with predefined values
|
|
248
|
+
auto?: {
|
|
249
|
+
key: string; // schema field name (e.g., 'status')
|
|
250
|
+
options: string[]; // values that become tabs
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// Manual scope — full control with a handler
|
|
254
|
+
manual?: {
|
|
255
|
+
options: string[]; // tab labels
|
|
256
|
+
handler: (filter, scope, currentUser) => Promise<filter>;
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Auto scope example** — creates tabs for each `status` value:
|
|
262
|
+
```typescript
|
|
263
|
+
scopes: { isAccessible: true, auto: { key: 'status', options: ['active', 'inactive', 'pending'] } }
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**Manual scope example** — custom logic per tab:
|
|
267
|
+
```typescript
|
|
268
|
+
scopes: {
|
|
269
|
+
isAccessible: true,
|
|
270
|
+
manual: {
|
|
271
|
+
options: ['Today', 'This Week', 'This Month'],
|
|
272
|
+
handler: async (filter, scope) => {
|
|
273
|
+
const now = new Date();
|
|
274
|
+
switch (scope) {
|
|
275
|
+
case 'Today':
|
|
276
|
+
filter.createdAt = { $gte: new Date(now.setHours(0,0,0,0)) };
|
|
277
|
+
break;
|
|
278
|
+
case 'This Week':
|
|
279
|
+
filter.createdAt = { $gte: new Date(now.setDate(now.getDate() - now.getDay())) };
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
return filter;
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Search Bar
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
searchBar?: {
|
|
292
|
+
isAccessible: boolean; // default true
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## CRUD Operations (`properties.crudOperations`)
|
|
297
|
+
|
|
298
|
+
Intercept any CRUD lifecycle stage. Each hook receives different arguments and must return a specific type — pay close attention to parameter order and return types.
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
properties: {
|
|
302
|
+
crudOperations?: ICrudOperations;
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
### `index` — List view
|
|
309
|
+
|
|
310
|
+
#### `index.before`
|
|
311
|
+
```typescript
|
|
312
|
+
before?: (
|
|
313
|
+
req: IRequest,
|
|
314
|
+
filter: { [key: string]: any },
|
|
315
|
+
currentUser: Document
|
|
316
|
+
) => Promise<{ [key: string]: any }>
|
|
317
|
+
```
|
|
318
|
+
Modify the MongoDB filter object before the query runs. Return the (possibly modified) filter.
|
|
319
|
+
|
|
320
|
+
#### `index.after`
|
|
321
|
+
```typescript
|
|
322
|
+
after?: (
|
|
323
|
+
req: IRequest,
|
|
324
|
+
documents: Document[],
|
|
325
|
+
currentUser: Document
|
|
326
|
+
) => Promise<Document[]>
|
|
327
|
+
```
|
|
328
|
+
Transform the result array after the query completes. Return the modified documents array.
|
|
329
|
+
|
|
330
|
+
#### `index.index` (custom query)
|
|
331
|
+
```typescript
|
|
332
|
+
index?: (
|
|
333
|
+
req: IRequest,
|
|
334
|
+
filter: { [key: string]: any },
|
|
335
|
+
sortQuery: { [key: string]: any },
|
|
336
|
+
paginateParams: PaginateParams | undefined,
|
|
337
|
+
populate: any,
|
|
338
|
+
currentUser: Document
|
|
339
|
+
) => Promise<{ records: Document[]; pageInfo?: PageInfo }>
|
|
340
|
+
```
|
|
341
|
+
Replace the entire list query with custom logic. You receive the raw filter, sort, pagination, and populate params. Return `{ records, pageInfo? }`.
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
### `create` — Create record
|
|
346
|
+
|
|
347
|
+
#### `create.before`
|
|
348
|
+
```typescript
|
|
349
|
+
before?: (
|
|
350
|
+
req: IRequest,
|
|
351
|
+
params: any,
|
|
352
|
+
currentUser: Document
|
|
353
|
+
) => Promise<any>
|
|
354
|
+
```
|
|
355
|
+
Modify the request body params before the document is saved. Return the (possibly modified) params. Common use: inject `createdBy` from `currentUser._id`.
|
|
356
|
+
|
|
357
|
+
#### `create.after`
|
|
358
|
+
```typescript
|
|
359
|
+
after?: (
|
|
360
|
+
req: IRequest,
|
|
361
|
+
document: Document,
|
|
362
|
+
currentUser: Document,
|
|
363
|
+
params: any
|
|
364
|
+
) => Promise<Document>
|
|
365
|
+
```
|
|
366
|
+
Called after the document is saved. Receives both the saved document and the original params. Return the (possibly modified) document.
|
|
367
|
+
|
|
368
|
+
**Argument order:** `req, document, currentUser, params` — note `currentUser` comes before `params`.
|
|
369
|
+
|
|
370
|
+
#### `create.validators`
|
|
371
|
+
```typescript
|
|
372
|
+
validators?: ValidationChain[]
|
|
373
|
+
```
|
|
374
|
+
Array of [express-validator](https://express-validator.github.io) chains run before the save query.
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
### `update` — Update record
|
|
379
|
+
|
|
380
|
+
#### `update.before`
|
|
381
|
+
```typescript
|
|
382
|
+
before?: (
|
|
383
|
+
req: IRequest,
|
|
384
|
+
params: any,
|
|
385
|
+
currentUser: Document
|
|
386
|
+
) => Promise<any>
|
|
387
|
+
```
|
|
388
|
+
Modify the request body params before the document is updated. Return the (possibly modified) params.
|
|
389
|
+
|
|
390
|
+
#### `update.after`
|
|
391
|
+
```typescript
|
|
392
|
+
after?: (
|
|
393
|
+
req: IRequest,
|
|
394
|
+
document: Document,
|
|
395
|
+
params: any,
|
|
396
|
+
currentUser: Document
|
|
397
|
+
) => Promise<Document>
|
|
398
|
+
```
|
|
399
|
+
Called after the document is updated. Receives the updated document, the submitted params, and the current user.
|
|
400
|
+
|
|
401
|
+
**Argument order:** `req, document, params, currentUser` — different from `create.after` where `currentUser` comes before `params`.
|
|
402
|
+
|
|
403
|
+
#### `update.update` (custom update)
|
|
404
|
+
```typescript
|
|
405
|
+
update?: (
|
|
406
|
+
req: IRequest,
|
|
407
|
+
record: Document,
|
|
408
|
+
recordParams: any,
|
|
409
|
+
currentUser: Document
|
|
410
|
+
) => Promise<SaveResult<any>>
|
|
411
|
+
```
|
|
412
|
+
Replace the entire update logic. Receives the existing `record`, the `recordParams` from the request, and the current user. Return a `SaveResult<any>`.
|
|
413
|
+
|
|
414
|
+
#### `update.validators`
|
|
415
|
+
```typescript
|
|
416
|
+
validators?: ValidationChain[]
|
|
417
|
+
```
|
|
418
|
+
Array of express-validator chains run before the update query.
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
### `show` — Detail view
|
|
423
|
+
|
|
424
|
+
#### `show.before`
|
|
425
|
+
```typescript
|
|
426
|
+
before?: (
|
|
427
|
+
req: IRequest,
|
|
428
|
+
filter: { [key: string]: any },
|
|
429
|
+
currentUser: Document
|
|
430
|
+
) => Promise<{ [key: string]: any }>
|
|
431
|
+
```
|
|
432
|
+
Modify the lookup filter before the record is fetched. Return the (possibly modified) filter.
|
|
433
|
+
|
|
434
|
+
#### `show.after`
|
|
435
|
+
```typescript
|
|
436
|
+
after?: (
|
|
437
|
+
req: IRequest,
|
|
438
|
+
record: Document
|
|
439
|
+
) => Promise<{ record: Document; [key: string]: any }>
|
|
440
|
+
```
|
|
441
|
+
Add extra data to the show response. **Note:** this hook does NOT receive `currentUser`. Return an object containing the `record` plus any additional fields.
|
|
442
|
+
|
|
443
|
+
```typescript
|
|
444
|
+
// Example: attach related data to the response
|
|
445
|
+
show: {
|
|
446
|
+
after: async (req, record) => {
|
|
447
|
+
const stats = await Stats.findOne({ userId: record._id });
|
|
448
|
+
return { record, stats };
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
#### `show.nextPreviousButtonHandler`
|
|
454
|
+
```typescript
|
|
455
|
+
nextPreviousButtonHandler?: (
|
|
456
|
+
req: IRequest,
|
|
457
|
+
filter: { [key: string]: any },
|
|
458
|
+
currentUser: Document,
|
|
459
|
+
direction: NeighborTypes // 'NEXT' | 'PREVIOUS'
|
|
460
|
+
) => Promise<{ [key: string]: any }>
|
|
461
|
+
```
|
|
462
|
+
Custom logic for navigating to the next or previous record. Modify the filter to scope which records are eligible for neighbor navigation. Return the filter.
|
|
463
|
+
|
|
464
|
+
## Population (`properties.populate`)
|
|
465
|
+
|
|
466
|
+
Control how referenced fields are populated:
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
populate?: {
|
|
470
|
+
all?: PopulateFunction; // applied to all endpoints
|
|
471
|
+
list?: PopulateFunction; // applied only to list endpoint
|
|
472
|
+
show?: PopulateFunction; // applied to show, create, update
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// PopulateFunction = (populatedString: any) => Promise<any>
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
The function receives the current populate string and can modify it before execution.
|
|
479
|
+
|
|
480
|
+
## Localization
|
|
481
|
+
|
|
482
|
+
```typescript
|
|
483
|
+
keysTranslations?: { [key: string]: any }; // field label translations
|
|
484
|
+
actionsTranslations?: { [key: string]: any }; // action button translations
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Structure mirrors the locale JSON (see `src/locales/en.json`). Used when `enableLocalization: true` is set in the app configuration.
|
|
488
|
+
|
|
489
|
+
## Additional Options
|
|
490
|
+
|
|
491
|
+
| Property | Type | Default | Description |
|
|
492
|
+
|----------|------|---------|-------------|
|
|
493
|
+
| `disableNextPreviousButtonsInShowPage` | `boolean` | `false` | Hide prev/next navigation in show |
|
|
494
|
+
| `disableNextPreviousButtonsInEditPage` | `boolean` | `false` | Hide prev/next navigation in edit |
|
|
495
|
+
| `displayEditPageInShowPage` | `boolean` | `false` | Open edit form instead of show view |
|
|
496
|
+
| `imageOnReferencePath` | `string` | — | Field path for thumbnail image in reference selectors |
|
|
497
|
+
| `disableImageOnReference` | `boolean` | `false` | Hide thumbnail images in reference selectors |
|
|
498
|
+
| `extras` | `{ [key]: any }` | — | Arbitrary extra data passed to the frontend |
|
|
499
|
+
| `sendDraftMail` | `(data: { to, subject, html }) => Promise<void>` | — | Handler for sending draft emails from mail log |
|
|
500
|
+
| `afterImport` | `(req, currentUser, data) => Promise<any>` | — | Post-import processing hook |
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
## Enums
|
|
505
|
+
|
|
506
|
+
### `FieldTypes`
|
|
507
|
+
|
|
508
|
+
| Value | Description |
|
|
509
|
+
|-------|-------------|
|
|
510
|
+
| `'String'` | Text input |
|
|
511
|
+
| `'Number'` | Number input |
|
|
512
|
+
| `'enum'` | Dropdown / chips |
|
|
513
|
+
| `'ref'` | Reference to another model |
|
|
514
|
+
| `'Date'` | Date picker |
|
|
515
|
+
| `'password'` | Masked password input |
|
|
516
|
+
| `'Boolean'` | Toggle switch |
|
|
517
|
+
| `'ObjectID'` | Object ID display |
|
|
518
|
+
| `'nestedSchema'` | Embedded sub-document |
|
|
519
|
+
| `'Array'` | Array of values |
|
|
520
|
+
| `'image'` | Image upload with preview |
|
|
521
|
+
| `'localizedString'` | Multi-language string |
|
|
522
|
+
| `'phoneNumber'` | Phone input with country code |
|
|
523
|
+
| `'color'` | Color picker |
|
|
524
|
+
| `'timePicker'` | Time selector |
|
|
525
|
+
| `'File'` | File upload |
|
|
526
|
+
| `'LOCATION'` | Map location picker |
|
|
527
|
+
| `'HTML'` | HTML rich text editor |
|
|
528
|
+
| `'RICH_TEXT_I'` | Rich text editor (type I) |
|
|
529
|
+
| `'RICH_TEXT_II'` | Rich text editor (type II) |
|
|
530
|
+
| `'JSON_RICH_TEXT'` | JSON-based rich text |
|
|
531
|
+
| `'EXTERNAL_LINK'` | External URL input |
|
|
532
|
+
| `'MULTIPLE_TEXT'` | Multiple text values |
|
|
533
|
+
|
|
534
|
+
### `ActionTypes`
|
|
535
|
+
|
|
536
|
+
- `'record'` — Per-row action in the list
|
|
537
|
+
- `'resource'` — Top-level action button
|
|
538
|
+
|
|
539
|
+
### `ActionNames`
|
|
540
|
+
|
|
541
|
+
- `'SHOW'`, `'LIST'`, `'NEW'`, `'EDIT'` — Redirection targets
|
|
542
|
+
|
|
543
|
+
### `Virtuals`
|
|
544
|
+
|
|
545
|
+
- `'SHOW'`, `'LIST'`, `'FORM'`, `'FILTER'` — Where a virtual field appears
|
|
546
|
+
|
|
547
|
+
### `HandlerStrategy`
|
|
548
|
+
|
|
549
|
+
- `'NORMAL'` — Standard handler execution
|
|
550
|
+
- `'FILE_DOWNLOAD'` — Returns a file for download
|
|
551
|
+
- `'CUSTOM_COMPONENT'` — Opens a custom React component dialog
|
|
552
|
+
|
|
553
|
+
### `FileTypes`
|
|
554
|
+
|
|
555
|
+
`'ALL'`, `'IMAGE'`, `'3D'`, `'PDF'`, `'EXCEL'`, `'WORD'`, `'VIDEO'`, `'TEXT'`, `'ZIP'`, `'POWER_POINT'`, `'AUDIO'`
|
|
556
|
+
|
|
557
|
+
### `ImageOptimizingCategories`
|
|
558
|
+
|
|
559
|
+
- `'NORMAL'` — Standard compression
|
|
560
|
+
- `'BANNERS'` — Banner-level compression
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
## Complete Example
|
|
565
|
+
|
|
566
|
+
```typescript
|
|
567
|
+
import { Model, Schema } from 'mongoose';
|
|
568
|
+
import { IResourceFile } from 'identity-admin/lib/types/IResourceFile';
|
|
569
|
+
import { FieldTypes, Virtuals, ActionTypes } from 'identity-admin/lib/types/helpers';
|
|
570
|
+
|
|
571
|
+
const UserResource: IResourceFile = {
|
|
572
|
+
properties: {
|
|
573
|
+
resource: User,
|
|
574
|
+
modelName: 'users',
|
|
575
|
+
name: 'Users',
|
|
576
|
+
title: 'fullName',
|
|
577
|
+
parent: { name: 'Access Control', icon: 'People' },
|
|
578
|
+
defaultOrderBy: 'createdAt',
|
|
579
|
+
defaultOrder: 'desc',
|
|
580
|
+
defaultrowsPerPage: 25,
|
|
581
|
+
isAllowed: async (user) => user.role === 'admin',
|
|
582
|
+
isVisible: async (user) => user.role !== 'viewer',
|
|
583
|
+
hiddenProperties: ['__v', 'encryptedPassword'],
|
|
584
|
+
model: {
|
|
585
|
+
fullName: { type: 'String' as FieldTypes, required: true },
|
|
586
|
+
email: { type: 'String' as FieldTypes, isEditable: false },
|
|
587
|
+
role: {
|
|
588
|
+
type: 'enum' as FieldTypes,
|
|
589
|
+
enumValues: {
|
|
590
|
+
admin: { label: 'Admin', color: '#FF6B6B', labelColor: '#FFF' },
|
|
591
|
+
editor: { label: 'Editor', color: '#4ECDC4', labelColor: '#FFF' },
|
|
592
|
+
viewer: { label: 'Viewer', color: '#95E1D3', labelColor: '#333' },
|
|
593
|
+
},
|
|
594
|
+
},
|
|
595
|
+
avatar: { type: 'image' as FieldTypes, mediaUploader: true, imageOptimizingCategory: 'NORMAL' as any },
|
|
596
|
+
phone: { type: 'phoneNumber' as FieldTypes, countryCodes: ['sa', 'eg', 'us'] },
|
|
597
|
+
bio: { type: 'HTML' as FieldTypes },
|
|
598
|
+
virtuals: {
|
|
599
|
+
password: { type: 'password', showIn: Virtuals.FORM, required: true },
|
|
600
|
+
posts: { type: 'ref', filterBy: 'author', showIn: Virtuals.SHOW, resource: Post },
|
|
601
|
+
},
|
|
602
|
+
},
|
|
603
|
+
actions: {
|
|
604
|
+
delete: { isAccessible: false },
|
|
605
|
+
bulkDelete: { isAccessible: true },
|
|
606
|
+
extras: [
|
|
607
|
+
{
|
|
608
|
+
key: 'sendWelcomeEmail',
|
|
609
|
+
name: 'Send Welcome',
|
|
610
|
+
icon: 'Email',
|
|
611
|
+
actionType: 'record' as ActionTypes,
|
|
612
|
+
handler: async (req, res, data) => {
|
|
613
|
+
await sendEmail(data.record.email, 'Welcome!');
|
|
614
|
+
return { action: 'LIST', path: data.resource.path };
|
|
615
|
+
},
|
|
616
|
+
},
|
|
617
|
+
],
|
|
618
|
+
},
|
|
619
|
+
filters: {
|
|
620
|
+
scopes: {
|
|
621
|
+
isAccessible: true,
|
|
622
|
+
auto: { key: 'role', options: ['admin', 'editor', 'viewer'] },
|
|
623
|
+
},
|
|
624
|
+
},
|
|
625
|
+
crudOperations: {
|
|
626
|
+
create: {
|
|
627
|
+
before: async (req, params, currentUser) => {
|
|
628
|
+
params.createdBy = currentUser._id;
|
|
629
|
+
return params;
|
|
630
|
+
},
|
|
631
|
+
},
|
|
632
|
+
index: {
|
|
633
|
+
before: async (req, filter) => {
|
|
634
|
+
if (req.query.search) filter.$text = { $search: req.query.search };
|
|
635
|
+
return filter;
|
|
636
|
+
},
|
|
637
|
+
},
|
|
638
|
+
},
|
|
639
|
+
populate: {
|
|
640
|
+
all: async (populateStr) => `${populateStr} createdBy`,
|
|
641
|
+
},
|
|
642
|
+
keysTranslations: {
|
|
643
|
+
fullName: { en: 'Full Name', ar: 'الاسم الكامل' },
|
|
644
|
+
email: { en: 'Email', ar: 'البريد الإلكتروني' },
|
|
645
|
+
},
|
|
646
|
+
disableNextPreviousButtonsInShowPage: true,
|
|
647
|
+
},
|
|
648
|
+
listProperties: ['fullName', 'email', 'role', 'createdAt'],
|
|
649
|
+
showProperties: ['fullName', 'email', 'role', 'avatar', 'bio', 'createdAt'],
|
|
650
|
+
formProperties: ['fullName', 'email', 'role', 'avatar', 'phone', 'bio', 'password'],
|
|
651
|
+
filterProperties: ['role', 'createdAt'],
|
|
652
|
+
quickFilterProperties: ['role'],
|
|
653
|
+
};
|
|
654
|
+
```
|