@saltcorn/server 0.8.0-beta.2 → 0.8.0-beta.4
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 +70 -52
- 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 +173 -164
- package/routes/utils.js +3 -2
- package/routes/view.js +9 -2
- package/s3storage.js +24 -11
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) {
|