@saltcorn/server 0.7.2-beta.9 → 0.7.3-beta.1
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 +3 -1
- package/locales/en.json +916 -906
- package/package.json +8 -8
- package/public/saltcorn-common.js +52 -6
- package/public/saltcorn.css +4 -0
- package/public/saltcorn.js +8 -4
- package/restart_watcher.js +2 -1
- package/routes/actions.js +1 -0
- package/routes/admin.js +153 -27
- package/routes/fields.js +4 -1
- package/routes/files.js +6 -2
- package/routes/tables.js +19 -4
- package/serve.js +15 -1
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3-beta.1",
|
|
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.7.
|
|
10
|
-
"@saltcorn/builder": "0.7.
|
|
11
|
-
"@saltcorn/data": "0.7.
|
|
12
|
-
"@saltcorn/admin-models": "0.7.
|
|
13
|
-
"@saltcorn/markup": "0.7.
|
|
14
|
-
"@saltcorn/sbadmin2": "0.7.
|
|
9
|
+
"@saltcorn/base-plugin": "0.7.3-beta.1",
|
|
10
|
+
"@saltcorn/builder": "0.7.3-beta.1",
|
|
11
|
+
"@saltcorn/data": "0.7.3-beta.1",
|
|
12
|
+
"@saltcorn/admin-models": "0.7.3-beta.1",
|
|
13
|
+
"@saltcorn/markup": "0.7.3-beta.1",
|
|
14
|
+
"@saltcorn/sbadmin2": "0.7.3-beta.1",
|
|
15
15
|
"@socket.io/cluster-adapter": "^0.1.0",
|
|
16
16
|
"@socket.io/sticky": "^1.0.1",
|
|
17
17
|
"aws-sdk": "^2.1037.0",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"pg": "^8.2.1",
|
|
49
49
|
"pluralize": "^8.0.0",
|
|
50
50
|
"qrcode": "1.5.0",
|
|
51
|
-
"sharp": "0.
|
|
51
|
+
"resize-with-sharp-or-jimp": "0.1.3",
|
|
52
52
|
"socket.io": "4.2.0",
|
|
53
53
|
"thirty-two": "1.0.2",
|
|
54
54
|
"tmp-promise": "^3.0.2",
|
|
@@ -215,6 +215,40 @@ function initialize_page() {
|
|
|
215
215
|
$(".blur-on-enter-keypress").bind("keyup", function (e) {
|
|
216
216
|
if (e.keyCode === 13) e.target.blur();
|
|
217
217
|
});
|
|
218
|
+
|
|
219
|
+
const validate_expression_elem = (target) => {
|
|
220
|
+
const next = target.next();
|
|
221
|
+
if (next.hasClass("expr-error")) next.remove();
|
|
222
|
+
const val = target.val();
|
|
223
|
+
if (target.hasClass("validate-expression-conditional")) {
|
|
224
|
+
const box = target
|
|
225
|
+
.closest(".form-namespace")
|
|
226
|
+
.find(`[name="${target.attr("name")}_formula"]`);
|
|
227
|
+
if (!box.prop("checked")) return;
|
|
228
|
+
}
|
|
229
|
+
if (!val) return;
|
|
230
|
+
try {
|
|
231
|
+
Function("return " + val);
|
|
232
|
+
} catch (error) {
|
|
233
|
+
target.after(`<small class="text-danger font-monospace d-block expr-error">
|
|
234
|
+
${error.message}
|
|
235
|
+
</small>`);
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
$(".validate-expression").bind("input", function (e) {
|
|
239
|
+
const target = $(e.target);
|
|
240
|
+
validate_expression_elem(target);
|
|
241
|
+
});
|
|
242
|
+
$(".validate-expression-conditional").each(function () {
|
|
243
|
+
const theInput = $(this);
|
|
244
|
+
theInput
|
|
245
|
+
.closest(".form-namespace")
|
|
246
|
+
.find(`[name="${theInput.attr("name")}_formula"]`)
|
|
247
|
+
.bind("change", function (e) {
|
|
248
|
+
validate_expression_elem(theInput);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
218
252
|
$("form").change(apply_showif);
|
|
219
253
|
apply_showif();
|
|
220
254
|
apply_showif();
|
|
@@ -437,7 +471,7 @@ function common_done(res, isWeb = true) {
|
|
|
437
471
|
|
|
438
472
|
const repeaterCopyValuesToForm = (form, editor) => {
|
|
439
473
|
const vs = JSON.parse(editor.getString());
|
|
440
|
-
|
|
474
|
+
|
|
441
475
|
const setVal = (k, ix, v) => {
|
|
442
476
|
const $e = form.find(`input[name="${k}_${ix}"]`);
|
|
443
477
|
if ($e.length) $e.val(v);
|
|
@@ -449,16 +483,22 @@ const repeaterCopyValuesToForm = (form, editor) => {
|
|
|
449
483
|
vs.forEach((v, ix) => {
|
|
450
484
|
Object.entries(v).forEach(([k, v]) => {
|
|
451
485
|
//console.log(ix, k, typeof v, v)
|
|
452
|
-
allNames.add(k);
|
|
453
486
|
if (typeof v === "boolean") setVal(k, ix, v ? "on" : "");
|
|
454
487
|
else setVal(k, ix, v);
|
|
455
488
|
});
|
|
456
489
|
});
|
|
457
490
|
//delete
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
491
|
+
//for (let ix = vs.length; ix < vs.length + 20; ix++) {
|
|
492
|
+
// $(`input[name="${k}_${ix}"]`).remove();
|
|
493
|
+
//}
|
|
494
|
+
$(`input[type=hidden]`).each(function () {
|
|
495
|
+
const name = $(this).attr("name");
|
|
496
|
+
if (!name) return;
|
|
497
|
+
const m = name.match(/_(\d+)$/);
|
|
498
|
+
if (!m || !m[1]) return;
|
|
499
|
+
const ix = parseInt(m[1], 10);
|
|
500
|
+
if (typeof ix !== "number" || isNaN(ix)) return;
|
|
501
|
+
if (ix >= vs.length) $(this).remove();
|
|
462
502
|
});
|
|
463
503
|
};
|
|
464
504
|
function align_dropdown(id) {
|
|
@@ -542,3 +582,9 @@ function unique_field_from_rows(
|
|
|
542
582
|
}
|
|
543
583
|
}
|
|
544
584
|
}
|
|
585
|
+
|
|
586
|
+
function cancel_form(form) {
|
|
587
|
+
if (!form) return;
|
|
588
|
+
$(form).append(`<input type="hidden" name="_cancel" value="on">`);
|
|
589
|
+
$(form).submit();
|
|
590
|
+
}
|
package/public/saltcorn.css
CHANGED
package/public/saltcorn.js
CHANGED
|
@@ -162,6 +162,13 @@ function globalErrorCatcher(message, source, lineno, colno, error) {
|
|
|
162
162
|
});
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
function close_saltcorn_modal() {
|
|
166
|
+
var myModalEl = document.getElementById("scmodal");
|
|
167
|
+
if (!myModalEl) return;
|
|
168
|
+
var modal = bootstrap.Modal.getInstance(myModalEl);
|
|
169
|
+
if (modal) modal.dispose();
|
|
170
|
+
}
|
|
171
|
+
|
|
165
172
|
function ajax_modal(url, opts = {}) {
|
|
166
173
|
if ($("#scmodal").length === 0) {
|
|
167
174
|
$("body").append(`<div id="scmodal", class="modal">
|
|
@@ -179,9 +186,7 @@ function ajax_modal(url, opts = {}) {
|
|
|
179
186
|
</div>
|
|
180
187
|
</div>`);
|
|
181
188
|
} else if ($("#scmodal").hasClass("show")) {
|
|
182
|
-
|
|
183
|
-
var modal = bootstrap.Modal.getInstance(myModalEl);
|
|
184
|
-
modal.dispose();
|
|
189
|
+
close_saltcorn_modal();
|
|
185
190
|
}
|
|
186
191
|
if (opts.submitReload === false) $("#scmodal").addClass("no-submit-reload");
|
|
187
192
|
else $("#scmodal").removeClass("no-submit-reload");
|
|
@@ -429,7 +434,6 @@ async function fill_formula_btn_click(btn, k) {
|
|
|
429
434
|
if (k) k();
|
|
430
435
|
}
|
|
431
436
|
|
|
432
|
-
|
|
433
437
|
/*
|
|
434
438
|
https://github.com/jeffdavidgreen/bootstrap-html5-history-tabs/blob/master/bootstrap-history-tabs.js
|
|
435
439
|
Copyright (c) 2015 Jeff Green
|
package/restart_watcher.js
CHANGED
|
@@ -17,6 +17,8 @@ const relevantPackages = [
|
|
|
17
17
|
"db-common",
|
|
18
18
|
"postgres",
|
|
19
19
|
"saltcorn-data",
|
|
20
|
+
"saltcorn-builder",
|
|
21
|
+
"saltcorn-admin-models",
|
|
20
22
|
"saltcorn-markup",
|
|
21
23
|
"saltcorn-sbadmin2",
|
|
22
24
|
"server",
|
|
@@ -28,7 +30,6 @@ const relevantPackages = [
|
|
|
28
30
|
*/
|
|
29
31
|
const excludePatterns = [
|
|
30
32
|
/\/node_modules/,
|
|
31
|
-
/\/public/,
|
|
32
33
|
/\.git/,
|
|
33
34
|
/\.docs/,
|
|
34
35
|
/\.docs/,
|
package/routes/actions.js
CHANGED
package/routes/admin.js
CHANGED
|
@@ -48,6 +48,7 @@ const { loadAllPlugins } = require("../load_plugins");
|
|
|
48
48
|
const {
|
|
49
49
|
create_backup,
|
|
50
50
|
restore,
|
|
51
|
+
auto_backup_now,
|
|
51
52
|
} = require("@saltcorn/admin-models/models/backup");
|
|
52
53
|
const {
|
|
53
54
|
runConfigurationCheck,
|
|
@@ -293,41 +294,163 @@ router.get(
|
|
|
293
294
|
"/backup",
|
|
294
295
|
isAdmin,
|
|
295
296
|
error_catcher(async (req, res) => {
|
|
297
|
+
const backupForm = autoBackupForm(req);
|
|
298
|
+
backupForm.values.auto_backup_frequency = getState().getConfig(
|
|
299
|
+
"auto_backup_frequency"
|
|
300
|
+
);
|
|
301
|
+
backupForm.values.auto_backup_destination = getState().getConfig(
|
|
302
|
+
"auto_backup_destination"
|
|
303
|
+
);
|
|
304
|
+
backupForm.values.auto_backup_directory = getState().getConfig(
|
|
305
|
+
"auto_backup_directory"
|
|
306
|
+
);
|
|
307
|
+
backupForm.values.auto_backup_expire_days = getState().getConfig(
|
|
308
|
+
"auto_backup_expire_days"
|
|
309
|
+
);
|
|
310
|
+
const isRoot = db.getTenantSchema() === db.connectObj.default_schema;
|
|
311
|
+
|
|
296
312
|
send_admin_page({
|
|
297
313
|
res,
|
|
298
314
|
req,
|
|
299
315
|
active_sub: "Backup",
|
|
300
316
|
contents: {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
317
|
+
above: [
|
|
318
|
+
{
|
|
319
|
+
type: "card",
|
|
320
|
+
title: req.__("Manual backup"),
|
|
321
|
+
contents: {
|
|
322
|
+
besides: [
|
|
307
323
|
div(
|
|
308
|
-
post_btn(
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
req.
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
324
|
+
post_btn(
|
|
325
|
+
"/admin/backup",
|
|
326
|
+
i({ class: "fas fa-download me-2" }) +
|
|
327
|
+
req.__("Download a backup"),
|
|
328
|
+
req.csrfToken(),
|
|
329
|
+
{
|
|
330
|
+
btnClass: "btn-outline-primary",
|
|
331
|
+
}
|
|
332
|
+
)
|
|
333
|
+
),
|
|
334
|
+
div(
|
|
335
|
+
restore_backup(req.csrfToken(), [
|
|
336
|
+
i({ class: "fas fa-2x fa-upload me-2" }),
|
|
337
|
+
"",
|
|
338
|
+
req.__("Restore a backup"),
|
|
339
|
+
])
|
|
340
|
+
),
|
|
341
|
+
],
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
isRoot
|
|
345
|
+
? {
|
|
346
|
+
type: "card",
|
|
347
|
+
title: req.__("Automated backup"),
|
|
348
|
+
contents: div(renderForm(backupForm, req.csrfToken())),
|
|
349
|
+
}
|
|
350
|
+
: { type: "blank", contents: "" },
|
|
351
|
+
],
|
|
326
352
|
},
|
|
327
353
|
});
|
|
328
354
|
})
|
|
329
355
|
);
|
|
330
356
|
|
|
357
|
+
/**
|
|
358
|
+
* Auto backup Form
|
|
359
|
+
* @param {object} req
|
|
360
|
+
* @returns {Form} form
|
|
361
|
+
*/
|
|
362
|
+
const autoBackupForm = (req) =>
|
|
363
|
+
new Form({
|
|
364
|
+
action: "/admin/set-auto-backup",
|
|
365
|
+
submitButtonClass: "btn-outline-primary",
|
|
366
|
+
onChange: "remove_outline(this)",
|
|
367
|
+
submitLabel: "Save settings",
|
|
368
|
+
additionalButtons: [
|
|
369
|
+
{
|
|
370
|
+
label: "Backup now",
|
|
371
|
+
id: "btnBackupNow",
|
|
372
|
+
class: "btn btn-outline-secondary",
|
|
373
|
+
onclick: "ajax_post('/admin/auto-backup-now')",
|
|
374
|
+
},
|
|
375
|
+
],
|
|
376
|
+
fields: [
|
|
377
|
+
{
|
|
378
|
+
type: "String",
|
|
379
|
+
label: req.__("Frequency"),
|
|
380
|
+
name: "auto_backup_frequency",
|
|
381
|
+
required: true,
|
|
382
|
+
attributes: { options: ["Never", "Daily", "Weekly"] },
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
type: "String",
|
|
386
|
+
label: req.__("Destination"),
|
|
387
|
+
name: "auto_backup_destination",
|
|
388
|
+
required: true,
|
|
389
|
+
showIf: { auto_backup_frequency: ["Daily", "Weekly"] },
|
|
390
|
+
attributes: { options: ["Saltcorn files", "Local directory"] },
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
type: "String",
|
|
394
|
+
label: req.__("Directory"),
|
|
395
|
+
name: "auto_backup_directory",
|
|
396
|
+
showIf: {
|
|
397
|
+
auto_backup_frequency: ["Daily", "Weekly"],
|
|
398
|
+
auto_backup_destination: "Local directory",
|
|
399
|
+
},
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
type: "Integer",
|
|
403
|
+
label: req.__("Expiration in days"),
|
|
404
|
+
sublabel: req.__(
|
|
405
|
+
"Delete old backup files in this directory after the set number of days"
|
|
406
|
+
),
|
|
407
|
+
name: "auto_backup_expire_days",
|
|
408
|
+
showIf: {
|
|
409
|
+
auto_backup_frequency: ["Daily", "Weekly"],
|
|
410
|
+
auto_backup_destination: "Local directory",
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
],
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
router.post(
|
|
417
|
+
"/set-auto-backup",
|
|
418
|
+
isAdmin,
|
|
419
|
+
error_catcher(async (req, res) => {
|
|
420
|
+
const form = await autoBackupForm(req);
|
|
421
|
+
form.validate(req.body);
|
|
422
|
+
if (form.hasErrors) {
|
|
423
|
+
send_admin_page({
|
|
424
|
+
res,
|
|
425
|
+
req,
|
|
426
|
+
active_sub: "Backup",
|
|
427
|
+
contents: {
|
|
428
|
+
type: "card",
|
|
429
|
+
title: req.__("Backup settings"),
|
|
430
|
+
contents: [renderForm(form, req.csrfToken())],
|
|
431
|
+
},
|
|
432
|
+
});
|
|
433
|
+
} else {
|
|
434
|
+
await save_config_from_form(form);
|
|
435
|
+
req.flash("success", req.__("Backup settings updated"));
|
|
436
|
+
res.redirect("/admin/backup");
|
|
437
|
+
}
|
|
438
|
+
})
|
|
439
|
+
);
|
|
440
|
+
router.post(
|
|
441
|
+
"/auto-backup-now",
|
|
442
|
+
isAdmin,
|
|
443
|
+
error_catcher(async (req, res) => {
|
|
444
|
+
try {
|
|
445
|
+
await auto_backup_now();
|
|
446
|
+
req.flash("success", req.__("Backup successful"));
|
|
447
|
+
} catch (e) {
|
|
448
|
+
req.flash("error", e.message);
|
|
449
|
+
}
|
|
450
|
+
res.json({ reload_page: true });
|
|
451
|
+
})
|
|
452
|
+
);
|
|
453
|
+
|
|
331
454
|
/**
|
|
332
455
|
* @name get/system
|
|
333
456
|
* @function
|
|
@@ -550,8 +673,8 @@ router.post(
|
|
|
550
673
|
const fileName = await create_backup();
|
|
551
674
|
res.type("application/zip");
|
|
552
675
|
res.attachment(fileName);
|
|
553
|
-
|
|
554
|
-
|
|
676
|
+
const file = fs.createReadStream(fileName);
|
|
677
|
+
file.on("end", function () {
|
|
555
678
|
fs.unlink(fileName, function () {});
|
|
556
679
|
});
|
|
557
680
|
file.pipe(res);
|
|
@@ -794,7 +917,10 @@ router.get(
|
|
|
794
917
|
? div(
|
|
795
918
|
{ class: "alert alert-success", role: "alert" },
|
|
796
919
|
i({ class: "fas fa-check-circle fa-lg me-2" }),
|
|
797
|
-
h5(
|
|
920
|
+
h5(
|
|
921
|
+
{ class: "d-inline" },
|
|
922
|
+
req.__("No errors detected during configuration check")
|
|
923
|
+
)
|
|
798
924
|
)
|
|
799
925
|
: errors.map(mkError)
|
|
800
926
|
),
|
package/routes/fields.js
CHANGED
|
@@ -300,7 +300,9 @@ const fieldFlow = (req) =>
|
|
|
300
300
|
name: "also_delete_file",
|
|
301
301
|
type: "Bool",
|
|
302
302
|
label: req.__("Cascade delete to file"),
|
|
303
|
-
sublabel: req.__(
|
|
303
|
+
sublabel: req.__(
|
|
304
|
+
"Deleting a row will also delete the file referenced by this field"
|
|
305
|
+
),
|
|
304
306
|
},
|
|
305
307
|
],
|
|
306
308
|
});
|
|
@@ -337,6 +339,7 @@ const fieldFlow = (req) =>
|
|
|
337
339
|
label: req.__("Formula"),
|
|
338
340
|
// todo sublabel
|
|
339
341
|
type: "String",
|
|
342
|
+
class: "validate-expression",
|
|
340
343
|
validator: expressionValidator,
|
|
341
344
|
}),
|
|
342
345
|
new Field({
|
package/routes/files.js
CHANGED
|
@@ -10,7 +10,7 @@ const File = require("@saltcorn/data/models/file");
|
|
|
10
10
|
const User = require("@saltcorn/data/models/user");
|
|
11
11
|
const { getState } = require("@saltcorn/data/db/state");
|
|
12
12
|
const s3storage = require("../s3storage");
|
|
13
|
-
const
|
|
13
|
+
const resizer = require("resize-with-sharp-or-jimp");
|
|
14
14
|
|
|
15
15
|
const {
|
|
16
16
|
mkTable,
|
|
@@ -214,7 +214,11 @@ router.get(
|
|
|
214
214
|
}
|
|
215
215
|
const fnm = `${file.location}_w${width}`;
|
|
216
216
|
if (!fs.existsSync(fnm)) {
|
|
217
|
-
await
|
|
217
|
+
await resizer({
|
|
218
|
+
fromFileName: file.location,
|
|
219
|
+
width,
|
|
220
|
+
toFileName: fnm,
|
|
221
|
+
});
|
|
218
222
|
}
|
|
219
223
|
res.sendFile(fnm);
|
|
220
224
|
}
|
package/routes/tables.js
CHANGED
|
@@ -21,7 +21,10 @@ const {
|
|
|
21
21
|
post_delete_btn,
|
|
22
22
|
post_dropdown_item,
|
|
23
23
|
} = require("@saltcorn/markup");
|
|
24
|
-
const {
|
|
24
|
+
const {
|
|
25
|
+
recalculate_for_stored,
|
|
26
|
+
expressionValidator,
|
|
27
|
+
} = require("@saltcorn/data/models/expression");
|
|
25
28
|
const { isAdmin, error_catcher, setTenant } = require("./utils.js");
|
|
26
29
|
const Form = require("@saltcorn/data/models/form");
|
|
27
30
|
const {
|
|
@@ -101,7 +104,9 @@ const tableForm = async (table, req) => {
|
|
|
101
104
|
{
|
|
102
105
|
name: "ownership_formula",
|
|
103
106
|
label: req.__("Ownership formula"),
|
|
107
|
+
validator: expressionValidator,
|
|
104
108
|
type: "String",
|
|
109
|
+
class: "validate-expression",
|
|
105
110
|
sublabel:
|
|
106
111
|
req.__("User is treated as owner if true. In scope: ") +
|
|
107
112
|
["user", ...fields.map((f) => f.name)]
|
|
@@ -878,10 +883,20 @@ router.post(
|
|
|
878
883
|
const { id, _csrf, ...rest } = v;
|
|
879
884
|
const table = await Table.findOne({ id: parseInt(id) });
|
|
880
885
|
const old_versioned = table.versioned;
|
|
886
|
+
let hasError = false;
|
|
881
887
|
if (!rest.versioned) rest.versioned = false;
|
|
882
|
-
if (rest.ownership_field_id === "_formula")
|
|
888
|
+
if (rest.ownership_field_id === "_formula") {
|
|
883
889
|
rest.ownership_field_id = null;
|
|
884
|
-
|
|
890
|
+
const fmlValidRes = expressionValidator(rest.ownership_formula);
|
|
891
|
+
console.log({ fmlValidRes });
|
|
892
|
+
if (typeof fmlValidRes === "string") {
|
|
893
|
+
req.flash(
|
|
894
|
+
"error",
|
|
895
|
+
req.__(`Invalid ownership formula: %s`, fmlValidRes)
|
|
896
|
+
);
|
|
897
|
+
hasError = true;
|
|
898
|
+
}
|
|
899
|
+
} else rest.ownership_formula = null;
|
|
885
900
|
await table.update(rest);
|
|
886
901
|
if (!old_versioned && rest.versioned)
|
|
887
902
|
req.flash(
|
|
@@ -893,7 +908,7 @@ router.post(
|
|
|
893
908
|
"success",
|
|
894
909
|
req.__("Table saved with version history disabled")
|
|
895
910
|
);
|
|
896
|
-
else req.flash("success", req.__("Table saved"));
|
|
911
|
+
else if (!hasError) req.flash("success", req.__("Table saved"));
|
|
897
912
|
|
|
898
913
|
res.redirect(`/table/${id}`);
|
|
899
914
|
}
|
package/serve.js
CHANGED
|
@@ -43,6 +43,7 @@ const {
|
|
|
43
43
|
eachTenant,
|
|
44
44
|
getAllTenants,
|
|
45
45
|
} = require("@saltcorn/admin-models/models/tenant");
|
|
46
|
+
const { auto_backup_now } = require("@saltcorn/admin-models/models/backup");
|
|
46
47
|
|
|
47
48
|
// helpful https://gist.github.com/jpoehls/2232358
|
|
48
49
|
/**
|
|
@@ -135,7 +136,13 @@ const onMessageFromWorker =
|
|
|
135
136
|
//console.log("worker msg", typeof msg, msg);
|
|
136
137
|
if (msg === "Start" && !masterState.started) {
|
|
137
138
|
masterState.started = true;
|
|
138
|
-
runScheduler({
|
|
139
|
+
runScheduler({
|
|
140
|
+
port,
|
|
141
|
+
watchReaper,
|
|
142
|
+
disableScheduler,
|
|
143
|
+
eachTenant,
|
|
144
|
+
auto_backup_now,
|
|
145
|
+
});
|
|
139
146
|
require("./systemd")({ port });
|
|
140
147
|
return true;
|
|
141
148
|
} else if (msg === "RestartServer") {
|
|
@@ -261,6 +268,13 @@ module.exports =
|
|
|
261
268
|
});
|
|
262
269
|
} else {
|
|
263
270
|
await nonGreenlockWorkerSetup(appargs, port);
|
|
271
|
+
runScheduler({
|
|
272
|
+
port,
|
|
273
|
+
watchReaper,
|
|
274
|
+
disableScheduler,
|
|
275
|
+
eachTenant,
|
|
276
|
+
auto_backup_now,
|
|
277
|
+
});
|
|
264
278
|
}
|
|
265
279
|
Trigger.emitEvent("Startup");
|
|
266
280
|
} else {
|