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.
- package/assets/add-9NSjG6Jx.js +1 -0
- package/assets/add-form-uUiOWEy_.js +1 -0
- package/assets/add-group-Db0HkA1m.js +1 -0
- package/assets/add-group-form-DMz0_Oo9.js +1 -0
- package/assets/add-user-BMklpOqf.js +1 -0
- package/assets/{add-user-form-DrclnTOd.js → add-user-form-izlXhv2-.js} +1 -1
- package/assets/{app-D8oqdt8J.css → app-BJd5vD4i.css} +1 -1
- package/assets/app-layout-DcgYmhNb.js +1 -0
- package/assets/{app-shell-CHEYhVco.js → app-shell-C8Cnr5Hy.js} +1 -1
- package/assets/app-sidebar-HwvXNZzk.js +1 -0
- package/assets/app-sidebar-header-C8TTx8yd.js +1 -0
- package/assets/app.js +5 -5
- package/assets/{breadcrumbs-C439DWrC.js → breadcrumbs-DSMzNYiS.js} +1 -1
- package/assets/catalog-C2INmTwI.js +6 -0
- package/assets/catalog-D4n6dpGl.css +1 -0
- package/assets/{dashboard-Bi5KeZu2.js → dashboard-DwFL6nqn.js} +1 -1
- package/assets/{date-picker-DbJ8nHp5.js → date-picker-kW3wZQr_.js} +1 -1
- package/assets/{del-modal-_b3CSNHb.js → del-modal-DyIWFflP.js} +1 -1
- package/assets/{field-renderer-4obZ_jUo.js → field-renderer-BNQVfOir.js} +3 -3
- package/assets/form-CAIoGuhZ.js +1 -0
- package/assets/form-NUd-JZJN.js +1 -0
- package/assets/{geo-json-CadjdhwW.js → geo-json-YeWQOYnT.js} +1 -1
- package/assets/{home-BUoDaWe0.js → home-CteDT1us.js} +2 -2
- package/assets/{icon-DM49pZW3.js → icon-DpkedrXG.js} +1 -1
- package/assets/{init-user-DNrB8Xt5.js → init-user-DaOvt0vG.js} +1 -1
- package/assets/{input-error--IOnWghB.js → input-error-CmXZF6xy.js} +1 -1
- package/assets/list-CXQmJbH8.js +1 -0
- package/assets/{list-table-BKxxQkCW.js → list-table-BPpHDVPf.js} +4 -4
- package/assets/{login-6Xb8bcPq.js → login-DR6fvKtm.js} +1 -1
- package/assets/manifest.json +82 -82
- package/assets/{material-icon-BedgD2NE.js → material-icon-DwkE6wKL.js} +1 -1
- package/assets/media-manager-DYOfUh8F.js +14 -0
- package/assets/{module-B4-7WkY5.js → module-BIUqcf4-.js} +1 -1
- package/assets/{nav-footer-BwkQkwow.js → nav-footer-B85HLj-j.js} +1 -1
- package/assets/{nav-main-9Eb_A0rf.js → nav-main-BqKm87JZ.js} +1 -1
- package/assets/nav-user-DuCZNsZX.js +1 -0
- package/assets/notification-BQTjxH2H.js +27 -0
- package/assets/pagination-render-io0M2m2O.js +1 -0
- package/assets/{register-BIyjCy8M.js → register-hJD1ETdf.js} +1 -1
- package/assets/{tabs-BK_5wdPA.js → tabs-BhkFoerH.js} +1 -1
- package/assets/{theme-switcher-CKiJbMkh.js → theme-switcher-cgyA7_cO.js} +1 -1
- package/assets/{toast-editor-BZM5RHph.js → toast-editor-DwRk6WqT.js} +1 -1
- package/assets/{user-info-CcYdmjMZ.js → user-info-BGQvqBmO.js} +1 -1
- package/assets/{user-menu-content-DbUk8ZeY.js → user-menu-content-BDm88xaM.js} +1 -1
- package/assets/welcome-ks57d2us.js +1 -0
- package/controllers/add.js +1 -1
- package/controllers/catalog/Catalog.js +21 -20
- package/controllers/catalog/FrontendCatalogAdapter.d.ts +82 -0
- package/controllers/catalog/FrontendCatalogAdapter.js +228 -0
- package/controllers/catalog/FrontentCatalogAdapter.d.ts +4 -4
- package/controllers/catalog/FrontentCatalogAdapter.js +28 -10
- package/controllers/edit.js +14 -5
- package/controllers/form.js +8 -6
- package/controllers/login.js +3 -0
- package/controllers/media-manager/ThumbController.js +1 -1
- package/controllers/media-manager/mediaManagerAdapter.js +1 -1
- package/controllers/media-manager/mediaManagerApi.js +1 -2
- package/controllers/notifications/NotificationController.d.ts +1 -1
- package/controllers/notifications/NotificationController.js +5 -4
- package/controllers/view.js +5 -3
- package/helpers/inertiaAddHelper.js +1 -2
- package/helpers/inertiaFromHelper.js +1 -2
- package/index.d.ts +5 -0
- package/index.js +5 -0
- package/interfaces/adminpanelConfig.d.ts +12 -0
- package/lib/Adminizer.d.ts +4 -3
- package/lib/Adminizer.js +16 -22
- package/lib/catalog/AbstractCatalog.d.ts +6 -4
- package/lib/catalog/AbstractCatalog.js +5 -4
- package/lib/catalog/Navigation.d.ts +9 -7
- package/lib/catalog/Navigation.js +69 -40
- package/lib/inertia/inertiaAdapter.js +31 -13
- package/lib/media-manager/AbstractMediaManager.d.ts +5 -3
- package/lib/media-manager/DefaultMediaManager.d.ts +3 -3
- package/lib/media-manager/DefaultMediaManager.js +18 -13
- package/lib/media-manager/Items.js +5 -4
- package/lib/media-manager/MediaManagerHandler.d.ts +3 -3
- package/lib/media-manager/MediaManagerHandler.js +3 -3
- package/lib/media-manager/Thumb.d.ts +2 -1
- package/lib/media-manager/Thumb.js +3 -4
- package/lib/media-manager/helpers/MediaManagerHelper.d.ts +7 -2
- package/lib/media-manager/helpers/MediaManagerHelper.js +12 -8
- package/lib/model/adapter/waterline.js +6 -0
- package/package.json +3 -1
- package/system/Router.js +10 -8
- package/system/bindAccessRights.js +7 -0
- package/system/bindCors.d.ts +2 -0
- package/system/bindCors.js +41 -0
- package/system/bindInertia.js +1 -1
- package/system/bindMediaManager.js +1 -2
- package/system/bindNavigation.d.ts +1 -1
- package/system/bindNavigation.js +33 -35
- package/system/bindNotifications.js +4 -4
- package/system/bindReqFunctions.js +4 -1
- package/system/defaults.js +8 -0
- package/translations/ru.json +121 -120
- package/ui/components/handsontable.js +6 -3
- package/ui/lib/utils.d.ts +1 -0
- package/ui/lib/utils.js +16 -0
- package/assets/add-1E1UsMVZ.js +0 -1
- package/assets/add-form-CGa9QbwE.js +0 -1
- package/assets/add-group-7yAK6uFY.js +0 -1
- package/assets/add-group-form-BNmpvW8K.js +0 -1
- package/assets/add-user-NoYkTfZi.js +0 -1
- package/assets/app-layout-i2zN9Rn-.js +0 -1
- package/assets/app-sidebar-DeF8WNmW.js +0 -1
- package/assets/app-sidebar-header-DdM1EOrb.js +0 -1
- package/assets/catalog-B9hdop59.js +0 -6
- package/assets/catalog-C71LuRag.css +0 -1
- package/assets/form-Bte5kzjB.js +0 -1
- package/assets/form-oUlsuu7h.js +0 -1
- package/assets/list-C04Krl_W.js +0 -1
- package/assets/media-manager-UQT6RhI8.js +0 -14
- package/assets/nav-user-CRAfyE-x.js +0 -1
- package/assets/notification-ma2x7vka.js +0 -27
- package/assets/pagination-render-D3UyVAlr.js +0 -1
- package/assets/welcome-cWh1qnl_.js +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AbstractCatalog, AbstractGroup, AbstractItem } from "./AbstractCatalog";
|
|
2
2
|
import { v4 as uuid } from "uuid";
|
|
3
3
|
import { Adminizer } from "../Adminizer";
|
|
4
|
-
class StorageService {
|
|
4
|
+
export class StorageService {
|
|
5
5
|
storageMap = new Map();
|
|
6
6
|
id;
|
|
7
7
|
model;
|
|
@@ -30,7 +30,7 @@ class StorageService {
|
|
|
30
30
|
return this.id;
|
|
31
31
|
}
|
|
32
32
|
async buildTree() {
|
|
33
|
-
const rootElements = await this.findElementsByParentId(
|
|
33
|
+
const rootElements = await this.findElementsByParentId(null, null);
|
|
34
34
|
const buildSubTree = async (elements) => {
|
|
35
35
|
const tree = [];
|
|
36
36
|
for (const element of elements) {
|
|
@@ -56,9 +56,9 @@ class StorageService {
|
|
|
56
56
|
return tree;
|
|
57
57
|
}
|
|
58
58
|
async populateFromTree(tree) {
|
|
59
|
-
const traverseTree = async (node, parentId =
|
|
59
|
+
const traverseTree = async (node, parentId = null) => {
|
|
60
60
|
const { children, ...itemData } = node;
|
|
61
|
-
const item = { ...itemData, parentId };
|
|
61
|
+
const item = { ...itemData, parentId: itemData.parentId === 0 ? null : itemData.parentId };
|
|
62
62
|
await this.setElement(item.id, item, true);
|
|
63
63
|
if (children && children.length > 0) {
|
|
64
64
|
for (const child of children) {
|
|
@@ -109,6 +109,8 @@ class StorageService {
|
|
|
109
109
|
async findElementsByParentId(parentId, type) {
|
|
110
110
|
const elements = [];
|
|
111
111
|
for (const item of this.storageMap.values()) {
|
|
112
|
+
if (parentId === 0)
|
|
113
|
+
parentId = null;
|
|
112
114
|
if (type === null && item.parentId === parentId) {
|
|
113
115
|
elements.push(item);
|
|
114
116
|
continue;
|
|
@@ -138,14 +140,16 @@ class StorageService {
|
|
|
138
140
|
}
|
|
139
141
|
}
|
|
140
142
|
export class StorageServices {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
storages = [];
|
|
144
|
+
constructor() {
|
|
145
|
+
}
|
|
146
|
+
add(storage) {
|
|
143
147
|
this.storages.push(storage);
|
|
144
148
|
}
|
|
145
|
-
|
|
149
|
+
get(id) {
|
|
146
150
|
return this.storages.find(storage => storage.getId() === id);
|
|
147
151
|
}
|
|
148
|
-
|
|
152
|
+
getAll() {
|
|
149
153
|
return this.storages;
|
|
150
154
|
}
|
|
151
155
|
}
|
|
@@ -155,17 +159,21 @@ export class Navigation extends AbstractCatalog {
|
|
|
155
159
|
icon = "box";
|
|
156
160
|
actionHandlers = [];
|
|
157
161
|
idList = [];
|
|
162
|
+
storageServices;
|
|
158
163
|
constructor(adminizer, config) {
|
|
159
164
|
let items = [];
|
|
165
|
+
const storageServices = new StorageServices();
|
|
160
166
|
for (const configElement of config.items) {
|
|
161
|
-
items.push(new NavigationItem(adminizer, configElement.title, configElement.model, config.model, configElement.urlPath));
|
|
167
|
+
items.push(new NavigationItem(adminizer, configElement.title, configElement.model, config.model, configElement.urlPath, storageServices));
|
|
162
168
|
}
|
|
163
|
-
items.push(new NavigationGroup(adminizer, config.groupField));
|
|
164
|
-
items.push(new LinkItem(adminizer));
|
|
169
|
+
items.push(new NavigationGroup(adminizer, config.groupField, storageServices));
|
|
170
|
+
items.push(new LinkItem(adminizer, storageServices));
|
|
171
|
+
super(adminizer, items);
|
|
172
|
+
this.storageServices = storageServices;
|
|
173
|
+
adminizer.storageServices = storageServices;
|
|
165
174
|
for (const section of config.sections) {
|
|
166
|
-
|
|
175
|
+
this.storageServices.add(new StorageService(adminizer, section, config.model));
|
|
167
176
|
}
|
|
168
|
-
super(adminizer, items);
|
|
169
177
|
this.movingGroupsRootOnly = config.movingGroupsRootOnly;
|
|
170
178
|
this.idList = config.sections ?? [];
|
|
171
179
|
}
|
|
@@ -183,7 +191,7 @@ class NavigationItem extends AbstractItem {
|
|
|
183
191
|
actionHandlers = [];
|
|
184
192
|
urlPath;
|
|
185
193
|
adminizer;
|
|
186
|
-
constructor(adminizer, name, model, navigationModel, urlPath) {
|
|
194
|
+
constructor(adminizer, name, model, navigationModel, urlPath, storageServices) {
|
|
187
195
|
super();
|
|
188
196
|
this.name = name;
|
|
189
197
|
this.navigationModel = navigationModel;
|
|
@@ -193,9 +201,10 @@ class NavigationItem extends AbstractItem {
|
|
|
193
201
|
let configModel = adminizer.config.models[this.model];
|
|
194
202
|
this.icon = configModel?.icon ?? 'file_present';
|
|
195
203
|
this.adminizer = adminizer;
|
|
204
|
+
this.storageServices = storageServices;
|
|
196
205
|
}
|
|
197
206
|
async create(data, catalogId) {
|
|
198
|
-
let storage =
|
|
207
|
+
let storage = this.storageServices.get(catalogId);
|
|
199
208
|
let storageData = null;
|
|
200
209
|
if (data._method === 'select') {
|
|
201
210
|
// Direct call by model adapter
|
|
@@ -203,7 +212,8 @@ class NavigationItem extends AbstractItem {
|
|
|
203
212
|
storageData = await this.dataPreparation({
|
|
204
213
|
record: record,
|
|
205
214
|
parentId: data.parentId,
|
|
206
|
-
targetBlank: data.targetBlank
|
|
215
|
+
targetBlank: data.targetBlank,
|
|
216
|
+
visible: data.visible
|
|
207
217
|
}, catalogId);
|
|
208
218
|
}
|
|
209
219
|
else {
|
|
@@ -212,13 +222,17 @@ class NavigationItem extends AbstractItem {
|
|
|
212
222
|
return await storage.setElement(data.id, storageData);
|
|
213
223
|
}
|
|
214
224
|
async dataPreparation(data, catalogId, sortOrder) {
|
|
215
|
-
let storage =
|
|
225
|
+
let storage = this.storageServices.get(catalogId);
|
|
216
226
|
let urlPath = eval('`' + this.urlPath + '`');
|
|
217
|
-
let parentId = data.parentId ? data.parentId :
|
|
227
|
+
let parentId = data.parentId ? data.parentId : null; // changed from 0 to null
|
|
228
|
+
if (parentId === 0)
|
|
229
|
+
parentId = null;
|
|
218
230
|
return {
|
|
219
231
|
id: uuid(),
|
|
220
232
|
modelId: data.record.id,
|
|
221
233
|
targetBlank: data.targetBlank ?? data.record.targetBlank,
|
|
234
|
+
visible: data.visible ?? data.record.visible,
|
|
235
|
+
isNavigation: true,
|
|
222
236
|
name: data.record.name ?? data.record.title ?? data.record.id,
|
|
223
237
|
parentId: parentId,
|
|
224
238
|
sortOrder: sortOrder ?? (await storage.findElementsByParentId(parentId, null)).length,
|
|
@@ -228,7 +242,7 @@ class NavigationItem extends AbstractItem {
|
|
|
228
242
|
};
|
|
229
243
|
}
|
|
230
244
|
async updateModelItems(modelId, data, catalogId) {
|
|
231
|
-
let storage =
|
|
245
|
+
let storage = this.storageServices.get(catalogId);
|
|
232
246
|
let items = await storage.findElementByModelId(modelId);
|
|
233
247
|
let urlPath = eval('`' + this.urlPath + '`');
|
|
234
248
|
let response = [];
|
|
@@ -237,21 +251,22 @@ class NavigationItem extends AbstractItem {
|
|
|
237
251
|
item.urlPath = urlPath;
|
|
238
252
|
if (item.id === data.record.treeId) {
|
|
239
253
|
item.targetBlank = data.record.targetBlank;
|
|
254
|
+
item.visible = data.record.visible;
|
|
240
255
|
}
|
|
241
256
|
response.push(await storage.setElement(item.id, item));
|
|
242
257
|
}
|
|
243
258
|
return response[0];
|
|
244
259
|
}
|
|
245
260
|
async update(itemId, data, catalogId) {
|
|
246
|
-
let storage =
|
|
261
|
+
let storage = this.storageServices.get(catalogId);
|
|
247
262
|
return await storage.setElement(itemId, data);
|
|
248
263
|
}
|
|
249
264
|
async deleteItem(itemId, catalogId) {
|
|
250
|
-
let storage =
|
|
265
|
+
let storage = this.storageServices.get(catalogId);
|
|
251
266
|
return await storage.removeElementById(itemId);
|
|
252
267
|
}
|
|
253
268
|
async find(itemId, catalogId) {
|
|
254
|
-
let storage =
|
|
269
|
+
let storage = this.storageServices.get(catalogId);
|
|
255
270
|
return await storage.findElementById(itemId);
|
|
256
271
|
}
|
|
257
272
|
/**
|
|
@@ -259,7 +274,7 @@ class NavigationItem extends AbstractItem {
|
|
|
259
274
|
* // TODO: need passing custom React module
|
|
260
275
|
*/
|
|
261
276
|
async getAddTemplate(req) {
|
|
262
|
-
let type = 'model';
|
|
277
|
+
let type = 'model.link';
|
|
263
278
|
// Direct call by model adapter
|
|
264
279
|
let itemsDB = await this.adminizer.modelHandler.model.get(this.model)["_find"]({});
|
|
265
280
|
let items = itemsDB.map((item) => {
|
|
@@ -278,24 +293,25 @@ class NavigationItem extends AbstractItem {
|
|
|
278
293
|
createTitle: `${req.i18n.__('create new')} ${req.i18n.__(this.name + 's')}`,
|
|
279
294
|
OR: req.i18n.__('OR'),
|
|
280
295
|
openInNewWindow: req.i18n.__('Open in a new window'),
|
|
296
|
+
visible: req.i18n.__('Visible')
|
|
281
297
|
}
|
|
282
298
|
}
|
|
283
299
|
};
|
|
284
300
|
}
|
|
285
301
|
async getChilds(parentId, catalogId) {
|
|
286
|
-
let storage =
|
|
302
|
+
let storage = this.storageServices.get(catalogId);
|
|
287
303
|
return await storage.findElementsByParentId(parentId, this.type);
|
|
288
304
|
}
|
|
289
305
|
async getEditTemplate(id, catalogId, req, modelId) {
|
|
290
306
|
return Promise.resolve({
|
|
291
|
-
type: 'model',
|
|
307
|
+
type: 'model.link',
|
|
292
308
|
data: {
|
|
293
309
|
item: await this.find(id, catalogId)
|
|
294
310
|
}
|
|
295
311
|
});
|
|
296
312
|
}
|
|
297
313
|
async search(s, catalogId) {
|
|
298
|
-
let storage =
|
|
314
|
+
let storage = this.storageServices.get(catalogId);
|
|
299
315
|
return await storage.search(s, this.type);
|
|
300
316
|
}
|
|
301
317
|
}
|
|
@@ -304,13 +320,14 @@ class NavigationGroup extends AbstractGroup {
|
|
|
304
320
|
name = "Group";
|
|
305
321
|
groupField;
|
|
306
322
|
adminizer;
|
|
307
|
-
constructor(adminizer, groupField) {
|
|
323
|
+
constructor(adminizer, groupField, storageServices) {
|
|
308
324
|
super();
|
|
309
325
|
this.groupField = groupField;
|
|
310
326
|
this.adminizer = adminizer;
|
|
327
|
+
this.storageServices = storageServices;
|
|
311
328
|
}
|
|
312
329
|
async create(data, catalogId) {
|
|
313
|
-
let storage =
|
|
330
|
+
let storage = this.storageServices.get(catalogId);
|
|
314
331
|
let storageData = await this.dataPreparation(data, catalogId);
|
|
315
332
|
delete data.name;
|
|
316
333
|
delete data.parentId;
|
|
@@ -318,12 +335,16 @@ class NavigationGroup extends AbstractGroup {
|
|
|
318
335
|
return await storage.setElement(storageData.id, storageData);
|
|
319
336
|
}
|
|
320
337
|
async dataPreparation(data, catalogId, sortOrder) {
|
|
321
|
-
let storage =
|
|
322
|
-
let parentId = data.parentId ? data.parentId :
|
|
338
|
+
let storage = this.storageServices.get(catalogId);
|
|
339
|
+
let parentId = data.parentId ? data.parentId : null; // changed from 0 to null
|
|
340
|
+
if (parentId === 0)
|
|
341
|
+
parentId = null;
|
|
323
342
|
return {
|
|
324
343
|
id: uuid(),
|
|
325
344
|
name: data.name,
|
|
326
345
|
targetBlank: data.targetBlank,
|
|
346
|
+
visible: data.visible,
|
|
347
|
+
isNavigation: true,
|
|
327
348
|
parentId: parentId,
|
|
328
349
|
sortOrder: sortOrder ?? (await storage.findElementsByParentId(parentId, null)).length,
|
|
329
350
|
icon: this.icon,
|
|
@@ -331,19 +352,19 @@ class NavigationGroup extends AbstractGroup {
|
|
|
331
352
|
};
|
|
332
353
|
}
|
|
333
354
|
async deleteItem(itemId, catalogId) {
|
|
334
|
-
let storage =
|
|
355
|
+
let storage = this.storageServices.get(catalogId);
|
|
335
356
|
return await storage.removeElementById(itemId);
|
|
336
357
|
}
|
|
337
358
|
async find(itemId, catalogId) {
|
|
338
|
-
let storage =
|
|
359
|
+
let storage = this.storageServices.get(catalogId);
|
|
339
360
|
return await storage.findElementById(itemId);
|
|
340
361
|
}
|
|
341
362
|
async update(itemId, data, catalogId) {
|
|
342
|
-
let storage =
|
|
363
|
+
let storage = this.storageServices.get(catalogId);
|
|
343
364
|
return await storage.setElement(itemId, data);
|
|
344
365
|
}
|
|
345
366
|
async updateModelItems(modelId, data, catalogId) {
|
|
346
|
-
let storage =
|
|
367
|
+
let storage = this.storageServices.get(catalogId);
|
|
347
368
|
return await storage.setElement(modelId, data);
|
|
348
369
|
}
|
|
349
370
|
getAddTemplate(req) {
|
|
@@ -353,6 +374,7 @@ class NavigationGroup extends AbstractGroup {
|
|
|
353
374
|
resItems = this.groupField.map((field) => {
|
|
354
375
|
return {
|
|
355
376
|
name: field.name,
|
|
377
|
+
label: field.label,
|
|
356
378
|
required: field.required
|
|
357
379
|
};
|
|
358
380
|
});
|
|
@@ -363,6 +385,7 @@ class NavigationGroup extends AbstractGroup {
|
|
|
363
385
|
items: resItems,
|
|
364
386
|
labels: {
|
|
365
387
|
openInNewWindow: req.i18n.__('Open in a new window'),
|
|
388
|
+
visible: req.i18n.__('Visible'),
|
|
366
389
|
title: req.i18n.__('Title'),
|
|
367
390
|
save: req.i18n.__('Save')
|
|
368
391
|
}
|
|
@@ -377,6 +400,7 @@ class NavigationGroup extends AbstractGroup {
|
|
|
377
400
|
resItems = this.groupField.map((field) => {
|
|
378
401
|
return {
|
|
379
402
|
name: field.name,
|
|
403
|
+
label: field.label,
|
|
380
404
|
required: field.required
|
|
381
405
|
};
|
|
382
406
|
});
|
|
@@ -388,6 +412,7 @@ class NavigationGroup extends AbstractGroup {
|
|
|
388
412
|
item: item,
|
|
389
413
|
labels: {
|
|
390
414
|
openInNewWindow: req.i18n.__('Open in a new window'),
|
|
415
|
+
visible: req.i18n.__('Visible'),
|
|
391
416
|
title: req.i18n.__('Title'),
|
|
392
417
|
save: req.i18n.__('Save')
|
|
393
418
|
}
|
|
@@ -395,11 +420,11 @@ class NavigationGroup extends AbstractGroup {
|
|
|
395
420
|
});
|
|
396
421
|
}
|
|
397
422
|
async getChilds(parentId, catalogId) {
|
|
398
|
-
let storage =
|
|
423
|
+
let storage = this.storageServices.get(catalogId);
|
|
399
424
|
return await storage.findElementsByParentId(parentId, this.type);
|
|
400
425
|
}
|
|
401
426
|
async search(s, catalogId) {
|
|
402
|
-
let storage =
|
|
427
|
+
let storage = this.storageServices.get(catalogId);
|
|
403
428
|
return await storage.search(s, this.type);
|
|
404
429
|
}
|
|
405
430
|
}
|
|
@@ -409,14 +434,15 @@ class LinkItem extends NavigationGroup {
|
|
|
409
434
|
name = 'Link';
|
|
410
435
|
type = 'link';
|
|
411
436
|
isGroup = false;
|
|
412
|
-
constructor(adminizer) {
|
|
413
|
-
super(adminizer, []);
|
|
437
|
+
constructor(adminizer, storageServices) {
|
|
438
|
+
super(adminizer, [], storageServices);
|
|
414
439
|
}
|
|
415
440
|
getAddTemplate(req) {
|
|
416
441
|
let type = 'navigation.link';
|
|
417
442
|
let resItems = [
|
|
418
443
|
{
|
|
419
|
-
|
|
444
|
+
label: req.i18n.__('Link'),
|
|
445
|
+
name: "link",
|
|
420
446
|
required: true
|
|
421
447
|
}
|
|
422
448
|
];
|
|
@@ -427,6 +453,7 @@ class LinkItem extends NavigationGroup {
|
|
|
427
453
|
labels: {
|
|
428
454
|
title: req.i18n.__('Title'),
|
|
429
455
|
openInNewWindow: req.i18n.__('Open in a new window'),
|
|
456
|
+
visible: req.i18n.__('Visible'),
|
|
430
457
|
save: req.i18n.__('Save')
|
|
431
458
|
}
|
|
432
459
|
}
|
|
@@ -437,7 +464,8 @@ class LinkItem extends NavigationGroup {
|
|
|
437
464
|
let type = 'navigation.group';
|
|
438
465
|
let resItems = [
|
|
439
466
|
{
|
|
440
|
-
|
|
467
|
+
label: req.i18n.__('Link'),
|
|
468
|
+
name: 'link',
|
|
441
469
|
required: true
|
|
442
470
|
}
|
|
443
471
|
];
|
|
@@ -448,6 +476,7 @@ class LinkItem extends NavigationGroup {
|
|
|
448
476
|
item: item,
|
|
449
477
|
labels: {
|
|
450
478
|
openInNewWindow: req.i18n.__('Open in a new window'),
|
|
479
|
+
visible: req.i18n.__('Visible'),
|
|
451
480
|
title: req.i18n.__('Title'),
|
|
452
481
|
save: req.i18n.__('Save')
|
|
453
482
|
}
|
|
@@ -11,19 +11,24 @@ const inertiaExpressAdapter = function ({ version, html, flashMessages, enableRe
|
|
|
11
11
|
}) {
|
|
12
12
|
return (req, res, next) => {
|
|
13
13
|
if (csrf.enabled) {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
14
|
+
const isApiRoute = isApiRequest(req);
|
|
15
|
+
if (!isApiRoute) {
|
|
16
|
+
const csrfToken = randomBytes(32).toString('hex');
|
|
17
|
+
res.cookie('XSRF-TOKEN', csrfToken, {
|
|
18
|
+
httpOnly: false,
|
|
19
|
+
secure: process.env.NODE_ENV === 'production' && process.env.CSRF_COOKIE_INSECURE !== '1',
|
|
20
|
+
sameSite: 'lax',
|
|
21
|
+
});
|
|
22
|
+
// Проверяем CSRF только для не-GET запросов И не-API routes
|
|
23
|
+
if (!['GET', 'HEAD', 'OPTIONS'].includes(req.method)) {
|
|
24
|
+
const csrfCookie = req.cookies['XSRF-TOKEN'];
|
|
25
|
+
const csrfHeader = req.headers[csrf.headerName || 'x-xsrf-token'];
|
|
26
|
+
if (!csrfCookie || !csrfHeader || csrfCookie !== csrfHeader) {
|
|
27
|
+
return res.status(403).json({
|
|
28
|
+
message: 'Invalid CSRF token',
|
|
29
|
+
type: 'csrf_error'
|
|
30
|
+
});
|
|
31
|
+
}
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
}
|
|
@@ -129,4 +134,17 @@ const inertiaExpressAdapter = function ({ version, html, flashMessages, enableRe
|
|
|
129
134
|
return next();
|
|
130
135
|
};
|
|
131
136
|
};
|
|
137
|
+
// Вспомогательная функция для определения API routes
|
|
138
|
+
function isApiRequest(req) {
|
|
139
|
+
const adminizer = req.adminizer;
|
|
140
|
+
if (!adminizer?.config?.cors?.enabled) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
const corsConfig = adminizer.config.cors;
|
|
144
|
+
const routePrefix = adminizer.config.routePrefix || '';
|
|
145
|
+
// Создаем базовый путь для API
|
|
146
|
+
const apiBasePath = `${routePrefix}/${corsConfig.path?.replace('*', '')}`;
|
|
147
|
+
// Проверяем начинается ли путь с API base path
|
|
148
|
+
return req.path.startsWith(apiBasePath);
|
|
149
|
+
}
|
|
132
150
|
export default inertiaExpressAdapter;
|
|
@@ -36,8 +36,10 @@ export interface MediaManagerWidgetClientItem extends MediaManagerWidgetItem {
|
|
|
36
36
|
url?: string;
|
|
37
37
|
}
|
|
38
38
|
export interface MediaManagerWidgetJSON {
|
|
39
|
-
list: MediaManagerWidgetItem[];
|
|
40
39
|
mediaManagerId: string;
|
|
40
|
+
model: string;
|
|
41
|
+
widgetName: string;
|
|
42
|
+
modelId: string | number;
|
|
41
43
|
}
|
|
42
44
|
export interface MediaManagerWidgetData {
|
|
43
45
|
id: string;
|
|
@@ -207,8 +209,8 @@ export declare abstract class AbstractMediaManager {
|
|
|
207
209
|
/**
|
|
208
210
|
* widget Id in the model in which the mediafile was added
|
|
209
211
|
*/
|
|
210
|
-
modelId:
|
|
211
|
-
abstract
|
|
212
|
+
modelId: number, widgetName: string): Promise<void>;
|
|
213
|
+
abstract getRelations(model: string, widgetName: string, modelId: string | number): Promise<MediaManagerWidgetClientItem[]>;
|
|
212
214
|
/**
|
|
213
215
|
* Search all items.
|
|
214
216
|
* If not this.allowSearch = true then it will not come here
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AbstractMediaManager, MediaManagerItem, File,
|
|
1
|
+
import { AbstractMediaManager, MediaManagerItem, File, MediaManagerWidgetData, MediaManagerWidgetClientItem, SortCriteria } from "./AbstractMediaManager";
|
|
2
2
|
import { Adminizer } from "../Adminizer";
|
|
3
3
|
export declare class DefaultMediaManager extends AbstractMediaManager {
|
|
4
4
|
readonly itemTypes: File<MediaManagerItem>[];
|
|
@@ -12,6 +12,6 @@ export declare class DefaultMediaManager extends AbstractMediaManager {
|
|
|
12
12
|
next: boolean;
|
|
13
13
|
}>;
|
|
14
14
|
searchAll(s: string, group: string): Promise<MediaManagerItem[]>;
|
|
15
|
-
setRelations(data: MediaManagerWidgetData[], model: string, modelId:
|
|
16
|
-
|
|
15
|
+
setRelations(data: MediaManagerWidgetData[], model: string, modelId: number, widgetName: string): Promise<void>;
|
|
16
|
+
getRelations(model: string, widgetName: string, modelId: string | number): Promise<MediaManagerWidgetClientItem[]>;
|
|
17
17
|
}
|
|
@@ -57,7 +57,7 @@ export class DefaultMediaManager extends AbstractMediaManager {
|
|
|
57
57
|
}
|
|
58
58
|
async setRelations(data, model, modelId, widgetName) {
|
|
59
59
|
let modelAssociations = await this.adminizer.modelHandler.model.get(this.modelAssoc)["_find"]({
|
|
60
|
-
where: { modelId: modelId, model: model, widgetName: widgetName },
|
|
60
|
+
where: { modelId: +modelId, model: model.toLowerCase(), widgetName: widgetName },
|
|
61
61
|
});
|
|
62
62
|
for (const modelAssociation of modelAssociations) {
|
|
63
63
|
const q = {};
|
|
@@ -69,26 +69,31 @@ export class DefaultMediaManager extends AbstractMediaManager {
|
|
|
69
69
|
for (const [key, widgetItem] of data.entries()) {
|
|
70
70
|
await this.adminizer.modelHandler.model.get(this.modelAssoc)["_create"]({
|
|
71
71
|
mediaManagerId: this.id,
|
|
72
|
-
model: model,
|
|
73
|
-
modelId: modelId,
|
|
72
|
+
model: model.toLowerCase(),
|
|
73
|
+
modelId: +modelId,
|
|
74
74
|
[fieldName]: widgetItem.id,
|
|
75
75
|
widgetName: widgetName,
|
|
76
76
|
sortOrder: key + 1,
|
|
77
77
|
});
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
async
|
|
80
|
+
async getRelations(model, widgetName, modelId) {
|
|
81
81
|
let widgetItems = [];
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
const fieldName = this.adminizer.ormAdapters[0].ormType === 'sequelize' ? 'fileRef' : 'file';
|
|
83
|
+
let files = await this.adminizer.modelHandler.model.get(this.modelAssoc)['_find']({
|
|
84
|
+
where: {
|
|
85
|
+
model: model.toLowerCase(),
|
|
86
|
+
widgetName: widgetName,
|
|
87
|
+
modelId: +modelId
|
|
88
|
+
},
|
|
89
|
+
sort: "sortOrder ASC"
|
|
90
|
+
}, { populate: [[fieldName, {}]] });
|
|
91
|
+
for (const file of files) {
|
|
87
92
|
widgetItems.push({
|
|
88
|
-
id: file.id,
|
|
89
|
-
mimeType: file.mimeType,
|
|
90
|
-
url: file.url,
|
|
91
|
-
variants:
|
|
93
|
+
id: file[fieldName].id,
|
|
94
|
+
mimeType: file[fieldName].mimeType,
|
|
95
|
+
url: file[fieldName].url,
|
|
96
|
+
variants: []
|
|
92
97
|
});
|
|
93
98
|
}
|
|
94
99
|
return widgetItems;
|
|
@@ -4,6 +4,7 @@ import sizeOf from "image-size";
|
|
|
4
4
|
import sharp from "sharp";
|
|
5
5
|
import * as fs from 'fs';
|
|
6
6
|
import * as path from 'path';
|
|
7
|
+
import * as process from "node:process";
|
|
7
8
|
export class ImageItem extends File {
|
|
8
9
|
type = "image";
|
|
9
10
|
model = "mediamanagerap";
|
|
@@ -55,7 +56,7 @@ export class ImageItem extends File {
|
|
|
55
56
|
parent: null,
|
|
56
57
|
mimeType: file.mimetype,
|
|
57
58
|
size: file.size,
|
|
58
|
-
path:
|
|
59
|
+
path: `${this.fileStoragePath}/${this.urlPathPrefix}/${filename}`,
|
|
59
60
|
group: group,
|
|
60
61
|
tag: "origin",
|
|
61
62
|
filename: origFileName,
|
|
@@ -64,7 +65,7 @@ export class ImageItem extends File {
|
|
|
64
65
|
await this.createMeta(parent.id);
|
|
65
66
|
await this.addFileMeta(file.path, parent.id);
|
|
66
67
|
// create file variants
|
|
67
|
-
if (Object.keys(this.imageSizes).length) {
|
|
68
|
+
if (Object.keys(this.imageSizes).length && file.mimetype !== 'image/svg+xml') {
|
|
68
69
|
await this.createVariants(file, parent, filename, group);
|
|
69
70
|
}
|
|
70
71
|
// TODO refactor CRUD functions for DataAccessor usage
|
|
@@ -148,7 +149,7 @@ export class ImageItem extends File {
|
|
|
148
149
|
}
|
|
149
150
|
async resizeImage(input, output, width, height) {
|
|
150
151
|
// Get the directory from the output path
|
|
151
|
-
const outputDir = path.dirname(output)
|
|
152
|
+
const outputDir = `${process.cwd()}/${path.dirname(output)}`;
|
|
152
153
|
// Check if the directory exists, and create it if it doesn't
|
|
153
154
|
if (!fs.existsSync(outputDir)) {
|
|
154
155
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
@@ -209,7 +210,7 @@ export class TextItem extends ImageItem {
|
|
|
209
210
|
parent: null,
|
|
210
211
|
mimeType: file.mimetype,
|
|
211
212
|
size: file.size,
|
|
212
|
-
path:
|
|
213
|
+
path: `${this.fileStoragePath}/${filename}`,
|
|
213
214
|
group: group,
|
|
214
215
|
filename: origFileName,
|
|
215
216
|
tag: "origin",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AbstractMediaManager } from "./AbstractMediaManager";
|
|
2
2
|
export declare class MediaManagerHandler {
|
|
3
|
-
private
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
private managers;
|
|
4
|
+
add(manager: AbstractMediaManager): void;
|
|
5
|
+
get(id: string): AbstractMediaManager;
|
|
6
6
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Adminizer } from "../Adminizer";
|
|
2
2
|
export class MediaManagerHandler {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
managers = [];
|
|
4
|
+
add(manager) {
|
|
5
5
|
this.managers.push(manager);
|
|
6
6
|
}
|
|
7
|
-
|
|
7
|
+
get(id) {
|
|
8
8
|
let instance = this.managers.find(e => e.id === id);
|
|
9
9
|
/**
|
|
10
10
|
* ✨ We magically get one
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Adminizer } from "../Adminizer";
|
|
1
2
|
export declare class MediaManagerThumb {
|
|
2
|
-
static getThumb(id: string, managerId: string): Promise<Buffer<ArrayBufferLike>>;
|
|
3
|
+
static getThumb(id: string, managerId: string, adminizer: Adminizer): Promise<Buffer<ArrayBufferLike>>;
|
|
3
4
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import sharp from "sharp";
|
|
2
2
|
import { promises as fs } from 'fs';
|
|
3
|
-
import { MediaManagerHandler } from "./MediaManagerHandler";
|
|
4
3
|
export class MediaManagerThumb {
|
|
5
|
-
static async getThumb(id, managerId) {
|
|
4
|
+
static async getThumb(id, managerId, adminizer) {
|
|
6
5
|
const fileExists = async (path) => !!(await fs.stat(path).catch(e => false));
|
|
7
|
-
const manager =
|
|
6
|
+
const manager = adminizer.mediaManagerHandler.get(managerId);
|
|
8
7
|
const path = await manager.getOrigin(id);
|
|
9
8
|
const baseThumbPath = `${process.cwd()}/.tmp/thumbs`;
|
|
10
9
|
await fs.mkdir(baseThumbPath, { recursive: true });
|
|
@@ -13,7 +12,7 @@ export class MediaManagerThumb {
|
|
|
13
12
|
return await fs.readFile(thumb);
|
|
14
13
|
}
|
|
15
14
|
else {
|
|
16
|
-
await sharp(path)
|
|
15
|
+
await sharp(`${process.cwd()}/${path}`)
|
|
17
16
|
.resize({ width: 150, height: 150 })
|
|
18
17
|
.toFile(thumb);
|
|
19
18
|
return await fs.readFile(thumb);
|
|
@@ -11,19 +11,24 @@ type PostParams = Record<string, string | number | boolean | object | string[] |
|
|
|
11
11
|
export declare function randomFileName(filenameOrig: string, type: string, prefix: boolean): string;
|
|
12
12
|
/**
|
|
13
13
|
* Save media manager relations to database.
|
|
14
|
+
* @param adminizer
|
|
14
15
|
* @param fields
|
|
15
16
|
* @param reqData
|
|
16
17
|
* @param model
|
|
17
18
|
* @param recordId
|
|
18
19
|
*/
|
|
19
|
-
export declare function saveRelationsMediaManager(fields: Fields, reqData: PostParams, model: string, recordId:
|
|
20
|
+
export declare function saveRelationsMediaManager(adminizer: Adminizer, fields: Fields, reqData: PostParams, model: string, recordId: number): Promise<void>;
|
|
20
21
|
/**
|
|
21
22
|
* Get realtions
|
|
23
|
+
* @param adminizer
|
|
22
24
|
* @param data
|
|
25
|
+
* @param model
|
|
26
|
+
* @param widgetName
|
|
23
27
|
*/
|
|
24
|
-
export declare function getRelationsMediaManager(data: MediaManagerWidgetJSON): Promise<import("../AbstractMediaManager").MediaManagerWidgetClientItem[]>;
|
|
28
|
+
export declare function getRelationsMediaManager(adminizer: Adminizer, data: MediaManagerWidgetJSON): Promise<import("../AbstractMediaManager").MediaManagerWidgetClientItem[]>;
|
|
25
29
|
/**
|
|
26
30
|
* Delate Ralations
|
|
31
|
+
* @param adminizer
|
|
27
32
|
* @param model
|
|
28
33
|
* @param record
|
|
29
34
|
*/
|