@saltcorn/server 0.8.0-beta.1 → 0.8.0-beta.3
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/auth/admin.js +3 -19
- package/locales/en.json +10 -2
- package/locales/it.json +1 -1
- package/locales/ru.json +25 -1
- package/markup/admin.js +3 -11
- package/markup/forms.js +27 -23
- package/package.json +8 -8
- package/public/saltcorn.js +2 -2
- package/routes/admin.js +136 -142
- package/routes/fields.js +15 -4
- package/routes/files.js +83 -22
- package/routes/homepage.js +70 -64
- package/routes/infoarch.js +10 -7
- package/routes/menu.js +22 -12
- package/routes/page.js +6 -1
- package/routes/plugins.js +112 -106
- package/routes/tables.js +3 -1
- package/routes/utils.js +3 -2
- package/s3storage.js +24 -11
package/routes/fields.js
CHANGED
|
@@ -66,7 +66,7 @@ const fieldForm = async (req, fkey_opts, existing_names, id, hasData) => {
|
|
|
66
66
|
return new Form({
|
|
67
67
|
action: "/field",
|
|
68
68
|
validator: (vs) => {
|
|
69
|
-
if (vs.calculated && vs.type
|
|
69
|
+
if (vs.calculated && vs.type === "File")
|
|
70
70
|
return req.__("Calculated fields cannot have File type");
|
|
71
71
|
if (vs.calculated && vs.type.startsWith("Key to"))
|
|
72
72
|
return req.__("Calculated fields cannot have Key type");
|
|
@@ -182,8 +182,8 @@ const fieldFlow = (req) =>
|
|
|
182
182
|
new Workflow({
|
|
183
183
|
action: "/field",
|
|
184
184
|
onDone: async (context) => {
|
|
185
|
-
const thetype = getState().types[context.type];
|
|
186
|
-
|
|
185
|
+
//const thetype = getState().types[context.type];
|
|
186
|
+
const attributes = context.attributes || {};
|
|
187
187
|
attributes.default = context.default;
|
|
188
188
|
attributes.summary_field = context.summary_field;
|
|
189
189
|
attributes.include_fts = context.include_fts;
|
|
@@ -291,6 +291,8 @@ const fieldFlow = (req) =>
|
|
|
291
291
|
form: async (context) => {
|
|
292
292
|
if (context.type === "File") {
|
|
293
293
|
const roles = await User.get_roles();
|
|
294
|
+
const default_file_accept_filter = await getState().getConfig("files_accept_filter_default");
|
|
295
|
+
//console.log("default_file_accept_filter",default_file_accept_filter);
|
|
294
296
|
return new Form({
|
|
295
297
|
fields: [
|
|
296
298
|
{
|
|
@@ -310,6 +312,15 @@ const fieldFlow = (req) =>
|
|
|
310
312
|
"Deleting a row will also delete the file referenced by this field"
|
|
311
313
|
),
|
|
312
314
|
},
|
|
315
|
+
{
|
|
316
|
+
name: "files_accept_filter",
|
|
317
|
+
type: "String",
|
|
318
|
+
label: req.__("Files accept filter"),
|
|
319
|
+
sublabel: req.__(
|
|
320
|
+
"Specifies a filter for what file types the user can pick from the file input dialog box. Example is `.doc,audio/*,video/*,image/*`"
|
|
321
|
+
),
|
|
322
|
+
default: default_file_accept_filter,
|
|
323
|
+
},
|
|
313
324
|
],
|
|
314
325
|
});
|
|
315
326
|
} else {
|
|
@@ -634,7 +645,7 @@ router.post(
|
|
|
634
645
|
);
|
|
635
646
|
|
|
636
647
|
/**
|
|
637
|
-
*
|
|
648
|
+
* Test formula
|
|
638
649
|
* @function
|
|
639
650
|
* @memberof module:routes/fields~fieldsRouter
|
|
640
651
|
* @function
|
package/routes/files.js
CHANGED
|
@@ -13,24 +13,12 @@ const s3storage = require("../s3storage");
|
|
|
13
13
|
const resizer = require("resize-with-sharp-or-jimp");
|
|
14
14
|
const db = require("@saltcorn/data/db");
|
|
15
15
|
|
|
16
|
-
const {
|
|
17
|
-
mkTable,
|
|
18
|
-
renderForm,
|
|
19
|
-
link,
|
|
20
|
-
//post_btn,
|
|
21
|
-
post_delete_btn,
|
|
22
|
-
} = require("@saltcorn/markup");
|
|
16
|
+
const { renderForm } = require("@saltcorn/markup");
|
|
23
17
|
const { isAdmin, error_catcher, setTenant } = require("./utils.js");
|
|
24
|
-
const { h1, div, text
|
|
25
|
-
// const { csrfField } = require("./utils");
|
|
18
|
+
const { h1, div, text } = require("@saltcorn/markup/tags");
|
|
26
19
|
const { editRoleForm, fileUploadForm } = require("../markup/forms.js");
|
|
27
20
|
const { strictParseInt } = require("@saltcorn/data/plugin-helper");
|
|
28
|
-
const {
|
|
29
|
-
send_files_page,
|
|
30
|
-
config_fields_form,
|
|
31
|
-
save_config_from_form,
|
|
32
|
-
} = require("../markup/admin");
|
|
33
|
-
// const fsp = require("fs").promises;
|
|
21
|
+
const { send_files_page, config_fields_form, save_config_from_form } = require("../markup/admin");
|
|
34
22
|
const fs = require("fs");
|
|
35
23
|
const path = require("path");
|
|
36
24
|
|
|
@@ -74,7 +62,6 @@ router.get(
|
|
|
74
62
|
const safeDir = File.normalise(dir || "/")
|
|
75
63
|
const rows = await File.find({ folder: dir }, { orderBy: "filename" });
|
|
76
64
|
const roles = await User.get_roles();
|
|
77
|
-
//console.log(rows);
|
|
78
65
|
if (safeDir && safeDir !== "/" && safeDir !== ".") {
|
|
79
66
|
let dirname = path.dirname(safeDir)
|
|
80
67
|
if (dirname === ".") dirname = "/"
|
|
@@ -314,7 +301,7 @@ router.post(
|
|
|
314
301
|
*/
|
|
315
302
|
router.post(
|
|
316
303
|
"/upload",
|
|
317
|
-
setTenant,
|
|
304
|
+
setTenant,
|
|
318
305
|
error_catcher(async (req, res) => {
|
|
319
306
|
let { folder } = req.body
|
|
320
307
|
let jsonResp = {};
|
|
@@ -395,12 +382,12 @@ router.post(
|
|
|
395
382
|
);
|
|
396
383
|
|
|
397
384
|
/**
|
|
398
|
-
* Storage settings form definition
|
|
385
|
+
* S3 Storage settings form definition
|
|
399
386
|
* @param {object} req request
|
|
400
387
|
* @returns {Promise<Form>} form
|
|
401
388
|
*/
|
|
402
389
|
const storage_form = async (req) => {
|
|
403
|
-
|
|
390
|
+
return await config_fields_form({
|
|
404
391
|
req,
|
|
405
392
|
field_names: [
|
|
406
393
|
"storage_s3_enabled",
|
|
@@ -414,11 +401,10 @@ const storage_form = async (req) => {
|
|
|
414
401
|
],
|
|
415
402
|
action: "/files/storage",
|
|
416
403
|
});
|
|
417
|
-
return form;
|
|
418
404
|
};
|
|
419
405
|
|
|
420
406
|
/**
|
|
421
|
-
*
|
|
407
|
+
* Show S3 Settings
|
|
422
408
|
* @function
|
|
423
409
|
* @memberof module:routes/admin~routes/adminRouter
|
|
424
410
|
*/
|
|
@@ -441,7 +427,7 @@ router.get(
|
|
|
441
427
|
);
|
|
442
428
|
|
|
443
429
|
/**
|
|
444
|
-
*
|
|
430
|
+
* Update S3 Settings
|
|
445
431
|
* @function
|
|
446
432
|
* @memberof module:routes/admin~routes/adminRouter
|
|
447
433
|
*/
|
|
@@ -472,3 +458,78 @@ router.post(
|
|
|
472
458
|
}
|
|
473
459
|
})
|
|
474
460
|
);
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Files settings form definition
|
|
464
|
+
* @param {object} req request
|
|
465
|
+
* @returns {Promise<Form>} form
|
|
466
|
+
*/
|
|
467
|
+
const files_settings_form = async (req) => {
|
|
468
|
+
return await config_fields_form({
|
|
469
|
+
req,
|
|
470
|
+
field_names: [
|
|
471
|
+
"min_role_upload",
|
|
472
|
+
"file_accept_filter_default",
|
|
473
|
+
"file_upload_debug",
|
|
474
|
+
"file_upload_limit",
|
|
475
|
+
"file_upload_timeout",
|
|
476
|
+
],
|
|
477
|
+
action: "/files/settings",
|
|
478
|
+
});
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Show Files Settings
|
|
483
|
+
* @function
|
|
484
|
+
* @memberof module:routes/admin~routes/adminRouter
|
|
485
|
+
*/
|
|
486
|
+
router.get(
|
|
487
|
+
"/settings",
|
|
488
|
+
isAdmin,
|
|
489
|
+
error_catcher(async (req, res) => {
|
|
490
|
+
const form = await files_settings_form(req);
|
|
491
|
+
send_files_page({
|
|
492
|
+
res,
|
|
493
|
+
req,
|
|
494
|
+
active_sub: "Settings",
|
|
495
|
+
contents: {
|
|
496
|
+
type: "card",
|
|
497
|
+
title: req.__("Files settings"),
|
|
498
|
+
contents: [renderForm(form, req.csrfToken())],
|
|
499
|
+
},
|
|
500
|
+
});
|
|
501
|
+
})
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Update Files Settings
|
|
506
|
+
* @function
|
|
507
|
+
* @memberof module:routes/admin~routes/adminRouter
|
|
508
|
+
*/
|
|
509
|
+
router.post(
|
|
510
|
+
"/settings",
|
|
511
|
+
isAdmin,
|
|
512
|
+
error_catcher(async (req, res) => {
|
|
513
|
+
const form = await files_settings_form(req);
|
|
514
|
+
form.validate(req.body);
|
|
515
|
+
if (form.hasErrors) {
|
|
516
|
+
send_admin_page({
|
|
517
|
+
res,
|
|
518
|
+
req,
|
|
519
|
+
active_sub: "Settings",
|
|
520
|
+
contents: {
|
|
521
|
+
type: "card",
|
|
522
|
+
title: req.__("Files settings"),
|
|
523
|
+
contents: [renderForm(form, req.csrfToken())],
|
|
524
|
+
},
|
|
525
|
+
});
|
|
526
|
+
} else {
|
|
527
|
+
await save_config_from_form(form);
|
|
528
|
+
|
|
529
|
+
if (!req.xhr) {
|
|
530
|
+
req.flash("success", req.__("Files settings updated"));
|
|
531
|
+
res.redirect("/files/settings");
|
|
532
|
+
} else res.json({ success: "ok" });
|
|
533
|
+
}
|
|
534
|
+
})
|
|
535
|
+
);
|
package/routes/homepage.js
CHANGED
|
@@ -15,7 +15,7 @@ const Page = require("@saltcorn/data/models/page");
|
|
|
15
15
|
const { link, mkTable } = require("@saltcorn/markup");
|
|
16
16
|
const { div, a, p, i } = require("@saltcorn/markup/tags");
|
|
17
17
|
const Table = require("@saltcorn/data/models/table");
|
|
18
|
-
const {
|
|
18
|
+
const { get_cached_packs } = require("@saltcorn/admin-models/models/pack");
|
|
19
19
|
// const { restore_backup } = require("../markup/admin");
|
|
20
20
|
const { get_latest_npm_version } = require("@saltcorn/data/models/config");
|
|
21
21
|
const packagejson = require("../package.json");
|
|
@@ -54,9 +54,9 @@ const tableCard = (tables, req) => ({
|
|
|
54
54
|
contents:
|
|
55
55
|
(tables.length <= 1
|
|
56
56
|
? p(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
{ class: "mt-2 pe-2" },
|
|
58
|
+
i(req.__("Tables organise data by fields and rows."))
|
|
59
|
+
)
|
|
60
60
|
: "") + tableTable(tables, req),
|
|
61
61
|
bodyClass: "py-0 pe-0",
|
|
62
62
|
footer: div(
|
|
@@ -107,13 +107,13 @@ const viewCard = (views, req) => ({
|
|
|
107
107
|
contents:
|
|
108
108
|
(views.length <= 1
|
|
109
109
|
? p(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
{ class: "mt-2 pe-2" },
|
|
111
|
+
i(
|
|
112
|
+
req.__(
|
|
113
|
+
"Views display data from tables. A view is a view pattern applied to a table, with configuration."
|
|
114
|
+
)
|
|
114
115
|
)
|
|
115
116
|
)
|
|
116
|
-
)
|
|
117
117
|
: "") +
|
|
118
118
|
(views.length > 0 ? viewTable(views, req) : p(req.__("No views"))),
|
|
119
119
|
|
|
@@ -160,13 +160,13 @@ const pageCard = (pages, req) => ({
|
|
|
160
160
|
contents:
|
|
161
161
|
(pages.length <= 1
|
|
162
162
|
? p(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
163
|
+
{ class: "mt-2 pe-2" },
|
|
164
|
+
i(
|
|
165
|
+
req.__(
|
|
166
|
+
"Pages are the web pages of your application built with a drag-and-drop builder. They have static content, and by embedding views, dynamic content."
|
|
167
|
+
)
|
|
167
168
|
)
|
|
168
169
|
)
|
|
169
|
-
)
|
|
170
170
|
: "") +
|
|
171
171
|
(pages.length > 0
|
|
172
172
|
? pageTable(pages, req)
|
|
@@ -191,16 +191,19 @@ const filesTab = async (req) => {
|
|
|
191
191
|
files.length === 0
|
|
192
192
|
? p(req.__("No files"))
|
|
193
193
|
: mkTable(
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
194
|
+
[
|
|
195
|
+
{
|
|
196
|
+
label: req.__("Filename"),
|
|
197
|
+
key: (r) =>
|
|
198
|
+
r.isDirectory
|
|
199
|
+
? r.filename
|
|
200
|
+
: link(`/files/serve/${r.path_to_serve}`, r.filename),
|
|
201
|
+
},
|
|
202
|
+
{ label: req.__("Size (KiB)"), key: "size_kb", align: "right" },
|
|
203
|
+
{ label: req.__("Media type"), key: (r) => r.mimetype },
|
|
204
|
+
],
|
|
205
|
+
files
|
|
206
|
+
),
|
|
204
207
|
fileUploadForm(req)
|
|
205
208
|
);
|
|
206
209
|
};
|
|
@@ -244,30 +247,30 @@ const actionsTab = async (req, triggers) => {
|
|
|
244
247
|
return div(
|
|
245
248
|
{ class: "pb-3" },
|
|
246
249
|
triggers.length <= 1 &&
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
250
|
+
p(
|
|
251
|
+
{ class: "mt-2 pe-2" },
|
|
252
|
+
i(req.__("Triggers run actions in response to events."))
|
|
253
|
+
),
|
|
251
254
|
triggers.length === 0
|
|
252
255
|
? p(req.__("No triggers"))
|
|
253
256
|
: mkTable(
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
257
|
+
[
|
|
258
|
+
{ label: req.__("Name"), key: "name" },
|
|
259
|
+
{ label: req.__("Action"), key: "action" },
|
|
260
|
+
{
|
|
261
|
+
label: req.__("Table or Channel"),
|
|
262
|
+
key: (r) => r.table_name || r.channel,
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
label: req.__("When"),
|
|
266
|
+
key: (a) =>
|
|
267
|
+
a.when_trigger === "API call"
|
|
268
|
+
? `API: ${base_url}api/action/${a.name}`
|
|
269
|
+
: a.when_trigger,
|
|
270
|
+
},
|
|
271
|
+
],
|
|
272
|
+
triggers
|
|
273
|
+
),
|
|
271
274
|
a(
|
|
272
275
|
{ href: "/actions/new", class: "btn btn-secondary my-3" },
|
|
273
276
|
req.__("Add trigger")
|
|
@@ -350,7 +353,7 @@ const helpCard = (req) =>
|
|
|
350
353
|
* @returns {Promise<object>}
|
|
351
354
|
*/
|
|
352
355
|
const welcome_page = async (req) => {
|
|
353
|
-
const packs_available = await
|
|
356
|
+
const packs_available = await get_cached_packs();
|
|
354
357
|
const packlist = [
|
|
355
358
|
...(packs_available || []).slice(0, 5),
|
|
356
359
|
{ name: req.__("More..."), description: "" },
|
|
@@ -385,15 +388,15 @@ const welcome_page = async (req) => {
|
|
|
385
388
|
tabContents:
|
|
386
389
|
triggers.length > 0
|
|
387
390
|
? {
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
391
|
+
Triggers: await actionsTab(req, triggers),
|
|
392
|
+
Files: await filesTab(req),
|
|
393
|
+
Packs: packTab(req, packlist),
|
|
394
|
+
}
|
|
392
395
|
: {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
396
|
+
Packs: packTab(req, packlist),
|
|
397
|
+
Triggers: await actionsTab(req, triggers),
|
|
398
|
+
Files: await filesTab(req),
|
|
399
|
+
},
|
|
397
400
|
},
|
|
398
401
|
{
|
|
399
402
|
type: "card",
|
|
@@ -403,13 +406,13 @@ const welcome_page = async (req) => {
|
|
|
403
406
|
tabContents:
|
|
404
407
|
users.length > 4
|
|
405
408
|
? {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
+
Users: await usersTab(req, users, roleMap),
|
|
410
|
+
Help: helpCard(req),
|
|
411
|
+
}
|
|
409
412
|
: {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
+
Help: helpCard(req),
|
|
414
|
+
Users: await usersTab(req, users, roleMap),
|
|
415
|
+
},
|
|
413
416
|
},
|
|
414
417
|
],
|
|
415
418
|
},
|
|
@@ -429,9 +432,12 @@ const no_views_logged_in = async (req, res) => {
|
|
|
429
432
|
res.sendWrap(req.__("Hello"), req.__("Welcome to Saltcorn!"));
|
|
430
433
|
else {
|
|
431
434
|
const isRoot = db.getTenantSchema() === db.connectObj.default_schema;
|
|
432
|
-
const latest =
|
|
435
|
+
const latest =
|
|
436
|
+
isRoot && (await get_latest_npm_version("@saltcorn/cli", 500));
|
|
433
437
|
const can_update =
|
|
434
|
-
packagejson.version !== latest &&
|
|
438
|
+
packagejson.version !== latest &&
|
|
439
|
+
latest &&
|
|
440
|
+
!process.env.SALTCORN_DISABLE_UPGRADE;
|
|
435
441
|
if (latest && can_update && isRoot)
|
|
436
442
|
req.flash(
|
|
437
443
|
"warning",
|
|
@@ -440,8 +446,8 @@ const no_views_logged_in = async (req, res) => {
|
|
|
440
446
|
packagejson.version,
|
|
441
447
|
latest
|
|
442
448
|
) +
|
|
443
|
-
|
|
444
|
-
|
|
449
|
+
" " +
|
|
450
|
+
a({ href: "/admin/system" }, req.__("Upgrade here"))
|
|
445
451
|
);
|
|
446
452
|
|
|
447
453
|
res.sendWrap(req.__("Hello"), await welcome_page(req));
|
package/routes/infoarch.js
CHANGED
|
@@ -45,11 +45,11 @@ router.get(
|
|
|
45
45
|
* @param {object} req
|
|
46
46
|
* @returns {Form}
|
|
47
47
|
*/
|
|
48
|
-
const languageForm = (req) =>
|
|
48
|
+
const languageForm = (req, hasSaveButton) =>
|
|
49
49
|
new Form({
|
|
50
50
|
action: "/site-structure/localizer/save-lang",
|
|
51
|
-
onChange: "saveAndContinue(this)",
|
|
52
|
-
noSubmitButton:
|
|
51
|
+
onChange: hasSaveButton ? undefined : "saveAndContinue(this)",
|
|
52
|
+
noSubmitButton: !hasSaveButton,
|
|
53
53
|
fields: [
|
|
54
54
|
{
|
|
55
55
|
name: "name",
|
|
@@ -60,15 +60,18 @@ const languageForm = (req) =>
|
|
|
60
60
|
{
|
|
61
61
|
name: "locale",
|
|
62
62
|
label: req.__("Locale"),
|
|
63
|
-
sublabel: req.__(
|
|
63
|
+
sublabel: req.__(
|
|
64
|
+
"Locale identifier short code, e.g. en, zh, fr, ar etc. "
|
|
65
|
+
),
|
|
64
66
|
type: "String",
|
|
65
67
|
required: true,
|
|
66
68
|
},
|
|
67
69
|
{
|
|
68
70
|
name: "is_default",
|
|
69
71
|
label: req.__("Default language"),
|
|
70
|
-
sublabel:
|
|
71
|
-
|
|
72
|
+
sublabel: req.__(
|
|
73
|
+
"Is this the default language in which the application is built?"
|
|
74
|
+
),
|
|
72
75
|
type: "Bool",
|
|
73
76
|
},
|
|
74
77
|
],
|
|
@@ -150,7 +153,7 @@ router.get(
|
|
|
150
153
|
sub2_page: "New",
|
|
151
154
|
contents: {
|
|
152
155
|
type: "card",
|
|
153
|
-
contents: [renderForm(languageForm(req), req.csrfToken())],
|
|
156
|
+
contents: [renderForm(languageForm(req, true), req.csrfToken())],
|
|
154
157
|
},
|
|
155
158
|
});
|
|
156
159
|
})
|
package/routes/menu.js
CHANGED
|
@@ -25,7 +25,6 @@ const Table = require("@saltcorn/data/models/table");
|
|
|
25
25
|
const Trigger = require("@saltcorn/data/models/trigger");
|
|
26
26
|
const { run_action_column } = require("@saltcorn/data/plugin-helper");
|
|
27
27
|
|
|
28
|
-
|
|
29
28
|
/**
|
|
30
29
|
* @type {object}
|
|
31
30
|
* @const
|
|
@@ -107,7 +106,7 @@ const menuForm = async (req) => {
|
|
|
107
106
|
"Dynamic",
|
|
108
107
|
"Search",
|
|
109
108
|
"Separator",
|
|
110
|
-
"Action"
|
|
109
|
+
"Action",
|
|
111
110
|
],
|
|
112
111
|
},
|
|
113
112
|
{
|
|
@@ -117,7 +116,15 @@ const menuForm = async (req) => {
|
|
|
117
116
|
input_type: "text",
|
|
118
117
|
required: true,
|
|
119
118
|
showIf: {
|
|
120
|
-
type: [
|
|
119
|
+
type: [
|
|
120
|
+
"View",
|
|
121
|
+
"Page",
|
|
122
|
+
"Link",
|
|
123
|
+
"Header",
|
|
124
|
+
"Dynamic",
|
|
125
|
+
"Search",
|
|
126
|
+
"Action",
|
|
127
|
+
],
|
|
121
128
|
},
|
|
122
129
|
},
|
|
123
130
|
{
|
|
@@ -244,7 +251,9 @@ const menuForm = async (req) => {
|
|
|
244
251
|
class: "item-menu",
|
|
245
252
|
type: "String",
|
|
246
253
|
required: true,
|
|
247
|
-
showIf: {
|
|
254
|
+
showIf: {
|
|
255
|
+
type: ["View", "Page", "Link", "Header", "Dynamic", "Action"],
|
|
256
|
+
},
|
|
248
257
|
attributes: {
|
|
249
258
|
options: [
|
|
250
259
|
{ name: "", label: "Link" },
|
|
@@ -266,7 +275,9 @@ const menuForm = async (req) => {
|
|
|
266
275
|
{
|
|
267
276
|
name: "location",
|
|
268
277
|
label: req.__("Location"),
|
|
269
|
-
showIf: {
|
|
278
|
+
showIf: {
|
|
279
|
+
type: ["View", "Page", "Link", "Header", "Dynamic", "Action"],
|
|
280
|
+
},
|
|
270
281
|
sublabel: req.__("Not all themes support all locations"),
|
|
271
282
|
class: "item-menu",
|
|
272
283
|
type: "String",
|
|
@@ -440,15 +451,14 @@ router.post(
|
|
|
440
451
|
const state = getState();
|
|
441
452
|
const menu_items = state.getConfig("menu_items");
|
|
442
453
|
let menu_item;
|
|
443
|
-
const search = items =>
|
|
454
|
+
const search = (items) =>
|
|
444
455
|
items
|
|
445
456
|
.filter((item) => role <= +item.min_role)
|
|
446
|
-
.forEach(item => {
|
|
457
|
+
.forEach((item) => {
|
|
447
458
|
if (item.type === "Action" && item.action_name === name)
|
|
448
459
|
menu_item = item;
|
|
449
|
-
else if (item.subitems)
|
|
450
|
-
|
|
451
|
-
})
|
|
460
|
+
else if (item.subitems) search(item.subitems);
|
|
461
|
+
});
|
|
452
462
|
search(menu_items);
|
|
453
463
|
if (menu_item)
|
|
454
464
|
try {
|
|
@@ -456,12 +466,12 @@ router.post(
|
|
|
456
466
|
col: menu_item,
|
|
457
467
|
referrer: req.get("Referrer"),
|
|
458
468
|
req,
|
|
469
|
+
res,
|
|
459
470
|
});
|
|
460
471
|
res.json({ success: "ok", ...(result || {}) });
|
|
461
472
|
} catch (e) {
|
|
462
473
|
res.status(400).json({ error: e.message || e });
|
|
463
474
|
}
|
|
464
|
-
|
|
465
475
|
else res.status(404).json({ error: "Action not found" });
|
|
466
476
|
})
|
|
467
|
-
);
|
|
477
|
+
);
|
package/routes/page.js
CHANGED
|
@@ -8,7 +8,11 @@ const Router = require("express-promise-router");
|
|
|
8
8
|
|
|
9
9
|
const Page = require("@saltcorn/data/models/page");
|
|
10
10
|
const { getState } = require("@saltcorn/data/db/state");
|
|
11
|
-
const {
|
|
11
|
+
const {
|
|
12
|
+
error_catcher,
|
|
13
|
+
scan_for_page_title,
|
|
14
|
+
isAdmin,
|
|
15
|
+
} = require("../routes/utils.js");
|
|
12
16
|
const { add_edit_bar } = require("../markup/admin.js");
|
|
13
17
|
const { traverseSync } = require("@saltcorn/data/models/layout");
|
|
14
18
|
const { run_action_column } = require("@saltcorn/data/plugin-helper");
|
|
@@ -105,6 +109,7 @@ router.post(
|
|
|
105
109
|
col,
|
|
106
110
|
referrer: req.get("Referrer"),
|
|
107
111
|
req,
|
|
112
|
+
res,
|
|
108
113
|
});
|
|
109
114
|
res.json({ success: "ok", ...(result || {}) });
|
|
110
115
|
} catch (e) {
|