@saltcorn/server 0.7.4-beta.1 → 0.7.4-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/routes.js +64 -86
- package/locales/en.json +36 -1
- package/locales/ru.json +60 -7
- package/markup/admin.js +17 -4
- package/markup/expression_blurb.js +1 -1
- package/package.json +7 -7
- package/public/blockly.js +11 -5
- package/public/gridedit.js +7 -2
- package/public/saltcorn-common.js +27 -29
- package/public/saltcorn.css +24 -1
- package/public/saltcorn.js +56 -19
- package/routes/actions.js +2 -39
- package/routes/admin.js +16 -17
- package/routes/api.js +7 -6
- package/routes/common_lists.js +419 -0
- package/routes/diagram.js +59 -0
- package/routes/fields.js +42 -12
- package/routes/index.js +6 -0
- package/routes/pageedit.js +14 -108
- package/routes/plugins.js +15 -15
- package/routes/tables.js +10 -41
- package/routes/tag_entries.js +173 -0
- package/routes/tags.js +266 -0
- package/routes/viewedit.js +19 -136
- package/tests/page.test.js +9 -0
- package/tests/viewedit.test.js +16 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
const User = require("@saltcorn/data/models/user");
|
|
2
|
+
const Table = require("@saltcorn/data/models/table");
|
|
3
|
+
const { editRoleForm } = require("../markup/forms.js");
|
|
4
|
+
const {
|
|
5
|
+
mkTable,
|
|
6
|
+
link,
|
|
7
|
+
post_delete_btn,
|
|
8
|
+
settingsDropdown,
|
|
9
|
+
post_dropdown_item,
|
|
10
|
+
} = require("@saltcorn/markup");
|
|
11
|
+
|
|
12
|
+
const { h4, p, div, a, input, text } = require("@saltcorn/markup/tags");
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {string} col
|
|
16
|
+
* @param {string} lbl
|
|
17
|
+
* @returns {string}
|
|
18
|
+
*/
|
|
19
|
+
const badge = (col, lbl) => `<span class="badge bg-${col}">${lbl}</span> `;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Table badges to show in System Table list views
|
|
23
|
+
* Currently supports:
|
|
24
|
+
* - Owned - if ownership_field_id? What is it?
|
|
25
|
+
* - History - if table has versioning
|
|
26
|
+
* - External - if this is external table
|
|
27
|
+
* @param {object} t table object
|
|
28
|
+
* @param {object} req http request
|
|
29
|
+
* @returns {string} html string with list of badges
|
|
30
|
+
*/
|
|
31
|
+
const tableBadges = (t, req) => {
|
|
32
|
+
let s = "";
|
|
33
|
+
if (t.ownership_field_id) s += badge("primary", req.__("Owned"));
|
|
34
|
+
if (t.versioned) s += badge("success", req.__("History"));
|
|
35
|
+
if (t.external) s += badge("info", req.__("External"));
|
|
36
|
+
return s;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const valIfSet = (check, value) => (check ? value : "");
|
|
40
|
+
|
|
41
|
+
const listClass = (tagId, showList) =>
|
|
42
|
+
valIfSet(tagId, `collapse ${valIfSet(showList, "show")}`);
|
|
43
|
+
|
|
44
|
+
const tablesList = async (tables, req, { tagId, domId, showList } = {}) => {
|
|
45
|
+
const roles = await User.get_roles();
|
|
46
|
+
const getRole = (rid) => roles.find((r) => r.id === rid).role;
|
|
47
|
+
return tables.length > 0
|
|
48
|
+
? mkTable(
|
|
49
|
+
[
|
|
50
|
+
{
|
|
51
|
+
label: req.__("Name"),
|
|
52
|
+
key: (r) => link(`/table/${r.id || r.name}`, text(r.name)),
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
label: "",
|
|
56
|
+
key: (r) => tableBadges(r, req),
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
label: req.__("Access Read/Write"),
|
|
60
|
+
key: (t) =>
|
|
61
|
+
t.external
|
|
62
|
+
? `${getRole(t.min_role_read)} (read only)`
|
|
63
|
+
: `${getRole(t.min_role_read)}/${getRole(t.min_role_write)}`,
|
|
64
|
+
},
|
|
65
|
+
!tagId
|
|
66
|
+
? {
|
|
67
|
+
label: req.__("Delete"),
|
|
68
|
+
key: (r) =>
|
|
69
|
+
r.name === "users" || r.external
|
|
70
|
+
? ""
|
|
71
|
+
: post_delete_btn(`/table/delete/${r.id}`, req, r.name),
|
|
72
|
+
}
|
|
73
|
+
: {
|
|
74
|
+
label: req.__("Remove From Tag"),
|
|
75
|
+
key: (r) =>
|
|
76
|
+
post_delete_btn(
|
|
77
|
+
`/tag-entries/remove/tables/${r.id}/${tagId}`,
|
|
78
|
+
req,
|
|
79
|
+
`${r.name} from this tag`
|
|
80
|
+
),
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
tables,
|
|
84
|
+
{
|
|
85
|
+
hover: true,
|
|
86
|
+
tableClass: listClass(tagId, showList),
|
|
87
|
+
tableId: domId,
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
: div(
|
|
91
|
+
{ class: listClass(tagId, showList), id: domId },
|
|
92
|
+
h4(req.__("No tables defined")),
|
|
93
|
+
p(req.__("Tables hold collections of similar data"))
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @param {object} view
|
|
99
|
+
* @param {object[]} roles
|
|
100
|
+
* @param {object} req
|
|
101
|
+
* @returns {Form}
|
|
102
|
+
*/
|
|
103
|
+
const editViewRoleForm = (view, roles, req) =>
|
|
104
|
+
editRoleForm({
|
|
105
|
+
url: `/viewedit/setrole/${view.id}`,
|
|
106
|
+
current_role: view.min_role,
|
|
107
|
+
roles,
|
|
108
|
+
req,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @param {object} view
|
|
113
|
+
* @param {object} req
|
|
114
|
+
* @returns {div}
|
|
115
|
+
*/
|
|
116
|
+
const view_dropdown = (view, req) =>
|
|
117
|
+
settingsDropdown(`dropdownMenuButton${view.id}`, [
|
|
118
|
+
a(
|
|
119
|
+
{
|
|
120
|
+
class: "dropdown-item",
|
|
121
|
+
href: `/view/${encodeURIComponent(view.name)}`,
|
|
122
|
+
},
|
|
123
|
+
'<i class="fas fa-running"></i> ' + req.__("Run")
|
|
124
|
+
),
|
|
125
|
+
a(
|
|
126
|
+
{
|
|
127
|
+
class: "dropdown-item",
|
|
128
|
+
href: `/viewedit/edit/${encodeURIComponent(view.name)}`,
|
|
129
|
+
},
|
|
130
|
+
'<i class="fas fa-edit"></i> ' + req.__("Edit")
|
|
131
|
+
),
|
|
132
|
+
post_dropdown_item(
|
|
133
|
+
`/viewedit/add-to-menu/${view.id}`,
|
|
134
|
+
'<i class="fas fa-bars"></i> ' + req.__("Add to menu"),
|
|
135
|
+
req
|
|
136
|
+
),
|
|
137
|
+
post_dropdown_item(
|
|
138
|
+
`/viewedit/clone/${view.id}`,
|
|
139
|
+
'<i class="far fa-copy"></i> ' + req.__("Duplicate"),
|
|
140
|
+
req
|
|
141
|
+
),
|
|
142
|
+
a(
|
|
143
|
+
{
|
|
144
|
+
class: "dropdown-item",
|
|
145
|
+
href: `javascript:ajax_modal('/admin/snapshot-restore/view/${view.name}')`,
|
|
146
|
+
},
|
|
147
|
+
'<i class="fas fa-undo-alt"></i> ' + req.__("Restore")
|
|
148
|
+
),
|
|
149
|
+
div({ class: "dropdown-divider" }),
|
|
150
|
+
post_dropdown_item(
|
|
151
|
+
`/viewedit/delete/${view.id}`,
|
|
152
|
+
'<i class="far fa-trash-alt"></i> ' + req.__("Delete"),
|
|
153
|
+
req,
|
|
154
|
+
true,
|
|
155
|
+
view.name
|
|
156
|
+
),
|
|
157
|
+
]);
|
|
158
|
+
|
|
159
|
+
const setTableRefs = async (views) => {
|
|
160
|
+
const tables = await Table.find();
|
|
161
|
+
const getTable = (tid) => tables.find((t) => t.id === tid).name;
|
|
162
|
+
|
|
163
|
+
views.forEach((v) => {
|
|
164
|
+
if (v.table_id) v.table = getTable(v.table_id);
|
|
165
|
+
else if (v.exttable_name) v.table = v.exttable_name;
|
|
166
|
+
else v.table = "";
|
|
167
|
+
});
|
|
168
|
+
return views;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const viewsList = async (views, req, { tagId, domId, showList } = {}) => {
|
|
172
|
+
const roles = await User.get_roles();
|
|
173
|
+
|
|
174
|
+
return views.length > 0
|
|
175
|
+
? mkTable(
|
|
176
|
+
[
|
|
177
|
+
{
|
|
178
|
+
label: req.__("Name"),
|
|
179
|
+
key: (r) => link(`/view/${encodeURIComponent(r.name)}`, r.name),
|
|
180
|
+
sortlink: !tagId
|
|
181
|
+
? `javascript:set_state_field('_sortby', 'name')`
|
|
182
|
+
: undefined,
|
|
183
|
+
},
|
|
184
|
+
// description - currently I dont want to show description in view list
|
|
185
|
+
// because description can be long
|
|
186
|
+
/*
|
|
187
|
+
{
|
|
188
|
+
label: req.__("Description"),
|
|
189
|
+
key: "description",
|
|
190
|
+
// this is sorting by column
|
|
191
|
+
sortlink: `javascript:set_state_field('_sortby', 'description')`,
|
|
192
|
+
},
|
|
193
|
+
*/
|
|
194
|
+
// template
|
|
195
|
+
{
|
|
196
|
+
label: req.__("Pattern"),
|
|
197
|
+
key: "viewtemplate",
|
|
198
|
+
sortlink: !tagId
|
|
199
|
+
? `javascript:set_state_field('_sortby', 'viewtemplate')`
|
|
200
|
+
: undefined,
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
label: req.__("Table"),
|
|
204
|
+
key: (r) => link(`/table/${r.table}`, r.table),
|
|
205
|
+
sortlink: !tagId
|
|
206
|
+
? `javascript:set_state_field('_sortby', 'table')`
|
|
207
|
+
: undefined,
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
label: req.__("Role to access"),
|
|
211
|
+
key: (row) => editViewRoleForm(row, roles, req),
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
label: "",
|
|
215
|
+
key: (r) =>
|
|
216
|
+
link(
|
|
217
|
+
`/viewedit/config/${encodeURIComponent(r.name)}`,
|
|
218
|
+
req.__("Configure")
|
|
219
|
+
),
|
|
220
|
+
},
|
|
221
|
+
!tagId
|
|
222
|
+
? {
|
|
223
|
+
label: "",
|
|
224
|
+
key: (r) => view_dropdown(r, req),
|
|
225
|
+
}
|
|
226
|
+
: {
|
|
227
|
+
label: req.__("Remove From Tag"),
|
|
228
|
+
key: (r) =>
|
|
229
|
+
post_delete_btn(
|
|
230
|
+
`/tag-entries/remove/views/${r.id}/${tagId}`,
|
|
231
|
+
req,
|
|
232
|
+
`${r.name} from this tag`
|
|
233
|
+
),
|
|
234
|
+
},
|
|
235
|
+
],
|
|
236
|
+
views,
|
|
237
|
+
{
|
|
238
|
+
hover: true,
|
|
239
|
+
tableClass: listClass(tagId, showList),
|
|
240
|
+
tableId: domId,
|
|
241
|
+
}
|
|
242
|
+
)
|
|
243
|
+
: div(
|
|
244
|
+
{ class: listClass(tagId, showList), id: domId },
|
|
245
|
+
h4(req.__("No views defined")),
|
|
246
|
+
p(req.__("Views define how table rows are displayed to the user"))
|
|
247
|
+
);
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @param {object} page
|
|
252
|
+
* @param {object} req
|
|
253
|
+
* @returns {string}
|
|
254
|
+
*/
|
|
255
|
+
const page_dropdown = (page, req) =>
|
|
256
|
+
settingsDropdown(`dropdownMenuButton${page.id}`, [
|
|
257
|
+
a(
|
|
258
|
+
{
|
|
259
|
+
class: "dropdown-item",
|
|
260
|
+
href: `/page/${encodeURIComponent(page.name)}`,
|
|
261
|
+
},
|
|
262
|
+
'<i class="fas fa-running"></i> ' + req.__("Run")
|
|
263
|
+
),
|
|
264
|
+
a(
|
|
265
|
+
{
|
|
266
|
+
class: "dropdown-item",
|
|
267
|
+
href: `/pageedit/edit-properties/${encodeURIComponent(page.name)}`,
|
|
268
|
+
},
|
|
269
|
+
'<i class="fas fa-edit"></i> ' + req.__("Edit properties")
|
|
270
|
+
),
|
|
271
|
+
post_dropdown_item(
|
|
272
|
+
`/pageedit/add-to-menu/${page.id}`,
|
|
273
|
+
'<i class="fas fa-bars"></i> ' + req.__("Add to menu"),
|
|
274
|
+
req
|
|
275
|
+
),
|
|
276
|
+
post_dropdown_item(
|
|
277
|
+
`/pageedit/clone/${page.id}`,
|
|
278
|
+
'<i class="far fa-copy"></i> ' + req.__("Duplicate"),
|
|
279
|
+
req
|
|
280
|
+
),
|
|
281
|
+
a(
|
|
282
|
+
{
|
|
283
|
+
class: "dropdown-item",
|
|
284
|
+
href: `javascript:ajax_modal('/admin/snapshot-restore/page/${page.name}')`,
|
|
285
|
+
},
|
|
286
|
+
'<i class="fas fa-undo-alt"></i> ' + req.__("Restore")
|
|
287
|
+
),
|
|
288
|
+
div({ class: "dropdown-divider" }),
|
|
289
|
+
post_dropdown_item(
|
|
290
|
+
`/pageedit/delete/${page.id}`,
|
|
291
|
+
'<i class="far fa-trash-alt"></i> ' + req.__("Delete"),
|
|
292
|
+
req,
|
|
293
|
+
true,
|
|
294
|
+
page.name
|
|
295
|
+
),
|
|
296
|
+
]);
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* @param {object} page
|
|
300
|
+
* @param {*} roles
|
|
301
|
+
* @param {object} req
|
|
302
|
+
* @returns {Form}
|
|
303
|
+
*/
|
|
304
|
+
const editPageRoleForm = (page, roles, req) =>
|
|
305
|
+
editRoleForm({
|
|
306
|
+
url: `/pageedit/setrole/${page.id}`,
|
|
307
|
+
current_role: page.min_role,
|
|
308
|
+
roles,
|
|
309
|
+
req,
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* @param {*} rows
|
|
314
|
+
* @param {*} roles
|
|
315
|
+
* @param {object} req
|
|
316
|
+
* @returns {div}
|
|
317
|
+
*/
|
|
318
|
+
const getPageList = (rows, roles, req, { tagId, domId, showList } = {}) => {
|
|
319
|
+
return mkTable(
|
|
320
|
+
[
|
|
321
|
+
{
|
|
322
|
+
label: req.__("Name"),
|
|
323
|
+
key: (r) => link(`/page/${r.name}`, r.name),
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
label: req.__("Role to access"),
|
|
327
|
+
key: (row) => editPageRoleForm(row, roles, req),
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
label: req.__("Edit"),
|
|
331
|
+
key: (r) => link(`/pageedit/edit/${r.name}`, req.__("Edit")),
|
|
332
|
+
},
|
|
333
|
+
!tagId
|
|
334
|
+
? {
|
|
335
|
+
label: "",
|
|
336
|
+
key: (r) => page_dropdown(r, req),
|
|
337
|
+
}
|
|
338
|
+
: {
|
|
339
|
+
label: req.__("Remove From Tag"),
|
|
340
|
+
key: (r) =>
|
|
341
|
+
post_delete_btn(
|
|
342
|
+
`/tag-entries/remove/pages/${r.id}/${tagId}`,
|
|
343
|
+
req,
|
|
344
|
+
`${r.name} from this tag`
|
|
345
|
+
),
|
|
346
|
+
},
|
|
347
|
+
,
|
|
348
|
+
],
|
|
349
|
+
rows,
|
|
350
|
+
{
|
|
351
|
+
hover: true,
|
|
352
|
+
tableClass: tagId ? `collapse ${showList ? "show" : ""}` : "",
|
|
353
|
+
tableId: domId,
|
|
354
|
+
}
|
|
355
|
+
);
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const getTriggerList = (triggers, req, { tagId, domId, showList } = {}) => {
|
|
359
|
+
return mkTable(
|
|
360
|
+
[
|
|
361
|
+
{ label: req.__("Name"), key: "name" },
|
|
362
|
+
{ label: req.__("Action"), key: "action" },
|
|
363
|
+
{
|
|
364
|
+
label: req.__("Table or Channel"),
|
|
365
|
+
key: (r) => r.table_name || r.channel,
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
label: req.__("When"),
|
|
369
|
+
key: (a) =>
|
|
370
|
+
a.when_trigger === "API call"
|
|
371
|
+
? `API: ${base_url}api/action/${a.name}`
|
|
372
|
+
: a.when_trigger,
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
label: req.__("Test run"),
|
|
376
|
+
key: (r) =>
|
|
377
|
+
r.table_id
|
|
378
|
+
? ""
|
|
379
|
+
: link(`/actions/testrun/${r.id}`, req.__("Test run")),
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
label: req.__("Edit"),
|
|
383
|
+
key: (r) => link(`/actions/edit/${r.id}`, req.__("Edit")),
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
label: req.__("Configure"),
|
|
387
|
+
key: (r) => link(`/actions/configure/${r.id}`, req.__("Configure")),
|
|
388
|
+
},
|
|
389
|
+
!tagId
|
|
390
|
+
? {
|
|
391
|
+
label: req.__("Delete"),
|
|
392
|
+
key: (r) => post_delete_btn(`/actions/delete/${r.id}`, req),
|
|
393
|
+
}
|
|
394
|
+
: {
|
|
395
|
+
label: req.__("Remove From Tag"),
|
|
396
|
+
key: (r) =>
|
|
397
|
+
post_delete_btn(
|
|
398
|
+
`/tag-entries/remove/trigger/${r.id}/${tagId}`,
|
|
399
|
+
req,
|
|
400
|
+
`${r.name} from this tag`
|
|
401
|
+
),
|
|
402
|
+
},
|
|
403
|
+
],
|
|
404
|
+
triggers,
|
|
405
|
+
{
|
|
406
|
+
hover: true,
|
|
407
|
+
tableClass: tagId ? `collapse ${showList ? "show" : ""}` : "",
|
|
408
|
+
tableId: domId,
|
|
409
|
+
}
|
|
410
|
+
);
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
module.exports = {
|
|
414
|
+
tablesList,
|
|
415
|
+
setTableRefs,
|
|
416
|
+
viewsList,
|
|
417
|
+
getPageList,
|
|
418
|
+
getTriggerList,
|
|
419
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const Page = require("@saltcorn/data/models/page");
|
|
2
|
+
const {
|
|
3
|
+
buildObjectTrees,
|
|
4
|
+
} = require("@saltcorn/data/diagram/node_extract_utils");
|
|
5
|
+
const { generateCyCode } = require("@saltcorn/data/diagram/cy_generate_utils");
|
|
6
|
+
const { getState } = require("@saltcorn/data/db/state");
|
|
7
|
+
const { div, script, domReady } = require("@saltcorn/markup/tags");
|
|
8
|
+
const { isAdmin, error_catcher } = require("./utils.js");
|
|
9
|
+
const Router = require("express-promise-router");
|
|
10
|
+
|
|
11
|
+
const router = new Router();
|
|
12
|
+
module.exports = router;
|
|
13
|
+
|
|
14
|
+
router.get(
|
|
15
|
+
"/",
|
|
16
|
+
isAdmin,
|
|
17
|
+
error_catcher(async (req, res) => {
|
|
18
|
+
const modernCfg = getState().getConfig("home_page_by_role");
|
|
19
|
+
let pages = null;
|
|
20
|
+
if (modernCfg) {
|
|
21
|
+
pages = Object.values(modernCfg)
|
|
22
|
+
.filter((val) => val)
|
|
23
|
+
.map((val) => Page.findOne({ name: val }));
|
|
24
|
+
} else {
|
|
25
|
+
pages = new Array();
|
|
26
|
+
for (const legacyRole of ["public", "user", "staff", "admin"]) {
|
|
27
|
+
const page = await Page.findOne({ name: `${legacyRole}_home` });
|
|
28
|
+
if (page) pages.push(page);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const cyCode = generateCyCode(await buildObjectTrees(pages));
|
|
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
|
+
{
|
|
49
|
+
above: [
|
|
50
|
+
{
|
|
51
|
+
type: "card",
|
|
52
|
+
title: req.__(`Application diagram`),
|
|
53
|
+
contents: [div({ id: "cy" }), script(domReady(cyCode))],
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
})
|
|
59
|
+
);
|
package/routes/fields.js
CHANGED
|
@@ -19,15 +19,17 @@ const {
|
|
|
19
19
|
expressionValidator,
|
|
20
20
|
get_async_expression_function,
|
|
21
21
|
get_expression_function,
|
|
22
|
+
freeVariables,
|
|
22
23
|
} = require("@saltcorn/data/models/expression");
|
|
23
24
|
const db = require("@saltcorn/data/db");
|
|
24
25
|
|
|
25
26
|
const { isAdmin, error_catcher } = require("./utils.js");
|
|
26
27
|
const expressionBlurb = require("../markup/expression_blurb");
|
|
27
|
-
const { readState } = require("@saltcorn/data/plugin-helper");
|
|
28
|
+
const { readState, add_free_variables_to_joinfields } = require("@saltcorn/data/plugin-helper");
|
|
28
29
|
const { wizardCardTitle } = require("../markup/forms.js");
|
|
29
30
|
const FieldRepeat = require("@saltcorn/data/models/fieldrepeat");
|
|
30
31
|
const { applyAsync } = require("@saltcorn/data/utils");
|
|
32
|
+
const { text } = require("@saltcorn/markup/tags");
|
|
31
33
|
|
|
32
34
|
/**
|
|
33
35
|
* @type {object}
|
|
@@ -620,7 +622,11 @@ router.post(
|
|
|
620
622
|
const { formula, tablename, stored } = req.body;
|
|
621
623
|
const table = await Table.findOne({ name: tablename });
|
|
622
624
|
const fields = await table.getFields();
|
|
623
|
-
const
|
|
625
|
+
const freeVars = freeVariables(formula)
|
|
626
|
+
const joinFields = {}
|
|
627
|
+
if (stored)
|
|
628
|
+
add_free_variables_to_joinfields(freeVars, joinFields, fields)
|
|
629
|
+
const rows = await table.getJoinedRows({ joinFields, orderBy: "RANDOM()", limit: 1 });
|
|
624
630
|
if (rows.length < 1) return "No rows in table";
|
|
625
631
|
let result;
|
|
626
632
|
try {
|
|
@@ -660,8 +666,12 @@ router.post(
|
|
|
660
666
|
return;
|
|
661
667
|
}
|
|
662
668
|
const fields = await table.getFields();
|
|
663
|
-
|
|
664
|
-
|
|
669
|
+
let row = { ...req.body };
|
|
670
|
+
if (!row || Object.keys(row).length === 0) {
|
|
671
|
+
const { id } = req.query
|
|
672
|
+
if (id) row = await table.getRow({ id })
|
|
673
|
+
} else
|
|
674
|
+
readState(row, fields);
|
|
665
675
|
|
|
666
676
|
if (fieldName.includes(".")) {
|
|
667
677
|
//join field
|
|
@@ -677,14 +687,30 @@ router.post(
|
|
|
677
687
|
(f) => f.name === kpath[1]
|
|
678
688
|
);
|
|
679
689
|
//console.log({ kpath, fieldview, targetField });
|
|
680
|
-
let fv = targetField.type.fieldviews[fieldview];
|
|
681
|
-
if (!fv) {
|
|
682
|
-
fv =
|
|
683
|
-
targetField.type.fieldviews.show ||
|
|
684
|
-
targetField.type.fieldviews.as_text;
|
|
685
|
-
}
|
|
686
690
|
const q = { [reftable.pk_name]: row[kpath[0]] };
|
|
687
691
|
const refRow = await reftable.getRow(q);
|
|
692
|
+
let fv;
|
|
693
|
+
if (targetField.type === "Key") {
|
|
694
|
+
fv = getState().keyFieldviews[fieldview]
|
|
695
|
+
if (!fv) {
|
|
696
|
+
const reftable2 = Table.findOne({ name: targetField.reftable_name })
|
|
697
|
+
const refRow2 = await reftable2.getRow({ [reftable2.pk_name]: refRow[kpath[1]] })
|
|
698
|
+
if (refRow2) {
|
|
699
|
+
res.send(text(`${refRow2[targetField.attributes.summary_field]}`));
|
|
700
|
+
} else {
|
|
701
|
+
res.send("");
|
|
702
|
+
}
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
} else {
|
|
706
|
+
fv = targetField.type.fieldviews[fieldview];
|
|
707
|
+
if (!fv)
|
|
708
|
+
fv =
|
|
709
|
+
targetField.type.fieldviews.show ||
|
|
710
|
+
targetField.type.fieldviews.as_text;
|
|
711
|
+
|
|
712
|
+
}
|
|
713
|
+
|
|
688
714
|
const configuration = req.query;
|
|
689
715
|
let configFields = [];
|
|
690
716
|
if (fv.configFields)
|
|
@@ -726,7 +752,9 @@ router.post(
|
|
|
726
752
|
|
|
727
753
|
let result;
|
|
728
754
|
try {
|
|
729
|
-
if (field.
|
|
755
|
+
if (!field.calculated) {
|
|
756
|
+
result = row[field.name]
|
|
757
|
+
} else if (field.stored) {
|
|
730
758
|
const f = get_async_expression_function(formula, fields);
|
|
731
759
|
result = await f(row);
|
|
732
760
|
} else {
|
|
@@ -734,7 +762,9 @@ router.post(
|
|
|
734
762
|
result = f(row);
|
|
735
763
|
}
|
|
736
764
|
const fv = field.type.fieldviews[fieldview];
|
|
737
|
-
|
|
765
|
+
if (!fv)
|
|
766
|
+
res.send(text(result));
|
|
767
|
+
else res.send(fv.run(result));
|
|
738
768
|
} catch (e) {
|
|
739
769
|
return res.status(400).send(`Error: ${e.message}`);
|
|
740
770
|
}
|
package/routes/index.js
CHANGED
|
@@ -70,6 +70,9 @@ const auth = require("../auth/routes");
|
|
|
70
70
|
const useradmin = require("../auth/admin");
|
|
71
71
|
const roleadmin = require("../auth/roleadmin");
|
|
72
72
|
const scapi = require("./scapi");
|
|
73
|
+
const tags = require("./tags");
|
|
74
|
+
const tagentries = require("./tag_entries");
|
|
75
|
+
const dataDiagram = require("./diagram");
|
|
73
76
|
|
|
74
77
|
module.exports =
|
|
75
78
|
/**
|
|
@@ -106,4 +109,7 @@ module.exports =
|
|
|
106
109
|
app.use("/useradmin", useradmin);
|
|
107
110
|
app.use("/roleadmin", roleadmin);
|
|
108
111
|
app.use("/scapi", scapi);
|
|
112
|
+
app.use("/tag", tags);
|
|
113
|
+
app.use("/tag-entries", tagentries);
|
|
114
|
+
app.use("/diagram", dataDiagram);
|
|
109
115
|
};
|