adminizer 4.3.0-build.99 → 4.3.0

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.
Files changed (117) hide show
  1. package/assets/add-9NSjG6Jx.js +1 -0
  2. package/assets/add-form-uUiOWEy_.js +1 -0
  3. package/assets/add-group-Db0HkA1m.js +1 -0
  4. package/assets/add-group-form-DMz0_Oo9.js +1 -0
  5. package/assets/add-user-BMklpOqf.js +1 -0
  6. package/assets/{add-user-form-DrclnTOd.js → add-user-form-izlXhv2-.js} +1 -1
  7. package/assets/{app-D8oqdt8J.css → app-BJd5vD4i.css} +1 -1
  8. package/assets/app-layout-DcgYmhNb.js +1 -0
  9. package/assets/{app-shell-CHEYhVco.js → app-shell-C8Cnr5Hy.js} +1 -1
  10. package/assets/app-sidebar-HwvXNZzk.js +1 -0
  11. package/assets/app-sidebar-header-C8TTx8yd.js +1 -0
  12. package/assets/app.js +5 -5
  13. package/assets/{breadcrumbs-C439DWrC.js → breadcrumbs-DSMzNYiS.js} +1 -1
  14. package/assets/catalog-C2INmTwI.js +6 -0
  15. package/assets/catalog-D4n6dpGl.css +1 -0
  16. package/assets/{dashboard-Bi5KeZu2.js → dashboard-DwFL6nqn.js} +1 -1
  17. package/assets/{date-picker-DbJ8nHp5.js → date-picker-kW3wZQr_.js} +1 -1
  18. package/assets/{del-modal-_b3CSNHb.js → del-modal-DyIWFflP.js} +1 -1
  19. package/assets/{field-renderer-4obZ_jUo.js → field-renderer-BNQVfOir.js} +3 -3
  20. package/assets/form-CAIoGuhZ.js +1 -0
  21. package/assets/form-NUd-JZJN.js +1 -0
  22. package/assets/{geo-json-CadjdhwW.js → geo-json-YeWQOYnT.js} +1 -1
  23. package/assets/{home-BUoDaWe0.js → home-CteDT1us.js} +2 -2
  24. package/assets/{icon-DM49pZW3.js → icon-DpkedrXG.js} +1 -1
  25. package/assets/{init-user-DNrB8Xt5.js → init-user-DaOvt0vG.js} +1 -1
  26. package/assets/{input-error--IOnWghB.js → input-error-CmXZF6xy.js} +1 -1
  27. package/assets/list-CXQmJbH8.js +1 -0
  28. package/assets/{list-table-BKxxQkCW.js → list-table-BPpHDVPf.js} +4 -4
  29. package/assets/{login-6Xb8bcPq.js → login-DR6fvKtm.js} +1 -1
  30. package/assets/manifest.json +82 -82
  31. package/assets/{material-icon-BedgD2NE.js → material-icon-DwkE6wKL.js} +1 -1
  32. package/assets/media-manager-DYOfUh8F.js +14 -0
  33. package/assets/{module-B4-7WkY5.js → module-BIUqcf4-.js} +1 -1
  34. package/assets/{nav-footer-BwkQkwow.js → nav-footer-B85HLj-j.js} +1 -1
  35. package/assets/{nav-main-9Eb_A0rf.js → nav-main-BqKm87JZ.js} +1 -1
  36. package/assets/nav-user-DuCZNsZX.js +1 -0
  37. package/assets/notification-BQTjxH2H.js +27 -0
  38. package/assets/pagination-render-io0M2m2O.js +1 -0
  39. package/assets/{register-BIyjCy8M.js → register-hJD1ETdf.js} +1 -1
  40. package/assets/{tabs-BK_5wdPA.js → tabs-BhkFoerH.js} +1 -1
  41. package/assets/{theme-switcher-CKiJbMkh.js → theme-switcher-cgyA7_cO.js} +1 -1
  42. package/assets/{toast-editor-BZM5RHph.js → toast-editor-DwRk6WqT.js} +1 -1
  43. package/assets/{user-info-CcYdmjMZ.js → user-info-BGQvqBmO.js} +1 -1
  44. package/assets/{user-menu-content-DbUk8ZeY.js → user-menu-content-BDm88xaM.js} +1 -1
  45. package/assets/welcome-ks57d2us.js +1 -0
  46. package/controllers/add.js +1 -1
  47. package/controllers/catalog/Catalog.js +21 -20
  48. package/controllers/catalog/FrontendCatalogAdapter.d.ts +82 -0
  49. package/controllers/catalog/FrontendCatalogAdapter.js +228 -0
  50. package/controllers/catalog/FrontentCatalogAdapter.d.ts +4 -4
  51. package/controllers/catalog/FrontentCatalogAdapter.js +28 -10
  52. package/controllers/edit.js +14 -5
  53. package/controllers/form.js +8 -6
  54. package/controllers/login.js +3 -0
  55. package/controllers/media-manager/ThumbController.js +1 -1
  56. package/controllers/media-manager/mediaManagerAdapter.js +1 -1
  57. package/controllers/media-manager/mediaManagerApi.js +1 -2
  58. package/controllers/notifications/NotificationController.d.ts +1 -1
  59. package/controllers/notifications/NotificationController.js +5 -4
  60. package/controllers/view.js +5 -3
  61. package/helpers/inertiaAddHelper.js +1 -2
  62. package/helpers/inertiaFromHelper.js +1 -2
  63. package/index.d.ts +5 -0
  64. package/index.js +5 -0
  65. package/interfaces/adminpanelConfig.d.ts +12 -0
  66. package/lib/Adminizer.d.ts +4 -3
  67. package/lib/Adminizer.js +16 -22
  68. package/lib/catalog/AbstractCatalog.d.ts +6 -4
  69. package/lib/catalog/AbstractCatalog.js +5 -4
  70. package/lib/catalog/Navigation.d.ts +9 -7
  71. package/lib/catalog/Navigation.js +69 -40
  72. package/lib/inertia/inertiaAdapter.js +31 -13
  73. package/lib/media-manager/AbstractMediaManager.d.ts +5 -3
  74. package/lib/media-manager/DefaultMediaManager.d.ts +3 -3
  75. package/lib/media-manager/DefaultMediaManager.js +18 -13
  76. package/lib/media-manager/Items.js +5 -4
  77. package/lib/media-manager/MediaManagerHandler.d.ts +3 -3
  78. package/lib/media-manager/MediaManagerHandler.js +3 -3
  79. package/lib/media-manager/Thumb.d.ts +2 -1
  80. package/lib/media-manager/Thumb.js +3 -4
  81. package/lib/media-manager/helpers/MediaManagerHelper.d.ts +7 -2
  82. package/lib/media-manager/helpers/MediaManagerHelper.js +12 -8
  83. package/lib/model/adapter/waterline.js +6 -0
  84. package/package.json +3 -1
  85. package/system/Router.js +10 -8
  86. package/system/bindAccessRights.js +7 -0
  87. package/system/bindCors.d.ts +2 -0
  88. package/system/bindCors.js +41 -0
  89. package/system/bindInertia.js +1 -1
  90. package/system/bindMediaManager.js +1 -2
  91. package/system/bindNavigation.d.ts +1 -1
  92. package/system/bindNavigation.js +33 -35
  93. package/system/bindNotifications.js +4 -4
  94. package/system/bindReqFunctions.js +4 -1
  95. package/system/defaults.js +8 -0
  96. package/translations/ru.json +121 -120
  97. package/ui/components/handsontable.js +6 -3
  98. package/ui/lib/utils.d.ts +1 -0
  99. package/ui/lib/utils.js +16 -0
  100. package/assets/add-1E1UsMVZ.js +0 -1
  101. package/assets/add-form-CGa9QbwE.js +0 -1
  102. package/assets/add-group-7yAK6uFY.js +0 -1
  103. package/assets/add-group-form-BNmpvW8K.js +0 -1
  104. package/assets/add-user-NoYkTfZi.js +0 -1
  105. package/assets/app-layout-i2zN9Rn-.js +0 -1
  106. package/assets/app-sidebar-DeF8WNmW.js +0 -1
  107. package/assets/app-sidebar-header-DdM1EOrb.js +0 -1
  108. package/assets/catalog-B9hdop59.js +0 -6
  109. package/assets/catalog-C71LuRag.css +0 -1
  110. package/assets/form-Bte5kzjB.js +0 -1
  111. package/assets/form-oUlsuu7h.js +0 -1
  112. package/assets/list-C04Krl_W.js +0 -1
  113. package/assets/media-manager-UQT6RhI8.js +0 -14
  114. package/assets/nav-user-CRAfyE-x.js +0 -1
  115. package/assets/notification-ma2x7vka.js +0 -27
  116. package/assets/pagination-render-D3UyVAlr.js +0 -1
  117. package/assets/welcome-cWh1qnl_.js +0 -1
