@saltcorn/server 0.7.4-beta.3 → 0.7.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/app.js +26 -12
- package/auth/routes.js +41 -27
- package/locales/en.json +10 -1
- package/package.json +7 -7
- package/public/saltcorn-common.js +86 -21
- package/public/saltcorn.css +16 -10
- package/public/saltcorn.js +13 -7
- package/routes/actions.js +15 -5
- package/routes/admin.js +21 -10
- package/routes/diagram.js +436 -35
- package/routes/pageedit.js +9 -6
- package/routes/tags.js +26 -22
- package/routes/utils.js +60 -20
- package/routes/viewedit.js +40 -20
package/routes/diagram.js
CHANGED
|
@@ -2,58 +2,459 @@ const Page = require("@saltcorn/data/models/page");
|
|
|
2
2
|
const {
|
|
3
3
|
buildObjectTrees,
|
|
4
4
|
} = require("@saltcorn/data/diagram/node_extract_utils");
|
|
5
|
-
const {
|
|
5
|
+
const {
|
|
6
|
+
generateCyCode,
|
|
7
|
+
genereateCyCfg,
|
|
8
|
+
} = require("@saltcorn/data/diagram/cy_generate_utils");
|
|
6
9
|
const { getState } = require("@saltcorn/data/db/state");
|
|
7
|
-
const {
|
|
10
|
+
const {
|
|
11
|
+
a,
|
|
12
|
+
input,
|
|
13
|
+
label,
|
|
14
|
+
button,
|
|
15
|
+
div,
|
|
16
|
+
script,
|
|
17
|
+
i,
|
|
18
|
+
domReady,
|
|
19
|
+
} = require("@saltcorn/markup/tags");
|
|
20
|
+
const { send_infoarch_page } = require("../markup/admin");
|
|
8
21
|
const { isAdmin, error_catcher } = require("./utils.js");
|
|
22
|
+
const Tag = require("@saltcorn/data/models/tag");
|
|
9
23
|
const Router = require("express-promise-router");
|
|
10
24
|
|
|
11
25
|
const router = new Router();
|
|
12
26
|
module.exports = router;
|
|
13
27
|
|
|
28
|
+
function reloadCy() {
|
|
29
|
+
$.ajax("/diagram/data", {
|
|
30
|
+
dataType: "json",
|
|
31
|
+
type: "GET",
|
|
32
|
+
headers: { "CSRF-Token": _sc_globalCsrf },
|
|
33
|
+
data: !tagFilterEnabled ? entityFilter : { ...entityFilter, tagFilterIds },
|
|
34
|
+
}).done((res) => {
|
|
35
|
+
const cfg = {
|
|
36
|
+
container: document.getElementById("cy"),
|
|
37
|
+
...res,
|
|
38
|
+
};
|
|
39
|
+
window.cy = cytoscape(cfg);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function toggleEntityFilter(type) {
|
|
44
|
+
switch (type) {
|
|
45
|
+
case "views": {
|
|
46
|
+
entityFilter.showViews = !entityFilter.showViews;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
case "pages": {
|
|
50
|
+
entityFilter.showPages = !entityFilter.showPages;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
case "tables": {
|
|
54
|
+
entityFilter.showTables = !entityFilter.showTables;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
case "trigger": {
|
|
58
|
+
entityFilter.showTrigger = !entityFilter.showTrigger;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function toggleTagFilter(id) {
|
|
65
|
+
if (!tagFilterEnabled) enableTagFilter();
|
|
66
|
+
const index = tagFilterIds.indexOf(id);
|
|
67
|
+
if (index > -1) {
|
|
68
|
+
tagFilterIds.splice(index, 1);
|
|
69
|
+
} else {
|
|
70
|
+
tagFilterIds.push(id);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function enableTagFilter() {
|
|
75
|
+
tagFilterEnabled = true;
|
|
76
|
+
for (const node of document.querySelectorAll('[id^="tagFilter_box_"]')) {
|
|
77
|
+
node.style = "";
|
|
78
|
+
}
|
|
79
|
+
for (const node of document.querySelectorAll('[id^="tagFilter_label_"]')) {
|
|
80
|
+
node.style = "";
|
|
81
|
+
}
|
|
82
|
+
const box = document.getElementById("noTagsId");
|
|
83
|
+
box.checked = false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function toggleTagFilterMode() {
|
|
87
|
+
if (tagFilterEnabled) {
|
|
88
|
+
tagFilterEnabled = false;
|
|
89
|
+
for (const node of document.querySelectorAll('[id^="tagFilter_box_"]')) {
|
|
90
|
+
node.style = "opacity: 0.5;";
|
|
91
|
+
}
|
|
92
|
+
for (const node of document.querySelectorAll('[id^="tagFilter_label_"]')) {
|
|
93
|
+
node.style = "opacity: 0.5;";
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
enableTagFilter();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const buildScript = () => {
|
|
101
|
+
return `const entityFilter = {
|
|
102
|
+
showViews: true,
|
|
103
|
+
showPages: true,
|
|
104
|
+
showTables: true,
|
|
105
|
+
showTrigger: true,
|
|
106
|
+
};
|
|
107
|
+
const tagFilterIds = [];
|
|
108
|
+
let tagFilterEnabled = false;
|
|
109
|
+
${reloadCy.toString()}
|
|
110
|
+
${toggleTagFilterMode.toString()}
|
|
111
|
+
${enableTagFilter.toString()}
|
|
112
|
+
${toggleEntityFilter.toString()}
|
|
113
|
+
${toggleTagFilter.toString()}`;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const findEntryPages = async () => {
|
|
117
|
+
const modernCfg = getState().getConfig("home_page_by_role");
|
|
118
|
+
let pages = null;
|
|
119
|
+
if (modernCfg) {
|
|
120
|
+
pages = Object.values(modernCfg)
|
|
121
|
+
.filter((val) => val)
|
|
122
|
+
.map((val) => Page.findOne({ name: val }));
|
|
123
|
+
} else {
|
|
124
|
+
pages = new Array();
|
|
125
|
+
for (const legacyRole of ["public", "user", "staff", "admin"]) {
|
|
126
|
+
const page = await Page.findOne({ name: `${legacyRole}_home` });
|
|
127
|
+
if (page) pages.push(page);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return pages;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const buildFilterIds = async (tags) => {
|
|
134
|
+
if (!tags || tags.length === 0) return null;
|
|
135
|
+
else {
|
|
136
|
+
const viewFilterIds = new Set();
|
|
137
|
+
const pageFilterIds = new Set();
|
|
138
|
+
const tableFilterIds = new Set();
|
|
139
|
+
const triggerFilterIds = new Set();
|
|
140
|
+
for (const tag of tags) {
|
|
141
|
+
for (const id of await tag.getViewIds()) viewFilterIds.add(id);
|
|
142
|
+
for (const id of await tag.getPageIds()) pageFilterIds.add(id);
|
|
143
|
+
for (const id of await tag.getTableIds()) tableFilterIds.add(id);
|
|
144
|
+
for (const id of await tag.getTriggerIds()) triggerFilterIds.add(id);
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
viewFilterIds,
|
|
148
|
+
pageFilterIds,
|
|
149
|
+
tableFilterIds,
|
|
150
|
+
triggerFilterIds,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const parseBool = (str) => {
|
|
156
|
+
return str === "true";
|
|
157
|
+
};
|
|
158
|
+
|
|
14
159
|
router.get(
|
|
15
160
|
"/",
|
|
16
161
|
isAdmin,
|
|
17
162
|
error_catcher(async (req, res) => {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
res.sendWrap(
|
|
33
|
-
{
|
|
34
|
-
title: req.__(`Application diagram`),
|
|
35
|
-
headers: [
|
|
36
|
-
{
|
|
37
|
-
script:
|
|
38
|
-
"https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.22.1/cytoscape.min.js",
|
|
39
|
-
style: `
|
|
40
|
-
#cy {
|
|
41
|
-
width: 100%;
|
|
42
|
-
height: 900px;
|
|
43
|
-
display: block;
|
|
44
|
-
}`,
|
|
45
|
-
},
|
|
46
|
-
],
|
|
47
|
-
},
|
|
48
|
-
{
|
|
163
|
+
const extractOpts = {
|
|
164
|
+
entryPages: await findEntryPages(),
|
|
165
|
+
showViews: true,
|
|
166
|
+
showPages: true,
|
|
167
|
+
showTables: true,
|
|
168
|
+
showTrigger: true,
|
|
169
|
+
};
|
|
170
|
+
const initialCyCode = generateCyCode(await buildObjectTrees(extractOpts));
|
|
171
|
+
const tags = await Tag.find();
|
|
172
|
+
send_infoarch_page({
|
|
173
|
+
res,
|
|
174
|
+
req,
|
|
175
|
+
active_sub: "Diagram",
|
|
176
|
+
contents: {
|
|
49
177
|
above: [
|
|
50
178
|
{
|
|
51
179
|
type: "card",
|
|
52
180
|
title: req.__(`Application diagram`),
|
|
53
|
-
contents: [
|
|
181
|
+
contents: [
|
|
182
|
+
div(
|
|
183
|
+
{ class: "btn-group" },
|
|
184
|
+
// New dropdown
|
|
185
|
+
button(
|
|
186
|
+
{
|
|
187
|
+
type: "button",
|
|
188
|
+
class: "btn btn-primary m-2 rounded",
|
|
189
|
+
"data-bs-toggle": "dropdown",
|
|
190
|
+
"aria-expanded": false,
|
|
191
|
+
},
|
|
192
|
+
"New",
|
|
193
|
+
i({ class: "fas fa-plus-square ms-2" })
|
|
194
|
+
),
|
|
195
|
+
|
|
196
|
+
div(
|
|
197
|
+
{
|
|
198
|
+
class: "dropdown-menu",
|
|
199
|
+
},
|
|
200
|
+
input({
|
|
201
|
+
type: "hidden",
|
|
202
|
+
name: "_csrf",
|
|
203
|
+
value: req.csrfToken(),
|
|
204
|
+
}),
|
|
205
|
+
// New View
|
|
206
|
+
div(
|
|
207
|
+
{ class: "m-3" },
|
|
208
|
+
|
|
209
|
+
a(
|
|
210
|
+
{
|
|
211
|
+
href: "/viewedit/new?on_done_redirect=diagram",
|
|
212
|
+
},
|
|
213
|
+
req.__("View")
|
|
214
|
+
)
|
|
215
|
+
),
|
|
216
|
+
// New Page
|
|
217
|
+
div(
|
|
218
|
+
{ class: "m-3" },
|
|
219
|
+
a(
|
|
220
|
+
{
|
|
221
|
+
href: "/pageedit/new?on_done_redirect=diagram",
|
|
222
|
+
},
|
|
223
|
+
req.__("Page")
|
|
224
|
+
)
|
|
225
|
+
),
|
|
226
|
+
// New Table
|
|
227
|
+
div(
|
|
228
|
+
{ class: "m-3" },
|
|
229
|
+
a(
|
|
230
|
+
{
|
|
231
|
+
href: "/table/new",
|
|
232
|
+
},
|
|
233
|
+
req.__("Table")
|
|
234
|
+
)
|
|
235
|
+
),
|
|
236
|
+
// New Trigger
|
|
237
|
+
div(
|
|
238
|
+
{ class: "m-3" },
|
|
239
|
+
a(
|
|
240
|
+
{
|
|
241
|
+
href: "/actions/new?on_done_redirect=diagram",
|
|
242
|
+
},
|
|
243
|
+
req.__("Trigger")
|
|
244
|
+
)
|
|
245
|
+
)
|
|
246
|
+
),
|
|
247
|
+
// Entity type filter dropdown
|
|
248
|
+
button(
|
|
249
|
+
{
|
|
250
|
+
type: "button",
|
|
251
|
+
class: "btn btn-primary m-2 rounded",
|
|
252
|
+
"data-bs-toggle": "dropdown",
|
|
253
|
+
"aria-expanded": false,
|
|
254
|
+
},
|
|
255
|
+
"All entities"
|
|
256
|
+
),
|
|
257
|
+
div(
|
|
258
|
+
{
|
|
259
|
+
class: "dropdown-menu",
|
|
260
|
+
},
|
|
261
|
+
input({
|
|
262
|
+
type: "hidden",
|
|
263
|
+
name: "_csrf",
|
|
264
|
+
value: req.csrfToken(),
|
|
265
|
+
}),
|
|
266
|
+
// Views checkbox
|
|
267
|
+
div(
|
|
268
|
+
{ class: "m-3 form-check" },
|
|
269
|
+
label(
|
|
270
|
+
{ class: "form-check-label", for: "showViewsId" },
|
|
271
|
+
"Views"
|
|
272
|
+
),
|
|
273
|
+
input({
|
|
274
|
+
type: "checkbox",
|
|
275
|
+
class: "form-check-input",
|
|
276
|
+
id: "showViewsId",
|
|
277
|
+
checked: true,
|
|
278
|
+
name: "show_views",
|
|
279
|
+
value: "true",
|
|
280
|
+
onclick: "toggleEntityFilter('views'); reloadCy();",
|
|
281
|
+
autocomplete: "off",
|
|
282
|
+
})
|
|
283
|
+
),
|
|
284
|
+
// Pages checkbox
|
|
285
|
+
div(
|
|
286
|
+
{ class: "m-3 form-check" },
|
|
287
|
+
label(
|
|
288
|
+
{ class: "form-check-label", for: "showPagesId" },
|
|
289
|
+
"Pages"
|
|
290
|
+
),
|
|
291
|
+
input({
|
|
292
|
+
type: "checkbox",
|
|
293
|
+
class: "form-check-input",
|
|
294
|
+
id: "showPagesId",
|
|
295
|
+
name: "show_pages",
|
|
296
|
+
value: "true",
|
|
297
|
+
checked: true,
|
|
298
|
+
onclick: "toggleEntityFilter('pages'); reloadCy();",
|
|
299
|
+
autocomplete: "off",
|
|
300
|
+
})
|
|
301
|
+
),
|
|
302
|
+
// Tables checkbox
|
|
303
|
+
div(
|
|
304
|
+
{ class: "m-3 form-check" },
|
|
305
|
+
label(
|
|
306
|
+
{ class: "form-check-label", for: "showTablesId" },
|
|
307
|
+
"Tables"
|
|
308
|
+
),
|
|
309
|
+
input({
|
|
310
|
+
type: "checkbox",
|
|
311
|
+
class: "form-check-input",
|
|
312
|
+
id: "showTablesId",
|
|
313
|
+
name: "show_tables",
|
|
314
|
+
value: "true",
|
|
315
|
+
checked: true,
|
|
316
|
+
onclick: "toggleEntityFilter('tables'); reloadCy();",
|
|
317
|
+
autocomplete: "off",
|
|
318
|
+
})
|
|
319
|
+
),
|
|
320
|
+
// Trigger checkbox
|
|
321
|
+
div(
|
|
322
|
+
{ class: "m-3 form-check" },
|
|
323
|
+
label(
|
|
324
|
+
{ class: "form-check-label", for: "showTriggerId" },
|
|
325
|
+
"Trigger"
|
|
326
|
+
),
|
|
327
|
+
input({
|
|
328
|
+
type: "checkbox",
|
|
329
|
+
class: "form-check-input",
|
|
330
|
+
id: "showTriggerId",
|
|
331
|
+
name: "show_trigger",
|
|
332
|
+
value: "true",
|
|
333
|
+
checked: true,
|
|
334
|
+
onclick: "toggleEntityFilter('trigger'); reloadCy();",
|
|
335
|
+
autocomplete: "off",
|
|
336
|
+
})
|
|
337
|
+
)
|
|
338
|
+
),
|
|
339
|
+
// Tags filter dropdown
|
|
340
|
+
button(
|
|
341
|
+
{
|
|
342
|
+
type: "button",
|
|
343
|
+
class: "btn btn-primary m-2 rounded",
|
|
344
|
+
"data-bs-toggle": "dropdown",
|
|
345
|
+
"aria-expanded": false,
|
|
346
|
+
},
|
|
347
|
+
"Tags"
|
|
348
|
+
),
|
|
349
|
+
div(
|
|
350
|
+
{
|
|
351
|
+
class: "dropdown-menu",
|
|
352
|
+
},
|
|
353
|
+
input({
|
|
354
|
+
type: "hidden",
|
|
355
|
+
name: "_csrf",
|
|
356
|
+
value: req.csrfToken(),
|
|
357
|
+
}),
|
|
358
|
+
// no tags checkbox
|
|
359
|
+
div(
|
|
360
|
+
{ class: "m-3 form-check" },
|
|
361
|
+
label(
|
|
362
|
+
{ class: "form-check-label", for: "noTagsId" },
|
|
363
|
+
"no tags"
|
|
364
|
+
),
|
|
365
|
+
input({
|
|
366
|
+
type: "checkbox",
|
|
367
|
+
class: "form-check-input",
|
|
368
|
+
id: "noTagsId",
|
|
369
|
+
name: "no_tags",
|
|
370
|
+
value: "true",
|
|
371
|
+
checked: true,
|
|
372
|
+
onclick: "toggleTagFilterMode(); reloadCy();",
|
|
373
|
+
autocomplete: "off",
|
|
374
|
+
})
|
|
375
|
+
),
|
|
376
|
+
tags.map((tag) => {
|
|
377
|
+
const inputId = `tagFilter_box_${tag.name}_id`;
|
|
378
|
+
return div(
|
|
379
|
+
{ class: "m-3 form-check" },
|
|
380
|
+
label(
|
|
381
|
+
{
|
|
382
|
+
class: "form-check-label",
|
|
383
|
+
id: `tagFilter_label_${tag.name}`,
|
|
384
|
+
style: "opacity: 0.5;",
|
|
385
|
+
for: inputId,
|
|
386
|
+
},
|
|
387
|
+
tag.name
|
|
388
|
+
),
|
|
389
|
+
input({
|
|
390
|
+
type: "checkbox",
|
|
391
|
+
class: "form-check-input",
|
|
392
|
+
id: inputId,
|
|
393
|
+
name: "choice",
|
|
394
|
+
value: tag.id,
|
|
395
|
+
checked: false,
|
|
396
|
+
onclick: `toggleTagFilter(${tag.id}); reloadCy();`,
|
|
397
|
+
autocomplete: "off",
|
|
398
|
+
})
|
|
399
|
+
);
|
|
400
|
+
}),
|
|
401
|
+
div(
|
|
402
|
+
{ class: "m-3" },
|
|
403
|
+
a(
|
|
404
|
+
{
|
|
405
|
+
href: "/tag/new",
|
|
406
|
+
},
|
|
407
|
+
req.__("Add tag"),
|
|
408
|
+
i({ class: "fas fa-plus ms-2" })
|
|
409
|
+
)
|
|
410
|
+
)
|
|
411
|
+
)
|
|
412
|
+
),
|
|
413
|
+
div({ id: "cy" }),
|
|
414
|
+
script(domReady(initialCyCode)),
|
|
415
|
+
script(buildScript()),
|
|
416
|
+
],
|
|
54
417
|
},
|
|
55
418
|
],
|
|
56
|
-
}
|
|
419
|
+
},
|
|
420
|
+
headers: [
|
|
421
|
+
{
|
|
422
|
+
script:
|
|
423
|
+
"https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.22.1/cytoscape.min.js",
|
|
424
|
+
style: `
|
|
425
|
+
#cy {
|
|
426
|
+
width: 100%;
|
|
427
|
+
height: 900px;
|
|
428
|
+
display: block;
|
|
429
|
+
}`,
|
|
430
|
+
},
|
|
431
|
+
],
|
|
432
|
+
});
|
|
433
|
+
})
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
router.get(
|
|
437
|
+
"/data",
|
|
438
|
+
isAdmin,
|
|
439
|
+
error_catcher(async (req, res) => {
|
|
440
|
+
const { showViews, showPages, showTables, showTrigger } = req.query;
|
|
441
|
+
const tagFilterIds = req.query.tagFilterIds
|
|
442
|
+
? req.query.tagFilterIds.map((id) => parseInt(id))
|
|
443
|
+
: [];
|
|
444
|
+
const tags = (await Tag.find()).filter(
|
|
445
|
+
(tag) => tagFilterIds.indexOf(tag.id) > -1
|
|
57
446
|
);
|
|
447
|
+
let extractOpts = {
|
|
448
|
+
entryPages: await findEntryPages(),
|
|
449
|
+
showViews: parseBool(showViews),
|
|
450
|
+
showPages: parseBool(showPages),
|
|
451
|
+
showTables: parseBool(showTables),
|
|
452
|
+
showTrigger: parseBool(showTrigger),
|
|
453
|
+
};
|
|
454
|
+
const filterIds = await buildFilterIds(tags);
|
|
455
|
+
if (filterIds) {
|
|
456
|
+
extractOpts = { ...extractOpts, ...filterIds };
|
|
457
|
+
}
|
|
458
|
+
res.json(genereateCyCfg(await buildObjectTrees(extractOpts)));
|
|
58
459
|
})
|
|
59
460
|
);
|
package/routes/pageedit.js
CHANGED
|
@@ -21,7 +21,7 @@ const { add_to_menu } = require("@saltcorn/admin-models/models/pack");
|
|
|
21
21
|
const db = require("@saltcorn/data/db");
|
|
22
22
|
const { getPageList } = require("./common_lists");
|
|
23
23
|
|
|
24
|
-
const { isAdmin, error_catcher } = require("./utils.js");
|
|
24
|
+
const { isAdmin, error_catcher, addOnDoneRedirect } = require("./utils.js");
|
|
25
25
|
const {
|
|
26
26
|
mkTable,
|
|
27
27
|
renderForm,
|
|
@@ -54,7 +54,7 @@ const pagePropertiesForm = async (req) => {
|
|
|
54
54
|
const roles = await User.get_roles();
|
|
55
55
|
|
|
56
56
|
const form = new Form({
|
|
57
|
-
action: "/pageedit/edit-properties",
|
|
57
|
+
action: addOnDoneRedirect("/pageedit/edit-properties", req),
|
|
58
58
|
fields: [
|
|
59
59
|
new Field({
|
|
60
60
|
label: req.__("Name"),
|
|
@@ -357,7 +357,7 @@ router.post(
|
|
|
357
357
|
if (!pageRow.fixed_states) pageRow.fixed_states = {};
|
|
358
358
|
if (!pageRow.layout) pageRow.layout = {};
|
|
359
359
|
await Page.create(pageRow);
|
|
360
|
-
res.redirect(`/pageedit/edit/${pageRow.name}
|
|
360
|
+
res.redirect(addOnDoneRedirect(`/pageedit/edit/${pageRow.name}`, req));
|
|
361
361
|
}
|
|
362
362
|
}
|
|
363
363
|
})
|
|
@@ -416,20 +416,23 @@ router.post(
|
|
|
416
416
|
error_catcher(async (req, res) => {
|
|
417
417
|
const { pagename } = req.params;
|
|
418
418
|
|
|
419
|
+
let redirectTarget = req.query.on_done_redirect
|
|
420
|
+
? `/${req.query.on_done_redirect}`
|
|
421
|
+
: "/pageedit";
|
|
419
422
|
const page = await Page.findOne({ name: pagename });
|
|
420
423
|
if (!page) {
|
|
421
424
|
req.flash("error", req.__(`Page %s not found`, pagename));
|
|
422
|
-
res.redirect(
|
|
425
|
+
res.redirect(redirectTarget);
|
|
423
426
|
} else if (req.body.layout) {
|
|
424
427
|
await Page.update(page.id, {
|
|
425
428
|
layout: decodeURIComponent(req.body.layout),
|
|
426
429
|
});
|
|
427
430
|
|
|
428
431
|
req.flash("success", req.__(`Page %s saved`, pagename));
|
|
429
|
-
res.redirect(
|
|
432
|
+
res.redirect(redirectTarget);
|
|
430
433
|
} else {
|
|
431
434
|
req.flash("error", req.__(`Error processing page`));
|
|
432
|
-
res.redirect(
|
|
435
|
+
res.redirect(redirectTarget);
|
|
433
436
|
}
|
|
434
437
|
})
|
|
435
438
|
);
|
package/routes/tags.js
CHANGED
|
@@ -35,30 +35,34 @@ router.get(
|
|
|
35
35
|
res,
|
|
36
36
|
req,
|
|
37
37
|
active_sub: "Tags",
|
|
38
|
-
contents:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
contents: {
|
|
39
|
+
type: "card",
|
|
40
|
+
title: req.__("Tags"),
|
|
41
|
+
contents: [
|
|
42
|
+
mkTable(
|
|
43
|
+
[
|
|
44
|
+
{
|
|
45
|
+
label: req.__("Tagname"),
|
|
46
|
+
key: (r) =>
|
|
47
|
+
link(`/tag/${r.id || r.name}?show_list=tables`, text(r.name)),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
label: req.__("Delete"),
|
|
51
|
+
key: (r) => post_delete_btn(`/tag/delete/${r.id}`, req, r.name),
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
rows,
|
|
55
|
+
{}
|
|
56
|
+
),
|
|
57
|
+
a(
|
|
46
58
|
{
|
|
47
|
-
|
|
48
|
-
|
|
59
|
+
href: `/tag/new`,
|
|
60
|
+
class: "btn btn-primary",
|
|
49
61
|
},
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
a(
|
|
55
|
-
{
|
|
56
|
-
href: `/tag/new`,
|
|
57
|
-
class: "btn btn-primary",
|
|
58
|
-
},
|
|
59
|
-
req.__("Create tag")
|
|
60
|
-
),
|
|
61
|
-
],
|
|
62
|
+
req.__("Create tag")
|
|
63
|
+
),
|
|
64
|
+
],
|
|
65
|
+
},
|
|
62
66
|
});
|
|
63
67
|
})
|
|
64
68
|
);
|