@saltcorn/server 0.9.4-beta.1 → 0.9.4-beta.11
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/help/JavaScript action code.tmd +1 -0
- package/locales/en.json +18 -1
- package/package.json +8 -8
- package/public/saltcorn-builder.css +37 -2
- package/public/saltcorn.css +4 -0
- package/public/saltcorn.js +13 -9
- package/restart_watcher.js +1 -0
- package/routes/actions.js +24 -3
- package/routes/common_lists.js +305 -136
- package/routes/fields.js +11 -2
- package/routes/files.js +3 -1
- package/routes/list.js +5 -0
- package/routes/page.js +30 -13
- package/routes/page_groupedit.js +104 -83
- package/routes/pageedit.js +20 -5
- package/routes/tables.js +29 -6
- package/routes/tag_entries.js +12 -4
- package/routes/tags.js +61 -12
- package/routes/utils.js +19 -0
- package/routes/view.js +20 -2
- package/routes/viewedit.js +63 -4
- package/tests/page_group.test.js +1 -0
- package/tests/view.test.js +115 -15
- package/tests/viewedit.test.js +0 -21
- package/wrapper.js +2 -2
- package/public/relation_helpers.js +0 -351
package/routes/common_lists.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const User = require("@saltcorn/data/models/user");
|
|
2
2
|
const Table = require("@saltcorn/data/models/table");
|
|
3
|
+
const Tag = require("@saltcorn/data/models/tag");
|
|
4
|
+
const TagEntry = require("@saltcorn/data/models/tag_entry");
|
|
3
5
|
const { editRoleForm } = require("../markup/forms.js");
|
|
4
6
|
const {
|
|
5
7
|
mkTable,
|
|
@@ -7,16 +9,16 @@ const {
|
|
|
7
9
|
post_delete_btn,
|
|
8
10
|
settingsDropdown,
|
|
9
11
|
post_dropdown_item,
|
|
12
|
+
badge,
|
|
10
13
|
} = require("@saltcorn/markup");
|
|
11
14
|
const { get_base_url } = require("./utils.js");
|
|
12
|
-
const { h4, p, div, a, i, text } = require("@saltcorn/markup/tags");
|
|
15
|
+
const { h4, p, div, a, i, text, span, nbsp } = require("@saltcorn/markup/tags");
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
18
|
* @param {string} col
|
|
16
19
|
* @param {string} lbl
|
|
17
20
|
* @returns {string}
|
|
18
21
|
*/
|
|
19
|
-
const badge = (col, lbl) => `<span class="badge bg-${col}">${lbl}</span> `;
|
|
20
22
|
|
|
21
23
|
/**
|
|
22
24
|
* Table badges to show in System Table list views
|
|
@@ -42,57 +44,90 @@ const valIfSet = (check, value) => (check ? value : "");
|
|
|
42
44
|
const listClass = (tagId, showList) =>
|
|
43
45
|
valIfSet(tagId, `collapse ${valIfSet(showList, "show")}`);
|
|
44
46
|
|
|
45
|
-
const tablesList = async (
|
|
47
|
+
const tablesList = async (
|
|
48
|
+
tables,
|
|
49
|
+
req,
|
|
50
|
+
{ tagId, domId, showList, filterOnTag } = {}
|
|
51
|
+
) => {
|
|
46
52
|
const roles = await User.get_roles();
|
|
47
53
|
const getRole = (rid) => roles.find((r) => r.id === rid)?.role || "?";
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
`/tag-entries/remove/tables/${r.id}/${tagId}`,
|
|
79
|
-
req,
|
|
80
|
-
`${r.name} from this tag`
|
|
81
|
-
),
|
|
54
|
+
const tags = await Tag.find();
|
|
55
|
+
const tag_entries = await TagEntry.find({
|
|
56
|
+
not: { table_id: null },
|
|
57
|
+
});
|
|
58
|
+
const tagsById = {};
|
|
59
|
+
tags.forEach((t) => (tagsById[t.id] = t));
|
|
60
|
+
|
|
61
|
+
const tagBadges = (table) => {
|
|
62
|
+
const myTags = tag_entries.filter((te) => te.table_id === table.id);
|
|
63
|
+
return myTags
|
|
64
|
+
.map((te) => tagBadge(tagsById[te.tag_id], "tables"))
|
|
65
|
+
.join(nbsp);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
mkTable(
|
|
70
|
+
[
|
|
71
|
+
{
|
|
72
|
+
label: req.__("Name"),
|
|
73
|
+
key: (r) => link(`/table/${r.id || r.name}`, text(r.name)),
|
|
74
|
+
},
|
|
75
|
+
...(tagId
|
|
76
|
+
? []
|
|
77
|
+
: [
|
|
78
|
+
{
|
|
79
|
+
label: tagsDropdown(
|
|
80
|
+
tags,
|
|
81
|
+
filterOnTag ? `Tag:${filterOnTag.name}` : undefined
|
|
82
|
+
),
|
|
83
|
+
key: (r) => tagBadges(r),
|
|
82
84
|
},
|
|
83
|
-
|
|
84
|
-
tables,
|
|
85
|
+
]),
|
|
85
86
|
{
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
87
|
+
label: "",
|
|
88
|
+
key: (r) => tableBadges(r, req),
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
{
|
|
92
|
+
label: req.__("Access Read/Write"),
|
|
93
|
+
key: (t) =>
|
|
94
|
+
t.external
|
|
95
|
+
? `${getRole(t.min_role_read)} (read only)`
|
|
96
|
+
: `${getRole(t.min_role_read)}/${getRole(t.min_role_write)}`,
|
|
97
|
+
},
|
|
98
|
+
!tagId
|
|
99
|
+
? {
|
|
100
|
+
label: req.__("Delete"),
|
|
101
|
+
key: (r) =>
|
|
102
|
+
r.name === "users" || r.external
|
|
103
|
+
? ""
|
|
104
|
+
: post_delete_btn(`/table/delete/${r.id}`, req, r.name),
|
|
105
|
+
}
|
|
106
|
+
: {
|
|
107
|
+
label: req.__("Remove From Tag"),
|
|
108
|
+
key: (r) =>
|
|
109
|
+
post_delete_btn(
|
|
110
|
+
`/tag-entries/remove/tables/${r.id}/${tagId}`,
|
|
111
|
+
req,
|
|
112
|
+
`${r.name} from this tag`
|
|
113
|
+
),
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
tables,
|
|
117
|
+
{
|
|
118
|
+
hover: true,
|
|
119
|
+
tableClass: listClass(tagId, showList),
|
|
120
|
+
tableId: domId,
|
|
121
|
+
}
|
|
122
|
+
) +
|
|
123
|
+
(tables.length == 0 && !filterOnTag
|
|
124
|
+
? div(
|
|
125
|
+
{ class: listClass(tagId, showList), id: domId },
|
|
126
|
+
h4(req.__("No tables defined")),
|
|
127
|
+
p(req.__("Tables hold collections of similar data"))
|
|
128
|
+
)
|
|
129
|
+
: "")
|
|
130
|
+
);
|
|
96
131
|
};
|
|
97
132
|
|
|
98
133
|
/**
|
|
@@ -177,100 +212,176 @@ const setTableRefs = async (views) => {
|
|
|
177
212
|
return views;
|
|
178
213
|
};
|
|
179
214
|
|
|
215
|
+
const tagBadge = (tag, type) =>
|
|
216
|
+
a(
|
|
217
|
+
{
|
|
218
|
+
href: `/tag/${tag.id}?show_list=${type}`,
|
|
219
|
+
class: "badge bg-secondary",
|
|
220
|
+
},
|
|
221
|
+
tag.name
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
const tagsDropdown = (tags, altHeader) =>
|
|
225
|
+
div(
|
|
226
|
+
{ class: "dropdown" },
|
|
227
|
+
div(
|
|
228
|
+
{
|
|
229
|
+
class: "link-style",
|
|
230
|
+
"data-boundary": "viewport",
|
|
231
|
+
type: "button",
|
|
232
|
+
id: "tagsselector",
|
|
233
|
+
"data-bs-toggle": "dropdown",
|
|
234
|
+
"aria-haspopup": "true",
|
|
235
|
+
"aria-expanded": "false",
|
|
236
|
+
},
|
|
237
|
+
altHeader || "Tags",
|
|
238
|
+
i({ class: "ms-1 fas fa-caret-down" })
|
|
239
|
+
),
|
|
240
|
+
div(
|
|
241
|
+
{
|
|
242
|
+
class: "dropdown-menu",
|
|
243
|
+
"aria-labelledby": "tagsselector",
|
|
244
|
+
},
|
|
245
|
+
a(
|
|
246
|
+
{
|
|
247
|
+
class: "dropdown-item",
|
|
248
|
+
// TODO check url why view for page, what do we need for page group
|
|
249
|
+
href: `javascript:unset_state_field('_tag', this)`,
|
|
250
|
+
},
|
|
251
|
+
"All tags"
|
|
252
|
+
),
|
|
253
|
+
tags.map((tag) =>
|
|
254
|
+
a(
|
|
255
|
+
{
|
|
256
|
+
class: "dropdown-item",
|
|
257
|
+
// TODO check url why view for page, what do we need for page group
|
|
258
|
+
href: `javascript:set_state_field('_tag', ${tag.id}, this)`,
|
|
259
|
+
},
|
|
260
|
+
tag.name
|
|
261
|
+
)
|
|
262
|
+
),
|
|
263
|
+
a(
|
|
264
|
+
{
|
|
265
|
+
class: "dropdown-item",
|
|
266
|
+
// TODO check url why view for page, what do we need for page group
|
|
267
|
+
href: `tag`,
|
|
268
|
+
},
|
|
269
|
+
"Manage tags..."
|
|
270
|
+
)
|
|
271
|
+
)
|
|
272
|
+
);
|
|
273
|
+
|
|
180
274
|
const viewsList = async (
|
|
181
275
|
views,
|
|
182
276
|
req,
|
|
183
|
-
{ tagId, domId, showList, on_done_redirect, notable } = {}
|
|
277
|
+
{ tagId, domId, showList, on_done_redirect, notable, filterOnTag } = {}
|
|
184
278
|
) => {
|
|
185
279
|
const roles = await User.get_roles();
|
|
186
280
|
const on_done_redirect_str = on_done_redirect
|
|
187
281
|
? `?on_done_redirect=${on_done_redirect}`
|
|
188
282
|
: "";
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
key: (r) => link(`/table/${r.table}`, r.table),
|
|
223
|
-
sortlink: !tagId
|
|
224
|
-
? `set_state_field('_sortby', 'table', this)`
|
|
225
|
-
: undefined,
|
|
226
|
-
},
|
|
227
|
-
]),
|
|
228
|
-
{
|
|
229
|
-
label: req.__("Role to access"),
|
|
230
|
-
key: (row) =>
|
|
231
|
-
row.id
|
|
232
|
-
? editViewRoleForm(row, roles, req, on_done_redirect_str)
|
|
233
|
-
: "admin",
|
|
234
|
-
},
|
|
235
|
-
{
|
|
236
|
-
label: "",
|
|
237
|
-
key: (r) =>
|
|
238
|
-
r.id && r.viewtemplateObj?.configuration_workflow
|
|
239
|
-
? link(
|
|
240
|
-
`/viewedit/config/${encodeURIComponent(
|
|
241
|
-
r.name
|
|
242
|
-
)}${on_done_redirect_str}`,
|
|
243
|
-
req.__("Configure")
|
|
244
|
-
)
|
|
245
|
-
: "",
|
|
246
|
-
},
|
|
247
|
-
!tagId
|
|
248
|
-
? {
|
|
249
|
-
label: "",
|
|
250
|
-
key: (r) => view_dropdown(r, req, on_done_redirect_str),
|
|
251
|
-
}
|
|
252
|
-
: {
|
|
253
|
-
label: req.__("Remove From Tag"),
|
|
254
|
-
key: (r) =>
|
|
255
|
-
post_delete_btn(
|
|
256
|
-
`/tag-entries/remove/views/${r.id}/${tagId}`,
|
|
257
|
-
req,
|
|
258
|
-
`${r.name} from this tag`
|
|
259
|
-
),
|
|
283
|
+
const tags = await Tag.find();
|
|
284
|
+
const tag_entries = await TagEntry.find({
|
|
285
|
+
not: { view_id: null },
|
|
286
|
+
});
|
|
287
|
+
const tagsById = {};
|
|
288
|
+
tags.forEach((t) => (tagsById[t.id] = t));
|
|
289
|
+
|
|
290
|
+
const tagBadges = (view) => {
|
|
291
|
+
const myTags = tag_entries.filter((te) => te.view_id === view.id);
|
|
292
|
+
return myTags
|
|
293
|
+
.map((te) => tagBadge(tagsById[te.tag_id], "views"))
|
|
294
|
+
.join(nbsp);
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
return (
|
|
298
|
+
mkTable(
|
|
299
|
+
[
|
|
300
|
+
{
|
|
301
|
+
label: req.__("Name"),
|
|
302
|
+
key: (r) => link(`/view/${encodeURIComponent(r.name)}`, r.name),
|
|
303
|
+
sortlink: !tagId
|
|
304
|
+
? `set_state_field('_sortby', 'name', this)`
|
|
305
|
+
: undefined,
|
|
306
|
+
},
|
|
307
|
+
...(tagId
|
|
308
|
+
? []
|
|
309
|
+
: [
|
|
310
|
+
{
|
|
311
|
+
label: tagsDropdown(
|
|
312
|
+
tags,
|
|
313
|
+
filterOnTag ? `Tag:${filterOnTag.name}` : undefined
|
|
314
|
+
),
|
|
315
|
+
key: (r) => tagBadges(r),
|
|
260
316
|
},
|
|
261
|
-
|
|
262
|
-
views,
|
|
317
|
+
]),
|
|
263
318
|
{
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
319
|
+
label: req.__("Pattern"),
|
|
320
|
+
key: "viewtemplate",
|
|
321
|
+
sortlink: !tagId
|
|
322
|
+
? `set_state_field('_sortby', 'viewtemplate', this)`
|
|
323
|
+
: undefined,
|
|
324
|
+
},
|
|
325
|
+
...(notable
|
|
326
|
+
? []
|
|
327
|
+
: [
|
|
328
|
+
{
|
|
329
|
+
label: req.__("Table"),
|
|
330
|
+
key: (r) => link(`/table/${r.table}`, r.table),
|
|
331
|
+
sortlink: !tagId
|
|
332
|
+
? `set_state_field('_sortby', 'table', this)`
|
|
333
|
+
: undefined,
|
|
334
|
+
},
|
|
335
|
+
]),
|
|
336
|
+
{
|
|
337
|
+
label: req.__("Role to access"),
|
|
338
|
+
key: (row) =>
|
|
339
|
+
row.id
|
|
340
|
+
? editViewRoleForm(row, roles, req, on_done_redirect_str)
|
|
341
|
+
: "admin",
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
label: "",
|
|
345
|
+
key: (r) =>
|
|
346
|
+
r.id && r.viewtemplateObj?.configuration_workflow
|
|
347
|
+
? link(
|
|
348
|
+
`/viewedit/config/${encodeURIComponent(
|
|
349
|
+
r.name
|
|
350
|
+
)}${on_done_redirect_str}`,
|
|
351
|
+
req.__("Configure")
|
|
352
|
+
)
|
|
353
|
+
: "",
|
|
354
|
+
},
|
|
355
|
+
!tagId
|
|
356
|
+
? {
|
|
357
|
+
label: "",
|
|
358
|
+
key: (r) => view_dropdown(r, req, on_done_redirect_str),
|
|
359
|
+
}
|
|
360
|
+
: {
|
|
361
|
+
label: req.__("Remove From Tag"),
|
|
362
|
+
key: (r) =>
|
|
363
|
+
post_delete_btn(
|
|
364
|
+
`/tag-entries/remove/views/${r.id}/${tagId}`,
|
|
365
|
+
req,
|
|
366
|
+
`${r.name} from this tag`
|
|
367
|
+
),
|
|
368
|
+
},
|
|
369
|
+
],
|
|
370
|
+
views,
|
|
371
|
+
{
|
|
372
|
+
hover: true,
|
|
373
|
+
tableClass: listClass(tagId, showList),
|
|
374
|
+
tableId: domId,
|
|
375
|
+
}
|
|
376
|
+
) +
|
|
377
|
+
(views.length == 0 && !filterOnTag
|
|
378
|
+
? div(
|
|
379
|
+
{ class: listClass(tagId, showList), id: domId },
|
|
380
|
+
h4(req.__("No views defined")),
|
|
381
|
+
p(req.__("Views define how table rows are displayed to the user"))
|
|
382
|
+
)
|
|
383
|
+
: "")
|
|
384
|
+
);
|
|
274
385
|
};
|
|
275
386
|
|
|
276
387
|
const page_group_dropdown = (page_group, req) =>
|
|
@@ -371,13 +482,42 @@ const editPageRoleForm = (page, roles, req, isGroup) =>
|
|
|
371
482
|
* @param {object} req
|
|
372
483
|
* @returns {div}
|
|
373
484
|
*/
|
|
374
|
-
const getPageList = (
|
|
485
|
+
const getPageList = async (
|
|
486
|
+
rows,
|
|
487
|
+
roles,
|
|
488
|
+
req,
|
|
489
|
+
{ tagId, domId, showList, filterOnTag } = {}
|
|
490
|
+
) => {
|
|
491
|
+
const tags = await Tag.find();
|
|
492
|
+
const tag_entries = await TagEntry.find({
|
|
493
|
+
not: { page_id: null },
|
|
494
|
+
});
|
|
495
|
+
const tagsById = {};
|
|
496
|
+
tags.forEach((t) => (tagsById[t.id] = t));
|
|
497
|
+
|
|
498
|
+
const tagBadges = (page) => {
|
|
499
|
+
const myTags = tag_entries.filter((te) => te.page_id === page.id);
|
|
500
|
+
return myTags
|
|
501
|
+
.map((te) => tagBadge(tagsById[te.tag_id], "pages"))
|
|
502
|
+
.join(nbsp);
|
|
503
|
+
};
|
|
375
504
|
return mkTable(
|
|
376
505
|
[
|
|
377
506
|
{
|
|
378
507
|
label: req.__("Name"),
|
|
379
|
-
key: (r) => link(`/page/${r.name}`, r.name),
|
|
508
|
+
key: (r) => link(`/page/${encodeURIComponent(r.name)}`, r.name),
|
|
380
509
|
},
|
|
510
|
+
...(tagId
|
|
511
|
+
? []
|
|
512
|
+
: [
|
|
513
|
+
{
|
|
514
|
+
label: tagsDropdown(
|
|
515
|
+
tags,
|
|
516
|
+
filterOnTag ? `Tag:${filterOnTag.name}` : undefined
|
|
517
|
+
),
|
|
518
|
+
key: (r) => tagBadges(r),
|
|
519
|
+
},
|
|
520
|
+
]),
|
|
381
521
|
{
|
|
382
522
|
label: req.__("Role to access"),
|
|
383
523
|
key: (row) => editPageRoleForm(row, roles, req),
|
|
@@ -442,11 +582,40 @@ const getPageGroupList = (rows, roles, req) => {
|
|
|
442
582
|
);
|
|
443
583
|
};
|
|
444
584
|
|
|
445
|
-
const getTriggerList = (
|
|
585
|
+
const getTriggerList = async (
|
|
586
|
+
triggers,
|
|
587
|
+
req,
|
|
588
|
+
{ tagId, domId, showList, filterOnTag } = {}
|
|
589
|
+
) => {
|
|
446
590
|
const base_url = get_base_url(req);
|
|
591
|
+
const tags = await Tag.find();
|
|
592
|
+
|
|
593
|
+
const tag_entries = await TagEntry.find({
|
|
594
|
+
not: { trigger_id: null },
|
|
595
|
+
});
|
|
596
|
+
const tagsById = {};
|
|
597
|
+
tags.forEach((t) => (tagsById[t.id] = t));
|
|
598
|
+
|
|
599
|
+
const tagBadges = (trigger) => {
|
|
600
|
+
const myTags = tag_entries.filter((te) => te.trigger_id === trigger.id);
|
|
601
|
+
return myTags
|
|
602
|
+
.map((te) => tagBadge(tagsById[te.tag_id], "triggers"))
|
|
603
|
+
.join(nbsp);
|
|
604
|
+
};
|
|
447
605
|
return mkTable(
|
|
448
606
|
[
|
|
449
607
|
{ label: req.__("Name"), key: "name" },
|
|
608
|
+
...(tagId
|
|
609
|
+
? []
|
|
610
|
+
: [
|
|
611
|
+
{
|
|
612
|
+
label: tagsDropdown(
|
|
613
|
+
tags,
|
|
614
|
+
filterOnTag ? `Tag:${filterOnTag.name}` : undefined
|
|
615
|
+
),
|
|
616
|
+
key: (r) => tagBadges(r),
|
|
617
|
+
},
|
|
618
|
+
]),
|
|
450
619
|
{ label: req.__("Action"), key: "action" },
|
|
451
620
|
{
|
|
452
621
|
label: req.__("Table or Channel"),
|
package/routes/fields.js
CHANGED
|
@@ -479,6 +479,8 @@ const fieldFlow = (req) =>
|
|
|
479
479
|
// todo sublabel
|
|
480
480
|
type: "String",
|
|
481
481
|
class: "validate-expression",
|
|
482
|
+
fieldview: "textarea",
|
|
483
|
+
attributes: { rows: 2 },
|
|
482
484
|
validator: expressionValidator,
|
|
483
485
|
showIf: { expression_type: "JavaScript expression" },
|
|
484
486
|
}),
|
|
@@ -978,7 +980,7 @@ router.post(
|
|
|
978
980
|
const reftable = Table.findOne({ name: field.reftable_name });
|
|
979
981
|
if (!oldRow[ref]) break;
|
|
980
982
|
if (role > reftable.min_role_read) {
|
|
981
|
-
res.
|
|
983
|
+
res.status401.send("");
|
|
982
984
|
return;
|
|
983
985
|
}
|
|
984
986
|
const q = { [reftable.pk_name]: oldRow[ref] };
|
|
@@ -991,7 +993,14 @@ router.post(
|
|
|
991
993
|
}
|
|
992
994
|
if (oldRow) {
|
|
993
995
|
const value = oldRow[kpath[kpath.length - 1]];
|
|
994
|
-
|
|
996
|
+
//TODO run fieldview
|
|
997
|
+
res.send(
|
|
998
|
+
typeof value === "string"
|
|
999
|
+
? value
|
|
1000
|
+
: value?.toString
|
|
1001
|
+
? value.toString()
|
|
1002
|
+
: `${value}`
|
|
1003
|
+
);
|
|
995
1004
|
return;
|
|
996
1005
|
}
|
|
997
1006
|
}
|
package/routes/files.js
CHANGED
|
@@ -205,7 +205,8 @@ router.get(
|
|
|
205
205
|
) {
|
|
206
206
|
res.type(file.mimetype);
|
|
207
207
|
const cacheability = file.min_role_read === 100 ? "public" : "private";
|
|
208
|
-
|
|
208
|
+
const maxAge = getState().getConfig("files_cache_maxage", 86400);
|
|
209
|
+
res.set("Cache-Control", `${cacheability}, max-age=${maxAge}`);
|
|
209
210
|
if (file.s3_store) s3storage.serveObject(file, res, false);
|
|
210
211
|
else res.sendFile(file.location);
|
|
211
212
|
} else {
|
|
@@ -565,6 +566,7 @@ const files_settings_form = async (req) => {
|
|
|
565
566
|
field_names: [
|
|
566
567
|
"min_role_upload",
|
|
567
568
|
"file_accept_filter_default",
|
|
569
|
+
"files_cache_maxage",
|
|
568
570
|
"file_upload_debug",
|
|
569
571
|
"file_upload_limit",
|
|
570
572
|
"file_upload_timeout",
|
package/routes/list.js
CHANGED
|
@@ -161,6 +161,11 @@ const typeToGridType = (t, field) => {
|
|
|
161
161
|
jsgField.formatterParams = {
|
|
162
162
|
inputFormat: "iso",
|
|
163
163
|
};
|
|
164
|
+
|
|
165
|
+
if (field.attributes?.day_only) {
|
|
166
|
+
jsgField.editorParams = { dayOnly: true };
|
|
167
|
+
jsgField.formatter = "__isoDateFormatter";
|
|
168
|
+
}
|
|
164
169
|
} else if (t.name === "Color") {
|
|
165
170
|
jsgField.editor = "__colorEditor";
|
|
166
171
|
jsgField.formatter = "__colorFormatter";
|
package/routes/page.js
CHANGED
|
@@ -16,6 +16,7 @@ const {
|
|
|
16
16
|
isAdmin,
|
|
17
17
|
sendHtmlFile,
|
|
18
18
|
getEligiblePage,
|
|
19
|
+
getRandomPage,
|
|
19
20
|
} = require("../routes/utils.js");
|
|
20
21
|
const { isTest } = require("@saltcorn/data/utils");
|
|
21
22
|
const { add_edit_bar } = require("../markup/admin.js");
|
|
@@ -88,20 +89,36 @@ const runPage = async (page, req, res, tic) => {
|
|
|
88
89
|
const runPageGroup = async (pageGroup, req, res, tic) => {
|
|
89
90
|
const role = req.user && req.user.id ? req.user.role_id : 100;
|
|
90
91
|
if (role <= pageGroup.min_role) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (!
|
|
92
|
+
if (pageGroup.random_allocation) {
|
|
93
|
+
const page = getRandomPage(pageGroup, req);
|
|
94
|
+
if (typeof page === "string") {
|
|
95
|
+
getState().log(2, page);
|
|
96
|
+
res.status(400).sendWrap(req.__("Internal Error"), page);
|
|
97
|
+
} else if (!page) {
|
|
98
|
+
getState().log(2, `Unable to find a random page in ${pageGroup.name}`);
|
|
99
|
+
res
|
|
100
|
+
.status(404)
|
|
101
|
+
.sendWrap(
|
|
102
|
+
req.__("Internal Error"),
|
|
103
|
+
req.__("Unable to find a random page in %s", pageGroup.name)
|
|
104
|
+
);
|
|
105
|
+
} else await runPage(page, req, res, tic);
|
|
97
106
|
} else {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
.
|
|
101
|
-
.sendWrap(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
const eligible = await getEligiblePage(pageGroup, req, res);
|
|
108
|
+
if (typeof eligible === "string") {
|
|
109
|
+
getState().log(2, eligible);
|
|
110
|
+
res.status(400).sendWrap(req.__("Internal Error"), eligible);
|
|
111
|
+
} else if (eligible) {
|
|
112
|
+
if (!eligible.isReload) await runPage(eligible, req, res, tic);
|
|
113
|
+
} else {
|
|
114
|
+
getState().log(2, `Pagegroup ${pageGroup.name} has no eligible page`);
|
|
115
|
+
res
|
|
116
|
+
.status(404)
|
|
117
|
+
.sendWrap(
|
|
118
|
+
req.__("Internal Error"),
|
|
119
|
+
req.__("%s has no eligible page", pageGroup.name)
|
|
120
|
+
);
|
|
121
|
+
}
|
|
105
122
|
}
|
|
106
123
|
} else {
|
|
107
124
|
getState().log(2, `Pagegroup ${pageGroup.name} not authorized`);
|