@saltcorn/server 0.8.5-beta.2 → 0.8.5-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/locales/en.json +13 -1
- package/locales/pl.json +1110 -0
- package/package.json +9 -8
- package/public/saltcorn-common.js +44 -8
- package/routes/admin.js +17 -3
- package/routes/api.js +8 -8
- package/routes/tables.js +103 -33
- package/routes/utils.js +19 -0
- package/tests/table.test.js +2 -2
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "0.8.5-beta.
|
|
3
|
+
"version": "0.8.5-beta.3",
|
|
4
4
|
"description": "Server app for Saltcorn, open-source no-code platform",
|
|
5
5
|
"homepage": "https://saltcorn.com",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@saltcorn/base-plugin": "0.8.5-beta.
|
|
10
|
-
"@saltcorn/builder": "0.8.5-beta.
|
|
11
|
-
"@saltcorn/data": "0.8.5-beta.
|
|
12
|
-
"@saltcorn/admin-models": "0.8.5-beta.
|
|
13
|
-
"@saltcorn/filemanager": "0.8.5-beta.
|
|
14
|
-
"@saltcorn/markup": "0.8.5-beta.
|
|
15
|
-
"@saltcorn/sbadmin2": "0.8.5-beta.
|
|
9
|
+
"@saltcorn/base-plugin": "0.8.5-beta.3",
|
|
10
|
+
"@saltcorn/builder": "0.8.5-beta.3",
|
|
11
|
+
"@saltcorn/data": "0.8.5-beta.3",
|
|
12
|
+
"@saltcorn/admin-models": "0.8.5-beta.3",
|
|
13
|
+
"@saltcorn/filemanager": "0.8.5-beta.3",
|
|
14
|
+
"@saltcorn/markup": "0.8.5-beta.3",
|
|
15
|
+
"@saltcorn/sbadmin2": "0.8.5-beta.3",
|
|
16
16
|
"@socket.io/cluster-adapter": "^0.2.1",
|
|
17
17
|
"@socket.io/sticky": "^1.0.1",
|
|
18
18
|
"adm-zip": "0.5.10",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"qrcode": "1.5.1",
|
|
53
53
|
"resize-with-sharp-or-jimp": "0.1.6",
|
|
54
54
|
"socket.io": "4.6.0",
|
|
55
|
+
"systeminformation": "^5.11.12",
|
|
55
56
|
"thirty-two": "1.0.2",
|
|
56
57
|
"tmp-promise": "^3.0.2",
|
|
57
58
|
"uuid": "^8.2.0",
|
|
@@ -145,7 +145,7 @@ function apply_showif() {
|
|
|
145
145
|
});
|
|
146
146
|
element.dispatchEvent(new Event("RefreshSelectOptions"));
|
|
147
147
|
if (e.hasClass("selectized") && $().selectize) {
|
|
148
|
-
e.selectize()[0].selectize.clearOptions();
|
|
148
|
+
e.selectize()[0].selectize.clearOptions(true);
|
|
149
149
|
e.selectize()[0].selectize.addOption(dataOptions);
|
|
150
150
|
if (typeof currentDataOption !== "undefined")
|
|
151
151
|
e.selectize()[0].selectize.setValue(currentDataOption);
|
|
@@ -428,6 +428,10 @@ function initialize_page() {
|
|
|
428
428
|
var key = $(this).attr("data-inline-edit-field") || "value";
|
|
429
429
|
var ajax = !!$(this).attr("data-inline-edit-ajax");
|
|
430
430
|
var type = $(this).attr("data-inline-edit-type");
|
|
431
|
+
var schema = $(this).attr("data-inline-edit-schema");
|
|
432
|
+
if (schema) {
|
|
433
|
+
schema = JSON.parse(decodeURIComponent(schema));
|
|
434
|
+
}
|
|
431
435
|
var is_key = type?.startsWith("Key:");
|
|
432
436
|
const opts = encodeURIComponent(
|
|
433
437
|
JSON.stringify({
|
|
@@ -438,12 +442,16 @@ function initialize_page() {
|
|
|
438
442
|
current_label: $(this).attr("data-inline-edit-current-label"),
|
|
439
443
|
type,
|
|
440
444
|
is_key,
|
|
445
|
+
schema,
|
|
441
446
|
})
|
|
442
447
|
);
|
|
443
|
-
|
|
444
|
-
const [tblName, target] = type.replace("Key:", "").split(".");
|
|
448
|
+
const doAjaxOptionsFetch = (tblName, target) => {
|
|
445
449
|
$.ajax(`/api/${tblName}`).then((resp) => {
|
|
446
450
|
if (resp.success) {
|
|
451
|
+
resp.success.sort((a, b) =>
|
|
452
|
+
a[target]?.toLowerCase?.() > b[target]?.toLowerCase?.() ? 1 : -1
|
|
453
|
+
);
|
|
454
|
+
|
|
447
455
|
const selopts = resp.success.map(
|
|
448
456
|
(r) =>
|
|
449
457
|
`<option ${current == r.id ? `selected ` : ``}value="${
|
|
@@ -463,6 +471,14 @@ function initialize_page() {
|
|
|
463
471
|
);
|
|
464
472
|
}
|
|
465
473
|
});
|
|
474
|
+
};
|
|
475
|
+
if (type === "JSON" && schema && schema.type.startsWith("Key to ")) {
|
|
476
|
+
const tblName = schema.type.replace("Key to ", "");
|
|
477
|
+
const target = schema.summary_field || "id";
|
|
478
|
+
doAjaxOptionsFetch(tblName, target);
|
|
479
|
+
} else if (is_key) {
|
|
480
|
+
const [tblName, target] = type.replace("Key:", "").split(".");
|
|
481
|
+
doAjaxOptionsFetch(tblName, target);
|
|
466
482
|
} else
|
|
467
483
|
$(this).replaceWith(
|
|
468
484
|
`<form method="post" action="${url}" ${
|
|
@@ -590,7 +606,10 @@ $(initialize_page);
|
|
|
590
606
|
function cancel_inline_edit(e, opts1) {
|
|
591
607
|
var opts = JSON.parse(decodeURIComponent(opts1 || "") || "{}");
|
|
592
608
|
var form = $(e.target).closest("form");
|
|
593
|
-
|
|
609
|
+
var json_fk_opt;
|
|
610
|
+
if (opts.schema) {
|
|
611
|
+
json_fk_opt = form.find(`option[value="${opts.current}"]`).text();
|
|
612
|
+
}
|
|
594
613
|
form.replaceWith(`<div
|
|
595
614
|
data-inline-edit-field="${opts.key}"
|
|
596
615
|
${opts.ajax ? `data-inline-edit-ajax="true"` : ""}
|
|
@@ -601,8 +620,17 @@ function cancel_inline_edit(e, opts1) {
|
|
|
601
620
|
? `data-inline-edit-current-label="${opts.current_label}"`
|
|
602
621
|
: ""
|
|
603
622
|
}
|
|
623
|
+
${
|
|
624
|
+
opts.schema
|
|
625
|
+
? `data-inline-edit-schema="${encodeURIComponent(
|
|
626
|
+
JSON.stringify(opts.schema)
|
|
627
|
+
)}"`
|
|
628
|
+
: ""
|
|
629
|
+
}
|
|
604
630
|
data-inline-edit-dest-url="${opts.url}">
|
|
605
|
-
<span class="current">${
|
|
631
|
+
<span class="current">${
|
|
632
|
+
json_fk_opt || opts.current_label || opts.current
|
|
633
|
+
}</span>
|
|
606
634
|
<i class="editicon fas fa-edit ms-1"></i>
|
|
607
635
|
</div>`);
|
|
608
636
|
initialize_page();
|
|
@@ -624,15 +652,23 @@ function inline_ajax_submit(e, opts1) {
|
|
|
624
652
|
success: function (res) {
|
|
625
653
|
if (opts) {
|
|
626
654
|
let rawVal = formDataArray.find((f) => f.name == opts.key).value;
|
|
627
|
-
let val =
|
|
628
|
-
|
|
629
|
-
|
|
655
|
+
let val =
|
|
656
|
+
opts.is_key || (opts.schema && opts.schema.type.startsWith("Key to "))
|
|
657
|
+
? form.find("select").find("option:selected").text()
|
|
658
|
+
: rawVal;
|
|
630
659
|
|
|
631
660
|
$(e.target).replaceWith(`<div
|
|
632
661
|
data-inline-edit-field="${opts.key}"
|
|
633
662
|
${opts.ajax ? `data-inline-edit-ajax="true"` : ""}
|
|
634
663
|
${opts.type ? `data-inline-edit-type="${opts.type}"` : ""}
|
|
635
664
|
${opts.current ? `data-inline-edit-current="${rawVal}"` : ""}
|
|
665
|
+
${
|
|
666
|
+
opts.schema
|
|
667
|
+
? `data-inline-edit-schema="${encodeURIComponent(
|
|
668
|
+
JSON.stringify(opts.schema)
|
|
669
|
+
)}"`
|
|
670
|
+
: ""
|
|
671
|
+
}
|
|
636
672
|
${opts.current_label ? `data-inline-edit-current-label="${val}"` : ""}
|
|
637
673
|
data-inline-edit-dest-url="${opts.url}">
|
|
638
674
|
<span class="current">${val}</span>
|
package/routes/admin.js
CHANGED
|
@@ -10,6 +10,7 @@ const {
|
|
|
10
10
|
error_catcher,
|
|
11
11
|
getGitRevision,
|
|
12
12
|
setTenant,
|
|
13
|
+
get_sys_info,
|
|
13
14
|
} = require("./utils.js");
|
|
14
15
|
const Table = require("@saltcorn/data/models/table");
|
|
15
16
|
const Plugin = require("@saltcorn/data/models/plugin");
|
|
@@ -864,7 +865,7 @@ router.get(
|
|
|
864
865
|
const can_update =
|
|
865
866
|
!is_latest && !process.env.SALTCORN_DISABLE_UPGRADE && !git_commit;
|
|
866
867
|
const dbversion = await db.getVersion(true);
|
|
867
|
-
|
|
868
|
+
const { memUsage, diskUsage, cpuUsage } = await get_sys_info();
|
|
868
869
|
send_admin_page({
|
|
869
870
|
res,
|
|
870
871
|
req,
|
|
@@ -986,7 +987,20 @@ router.get(
|
|
|
986
987
|
tr(
|
|
987
988
|
th(req.__("Process uptime")),
|
|
988
989
|
td(moment(get_process_init_time()).fromNow(true))
|
|
989
|
-
)
|
|
990
|
+
),
|
|
991
|
+
tr(
|
|
992
|
+
th(req.__("Disk usage")),
|
|
993
|
+
diskUsage > 95
|
|
994
|
+
? td(
|
|
995
|
+
{ class: "text-danger fw-bold" },
|
|
996
|
+
diskUsage,
|
|
997
|
+
"%",
|
|
998
|
+
i({ class: "fas fa-exclamation-triangle ms-1" })
|
|
999
|
+
)
|
|
1000
|
+
: td(diskUsage, "%")
|
|
1001
|
+
),
|
|
1002
|
+
tr(th(req.__("CPU usage")), td(cpuUsage, "%")),
|
|
1003
|
+
tr(th(req.__("Mem usage")), td(memUsage, "%"))
|
|
990
1004
|
)
|
|
991
1005
|
),
|
|
992
1006
|
p(
|
|
@@ -1307,7 +1321,7 @@ router.get(
|
|
|
1307
1321
|
"/configuration-check",
|
|
1308
1322
|
isAdmin,
|
|
1309
1323
|
error_catcher(async (req, res) => {
|
|
1310
|
-
const filename = `${moment().format("
|
|
1324
|
+
const filename = `${moment().format("YYYYMMDDHHmm")}.html`;
|
|
1311
1325
|
await File.new_folder("configuration_checks");
|
|
1312
1326
|
const go = async () => {
|
|
1313
1327
|
const { passes, errors, pass, warnings } = await runConfigurationCheck(
|
package/routes/api.js
CHANGED
|
@@ -421,29 +421,29 @@ router.post(
|
|
|
421
421
|
readState(row, fields);
|
|
422
422
|
let errors = [];
|
|
423
423
|
let hasErrors = false;
|
|
424
|
-
Object.keys(row)
|
|
424
|
+
for (const k of Object.keys(row)) {
|
|
425
425
|
const field = fields.find((f) => f.name === k);
|
|
426
426
|
if (!field && k.includes(".")) {
|
|
427
427
|
const [fnm, jkey] = k.split(".");
|
|
428
428
|
const jfield = fields.find((f) => f.name === fnm);
|
|
429
429
|
if (jfield?.type?.name === "JSON") {
|
|
430
|
-
if (
|
|
431
|
-
|
|
430
|
+
if (typeof row[fnm] === "undefined") {
|
|
431
|
+
const dbrow = await table.getRow({ [table.pk_name]: id });
|
|
432
|
+
row[fnm] = dbrow[fnm] || {};
|
|
433
|
+
}
|
|
434
|
+
row[fnm][jkey] = row[k];
|
|
432
435
|
delete row[k];
|
|
433
436
|
}
|
|
434
437
|
} else if (!field || field.calculated) {
|
|
435
438
|
delete row[k];
|
|
436
|
-
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
if (field?.type && field.type.validate) {
|
|
439
|
+
} else if (field?.type && field.type.validate) {
|
|
440
440
|
const vres = field.type.validate(field.attributes || {})(row[k]);
|
|
441
441
|
if (vres.error) {
|
|
442
442
|
hasErrors = true;
|
|
443
443
|
errors.push(`${k}: ${vres.error}`);
|
|
444
444
|
}
|
|
445
445
|
}
|
|
446
|
-
}
|
|
446
|
+
}
|
|
447
447
|
if (hasErrors) {
|
|
448
448
|
res.status(400).json({ error: errors.join(", ") });
|
|
449
449
|
return;
|
package/routes/tables.js
CHANGED
|
@@ -762,18 +762,22 @@ router.get(
|
|
|
762
762
|
})
|
|
763
763
|
)
|
|
764
764
|
),
|
|
765
|
+
!table.external &&
|
|
766
|
+
div(
|
|
767
|
+
{ class: "mx-auto" },
|
|
768
|
+
a(
|
|
769
|
+
{ href: `/table/constraints/${table.id}` },
|
|
770
|
+
i({ class: "fas fa-2x fa-tasks" }),
|
|
771
|
+
"<br/>",
|
|
772
|
+
req.__("Constraints")
|
|
773
|
+
)
|
|
774
|
+
),
|
|
775
|
+
|
|
765
776
|
// only if table is not external
|
|
766
777
|
!table.external &&
|
|
767
778
|
div(
|
|
768
779
|
{ class: "mx-auto" },
|
|
769
780
|
settingsDropdown(`dataMenuButton`, [
|
|
770
|
-
a(
|
|
771
|
-
{
|
|
772
|
-
class: "dropdown-item",
|
|
773
|
-
href: `/table/constraints/${table.id}`,
|
|
774
|
-
},
|
|
775
|
-
'<i class="fas fa-ban"></i> ' + req.__("Constraints")
|
|
776
|
-
),
|
|
777
781
|
// rename table doesnt supported for sqlite
|
|
778
782
|
!db.isSQLite &&
|
|
779
783
|
table.name !== "users" &&
|
|
@@ -1154,8 +1158,15 @@ router.get(
|
|
|
1154
1158
|
[
|
|
1155
1159
|
{ label: req.__("Type"), key: "type" },
|
|
1156
1160
|
{
|
|
1157
|
-
label: req.__("
|
|
1158
|
-
key: (r) =>
|
|
1161
|
+
label: req.__("What"),
|
|
1162
|
+
key: (r) =>
|
|
1163
|
+
r.type === "Unique"
|
|
1164
|
+
? r.configuration.fields.join(", ")
|
|
1165
|
+
: r.type === "Index"
|
|
1166
|
+
? r.configuration.field
|
|
1167
|
+
: r.type === "Formula"
|
|
1168
|
+
? r.configuration.formula
|
|
1169
|
+
: "",
|
|
1159
1170
|
},
|
|
1160
1171
|
{
|
|
1161
1172
|
label: req.__("Delete"),
|
|
@@ -1166,7 +1177,12 @@ router.get(
|
|
|
1166
1177
|
cons,
|
|
1167
1178
|
{ hover: true }
|
|
1168
1179
|
),
|
|
1169
|
-
|
|
1180
|
+
req.__("Add constraint: "),
|
|
1181
|
+
link(`/table/add-constraint/${id}/Unique`, req.__("Unique")),
|
|
1182
|
+
" | ",
|
|
1183
|
+
link(`/table/add-constraint/${id}/Formula`, req.__("Formula")),
|
|
1184
|
+
" | ",
|
|
1185
|
+
link(`/table/add-constraint/${id}/Index`, req.__("Index")),
|
|
1170
1186
|
],
|
|
1171
1187
|
},
|
|
1172
1188
|
],
|
|
@@ -1181,18 +1197,68 @@ router.get(
|
|
|
1181
1197
|
* @param {object[]} fields
|
|
1182
1198
|
* @returns {Form}
|
|
1183
1199
|
*/
|
|
1184
|
-
const constraintForm = (req, table_id, fields) =>
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1200
|
+
const constraintForm = (req, table_id, fields, type) => {
|
|
1201
|
+
switch (type) {
|
|
1202
|
+
case "Formula":
|
|
1203
|
+
return new Form({
|
|
1204
|
+
action: `/table/add-constraint/${table_id}/${type}`,
|
|
1205
|
+
|
|
1206
|
+
fields: [
|
|
1207
|
+
{
|
|
1208
|
+
name: "formula",
|
|
1209
|
+
label: req.__("Constraint formula"),
|
|
1210
|
+
validator: expressionValidator,
|
|
1211
|
+
type: "String",
|
|
1212
|
+
class: "validate-expression",
|
|
1213
|
+
sublabel:
|
|
1214
|
+
req.__(
|
|
1215
|
+
"Formula must evaluate to true for valid rows. In scope: "
|
|
1216
|
+
) +
|
|
1217
|
+
fields
|
|
1218
|
+
.map((f) => f.name)
|
|
1219
|
+
.map((fn) => code(fn))
|
|
1220
|
+
.join(", "),
|
|
1221
|
+
},
|
|
1222
|
+
{
|
|
1223
|
+
name: "errormsg",
|
|
1224
|
+
label: "Error message",
|
|
1225
|
+
sublabel: "Shown the user if formula is false",
|
|
1226
|
+
type: "String",
|
|
1227
|
+
},
|
|
1228
|
+
],
|
|
1229
|
+
});
|
|
1230
|
+
case "Unique":
|
|
1231
|
+
return new Form({
|
|
1232
|
+
action: `/table/add-constraint/${table_id}/${type}`,
|
|
1233
|
+
blurb: req.__(
|
|
1234
|
+
"Tick the boxes for the fields that should be jointly unique"
|
|
1235
|
+
),
|
|
1236
|
+
fields: fields.map((f) => ({
|
|
1237
|
+
name: f.name,
|
|
1238
|
+
label: f.label,
|
|
1239
|
+
type: "Bool",
|
|
1240
|
+
})),
|
|
1241
|
+
});
|
|
1242
|
+
case "Index":
|
|
1243
|
+
return new Form({
|
|
1244
|
+
action: `/table/add-constraint/${table_id}/${type}`,
|
|
1245
|
+
blurb: req.__(
|
|
1246
|
+
"Choose the field to be indexed. This make searching the table faster."
|
|
1247
|
+
),
|
|
1248
|
+
fields: [
|
|
1249
|
+
{
|
|
1250
|
+
type: "String",
|
|
1251
|
+
name: "field",
|
|
1252
|
+
label: "Field",
|
|
1253
|
+
required: true,
|
|
1254
|
+
attributes: {
|
|
1255
|
+
options: fields.map((f) => ({ label: f.label, name: f.name })),
|
|
1256
|
+
},
|
|
1257
|
+
},
|
|
1258
|
+
],
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1196
1262
|
|
|
1197
1263
|
/**
|
|
1198
1264
|
* Add constraint GET handler
|
|
@@ -1203,10 +1269,10 @@ const constraintForm = (req, table_id, fields) =>
|
|
|
1203
1269
|
* @function
|
|
1204
1270
|
*/
|
|
1205
1271
|
router.get(
|
|
1206
|
-
"/add-constraint/:id",
|
|
1272
|
+
"/add-constraint/:id/:type",
|
|
1207
1273
|
isAdmin,
|
|
1208
1274
|
error_catcher(async (req, res) => {
|
|
1209
|
-
const { id } = req.params;
|
|
1275
|
+
const { id, type } = req.params;
|
|
1210
1276
|
const table = await Table.findOne({ id });
|
|
1211
1277
|
if (!table) {
|
|
1212
1278
|
req.flash("error", `Table not found`);
|
|
@@ -1214,7 +1280,7 @@ router.get(
|
|
|
1214
1280
|
return;
|
|
1215
1281
|
}
|
|
1216
1282
|
const fields = await table.getFields();
|
|
1217
|
-
const form = constraintForm(req, table.id, fields);
|
|
1283
|
+
const form = constraintForm(req, table.id, fields, type);
|
|
1218
1284
|
res.sendWrap(req.__(`Add constraint to %s`, table.name), {
|
|
1219
1285
|
above: [
|
|
1220
1286
|
{
|
|
@@ -1231,7 +1297,7 @@ router.get(
|
|
|
1231
1297
|
},
|
|
1232
1298
|
{
|
|
1233
1299
|
type: "card",
|
|
1234
|
-
title: req.__(`Add constraint to %s`, table.name),
|
|
1300
|
+
title: req.__(`Add %s constraint to %s`, type, table.name),
|
|
1235
1301
|
contents: renderForm(form, req.csrfToken()),
|
|
1236
1302
|
},
|
|
1237
1303
|
],
|
|
@@ -1247,10 +1313,10 @@ router.get(
|
|
|
1247
1313
|
* @function
|
|
1248
1314
|
*/
|
|
1249
1315
|
router.post(
|
|
1250
|
-
"/add-constraint/:id",
|
|
1316
|
+
"/add-constraint/:id/:type",
|
|
1251
1317
|
isAdmin,
|
|
1252
1318
|
error_catcher(async (req, res) => {
|
|
1253
|
-
const { id } = req.params;
|
|
1319
|
+
const { id, type } = req.params;
|
|
1254
1320
|
const table = await Table.findOne({ id });
|
|
1255
1321
|
if (!table) {
|
|
1256
1322
|
req.flash("error", `Table not found`);
|
|
@@ -1258,16 +1324,20 @@ router.post(
|
|
|
1258
1324
|
return;
|
|
1259
1325
|
}
|
|
1260
1326
|
const fields = await table.getFields();
|
|
1261
|
-
const form = constraintForm(req, table.id, fields);
|
|
1327
|
+
const form = constraintForm(req, table.id, fields, type);
|
|
1262
1328
|
form.validate(req.body);
|
|
1263
1329
|
if (form.hasErrors) req.flash("error", req.__("An error occurred"));
|
|
1264
1330
|
else {
|
|
1331
|
+
let configuration = {};
|
|
1332
|
+
if (type === "Unique")
|
|
1333
|
+
configuration.fields = fields
|
|
1334
|
+
.map((f) => f.name)
|
|
1335
|
+
.filter((f) => form.values[f]);
|
|
1336
|
+
else configuration = form.values;
|
|
1265
1337
|
await TableConstraint.create({
|
|
1266
1338
|
table_id: table.id,
|
|
1267
|
-
type
|
|
1268
|
-
configuration
|
|
1269
|
-
fields: fields.map((f) => f.name).filter((f) => form.values[f]),
|
|
1270
|
-
},
|
|
1339
|
+
type,
|
|
1340
|
+
configuration,
|
|
1271
1341
|
});
|
|
1272
1342
|
}
|
|
1273
1343
|
res.redirect(`/table/constraints/${table.id}`);
|
package/routes/utils.js
CHANGED
|
@@ -18,6 +18,24 @@ const cookieSession = require("cookie-session");
|
|
|
18
18
|
const is = require("contractis/is");
|
|
19
19
|
const { validateHeaderName, validateHeaderValue } = require("http");
|
|
20
20
|
const Crash = require("@saltcorn/data/models/crash");
|
|
21
|
+
const si = require("systeminformation");
|
|
22
|
+
|
|
23
|
+
const get_sys_info = async () => {
|
|
24
|
+
const disks = await si.fsSize();
|
|
25
|
+
let size = 0;
|
|
26
|
+
let used = 0;
|
|
27
|
+
disks.forEach((d) => {
|
|
28
|
+
if (d && d.used && d.size) {
|
|
29
|
+
size += d.size;
|
|
30
|
+
used += d.used;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const diskUsage = Math.round(100 * (used / size));
|
|
34
|
+
const simem = await si.mem();
|
|
35
|
+
const memUsage = Math.round(100 - 100 * (simem.available / simem.total));
|
|
36
|
+
const cpuUsage = Math.round((await si.currentLoad()).currentLoad);
|
|
37
|
+
return { memUsage, diskUsage, cpuUsage };
|
|
38
|
+
};
|
|
21
39
|
|
|
22
40
|
/**
|
|
23
41
|
* Checks that user logged or not.
|
|
@@ -314,4 +332,5 @@ module.exports = {
|
|
|
314
332
|
get_tenant_from_req,
|
|
315
333
|
addOnDoneRedirect,
|
|
316
334
|
is_relative_url,
|
|
335
|
+
get_sys_info,
|
|
317
336
|
};
|
package/tests/table.test.js
CHANGED
|
@@ -198,11 +198,11 @@ Gordon Kane, 217`;
|
|
|
198
198
|
.set("Cookie", loginCookie)
|
|
199
199
|
.expect(toInclude("books constraints"));
|
|
200
200
|
await request(app)
|
|
201
|
-
.get("/table/add-constraint/" + id)
|
|
201
|
+
.get("/table/add-constraint/" + id + "/Unique")
|
|
202
202
|
.set("Cookie", loginCookie)
|
|
203
203
|
.expect(toInclude("Add constraint to books"));
|
|
204
204
|
await request(app)
|
|
205
|
-
.post("/table/add-constraint/" + id)
|
|
205
|
+
.post("/table/add-constraint/" + id + "/Unique")
|
|
206
206
|
.send("author=on")
|
|
207
207
|
.send("pages=on")
|
|
208
208
|
.set("Cookie", loginCookie)
|