@@ -1,4 +1,3 @@
1
- import { MediaManagerHandler } from "../MediaManagerHandler";
2
1
  /**
3
2
  * Create a random file name with prefix and type. If prefix is true, the file name will be prefixed with a random string.
4
3
  * @param filenameOrig
@@ -13,32 +12,37 @@ export function randomFileName(filenameOrig, type, prefix) {
13
12
  }
14
13
  /**
15
14
  * Save media manager relations to database.
15
+ * @param adminizer
16
16
  * @param fields
17
17
  * @param reqData
18
18
  * @param model
19
19
  * @param recordId
20
20
  */
21
- export async function saveRelationsMediaManager(fields, reqData, model, recordId) {
21
+ export async function saveRelationsMediaManager(adminizer, fields, reqData, model, recordId) {
22
22
  for (let prop in reqData) {
23
23
  let fieldConfigConfig = fields[prop].config;
24
24
  let options = fieldConfigConfig.options;
25
25
  if (fieldConfigConfig.type === 'mediamanager') {
26
26
  let data = reqData[prop];
27
- let mediaManager = MediaManagerHandler.get(options?.id ?? 'default');
27
+ let mediaManager = adminizer.mediaManagerHandler.get(options?.id ?? 'default');
28
28
  await mediaManager.setRelations(data, model, recordId, prop);
29
29
  }
30
30
  }
31
31
  }
32
32
  /**
33
33
  * Get realtions
34
+ * @param adminizer
34
35
  * @param data
36
+ * @param model
37
+ * @param widgetName
35
38
  */
36
- export async function getRelationsMediaManager(data) {
37
- let mediaManager = MediaManagerHandler.get(data.mediaManagerId);
38
- return await mediaManager.getItemsList(data.list ?? []);
39
+ export async function getRelationsMediaManager(adminizer, data) {
40
+ let mediaManager = adminizer.mediaManagerHandler.get(data.mediaManagerId);
41
+ return await mediaManager.getRelations(data.model, data.widgetName, data.modelId);
39
42
  }
40
43
  /**
41
44
  * Delate Ralations
45
+ * @param adminizer
42
46
  * @param model
43
47
  * @param record
44
48
  */
@@ -48,9 +52,9 @@ export async function deleteRelationsMediaManager(adminizer, model, record) {
48
52
  let field = config.fields[key];
49
53
  if (field && field.type === 'mediamanager') {
50
54
  const option = field.options;
51
- let mediaManager = MediaManagerHandler.get(option?.id ?? 'default');
55
+ let mediaManager = adminizer.mediaManagerHandler.get(option?.id ?? 'default');
52
56
  let emptyData = [];
53
- await mediaManager.setRelations(emptyData, model, record[0].id, key);
57
+ await mediaManager.setRelations(emptyData, model, +record[0].id, key);
54
58
  }
55
59
  }
56
60
  }
@@ -33,6 +33,12 @@ export class WaterlineModel extends AbstractModel {
33
33
  return await query;
34
34
  }
35
35
  async _find(criteria = {}, options = {}) {
36
+ // Hack
37
+ const attributes = this.model.attributes;
38
+ const associations = Object.keys(attributes).filter(attr => attributes[attr].model || attributes[attr].collection);
39
+ //@ts-ignore
40
+ if (associations.includes(criteria?.sort?.split(' ')[0]) && JSON.stringify(criteria.where) === '{}')
41
+ criteria.sort = undefined;
36
42
  let query = this.model.find(criteria);
37
43
  if (options.populate && Array.isArray(options.populate) && options.populate.length > 0) {
38
44
  options.populate.forEach(([field, populateCriteria]) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "adminizer",
3
3
  "type": "module",
4
- "version": "4.3.0-build.99",
4
+ "version": "4.3.0",
5
5
  "main": "index.js",
6
6
  "exports": {
7
7
  ".": "./index.js",
@@ -16,6 +16,7 @@
16
16
  "dev:no-seed-clean": "cross-env VITE_ENV=dev NO_SEED_DATA=true CLEAN_TMP=true ORM=sequelize tsx watch --tsconfig ./fixture/tsconfig.json ./fixture/index.ts",
17
17
  "dev:waterline": "cross-env VITE_ENV=dev ORM=waterline tsx watch --tsconfig ./fixture/tsconfig.json ./fixture/index.ts",
18
18
  "dev:waterline:no-seed": "cross-env VITE_ENV=dev NO_SEED_DATA=true ORM=waterline tsx watch --tsconfig ./fixture/tsconfig.json ./fixture/index.ts",
19
+ "dev:cors": "cross-env VITE_ENV=dev NO_SEED_DATA=true ORM=waterline FRONTEND_URL=http://localhost:8080 tsx watch --tsconfig ./fixture/tsconfig.json ./fixture/index.ts",
19
20
  "build:assets": "vite build",
20
21
  "compile:backend": "tsc -p src/tsconfig.json",
21
22
  "compile:ui": "tsc -p tsconfig.ui.json",
@@ -72,6 +73,7 @@
72
73
  "typeorm": "^0.3.20",
73
74
  "uuid": "^11.0.5",
74
75
  "waterline": "^0.15.2",
76
+ "sequelize": "^6.37.7",
75
77
  "winston": "^3.17.0"
76
78
  },
77
79
  "devDependencies": {
package/system/Router.js CHANGED
@@ -67,7 +67,9 @@ export default class Router {
67
67
  * Edit form
68
68
  * */
69
69
  adminizer.app.all(`${adminizer.config.routePrefix}/form/:slug`, adminizer.policyManager.bindPolicies(policies, _form));
70
- // Create a base entity route
70
+ /**
71
+ * Create a base entity route
72
+ */
71
73
  let baseRoute = `${adminizer.config.routePrefix}/:entityType(form|model)/:entityName`;
72
74
  /**
73
75
  * Catalog
@@ -91,13 +93,13 @@ export default class Router {
91
93
  if (adminizer.config.notifications.enabled) {
92
94
  adminizer.app.get(`${adminizer.config.routePrefix}/notifications`, adminizer.policyManager.bindPolicies(policies, NotificationController.viewAll));
93
95
  adminizer.app.post(`${adminizer.config.routePrefix}/notifications`, adminizer.policyManager.bindPolicies(policies, NotificationController.viewAll));
94
- adminizer.app.get(`${adminizer.config.routePrefix}/api/notifications/stream`, adminizer.policyManager.bindPolicies(policies, NotificationController.getNotificationsStream));
95
- adminizer.app.get(`${adminizer.config.routePrefix}/api/notifications/get-classes`, adminizer.policyManager.bindPolicies(policies, NotificationController.getNotificationClasses));
96
- adminizer.app.get(`${adminizer.config.routePrefix}/api/notifications/:notificationClass`, adminizer.policyManager.bindPolicies(policies, NotificationController.getNotificationsByClass));
97
- adminizer.app.get(`${adminizer.config.routePrefix}/api/notifications`, adminizer.policyManager.bindPolicies(policies, NotificationController.getUserNotifications));
98
- adminizer.app.put(`${adminizer.config.routePrefix}/api/notifications/:notificationClass/:id/read`, adminizer.policyManager.bindPolicies(policies, NotificationController.markAsRead));
99
- adminizer.app.put(`${adminizer.config.routePrefix}/api/notifications/read-all`, adminizer.policyManager.bindPolicies(policies, NotificationController.markAllAsRead));
100
- adminizer.app.post(`${adminizer.config.routePrefix}/api/notifications/search`, adminizer.policyManager.bindPolicies(policies, NotificationController.search));
96
+ adminizer.app.get(`${adminizer.config.routePrefix}/notifications/api/stream`, adminizer.policyManager.bindPolicies(policies, NotificationController.getNotificationsStream));
97
+ adminizer.app.get(`${adminizer.config.routePrefix}/notifications/api/get-classes`, adminizer.policyManager.bindPolicies(policies, NotificationController.getNotificationClasses));
98
+ adminizer.app.get(`${adminizer.config.routePrefix}/notifications/api/:notificationClass`, adminizer.policyManager.bindPolicies(policies, NotificationController.getNotificationsByClass));
99
+ adminizer.app.get(`${adminizer.config.routePrefix}/notifications/api`, adminizer.policyManager.bindPolicies(policies, NotificationController.getUserNotifications));
100
+ adminizer.app.put(`${adminizer.config.routePrefix}/notifications/api/:notificationClass/:id/read`, adminizer.policyManager.bindPolicies(policies, NotificationController.markAsRead));
101
+ adminizer.app.put(`${adminizer.config.routePrefix}/notifications/api/read-all`, adminizer.policyManager.bindPolicies(policies, NotificationController.markAllAsRead));
102
+ adminizer.app.post(`${adminizer.config.routePrefix}/notifications/api/search`, adminizer.policyManager.bindPolicies(policies, NotificationController.search));
101
103
  }
102
104
  /**
103
105
  * List of records
@@ -60,6 +60,13 @@ export default async function bindAccessRights(adminizer) {
60
60
  id: `widgets`, name: "Widgets",
61
61
  description: "Access to widgets", department: "Widgets"
62
62
  });
63
+ // Allow access login
64
+ adminizer.accessRightsHelper.registerToken({
65
+ id: 'access-to-adminpanel',
66
+ name: "Allowed log in",
67
+ description: "Are users allowed to log in to the admin panel?",
68
+ department: "Admin panel"
69
+ });
63
70
  // Default user group
64
71
  if (adminizer.config.registration && adminizer.config.registration.enable) {
65
72
  // TODO refactor CRUD functions for DataAccessor usage
@@ -0,0 +1,2 @@
1
+ import { Adminizer } from "../lib/Adminizer";
2
+ export declare function bindCors(adminizer: Adminizer): void;
@@ -0,0 +1,41 @@
1
+ export function bindCors(adminizer) {
2
+ if (adminizer.config?.cors?.enabled) {
3
+ const corsConfig = adminizer.config.cors;
4
+ // Поддерживаем массив разрешенных origin
5
+ const allowedOrigins = Array.isArray(corsConfig.origin)
6
+ ? corsConfig.origin
7
+ : [corsConfig.origin];
8
+ adminizer.app.all(`${adminizer.config.routePrefix}/${corsConfig.path}`, (req, res, next) => {
9
+ const requestOrigin = req.headers.origin;
10
+ // Проверяем разрешен ли origin
11
+ const isOriginAllowed = !requestOrigin || allowedOrigins.includes(requestOrigin);
12
+ if (requestOrigin && !isOriginAllowed) {
13
+ console.log(`❌ CORS: Blocked request from ${requestOrigin}`);
14
+ if (req.method === 'OPTIONS') {
15
+ // Для preflight - 200 без CORS headers
16
+ return res.status(200).end();
17
+ }
18
+ else {
19
+ // Для основных запросов - ошибка
20
+ return res.status(403).json({
21
+ error: 'CORS policy: Origin not allowed'
22
+ });
23
+ }
24
+ }
25
+ // Запрос с разрешенного origin или без Origin
26
+ if (isOriginAllowed) {
27
+ // Для CORS запросов возвращаем тот же origin (или первый из списка)
28
+ const allowOrigin = requestOrigin || allowedOrigins[0];
29
+ res.header('Access-Control-Allow-Origin', allowOrigin);
30
+ res.header('Access-Control-Allow-Credentials', corsConfig.credentials !== false ? 'true' : 'false');
31
+ res.header('Access-Control-Allow-Methods', corsConfig.methods?.join(',') || 'GET,POST,PUT,DELETE,OPTIONS');
32
+ res.header('Access-Control-Allow-Headers', corsConfig.allowedHeaders?.join(',') || 'Content-Type,Authorization,X-Requested-With,X-CSRF-Token,x-xsrf-token');
33
+ }
34
+ if (req.method === 'OPTIONS') {
35
+ return res.status(200).end();
36
+ }
37
+ next();
38
+ });
39
+ console.log('✅ API CORS middleware enabled. Allowed origins:', allowedOrigins);
40
+ }
41
+ }
@@ -102,7 +102,7 @@ export function bindInertia(adminizer) {
102
102
  enabled: true,
103
103
  cookieName: 'XSRF-TOKEN',
104
104
  headerName: 'x-xsrf-token'
105
- },
105
+ }
106
106
  }));
107
107
  adminizer.app.use((req, _, next) => {
108
108
  checkAuth(req, adminizer);
@@ -1,5 +1,4 @@
1
1
  import { DefaultMediaManager } from "../lib/media-manager/DefaultMediaManager";
2
- import { MediaManagerHandler } from "../lib/media-manager/MediaManagerHandler";
3
2
  import serveStatic from "serve-static";
4
3
  import path from "path";
5
4
  export default function bindMediaManager(adminizer) {
@@ -8,7 +7,7 @@ export default function bindMediaManager(adminizer) {
8
7
  adminizer.emitter.on("adminizer:loaded", async () => {
9
8
  try {
10
9
  let mediaManager = new DefaultMediaManager(adminizer, 'default', 'media-manager', adminizer.config.mediamanager.fileStoragePath);
11
- MediaManagerHandler.add(mediaManager);
10
+ adminizer.mediaManagerHandler.add(mediaManager);
12
11
  }
13
12
  catch (e) {
14
13
  console.log(e);
@@ -1,2 +1,2 @@
1
1
  import { Adminizer } from "../lib/Adminizer";
2
- export default function bindNavigation(adminizer: Adminizer): void;
2
+ export declare function bindNavigation(adminizer: Adminizer): Promise<void>;
@@ -1,40 +1,38 @@
1
1
  import { Navigation } from "../lib/catalog/Navigation";
2
- export default function bindNavigation(adminizer) {
3
- adminizer.emitter.on("adminizer:loaded", async () => {
4
- if (adminizer.config.navigation) {
5
- try {
6
- adminizer.config.navigation.model = adminizer.config.navigation.model ? adminizer.config.navigation.model : 'NavigationAP';
7
- let navigation = new Navigation(adminizer, adminizer.config.navigation);
8
- adminizer.catalogHandler.add(navigation);
9
- adminizer.config.models[adminizer.config.navigation.model.toLowerCase()] = {
10
- add: false,
11
- edit: {
12
- controller: '../controllers/navigation/edit',
13
- },
2
+ export async function bindNavigation(adminizer) {
3
+ if (adminizer.config.navigation) {
4
+ try {
5
+ adminizer.config.navigation.model = adminizer.config.navigation.model ? adminizer.config.navigation.model : 'NavigationAP';
6
+ let navigation = new Navigation(adminizer, adminizer.config.navigation);
7
+ adminizer.catalogHandler.add(navigation);
8
+ adminizer.config.models[adminizer.config.navigation.model.toLowerCase()] = {
9
+ add: false,
10
+ edit: {
11
+ controller: '../controllers/navigation/edit',
12
+ },
13
+ fields: {
14
+ createdAt: false,
15
+ updatedAt: false
16
+ },
17
+ navbar: {
18
+ visible: false
19
+ },
20
+ icon: 'storage',
21
+ identifierField: "",
22
+ list: {
14
23
  fields: {
15
- createdAt: false,
16
- updatedAt: false
17
- },
18
- navbar: {
19
- visible: false
24
+ tree: false,
25
+ id: false,
20
26
  },
21
- icon: 'storage',
22
- identifierField: "",
23
- list: {
24
- fields: {
25
- tree: false,
26
- id: false,
27
- },
28
- },
29
- model: adminizer.config.navigation.model.toLowerCase(),
30
- remove: false,
31
- title: adminizer.config.navigation.model,
32
- tools: []
33
- };
34
- }
35
- catch (e) {
36
- console.log('bindNavigation Error: ', e);
37
- }
27
+ },
28
+ model: adminizer.config.navigation.model.toLowerCase(),
29
+ remove: false,
30
+ title: adminizer.config.navigation.model,
31
+ tools: []
32
+ };
33
+ }
34
+ catch (e) {
35
+ console.log('bindNavigation Error: ', e);
38
36
  }
39
- });
37
+ }
40
38
  }
@@ -1,4 +1,3 @@
1
- import { Adminizer } from '../lib/Adminizer';
2
1
  import { NotificationHandler } from '../lib/notifications/NotificationHandler';
3
2
  import { GeneralNotificationService } from '../lib/notifications/GeneralNotificationService';
4
3
  import { SystemNotificationService } from '../lib/notifications/SystemNotificationService';
@@ -6,9 +5,10 @@ export async function bindNotifications(adminizer) {
6
5
  // Создаем хендлер
7
6
  adminizer.notificationHandler = new NotificationHandler();
8
7
  // Регистрируем сервисы
9
- const generalService = new GeneralNotificationService(adminizer);
10
8
  const systemService = new SystemNotificationService(adminizer);
11
- adminizer.notificationHandler.registerService(generalService);
12
9
  adminizer.notificationHandler.registerService(systemService);
13
- Adminizer.log.info(`Notification system initialized with 2 services: ${systemService.notificationClass}, ${systemService.notificationClass}`);
10
+ if (adminizer.config.notifications.enableGeneral) {
11
+ const generalService = new GeneralNotificationService(adminizer);
12
+ adminizer.notificationHandler.registerService(generalService);
13
+ }
14
14
  }
@@ -11,7 +11,10 @@ export default function bindReqFunctions(adminizer) {
11
11
  /**
12
12
  * Add i18n
13
13
  * */
14
- req.i18n = new I18n({ locales: adminizer.config.translation !== false ? adminizer.config.translation.locales : [] });
14
+ req.i18n = new I18n({
15
+ locales: adminizer.config.translation !== false ? adminizer.config.translation.locales : [],
16
+ directory: adminizer.config.translation !== false ? adminizer.config.translation.path ?? null : null
17
+ });
15
18
  if (res.locals) {
16
19
  req.i18n.registerMethods(res.locals, req);
17
20
  }
@@ -140,6 +140,14 @@ let adminpanelConfig = {
140
140
  },
141
141
  notifications: {
142
142
  enabled: false
143
+ },
144
+ cors: {
145
+ enabled: false,
146
+ origin: 'http://localhost:8080',
147
+ path: 'api/*'
148
+ },
149
+ mediamanager: {
150
+ fileStoragePath: '.tmp/public',
143
151
  }
144
152
  };
145
153
  export function setDefaultConfig(config) {
@@ -1,122 +1,123 @@
1
1
  {
2
- "Action completed": "Действие завершено",
3
- "Actions": "Действия",
4
- "All": "Все",
5
- "Are you sure?": "Вы уверены?",
6
- "Back": " Назад",
7
- "Back to Login": "Назад ко входу",
8
- "Additional login page": "Дополнительная страница входа",
9
- "Clean": "Очистить",
10
- "Confirm Password": "Подтвердите пароль",
11
- "Confirm Password*": "Подтвердите пароль*",
12
- "Create": "Создать",
13
- "Create a new administrator": "Создание нового администратора",
14
- "Create an Account": "Создать аккаунт",
15
- "Custom": "Пользовательский виджет",
16
- "Delete": "Удалить",
17
- "E-mail": "E-mail",
18
- "Edit": "Редактировать",
19
- "Email": "Электронная почта",
20
- "Fast links": "Быстрые ссылки",
21
- "Full Name": "Полное имя",
22
- "Full name": "Полное имя",
23
- "Group description": "Описание группы",
24
- "Group name": "Название группы",
25
- "Group settings": "Настройки группы",
26
- "Info": "Информация",
27
- "Is Administrator": "Администратор",
28
- "Is confirmed": "Подтверждено",
29
- "Link": "Ссылка",
30
- "Locale": "Локаль",
31
- "Log in": "Вход",
32
- "Login": "Вход",
33
- "Members": "Участники",
34
- "New record was created": "Новая запись создана",
35
- "No": "Нет",
36
- "No records found !": "Записей не найдено",
37
- "No widgets found": "Виджеты не найдены",
38
- "Not found": "Ничего не найдено",
39
- "OR": "ИЛИ",
40
- "Open in a new window": "Открывать в новом окне",
41
- "Password": "Пароль",
42
- "Passwords do not match!": "Пароли не совпадают!",
43
- "Performing an action...": "Выполняется действие...",
44
- "Please fill out the fields below": "Пожалуйста, заполните поля ниже",
45
- "Pretend to be a user": "Притворится пользователем",
46
- "Profile expires": "Профиль истекает",
47
- "Quick actions": "Быстрые действия",
48
- "Record was not removed": "Запись не удалена",
49
- "Record was removed successfully !": "Запись удалена успешно!",
50
- "Record was updated": "Запись обновлена",
51
- "Register": "Регистрация",
52
- "Repeat password": "Повторить пароль",
53
- "Reset": "Сброс",
54
- "Save": "Сохранить",
55
- "Search": "Поиск",
56
- "Select": "Выберите",
57
- "Select Ids": "Выберите ID",
58
- "Select Item type": "Выберите Элемент",
59
- "Select Items": "Ничего не выбрано",
60
- "Switcher": "Переключатель",
61
- "Timezone": "Временная зона",
62
- "Title": "Title",
63
- "Toggle to change the grid. To save the grid, turn it off.": "Переключите для изменения сетки. Чтобы сохранить сетку, отключите.",
64
- "User groups": "Группы пользователя",
65
- "User settings": "Настроики пользователя",
66
- "Values in \"password\" and \"repeatPassword\" fields should be the same": "Значения в полях \"password\" и \"repeatPassword\" должны быть одинаковыми.",
67
- "View": "Просмотреть",
68
- "Welcome": "Здравствуйте",
69
- "Yes": "Да",
70
- "You don't have any widgets selected yet. You can add them by clicking on the plus sign at the top right.": "У вас пока нет выбранных виджетов. Вы можете добавить их, нажав на значок плюса в правом верхнем углу.",
71
- "create": "Создать",
72
- "create new": "создать новую",
73
- "Widget Switcher One": "Widget Switcher One",
74
- "Site Switcher": "Site Switcher",
75
- "Widget Switcher Two": "Widget Switcher Two",
76
- "Switcher Two": "Switcher Two",
77
- "Test": "Test",
78
- "Add Test Model": "Add Test Model",
79
- "example.com": "example.com",
80
- "link to example.com": "link to example.com",
81
- "Global Settings": "Global Settings",
82
- "Info widget One": "Info widget One",
83
- "Info One": "Info One",
84
- "Info widget Two": "Info widget Two",
85
- "Info Two": "Info Two",
86
- "Info widget 3": "Info widget 3",
87
- "Info 31111": "Info 31111",
88
- "Info widget 4": "Info widget 4",
89
- "Info 4": "Info 4",
90
- "Action One": "Action One",
91
- "Action Two": "Action Two",
92
- "Widget Custom One": "Widget Custom One",
93
- "Site Custom": "Site Custom",
94
- "id": "id",
95
- "Textarea": "Textarea",
96
- "Disabled": "Disabled",
97
- "Boolean": "Boolean",
98
- "time": "time",
99
- "Number": "Number",
100
- "Editor": "Editor",
101
- "Date and time": "Date and time",
102
- "testRelationExample": "testRelationExample",
103
- "owner": "owner",
104
- "title": "title",
105
- "slug": "slug",
106
- "Images 1": "Images 1",
107
- "Images": "Изображения",
108
- "Videos": "Видео",
109
- "Texts": "Текст",
110
- "Applications": "Приложения",
111
- "Table": "Таблица",
112
- "Tile": "Плитка",
113
- "Load more": "Загрузить еще",
114
- "File": "Файл",
115
- "Name": "Имя",
116
- "Date": "Дата",
117
- "Type": "Тип",
118
- "Size (orig.)": "Размер (orig.)",
119
- "W x H (orig.)": "W x H (orig.)",
120
- "Sizes/Ver": "Sizes/Ver",
121
- "Locales": "Locales"
2
+ "Action completed": "Действие завершено",
3
+ "Actions": "Действия",
4
+ "All": "Все",
5
+ "Are you sure?": "Вы уверены?",
6
+ "Back": " Назад",
7
+ "Back to Login": "Назад ко входу",
8
+ "Additional login page": "Дополнительная страница входа",
9
+ "Clean": "Очистить",
10
+ "Confirm Password": "Подтвердите пароль",
11
+ "Confirm Password*": "Подтвердите пароль*",
12
+ "Create": "Создать",
13
+ "Create a new administrator": "Создание нового администратора",
14
+ "Create an Account": "Создать аккаунт",
15
+ "Custom": "Пользовательский виджет",
16
+ "Delete": "Удалить",
17
+ "E-mail": "E-mail",
18
+ "Edit": "Редактировать",
19
+ "Email": "Электронная почта",
20
+ "Fast links": "Быстрые ссылки",
21
+ "Full Name": "Полное имя",
22
+ "Full name": "Полное имя",
23
+ "Group description": "Описание группы",
24
+ "Group name": "Название группы",
25
+ "Group settings": "Настройки группы",
26
+ "Info": "Информация",
27
+ "Is Administrator": "Администратор",
28
+ "Is confirmed": "Подтверждено",
29
+ "Link": "Ссылка",
30
+ "Locale": "Локаль",
31
+ "Log in": "Вход",
32
+ "Login": "Вход",
33
+ "Members": "Участники",
34
+ "New record was created": "Новая запись создана",
35
+ "No": "Нет",
36
+ "No records found !": "Записей не найдено",
37
+ "No widgets found": "Виджеты не найдены",
38
+ "Not found": "Ничего не найдено",
39
+ "OR": "ИЛИ",
40
+ "Open in a new window": "Открывать в новом окне",
41
+ "Password": "Пароль",
42
+ "Passwords do not match!": "Пароли не совпадают!",
43
+ "Performing an action...": "Выполняется действие...",
44
+ "Please fill out the fields below": "Пожалуйста, заполните поля ниже",
45
+ "Pretend to be a user": "Притворится пользователем",
46
+ "Profile expires": "Профиль истекает",
47
+ "Quick actions": "Быстрые действия",
48
+ "Record was not removed": "Запись не удалена",
49
+ "Record was removed successfully !": "Запись удалена успешно!",
50
+ "Record was updated": "Запись обновлена",
51
+ "Register": "Регистрация",
52
+ "Repeat password": "Повторить пароль",
53
+ "Reset": "Сброс",
54
+ "Save": "Сохранить",
55
+ "Search": "Поиск",
56
+ "Select": "Выберите",
57
+ "Select Ids": "Выберите ID",
58
+ "Select Item type": "Выберите Элемент",
59
+ "Select Items": "Ничего не выбрано",
60
+ "Switcher": "Переключатель",
61
+ "Timezone": "Временная зона",
62
+ "Title": "Title",
63
+ "Toggle to change the grid. To save the grid, turn it off.": "Переключите для изменения сетки. Чтобы сохранить сетку, отключите.",
64
+ "User groups": "Группы пользователя",
65
+ "User settings": "Настроики пользователя",
66
+ "Values in \"password\" and \"repeatPassword\" fields should be the same": "Значения в полях \"password\" и \"repeatPassword\" должны быть одинаковыми.",
67
+ "View": "Просмотреть",
68
+ "Welcome": "Здравствуйте",
69
+ "Yes": "Да",
70
+ "You don't have any widgets selected yet. You can add them by clicking on the plus sign at the top right.": "У вас пока нет выбранных виджетов. Вы можете добавить их, нажав на значок плюса в правом верхнем углу.",
71
+ "create": "Создать",
72
+ "create new": "создать новую",
73
+ "Widget Switcher One": "Widget Switcher One",
74
+ "Site Switcher": "Site Switcher",
75
+ "Widget Switcher Two": "Widget Switcher Two",
76
+ "Switcher Two": "Switcher Two",
77
+ "Test": "Test",
78
+ "Add Test Model": "Add Test Model",
79
+ "example.com": "example.com",
80
+ "link to example.com": "link to example.com",
81
+ "Global Settings": "Global Settings",
82
+ "Info widget One": "Info widget One",
83
+ "Info One": "Info One",
84
+ "Info widget Two": "Info widget Two",
85
+ "Info Two": "Info Two",
86
+ "Info widget 3": "Info widget 3",
87
+ "Info 31111": "Info 31111",
88
+ "Info widget 4": "Info widget 4",
89
+ "Info 4": "Info 4",
90
+ "Action One": "Action One",
91
+ "Action Two": "Action Two",
92
+ "Widget Custom One": "Widget Custom One",
93
+ "Site Custom": "Site Custom",
94
+ "id": "id",
95
+ "Textarea": "Textarea",
96
+ "Disabled": "Disabled",
97
+ "Boolean": "Boolean",
98
+ "time": "time",
99
+ "Number": "Number",
100
+ "Editor": "Editor",
101
+ "Date and time": "Date and time",
102
+ "testRelationExample": "testRelationExample",
103
+ "owner": "owner",
104
+ "title": "title",
105
+ "slug": "slug",
106
+ "Images 1": "Images 1",
107
+ "Images": "Изображения",
108
+ "Videos": "Видео",
109
+ "Texts": "Текст",
110
+ "Applications": "Приложения",
111
+ "Table": "Таблица",
112
+ "Tile": "Плитка",
113
+ "Load more": "Загрузить еще",
114
+ "File": "Файл",
115
+ "Name": "Имя",
116
+ "Date": "Дата",
117
+ "Type": "Тип",
118
+ "Size (orig.)": "Размер (orig.)",
119
+ "W x H (orig.)": "W x H (orig.)",
120
+ "Sizes/Ver": "Sizes/Ver",
121
+ "Locales": "Locales",
122
+ "Leave this field empty if you don't want to change the password": "Оставьте это поле пустым, если не хотите менять пароль"
122
123
  }
@@ -34,9 +34,12 @@ const HandsonTable = ({ config, data = [], onChange, disabled }) => {
34
34
  }, []);
35
35
  const hotTableRef = useRef(null);
36
36
  useEffect(() => {
37
- if (hotTableRef.current) {
38
- hotTableRef.current.hotInstance.loadData(data);
39
- }
37
+ const timer = setTimeout(() => {
38
+ if (hotTableRef.current?.hotInstance) {
39
+ hotTableRef.current.hotInstance.loadData(data);
40
+ }
41
+ }, 100);
42
+ return () => clearTimeout(timer);
40
43
  }, [data]);
41
44
  useEffect(() => {
42
45
  if (appearance === 'dark') {
package/ui/lib/utils.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  import { type ClassValue } from "clsx";
2
2
  export declare function cn(...inputs: ClassValue[]): string;
3
+ export declare function simpleSanitizeHtml(html: string): string;