adminizer 5.0.0-build.9 → 5.1.0-build.25
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/assets/abnfDiagram-VCTEODGH-BTgLIXrb.js +1 -0
- package/assets/add-C8V8qjvm.js +1 -0
- package/assets/add-group-Ezq_Ocot.js +1 -0
- package/assets/add-user-CluNf2QG.js +1 -0
- package/assets/ai-assistant/agent.es.js +28464 -0
- package/assets/app-C96pcs-J.js +138 -0
- package/assets/app-DPmI-MvN.css +1 -0
- package/assets/arc-G6n0TtRf.js +1 -0
- package/assets/architectureDiagram-5GKGNRK7-TQ4_iSAG.js +36 -0
- package/assets/asmcrypto-DZeQH0LC.js +1 -0
- package/assets/blockDiagram-I7D4REHJ-1q050zQd.js +129 -0
- package/assets/c4Diagram-7LVT6UL2-BXn0hW62.js +38 -0
- package/assets/{catalog-dk6a0I1u.js → catalog-Cpx4OH_r.js} +3 -3
- package/assets/channel-JZzXP_E5.js +1 -0
- package/assets/chunk-2Q5K7J3B-BSnocdBz.js +1 -0
- package/assets/chunk-5VM5RSS4-BvfoMSpq.js +15 -0
- package/assets/chunk-F27PBJKO-CMyFcBlX.js +1 -0
- package/assets/chunk-IMKFNOWR--8Y02hwt.js +231 -0
- package/assets/chunk-JWPE2WC7-C18m6v8d.js +1 -0
- package/assets/chunk-POPQ4Y6H-DzoTZe0a.js +1 -0
- package/assets/chunk-SVP7TREG-Ce98IXh7.js +88 -0
- package/assets/chunk-TICWLB2K-BeLoUlaL.js +206 -0
- package/assets/chunk-XXDRQBXY-DCZSZ1aW.js +1 -0
- package/assets/classDiagram-ZZMXUADV-jA4zeKxs.js +1 -0
- package/assets/classDiagram-v2-VYDZK3BY-jA4zeKxs.js +1 -0
- package/assets/controls/ckeditor.es.js +9382 -9320
- package/assets/controls/handsontable.es.js +11971 -11938
- package/assets/controls/jsoneditor.es.js +10442 -10233
- package/assets/controls/toast-ui.es.js +1308 -1279
- package/assets/cose-bilkent-JH36ORCC-Cy9np608.js +1 -0
- package/assets/cynefin-OW5HDTMX-Ba6uP79R.js +166 -0
- package/assets/cynefinDiagram-5FMLGOSQ-DhMBBq7T.js +62 -0
- package/assets/cytoscape.esm-DzSz-X2X.js +321 -0
- package/assets/dagre-GXQ25YYZ-BdAnQUCV.js +4 -0
- package/assets/dashboard-BFVFBIio.js +3 -0
- package/assets/debounce-B3mXI_sx.js +1 -0
- package/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/assets/diagram-S7CK7UJ4-BDYUGbNl.js +30 -0
- package/assets/diagram-UQ7AKVKN-PURK0-X-.js +41 -0
- package/assets/diagram-VSXAHHWV-DxHdFxl9.js +3 -0
- package/assets/diagram-VX7I27RA-Vz8xmeYc.js +24 -0
- package/assets/diagram-Z3DM3KII-CFXUpBMy.js +24 -0
- package/assets/docs-DU3h-HtS.js +1 -0
- package/assets/ebnfDiagram-PWID7BFC-BXNvxMGP.js +1 -0
- package/assets/erDiagram-RLTQ6QDP-DN0GgZEI.js +99 -0
- package/assets/flowDiagram-HODETNUW-DXdnwgBv.js +168 -0
- package/assets/ganttDiagram-EL5Y4UJY-Cv8_dxX3.js +292 -0
- package/assets/gitGraphDiagram-WWUBYQGX-BO8T858E.js +106 -0
- package/assets/history-BmwWpckq.js +1 -0
- package/assets/infoDiagram-27XIBGKW-DMSJ1RNc.js +2 -0
- package/assets/init-Gi6I4Gst.js +1 -0
- package/assets/init-user-BIdB8U_4.js +1 -0
- package/assets/isObject-DL-BuaBl.js +1 -0
- package/assets/ishikawaDiagram-5VMMS53U-_tLJESbl.js +70 -0
- package/assets/journeyDiagram-3NMN7TZE-DMMhdo-_.js +139 -0
- package/assets/kanban-definition-UXKFOSKX-CxQrB4t6.js +89 -0
- package/assets/katex-HP8lGamR.js +257 -0
- package/assets/layout-_oS_xxCJ.js +1 -0
- package/assets/linear-VLYuNK3x.js +1 -0
- package/assets/{list-CcMtS4hD.js → list-YTyJQtiR.js} +2 -2
- package/assets/login-B9GlhjZh.js +1 -0
- package/assets/manifest.json +834 -58
- package/assets/media-manager-Bb1VWlzd.js +6 -0
- package/assets/mermaid.core-BknV2vft.js +310 -0
- package/assets/mindmap-definition-YA3MSWOX-DBjjjDq4.js +96 -0
- package/assets/module-DQ1NK8Xg.js +1 -0
- package/assets/notification-CgNOsXvn.js +20 -0
- package/assets/ordinal-Cboi1Yqb.js +1 -0
- package/assets/pegDiagram-XKGWAZYB-uRznTaO4.js +1 -0
- package/assets/pieDiagram-E7YTZNPT-D1TkCH8I.js +39 -0
- package/assets/quadrantDiagram-AXDQQJYC-BofJ36Jz.js +7 -0
- package/assets/railroadDiagram-O6MQD6OU-e1ZM2IT1.js +1 -0
- package/assets/register-DjTtMayF.js +1 -0
- package/assets/requirementDiagram-BXWQKSXE-DQWArRbb.js +84 -0
- package/assets/ru-CqAtka69.js +1 -0
- package/assets/sankeyDiagram-P5KCCOFB-fVOu2jzi.js +40 -0
- package/assets/sequenceDiagram-WJ2MYXX4-Dj24cqpu.js +162 -0
- package/assets/sizeCapture-INFHLROL-CsApVrVi.js +1 -0
- package/assets/stateDiagram-D77RDMKH-IU2Szlid.js +1 -0
- package/assets/stateDiagram-v2-MP3YSRHH-B-EW3cIC.js +1 -0
- package/assets/swimlanes-42K2YHIH-97rBqTR-.js +1 -0
- package/assets/swimlanesDiagram-VR7AAH4N-CqG2iydK.js +8 -0
- package/assets/timeline-definition-24CTP7MA-DSgRzx1V.js +120 -0
- package/assets/toNumber-DZb-r9sy.js +1 -0
- package/assets/use-appearance-CXz2xWgT.js +1 -0
- package/assets/user-filters-list-BAR4CBN_.js +1 -0
- package/assets/vennDiagram-4TSXK5OY-BqMksFxE.js +34 -0
- package/assets/wardleyDiagram-VM6X3IG4-BMmxRODC.js +78 -0
- package/assets/welcome-CPXT7_4b.js +1 -0
- package/assets/with-app-layout-C6dqetfx.js +31 -0
- package/assets/xychartDiagram-S5SC5T6Z-3xRuF0l4.js +7 -0
- package/controllers/access-rights/permissionOptions.d.ts +2 -0
- package/controllers/access-rights/permissionOptions.js +23 -0
- package/controllers/add.js +2 -2
- package/controllers/addGroup.js +15 -6
- package/controllers/ai/AiAgentController.d.ts +66 -0
- package/controllers/ai/AiAgentController.js +435 -0
- package/controllers/ai/AiAssistantController.d.ts +0 -4
- package/controllers/ai/AiAssistantController.js +4 -78
- package/controllers/catalog/FrontendCatalogAdapter.js +7 -8
- package/controllers/docs/index.d.ts +22 -0
- package/controllers/docs/index.js +126 -0
- package/controllers/edit.js +2 -2
- package/controllers/editGroup.js +15 -6
- package/controllers/filter-fields/savedFilters.js +1 -1
- package/controllers/history-actions/HistoryController.js +7 -7
- package/controllers/inlineUpdate.js +10 -3
- package/controllers/list.js +1 -1
- package/controllers/login.js +1 -1
- package/controllers/notifications/NotificationController.js +14 -8
- package/controllers/view.js +3 -3
- package/controllers/widgets/filterInfo.js +1 -1
- package/helpers/accessRightsHelper.d.ts +63 -2
- package/helpers/accessRightsHelper.js +202 -13
- package/helpers/assetVersionHelper.d.ts +14 -0
- package/helpers/assetVersionHelper.js +42 -0
- package/helpers/configHelper.js +19 -18
- package/helpers/controllerHelper.d.ts +1 -0
- package/helpers/controllerHelper.js +25 -15
- package/helpers/fieldsHelper.d.ts +2 -1
- package/helpers/fieldsHelper.js +11 -5
- package/helpers/inertiaActionsHelper.d.ts +1 -1
- package/helpers/inertiaActionsHelper.js +4 -5
- package/helpers/inertiaAddHelper.d.ts +1 -1
- package/helpers/inertiaAddHelper.js +7 -6
- package/helpers/inertiaGroupHelper.js +10 -2
- package/helpers/inertiaListHelper.d.ts +1 -1
- package/helpers/inertiaListHelper.js +7 -8
- package/helpers/inertiaMenuHelper.d.ts +7 -2
- package/helpers/inertiaMenuHelper.js +12 -27
- package/helpers/menuHelper.d.ts +11 -1
- package/helpers/menuHelper.js +12 -0
- package/helpers/modelResourceHelper.d.ts +9 -0
- package/helpers/modelResourceHelper.js +43 -0
- package/helpers/navigationAccessHelper.d.ts +13 -0
- package/helpers/navigationAccessHelper.js +45 -0
- package/index.d.ts +11 -0
- package/index.js +11 -0
- package/interfaces/adminpanelConfig.d.ts +160 -2
- package/interfaces/queryCriteria.d.ts +13 -0
- package/interfaces/types.d.ts +169 -0
- package/lib/Adminizer.d.ts +8 -0
- package/lib/Adminizer.js +30 -2
- package/lib/DataAccessor.d.ts +100 -3
- package/lib/DataAccessor.js +454 -245
- package/lib/access-graph/AccessGraphResolver.d.ts +136 -0
- package/lib/access-graph/AccessGraphResolver.js +605 -0
- package/lib/access-graph/RecordAccessCache.d.ts +23 -0
- package/lib/access-graph/RecordAccessCache.js +30 -0
- package/lib/access-graph/RecordAccessResolver.d.ts +83 -0
- package/lib/access-graph/RecordAccessResolver.js +295 -0
- package/lib/access-graph/shared.d.ts +60 -0
- package/lib/access-graph/shared.js +121 -0
- package/lib/admin-links/AdminLinkHandler.d.ts +72 -0
- package/lib/admin-links/AdminLinkHandler.js +183 -0
- package/lib/ai-assistant/AbstractAiConversationHistoryService.d.ts +39 -0
- package/lib/ai-assistant/AbstractAiConversationHistoryService.js +98 -0
- package/lib/ai-assistant/AbstractAiModelService.d.ts +139 -2
- package/lib/ai-assistant/AbstractAiModelService.js +154 -1
- package/lib/ai-assistant/AiAgentRunManager.d.ts +35 -0
- package/lib/ai-assistant/AiAgentRunManager.js +109 -0
- package/lib/ai-assistant/AiAssistantAgentSkillHandler.d.ts +61 -0
- package/lib/ai-assistant/AiAssistantAgentSkillHandler.js +90 -0
- package/lib/ai-assistant/AiAssistantHandler.d.ts +1 -0
- package/lib/ai-assistant/AiAssistantHandler.js +4 -0
- package/lib/ai-assistant/AiAssistantUiMethodHandler.d.ts +60 -0
- package/lib/ai-assistant/AiAssistantUiMethodHandler.js +144 -0
- package/lib/ai-assistant/builtinAgentSkills.d.ts +9 -0
- package/lib/ai-assistant/builtinAgentSkills.js +259 -0
- package/lib/ai-assistant/jsonSafe.d.ts +13 -0
- package/lib/ai-assistant/jsonSafe.js +81 -0
- package/lib/app-manager/AdminizerApp.d.ts +40 -1
- package/lib/app-manager/AppManager.js +48 -42
- package/lib/app-manager/ConfigLayerHandler.js +4 -0
- package/lib/docs/AbstractDocumentation.d.ts +100 -0
- package/lib/docs/AbstractDocumentation.js +108 -0
- package/lib/docs/DocumentationHandler.d.ts +100 -0
- package/lib/docs/DocumentationHandler.js +198 -0
- package/lib/docs/FileDocumentation.d.ts +47 -0
- package/lib/docs/FileDocumentation.js +189 -0
- package/lib/docs/docsAgentSkills.d.ts +10 -0
- package/lib/docs/docsAgentSkills.js +93 -0
- package/lib/filters/FilterService.js +4 -3
- package/lib/history-actions/AbstractHistoryAdapter.d.ts +26 -1
- package/lib/history-actions/AbstractHistoryAdapter.js +155 -25
- package/lib/media-manager/helpers/MediaManagerHelper.js +9 -7
- package/lib/model/AbstractModel.d.ts +48 -0
- package/lib/model/AbstractModel.js +14 -4
- package/lib/model/ModelHandler.d.ts +61 -2
- package/lib/model/ModelHandler.js +136 -8
- package/lib/model/adapter/sequelize.d.ts +40 -1
- package/lib/model/adapter/sequelize.js +243 -77
- package/lib/model/adapter/typeorm.d.ts +16 -0
- package/lib/model/adapter/typeorm.js +136 -9
- package/lib/notifications/GeneralNotificationService.js +6 -5
- package/lib/notifications/SystemNotificationService.js +1 -1
- package/lib/ui-i18n/uiTranslationKeys.d.ts +2 -1
- package/lib/ui-i18n/uiTranslationKeys.js +42 -1
- package/lib/widgets/widgetHandler.js +10 -6
- package/models/Group.d.ts +2 -1
- package/package.json +35 -23
- package/policies/authPolicies.js +6 -6
- package/policies/permissionResolvers.d.ts +1 -0
- package/policies/permissionResolvers.js +3 -0
- package/system/Router.js +21 -3
- package/system/bindAccessRights.js +13 -3
- package/system/bindDocs.d.ts +13 -0
- package/system/bindDocs.js +77 -0
- package/system/bindInertia.js +30 -7
- package/system/buildInternalModelAccess.d.ts +9 -0
- package/system/buildInternalModelAccess.js +37 -4
- package/system/defaults.js +7 -1
- package/system/validateSystemModels.js +29 -9
- package/assets/add-CBlLpLr0.js +0 -1
- package/assets/add-group-H0IKIsNm.js +0 -1
- package/assets/add-user-CoTLmxtF.js +0 -1
- package/assets/app-DNXiApCk.css +0 -1
- package/assets/app-layout-xxJpLAvb.js +0 -1
- package/assets/app.js +0 -138
- package/assets/dashboard-DVJS5EPP.js +0 -3
- package/assets/debounce-BMmXVQ06.js +0 -1
- package/assets/history-bWRuzbye.js +0 -1
- package/assets/init-user-8aUohVDq.js +0 -1
- package/assets/login-CO4laf6m.js +0 -1
- package/assets/media-manager-BDbpSSjH.js +0 -6
- package/assets/module-CqO_BKsH.js +0 -1
- package/assets/notification-B5l2wwmi.js +0 -20
- package/assets/register-DBYIMXGQ.js +0 -1
- package/assets/ru-rYKdQbWF.js +0 -1
- package/assets/use-appearance-_EbbjHTh.js +0 -1
- package/assets/user-filters-list-C7kMKN5f.js +0 -1
- package/assets/welcome-6z-7sXnQ.js +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import inertiaActionsHelper from "./inertiaActionsHelper.js";
|
|
2
|
-
export function inertiaListHelper(modelResource, req, fields, activeFilterName) {
|
|
2
|
+
export async function inertiaListHelper(modelResource, req, fields, activeFilterName) {
|
|
3
3
|
const actionType = 'list';
|
|
4
4
|
// Check if filters are enabled for this model
|
|
5
5
|
// Preferred: model-level `models.<Model>.filters`; fallback: legacy top-level `modelFilters.<Model>`
|
|
@@ -31,23 +31,22 @@ export function inertiaListHelper(modelResource, req, fields, activeFilterName)
|
|
|
31
31
|
defaultPageSize: req.adminizer.config.list?.defaultPageSize ?? 50,
|
|
32
32
|
pageSizeOptions: [5, 20, 50],
|
|
33
33
|
};
|
|
34
|
-
if (modelResource.config.add && req.adminizer.accessRightsHelper.
|
|
34
|
+
if (modelResource.config.add && await req.adminizer.accessRightsHelper.checkPermission(`create-${modelResource.name}-model`, req.user)) {
|
|
35
35
|
props.crudActions.createTitle = req.i18n.__('create');
|
|
36
36
|
}
|
|
37
|
-
if (modelResource.config.edit && req.adminizer.accessRightsHelper.
|
|
37
|
+
if (modelResource.config.edit && await req.adminizer.accessRightsHelper.checkPermission(`update-${modelResource.name}-model`, req.user)) {
|
|
38
38
|
props.crudActions.editTitle = req.i18n.__('Edit');
|
|
39
39
|
}
|
|
40
|
-
if (modelResource.config.view && req.adminizer.accessRightsHelper.
|
|
40
|
+
if (modelResource.config.view && await req.adminizer.accessRightsHelper.checkPermission(`read-${modelResource.name}-model`, req.user)) {
|
|
41
41
|
props.crudActions.viewsTitle = req.i18n.__('View');
|
|
42
42
|
}
|
|
43
|
-
if (modelResource.config.remove && req.adminizer.accessRightsHelper.
|
|
43
|
+
if (modelResource.config.remove && await req.adminizer.accessRightsHelper.checkPermission(`delete-${modelResource.name}-model`, req.user)) {
|
|
44
44
|
props.crudActions.deleteTitle = req.i18n.__('Delete');
|
|
45
45
|
}
|
|
46
|
-
props.actions = inertiaActionsHelper(actionType, modelResource, req);
|
|
46
|
+
props.actions = await inertiaActionsHelper(actionType, modelResource, req);
|
|
47
47
|
if (req.adminizer.menuHelper.hasInlineActions(modelResource.config, 'list')) {
|
|
48
48
|
for (const inlineAction of req.adminizer.menuHelper.getInlineActions(modelResource.config, 'list')) {
|
|
49
|
-
|
|
50
|
-
if (req.adminizer.accessRightsHelper.hasPermission(inlineAction.accessRightsToken, req.user, context)) {
|
|
49
|
+
if (await req.adminizer.accessRightsHelper.checkPermission(inlineAction.accessRightsToken, req.user)) {
|
|
51
50
|
props.inlineActions.push({
|
|
52
51
|
icon: inlineAction.icon,
|
|
53
52
|
id: inlineAction.id,
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { Adminizer } from "../lib/Adminizer.js";
|
|
2
|
+
import { NavbarSectionConfig } from "../interfaces/adminpanelConfig.js";
|
|
2
3
|
import { MenuItem } from "./menuHelper.js";
|
|
3
4
|
export declare class InertiaMenuHelper {
|
|
4
5
|
private adminizer;
|
|
5
6
|
constructor(adminizer: Adminizer);
|
|
6
|
-
getMenuItems(req: ReqType): MenuItem[]
|
|
7
|
-
private filterAccessibleItems;
|
|
7
|
+
getMenuItems(req: ReqType): Promise<MenuItem[]>;
|
|
8
8
|
private translateMenuItem;
|
|
9
9
|
private translateHrefItem;
|
|
10
|
+
/**
|
|
11
|
+
* Navbar section metadata keyed by the *translated* section name, so the UI
|
|
12
|
+
* can look it up with the already-translated `section` of a menu item.
|
|
13
|
+
*/
|
|
14
|
+
getSections(req: ReqType): Record<string, NavbarSectionConfig>;
|
|
10
15
|
getBrandTitle(): string;
|
|
11
16
|
getLogoutUrl(): string;
|
|
12
17
|
}
|
|
@@ -1,35 +1,12 @@
|
|
|
1
|
+
import { listAccessibleMenuItems } from "./navigationAccessHelper.js";
|
|
1
2
|
export class InertiaMenuHelper {
|
|
2
3
|
adminizer;
|
|
3
4
|
constructor(adminizer) {
|
|
4
5
|
this.adminizer = adminizer;
|
|
5
6
|
}
|
|
6
|
-
getMenuItems(req) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const filteredActions = this.filterAccessibleItems(menuItem.actions ?? [], req);
|
|
10
|
-
const menuItemTokens = filteredActions.map(item => {
|
|
11
|
-
return item.accessRightsToken;
|
|
12
|
-
}).filter(item => {
|
|
13
|
-
return item;
|
|
14
|
-
});
|
|
15
|
-
if (menuItem.accessRightsToken)
|
|
16
|
-
menuItemTokens.push(menuItem.accessRightsToken);
|
|
17
|
-
if (this.adminizer.accessRightsHelper.enoughPermissions(menuItemTokens, req.user)) {
|
|
18
|
-
menu.push(this.translateMenuItem(req, {
|
|
19
|
-
...menuItem,
|
|
20
|
-
actions: filteredActions
|
|
21
|
-
}));
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return menu;
|
|
25
|
-
}
|
|
26
|
-
filterAccessibleItems(items, req) {
|
|
27
|
-
return items
|
|
28
|
-
.filter((item) => !item.accessRightsToken || this.adminizer.accessRightsHelper.hasPermission(item.accessRightsToken, req.user))
|
|
29
|
-
.map((item) => ({
|
|
30
|
-
...item,
|
|
31
|
-
subItems: item.subItems ? this.filterAccessibleItems(item.subItems, req) : item.subItems
|
|
32
|
-
}));
|
|
7
|
+
async getMenuItems(req) {
|
|
8
|
+
return (await listAccessibleMenuItems(this.adminizer, req.user))
|
|
9
|
+
.map((menuItem) => this.translateMenuItem(req, menuItem));
|
|
33
10
|
}
|
|
34
11
|
translateMenuItem(req, menuItem) {
|
|
35
12
|
return {
|
|
@@ -47,6 +24,14 @@ export class InertiaMenuHelper {
|
|
|
47
24
|
subItems: item.subItems?.map((subItem) => this.translateHrefItem(req, subItem)),
|
|
48
25
|
};
|
|
49
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Navbar section metadata keyed by the *translated* section name, so the UI
|
|
29
|
+
* can look it up with the already-translated `section` of a menu item.
|
|
30
|
+
*/
|
|
31
|
+
getSections(req) {
|
|
32
|
+
const sections = this.adminizer.menuHelper.getSections();
|
|
33
|
+
return Object.fromEntries(Object.entries(sections).map(([name, section]) => [req.i18n.__(name), section]));
|
|
34
|
+
}
|
|
50
35
|
getBrandTitle() {
|
|
51
36
|
return this.adminizer.menuHelper.getBrandTitle();
|
|
52
37
|
}
|
package/helpers/menuHelper.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @constructor
|
|
5
5
|
*/
|
|
6
6
|
import { User } from "../models/User.js";
|
|
7
|
-
import { ActionType, AdminpanelConfig, HrefConfig, ModelConfig } from "../interfaces/adminpanelConfig.js";
|
|
7
|
+
import { ActionType, AdminpanelConfig, HrefConfig, ModelConfig, NavbarSectionConfig } from "../interfaces/adminpanelConfig.js";
|
|
8
8
|
export type MenuItem = {
|
|
9
9
|
link: string;
|
|
10
10
|
title: string;
|
|
@@ -28,6 +28,16 @@ export declare class MenuHelper {
|
|
|
28
28
|
* @returns {string}
|
|
29
29
|
*/
|
|
30
30
|
getBrandTitle(): string;
|
|
31
|
+
/**
|
|
32
|
+
* Presentation metadata of navbar sections, keyed by section name.
|
|
33
|
+
*
|
|
34
|
+
* Only sections declared under `navbar.sections` are present: a section
|
|
35
|
+
* used by links but never configured simply has no entry, and the UI falls
|
|
36
|
+
* back to its default rendering.
|
|
37
|
+
*
|
|
38
|
+
* @returns {Record<string, NavbarSectionConfig>}
|
|
39
|
+
*/
|
|
40
|
+
getSections(): Record<string, NavbarSectionConfig>;
|
|
31
41
|
/**
|
|
32
42
|
* Check if global actions buttons added to action
|
|
33
43
|
*
|
package/helpers/menuHelper.js
CHANGED
|
@@ -63,6 +63,18 @@ export class MenuHelper {
|
|
|
63
63
|
}
|
|
64
64
|
return 'Adminizer';
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Presentation metadata of navbar sections, keyed by section name.
|
|
68
|
+
*
|
|
69
|
+
* Only sections declared under `navbar.sections` are present: a section
|
|
70
|
+
* used by links but never configured simply has no entry, and the UI falls
|
|
71
|
+
* back to its default rendering.
|
|
72
|
+
*
|
|
73
|
+
* @returns {Record<string, NavbarSectionConfig>}
|
|
74
|
+
*/
|
|
75
|
+
getSections() {
|
|
76
|
+
return { ...(this.config.navbar?.sections ?? {}) };
|
|
77
|
+
}
|
|
66
78
|
/**
|
|
67
79
|
* Check if global actions buttons added to action
|
|
68
80
|
*
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ModelConfig } from '../interfaces/adminpanelConfig.js';
|
|
2
|
+
import type { ModelResource } from '../interfaces/types.js';
|
|
3
|
+
import type { Adminizer } from '../lib/Adminizer.js';
|
|
4
|
+
/** Config defaults of a model resource declared as `true` in the panel config. */
|
|
5
|
+
export declare function normalizeModelConfig(name: string, config: ModelConfig | boolean): ModelConfig;
|
|
6
|
+
/** Every configured model resource whose model is actually registered. */
|
|
7
|
+
export declare function listModelResources(adminizer: Adminizer): ModelResource[];
|
|
8
|
+
/** Resolves a resource by its Adminizer name, then by a uniquely registered host model name. */
|
|
9
|
+
export declare function resolveModelResource(adminizer: Adminizer, modelName: string): ModelResource | undefined;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Config defaults of a model resource declared as `true` in the panel config. */
|
|
2
|
+
export function normalizeModelConfig(name, config) {
|
|
3
|
+
const baseConfig = {
|
|
4
|
+
model: name,
|
|
5
|
+
icon: "description",
|
|
6
|
+
title: name,
|
|
7
|
+
list: true,
|
|
8
|
+
add: true,
|
|
9
|
+
edit: true,
|
|
10
|
+
remove: true,
|
|
11
|
+
view: true,
|
|
12
|
+
};
|
|
13
|
+
if (typeof config === "boolean") {
|
|
14
|
+
return config ? baseConfig : { ...baseConfig, list: false, add: false, edit: false, remove: false, view: false };
|
|
15
|
+
}
|
|
16
|
+
return { ...baseConfig, ...config };
|
|
17
|
+
}
|
|
18
|
+
/** Every configured model resource whose model is actually registered. */
|
|
19
|
+
export function listModelResources(adminizer) {
|
|
20
|
+
const resources = [];
|
|
21
|
+
for (const [configName, configValue] of Object.entries(adminizer.config.models ?? {})) {
|
|
22
|
+
const config = normalizeModelConfig(configName, configValue);
|
|
23
|
+
const model = adminizer.modelHandler.getResource(configName);
|
|
24
|
+
if (!model)
|
|
25
|
+
continue;
|
|
26
|
+
resources.push({
|
|
27
|
+
name: configName,
|
|
28
|
+
uri: `${adminizer.config.routePrefix}/model/${configName}`,
|
|
29
|
+
config,
|
|
30
|
+
model,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return resources;
|
|
34
|
+
}
|
|
35
|
+
/** Resolves a resource by its Adminizer name, then by a uniquely registered host model name. */
|
|
36
|
+
export function resolveModelResource(adminizer, modelName) {
|
|
37
|
+
const requestedName = modelName.trim();
|
|
38
|
+
const resourceName = adminizer.modelHandler.getResourceRecord(requestedName)?.name
|
|
39
|
+
?? adminizer.modelHandler.resolveResourceByHostModel(requestedName);
|
|
40
|
+
return resourceName
|
|
41
|
+
? listModelResources(adminizer).find((resource) => resource.name === resourceName)
|
|
42
|
+
: undefined;
|
|
43
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { HrefConfig } from '../interfaces/adminpanelConfig.js';
|
|
2
|
+
import type { Adminizer } from '../lib/Adminizer.js';
|
|
3
|
+
import type { User } from '../models/User.js';
|
|
4
|
+
import type { MenuItem } from './menuHelper.js';
|
|
5
|
+
/** Drops the sub-items this user may not open, recursively. */
|
|
6
|
+
export declare function filterAccessibleHrefItems(adminizer: Adminizer, user: User, items: HrefConfig[]): Promise<HrefConfig[]>;
|
|
7
|
+
/**
|
|
8
|
+
* The navigation menu a user may actually open: configured models, additional
|
|
9
|
+
* links and app-contributed pages, filtered with the very same rules the
|
|
10
|
+
* sidebar uses. Titles are left untranslated, so callers that need i18n (the
|
|
11
|
+
* Inertia page props) translate on top of this.
|
|
12
|
+
*/
|
|
13
|
+
export declare function listAccessibleMenuItems(adminizer: Adminizer, user: User): Promise<MenuItem[]>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Drops the sub-items this user may not open, recursively. */
|
|
2
|
+
export async function filterAccessibleHrefItems(adminizer, user, items) {
|
|
3
|
+
const accessible = [];
|
|
4
|
+
for (const item of items) {
|
|
5
|
+
if (item.accessRightsToken && !await adminizer.accessRightsHelper.checkPermission(item.accessRightsToken, user)) {
|
|
6
|
+
continue;
|
|
7
|
+
}
|
|
8
|
+
accessible.push({
|
|
9
|
+
...item,
|
|
10
|
+
subItems: item.subItems ? await filterAccessibleHrefItems(adminizer, user, item.subItems) : item.subItems,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
return accessible;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The navigation menu a user may actually open: configured models, additional
|
|
17
|
+
* links and app-contributed pages, filtered with the very same rules the
|
|
18
|
+
* sidebar uses. Titles are left untranslated, so callers that need i18n (the
|
|
19
|
+
* Inertia page props) translate on top of this.
|
|
20
|
+
*/
|
|
21
|
+
export async function listAccessibleMenuItems(adminizer, user) {
|
|
22
|
+
const menu = [];
|
|
23
|
+
for (const menuItem of adminizer.menuHelper.getMenuItems(user)) {
|
|
24
|
+
const actions = await filterAccessibleHrefItems(adminizer, user, menuItem.actions ?? []);
|
|
25
|
+
const tokens = actions.map((item) => item.accessRightsToken).filter(Boolean);
|
|
26
|
+
if (menuItem.accessRightsToken)
|
|
27
|
+
tokens.push(menuItem.accessRightsToken);
|
|
28
|
+
if (await adminizer.accessRightsHelper.checkAnyPermission(tokens, user)) {
|
|
29
|
+
menu.push({ ...menuItem, actions });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
for (const link of await adminizer.adminLinkHandler.list(user)) {
|
|
33
|
+
menu.push({
|
|
34
|
+
id: link.id,
|
|
35
|
+
link: link.link,
|
|
36
|
+
title: link.title,
|
|
37
|
+
type: link.type === 'blank' ? 'blank' : 'self',
|
|
38
|
+
actions: null,
|
|
39
|
+
icon: null,
|
|
40
|
+
accessRightsToken: link.accessRightsToken ?? null,
|
|
41
|
+
section: link.section || 'Platform',
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return menu;
|
|
45
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -27,6 +27,9 @@ export * from "./lib/media-manager/AbstractMediaManager.js";
|
|
|
27
27
|
export * from "./lib/controls/Control.js";
|
|
28
28
|
export * from "./lib/controls/ControlsHandler.js";
|
|
29
29
|
export * from "./lib/Adminizer.js";
|
|
30
|
+
export * from "./lib/docs/AbstractDocumentation.js";
|
|
31
|
+
export * from "./lib/docs/DocumentationHandler.js";
|
|
32
|
+
export * from "./lib/docs/FileDocumentation.js";
|
|
30
33
|
export * from "./lib/I18n.js";
|
|
31
34
|
export * from "./models/Group.js";
|
|
32
35
|
export * from "./models/User.js";
|
|
@@ -43,7 +46,15 @@ export * from "./lib/helper/jwt.js";
|
|
|
43
46
|
export * from "./lib/notifications/AbstractNotificationService.js";
|
|
44
47
|
export * from "./lib/POWCaptcha.js";
|
|
45
48
|
export * from "./lib/ai-assistant/AbstractAiModelService.js";
|
|
49
|
+
export * from "./lib/ai-assistant/AbstractAiConversationHistoryService.js";
|
|
46
50
|
export * from "./lib/ai-assistant/AiAssistantHandler.js";
|
|
51
|
+
export * from "./lib/ai-assistant/AiAgentRunManager.js";
|
|
52
|
+
export * from "./lib/ai-assistant/jsonSafe.js";
|
|
53
|
+
export * from "./lib/ai-assistant/AiAssistantUiMethodHandler.js";
|
|
54
|
+
export * from "./lib/ai-assistant/AiAssistantAgentSkillHandler.js";
|
|
55
|
+
export * from "./lib/admin-links/AdminLinkHandler.js";
|
|
56
|
+
export * from "./helpers/modelResourceHelper.js";
|
|
57
|
+
export * from "./helpers/navigationAccessHelper.js";
|
|
47
58
|
export * from "./lib/DataAccessor.js";
|
|
48
59
|
export * from "./lib/history-actions/AbstractHistoryAdapter.js";
|
|
49
60
|
export * from "./lib/filters/CustomFilterHandler.js";
|
package/index.js
CHANGED
|
@@ -27,6 +27,9 @@ export * from "./lib/media-manager/AbstractMediaManager.js";
|
|
|
27
27
|
export * from "./lib/controls/Control.js";
|
|
28
28
|
export * from "./lib/controls/ControlsHandler.js";
|
|
29
29
|
export * from "./lib/Adminizer.js";
|
|
30
|
+
export * from "./lib/docs/AbstractDocumentation.js";
|
|
31
|
+
export * from "./lib/docs/DocumentationHandler.js";
|
|
32
|
+
export * from "./lib/docs/FileDocumentation.js";
|
|
30
33
|
export * from "./lib/I18n.js";
|
|
31
34
|
export * from "./models/Group.js";
|
|
32
35
|
export * from "./models/User.js";
|
|
@@ -43,7 +46,15 @@ export * from "./lib/helper/jwt.js";
|
|
|
43
46
|
export * from "./lib/notifications/AbstractNotificationService.js";
|
|
44
47
|
export * from "./lib/POWCaptcha.js";
|
|
45
48
|
export * from "./lib/ai-assistant/AbstractAiModelService.js";
|
|
49
|
+
export * from "./lib/ai-assistant/AbstractAiConversationHistoryService.js";
|
|
46
50
|
export * from "./lib/ai-assistant/AiAssistantHandler.js";
|
|
51
|
+
export * from "./lib/ai-assistant/AiAgentRunManager.js";
|
|
52
|
+
export * from "./lib/ai-assistant/jsonSafe.js";
|
|
53
|
+
export * from "./lib/ai-assistant/AiAssistantUiMethodHandler.js";
|
|
54
|
+
export * from "./lib/ai-assistant/AiAssistantAgentSkillHandler.js";
|
|
55
|
+
export * from "./lib/admin-links/AdminLinkHandler.js";
|
|
56
|
+
export * from "./helpers/modelResourceHelper.js";
|
|
57
|
+
export * from "./helpers/navigationAccessHelper.js";
|
|
47
58
|
export * from "./lib/DataAccessor.js";
|
|
48
59
|
export * from "./lib/history-actions/AbstractHistoryAdapter.js";
|
|
49
60
|
export * from "./lib/filters/CustomFilterHandler.js";
|
|
@@ -75,6 +75,26 @@ export interface AdminpanelConfig {
|
|
|
75
75
|
models: {
|
|
76
76
|
[key: string]: ModelConfig;
|
|
77
77
|
};
|
|
78
|
+
/**
|
|
79
|
+
* Relationship-based record access (ReBAC): each key declares one access graph —
|
|
80
|
+
* models whose records inherit visibility from a root model down parent edges.
|
|
81
|
+
* Membership is granted once, on root records (same `through` form as the membership
|
|
82
|
+
* variant of `userAccessRelation`), and every model of the graph is filtered by it
|
|
83
|
+
* transitively. The graph wins over a covered model's own `userAccessRelation`: once a
|
|
84
|
+
* graph covers a model, that declaration stops applying. Declaring both is a configuration
|
|
85
|
+
* error and is reported as one when the graph compiles.
|
|
86
|
+
* Global CRUD tokens remain the upper bound: the graph narrows visibility, it never
|
|
87
|
+
* grants access the token gates denied.
|
|
88
|
+
*
|
|
89
|
+
* EXPERIMENTAL: the configuration format and access semantics may change in a minor release.
|
|
90
|
+
* Declaring this section makes Adminizer log a warning at boot naming the graphs in use.
|
|
91
|
+
*
|
|
92
|
+
* @beta
|
|
93
|
+
*
|
|
94
|
+
*/
|
|
95
|
+
accessGraph?: {
|
|
96
|
+
[graphKey: string]: AccessGraphConfig;
|
|
97
|
+
};
|
|
78
98
|
/**
|
|
79
99
|
* For custom adminpanel sections, displays inside header
|
|
80
100
|
* */
|
|
@@ -107,6 +127,14 @@ export interface AdminpanelConfig {
|
|
|
107
127
|
sectionHandlers?: {
|
|
108
128
|
[section: string]: (user: User, links: HrefConfig[]) => HrefConfig[];
|
|
109
129
|
};
|
|
130
|
+
/**
|
|
131
|
+
* Presentation metadata for navbar sections, keyed by section name.
|
|
132
|
+
* The sections themselves are declared by the `section` field of individual
|
|
133
|
+
* links; this map only controls how a section header is drawn.
|
|
134
|
+
*/
|
|
135
|
+
sections?: {
|
|
136
|
+
[section: string]: NavbarSectionConfig;
|
|
137
|
+
};
|
|
110
138
|
};
|
|
111
139
|
/**
|
|
112
140
|
* Policies that will be executed before going to every page
|
|
@@ -223,6 +251,14 @@ export interface AdminpanelConfig {
|
|
|
223
251
|
defaultModel?: string;
|
|
224
252
|
models?: string[];
|
|
225
253
|
};
|
|
254
|
+
/**
|
|
255
|
+
* Knowledge base (built-in documentation). The implementation is
|
|
256
|
+
* registered separately: `adminizer.documentationHandler.register(service)`.
|
|
257
|
+
*/
|
|
258
|
+
documentation?: {
|
|
259
|
+
/** Master switch of the subsystem; nothing is brought up unless `true` */
|
|
260
|
+
enabled?: boolean;
|
|
261
|
+
};
|
|
226
262
|
cors?: {
|
|
227
263
|
enabled: boolean;
|
|
228
264
|
origin: string[] | string;
|
|
@@ -299,9 +335,14 @@ export interface ModelConfig {
|
|
|
299
335
|
adapter?: string;
|
|
300
336
|
title: string;
|
|
301
337
|
/**
|
|
302
|
-
*
|
|
338
|
+
* Physical host ORM model name.
|
|
303
339
|
* */
|
|
304
340
|
model: string;
|
|
341
|
+
/**
|
|
342
|
+
* Required only when two or more Adminizer resources use the same host model.
|
|
343
|
+
* The primary resource is selected for associations that reference the host model.
|
|
344
|
+
*/
|
|
345
|
+
primary?: boolean;
|
|
305
346
|
/**
|
|
306
347
|
* Optional display name for history. Should be a attribute of the model, or a function.
|
|
307
348
|
*/
|
|
@@ -392,16 +433,117 @@ export interface ModelConfig {
|
|
|
392
433
|
* */
|
|
393
434
|
identifierField?: string;
|
|
394
435
|
/** In this field we can set model field, for which we want to check user access right.
|
|
395
|
-
* May be association or association-many to User or Group
|
|
436
|
+
* May be association or association-many to User or Group
|
|
437
|
+
*
|
|
438
|
+
* @deprecated Declare record access with {@link AdminpanelConfig.accessGraph} instead.
|
|
439
|
+
* The membership form (`{field, through, via, group}`) is a single-edge access graph
|
|
440
|
+
* written in a second syntax — same `membership` declaration, `field` becomes the
|
|
441
|
+
* `include` edge's `parent`. The string and `{field, via}` forms have no graph
|
|
442
|
+
* equivalent yet (the graph seeds root ids from membership rows, not from an owner
|
|
443
|
+
* foreign key), so this option is removed in stages rather than at once.
|
|
444
|
+
* Note that this option is already inert wherever an `accessGraph` covers the model:
|
|
445
|
+
* the graph wins and the declaration below is ignored.
|
|
446
|
+
*
|
|
447
|
+
* TODO: removal plan, its prerequisites and the migration recipe live in
|
|
448
|
+
* `.ai-notes/todo/user-access-relation-removal.md`; the reasoning behind the
|
|
449
|
+
* deprecation — including the one behaviour the graph does not reproduce (its root
|
|
450
|
+
* model becomes record-restricted too) — in `.ai-notes/user-access-relation-deprecation.md`.
|
|
451
|
+
*/
|
|
396
452
|
userAccessRelation?: {
|
|
397
453
|
field: string;
|
|
398
454
|
via?: string;
|
|
455
|
+
/** Membership form: a join model holding exactly one relation to the model `field` points at,
|
|
456
|
+
* a `via` relation to User and, optionally, a `group` relation to Group. Records are then
|
|
457
|
+
* filtered to the targets the user has a membership row for. */
|
|
458
|
+
through?: string;
|
|
459
|
+
/** Field in `through` that associates with Group. When set, a membership only counts for the
|
|
460
|
+
* actions whose CRUD token (`<verb>-<model>-model`) that group carries, so the same user may
|
|
461
|
+
* hold different rights in different targets. Global tokens remain the upper bound: this
|
|
462
|
+
* narrows rows, it never grants access the token gates denied. */
|
|
463
|
+
group?: string;
|
|
399
464
|
} | string;
|
|
400
465
|
userAccessRelationCallback?: (userWithGroups: UserWithGroups, record: any) => boolean;
|
|
401
466
|
}
|
|
402
467
|
type UserWithGroups = User & {
|
|
403
468
|
groups: Group[];
|
|
404
469
|
};
|
|
470
|
+
/** CRUD verb of the action being performed, as used in `<verb>-<model>-model` tokens. */
|
|
471
|
+
export type AccessGraphActionVerb = "create" | "read" | "update" | "delete";
|
|
472
|
+
/** Ids of the root records the user may see, `"all"` for an explicit bypass, or
|
|
473
|
+
* `undefined` to fall back to the declared `membership`. */
|
|
474
|
+
export type AccessGraphRootIds = unknown[] | "all" | undefined;
|
|
475
|
+
/**
|
|
476
|
+
* One access graph: a root model carrying memberships plus the models that inherit
|
|
477
|
+
* its visibility down explicit parent edges.
|
|
478
|
+
*/
|
|
479
|
+
export interface AccessGraphConfig {
|
|
480
|
+
/** Root model of the graph; memberships are granted on its records. */
|
|
481
|
+
root: string;
|
|
482
|
+
/**
|
|
483
|
+
* Membership declaration at the root: `through` is a join model holding exactly one
|
|
484
|
+
* relation to the root model, a `via` relation to User and, optionally, a `group`
|
|
485
|
+
* relation to Group. With `group` declared, a membership only counts for the actions
|
|
486
|
+
* whose CRUD token (`<verb>-<model>-model`, checked against the model being accessed)
|
|
487
|
+
* that group carries.
|
|
488
|
+
*/
|
|
489
|
+
membership?: {
|
|
490
|
+
through: string;
|
|
491
|
+
via: string;
|
|
492
|
+
group?: string;
|
|
493
|
+
};
|
|
494
|
+
/**
|
|
495
|
+
* Models covered by the graph. Each entry names the association alias the model uses
|
|
496
|
+
* to look at its parent in the graph; the parent model is derived from that alias and
|
|
497
|
+
* must itself belong to the graph (the root or another `include` entry). Exactly one
|
|
498
|
+
* edge per model — the parent is never guessed from foreign keys.
|
|
499
|
+
*/
|
|
500
|
+
include?: {
|
|
501
|
+
[modelName: string]: {
|
|
502
|
+
/** Association alias on this model pointing at its parent in the graph. */
|
|
503
|
+
parent: string;
|
|
504
|
+
};
|
|
505
|
+
};
|
|
506
|
+
/**
|
|
507
|
+
* Stage 2: denormalized root-id columns. For a listed model the read filter collapses
|
|
508
|
+
* to one step — `{<column>: {in: graphRootIds}}` — instead of walking the parent chain.
|
|
509
|
+
* The column is maintained by the application; Adminizer only filters by it. The model
|
|
510
|
+
* still declares its `include` edge — writes keep validating the chosen parent.
|
|
511
|
+
*/
|
|
512
|
+
graphRootField?: {
|
|
513
|
+
[modelName: string]: string;
|
|
514
|
+
};
|
|
515
|
+
/**
|
|
516
|
+
* Stage 3: compile the read filter into one nested-subquery SQL emitted by the adapter
|
|
517
|
+
* instead of materializing intermediate id lists in the application. Applies when every
|
|
518
|
+
* model on the path (and the membership model) lives on the same adapter connection;
|
|
519
|
+
* otherwise the resolver falls back to per-level materialization automatically. The SQL
|
|
520
|
+
* is generated from this declaration — no hand-written queries.
|
|
521
|
+
*
|
|
522
|
+
* Why it exists: the default walk costs one query per level of the chain, and the last of
|
|
523
|
+
* them carries every intermediate id the user can reach as a literal `IN (...)` list. The
|
|
524
|
+
* price of the filter therefore grows with the size of the user's data, not with the size
|
|
525
|
+
* of the page — a member of 500 projects ships ~25 000 task ids to render 25 rows, while
|
|
526
|
+
* the pushed-down form emits one statement of constant size whatever the account holds.
|
|
527
|
+
* The accounts it slows down first are the biggest ones.
|
|
528
|
+
*
|
|
529
|
+
* Setting it is a permission, not a guarantee: a chain that cannot be compiled goes back to
|
|
530
|
+
* materialization, and the write path never uses pushdown at all. The fallback is invisible in
|
|
531
|
+
* the result, so it is logged — one warning per model, naming the graph and the reason. Silence
|
|
532
|
+
* means the chain compiled.
|
|
533
|
+
*/
|
|
534
|
+
pushdown?: boolean;
|
|
535
|
+
/**
|
|
536
|
+
* Token id that lets its holders see the whole graph unfiltered. Matched against the
|
|
537
|
+
* token grants of the user's global groups; it does not need to be a registered token.
|
|
538
|
+
*/
|
|
539
|
+
bypassToken?: string;
|
|
540
|
+
/**
|
|
541
|
+
* Replaces the membership source at the root without touching the graph below it.
|
|
542
|
+
* Returning `undefined` falls back to the declared `membership`; `"all"` is the
|
|
543
|
+
* explicit bypass. The result is still bounded by global tokens.
|
|
544
|
+
*/
|
|
545
|
+
resolveGraphRootIds?: (user: User, actionVerb: AccessGraphActionVerb) => Promise<AccessGraphRootIds> | AccessGraphRootIds;
|
|
546
|
+
}
|
|
405
547
|
export type ModelFieldConfig = (BaseFieldConfig | TuiEditorFieldConfig) & {
|
|
406
548
|
groupsAccessRights?: string[];
|
|
407
549
|
};
|
|
@@ -583,6 +725,22 @@ export interface HrefConfig {
|
|
|
583
725
|
*/
|
|
584
726
|
section?: string;
|
|
585
727
|
}
|
|
728
|
+
/**
|
|
729
|
+
* Presentation of a single navbar section header.
|
|
730
|
+
*/
|
|
731
|
+
export interface NavbarSectionConfig {
|
|
732
|
+
/**
|
|
733
|
+
* Icon of the section header. Also used as the section's trigger in the
|
|
734
|
+
* collapsed (icon-only) sidebar.
|
|
735
|
+
*/
|
|
736
|
+
icon?: MaterialIcon;
|
|
737
|
+
/**
|
|
738
|
+
* Explicit position of the section. Sections carrying an `order` are sorted
|
|
739
|
+
* ascending and placed before the ones without it, which keep the default
|
|
740
|
+
* ordering (`Platform` first, `System` last, the rest alphabetically).
|
|
741
|
+
*/
|
|
742
|
+
order?: number;
|
|
743
|
+
}
|
|
586
744
|
export interface MediaManagerConfig {
|
|
587
745
|
fileStoragePath: string;
|
|
588
746
|
allowMIME?: string[];
|
|
@@ -47,6 +47,19 @@ export interface QueryCriteria<TModel = any> {
|
|
|
47
47
|
where?: CriteriaWhere<TModel>;
|
|
48
48
|
select?: CriteriaSelect;
|
|
49
49
|
populate?: CriteriaPopulate<TModel>;
|
|
50
|
+
/**
|
|
51
|
+
* Record-access confinement of single populated associations, keyed by association
|
|
52
|
+
* name and ANDed into the populate JOIN's ON clause: a populated record failing the
|
|
53
|
+
* condition arrives as its bare foreign-key value instead of an object, while the
|
|
54
|
+
* owning row itself stays in the result — unlike `populate.<field>.where`, which
|
|
55
|
+
* confines the owning rows.
|
|
56
|
+
*
|
|
57
|
+
* Set exclusively by `DataAccessor.pushDownPopulateAccess` for the associations the
|
|
58
|
+
* adapter declared pushdown-capable (`AbstractModel.canPushdownPopulateAccess`);
|
|
59
|
+
* `sanitizeUserRelationAccess` discards an incoming value, so hand-built criteria
|
|
60
|
+
* cannot suppress the association verification that trusts this key.
|
|
61
|
+
*/
|
|
62
|
+
populateOn?: Record<string, CriteriaWhere>;
|
|
50
63
|
sort?: CriteriaSort;
|
|
51
64
|
limit?: number;
|
|
52
65
|
skip?: number;
|