@saltcorn/server 0.9.1-beta.4 → 0.9.1-beta.6
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/package.json +8 -8
- package/public/saltcorn-common.js +53 -12
- package/public/saltcorn.css +1 -0
- package/routes/common_lists.js +1 -5
- package/routes/fields.js +24 -0
- package/routes/pageedit.js +135 -23
- package/tests/fields.test.js +37 -1
- package/tests/page.test.js +37 -8
- package/tests/table.test.js +5 -1
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "0.9.1-beta.
|
|
3
|
+
"version": "0.9.1-beta.6",
|
|
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
9
|
"@aws-sdk/client-s3": "^3.451.0",
|
|
10
|
-
"@saltcorn/base-plugin": "0.9.1-beta.
|
|
11
|
-
"@saltcorn/builder": "0.9.1-beta.
|
|
12
|
-
"@saltcorn/data": "0.9.1-beta.
|
|
13
|
-
"@saltcorn/admin-models": "0.9.1-beta.
|
|
14
|
-
"@saltcorn/filemanager": "0.9.1-beta.
|
|
15
|
-
"@saltcorn/markup": "0.9.1-beta.
|
|
16
|
-
"@saltcorn/sbadmin2": "0.9.1-beta.
|
|
10
|
+
"@saltcorn/base-plugin": "0.9.1-beta.6",
|
|
11
|
+
"@saltcorn/builder": "0.9.1-beta.6",
|
|
12
|
+
"@saltcorn/data": "0.9.1-beta.6",
|
|
13
|
+
"@saltcorn/admin-models": "0.9.1-beta.6",
|
|
14
|
+
"@saltcorn/filemanager": "0.9.1-beta.6",
|
|
15
|
+
"@saltcorn/markup": "0.9.1-beta.6",
|
|
16
|
+
"@saltcorn/sbadmin2": "0.9.1-beta.6",
|
|
17
17
|
"@socket.io/cluster-adapter": "^0.2.1",
|
|
18
18
|
"@socket.io/sticky": "^1.0.1",
|
|
19
19
|
"adm-zip": "0.5.10",
|
|
@@ -285,9 +285,13 @@ function apply_showif() {
|
|
|
285
285
|
.closest(".form-namespace")
|
|
286
286
|
.find("input[name=_columndef]");
|
|
287
287
|
try {
|
|
288
|
-
const
|
|
289
|
-
def
|
|
290
|
-
|
|
288
|
+
const defval = $def.val();
|
|
289
|
+
const def =
|
|
290
|
+
typeof defval === "undefined" ? undefined : JSON.parse(defval);
|
|
291
|
+
if (def) {
|
|
292
|
+
def[k] = v;
|
|
293
|
+
$def.val(JSON.stringify(def));
|
|
294
|
+
}
|
|
291
295
|
} catch (e) {
|
|
292
296
|
console.error("Invalid json", e);
|
|
293
297
|
}
|
|
@@ -393,21 +397,26 @@ function get_form_record(e_in, select_labels) {
|
|
|
393
397
|
}
|
|
394
398
|
|
|
395
399
|
e.find("input[name],select[name],textarea[name]").each(function () {
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
400
|
+
const $this = $(this);
|
|
401
|
+
const name = $this.attr("data-fieldname") || $this.attr("name");
|
|
402
|
+
if (select_labels && $this.prop("tagName").toLowerCase() === "select")
|
|
403
|
+
rec[name] = $this.find("option:selected").text();
|
|
404
|
+
else if ($this.prop("type") === "checkbox")
|
|
405
|
+
rec[name] = $this.prop("checked");
|
|
406
|
+
else if ($this.prop("type") === "radio" && !$this.prop("checked")) {
|
|
407
|
+
//do nothing
|
|
408
|
+
} else rec[name] = $this.val();
|
|
402
409
|
});
|
|
403
410
|
return rec;
|
|
404
411
|
}
|
|
405
412
|
function showIfFormulaInputs(e, fml) {
|
|
406
413
|
const rec = get_form_record(e);
|
|
407
414
|
try {
|
|
408
|
-
return new Function(
|
|
409
|
-
|
|
410
|
-
|
|
415
|
+
return new Function(
|
|
416
|
+
"row",
|
|
417
|
+
`{${Object.keys(rec).join(",")}}`,
|
|
418
|
+
"return " + fml
|
|
419
|
+
)(rec, rec);
|
|
411
420
|
} catch (e) {
|
|
412
421
|
throw new Error(`Error in evaluating showIf formula ${fml}: ${e.message}`);
|
|
413
422
|
}
|
|
@@ -1380,3 +1389,35 @@ function check_saltcorn_notifications() {
|
|
|
1380
1389
|
}
|
|
1381
1390
|
});
|
|
1382
1391
|
}
|
|
1392
|
+
|
|
1393
|
+
function disable_inactive_tab_inputs(id) {
|
|
1394
|
+
setTimeout(() => {
|
|
1395
|
+
const isAccordion = $(`#${id}`).hasClass("accordion");
|
|
1396
|
+
const iterElem = isAccordion
|
|
1397
|
+
? `#${id} div.accordion-item .accordion-button`
|
|
1398
|
+
: `#${id} li a`;
|
|
1399
|
+
$(iterElem).each(function () {
|
|
1400
|
+
const isActive = isAccordion
|
|
1401
|
+
? !$(this).hasClass("collapsed")
|
|
1402
|
+
: $(this).hasClass("active");
|
|
1403
|
+
const target = isAccordion
|
|
1404
|
+
? $(this).attr("data-bs-target")
|
|
1405
|
+
: $(this).attr("href");
|
|
1406
|
+
if (isActive) {
|
|
1407
|
+
//activate previously disabled
|
|
1408
|
+
$(target)
|
|
1409
|
+
.find("[disabled-by-tab]")
|
|
1410
|
+
.prop("disabled", false)
|
|
1411
|
+
.removeAttr("disabled-by-tab");
|
|
1412
|
+
} else {
|
|
1413
|
+
//disable all input
|
|
1414
|
+
$(target)
|
|
1415
|
+
.find(
|
|
1416
|
+
"input:not(:disabled), textarea:not(:disabled), button:not(:disabled), select:not(:disabled)"
|
|
1417
|
+
)
|
|
1418
|
+
.prop("disabled", true)
|
|
1419
|
+
.attr("disabled-by-tab", "1");
|
|
1420
|
+
}
|
|
1421
|
+
});
|
|
1422
|
+
}, 100);
|
|
1423
|
+
}
|
package/public/saltcorn.css
CHANGED
package/routes/common_lists.js
CHANGED
|
@@ -344,11 +344,7 @@ const getPageList = (rows, roles, req, { tagId, domId, showList } = {}) => {
|
|
|
344
344
|
},
|
|
345
345
|
{
|
|
346
346
|
label: req.__("Edit"),
|
|
347
|
-
key: (r) =>
|
|
348
|
-
link(
|
|
349
|
-
`/pageedit/${!r.html_file ? "edit" : "edit-properties"}/${r.name}`,
|
|
350
|
-
req.__(!r.html_file ? "Edit" : "Edit properties")
|
|
351
|
-
),
|
|
347
|
+
key: (r) => link(`/pageedit/edit/${r.name}`, req.__("Edit")),
|
|
352
348
|
},
|
|
353
349
|
!tagId
|
|
354
350
|
? {
|
package/routes/fields.js
CHANGED
|
@@ -996,6 +996,30 @@ router.post(
|
|
|
996
996
|
result = row[field.name];
|
|
997
997
|
} else if (field.stored) {
|
|
998
998
|
const f = get_async_expression_function(formula, fields);
|
|
999
|
+
//are there join fields in formula?
|
|
1000
|
+
const joinFields = {};
|
|
1001
|
+
add_free_variables_to_joinfields(
|
|
1002
|
+
freeVariables(formula),
|
|
1003
|
+
joinFields,
|
|
1004
|
+
table.fields
|
|
1005
|
+
);
|
|
1006
|
+
for (const { target, ref, through, rename_object } of Object.values(
|
|
1007
|
+
joinFields
|
|
1008
|
+
)) {
|
|
1009
|
+
const jf = table.getField(ref);
|
|
1010
|
+
const jtable = Table.findOne(jf.reftable_name);
|
|
1011
|
+
const jrow = await jtable.getRow({ [jtable.pk_name]: row[ref] });
|
|
1012
|
+
row[ref] = jrow;
|
|
1013
|
+
if (through) {
|
|
1014
|
+
const jf2 = jtable.getField(through);
|
|
1015
|
+
const jtable2 = Table.findOne(jf2.reftable_name);
|
|
1016
|
+
const jrow2 = await jtable2.getRow({
|
|
1017
|
+
[jtable2.pk_name]: jrow[through],
|
|
1018
|
+
});
|
|
1019
|
+
row[ref][through] = jrow2;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
999
1023
|
result = await f(row);
|
|
1000
1024
|
} else {
|
|
1001
1025
|
const f = get_expression_function(formula, fields);
|
package/routes/pageedit.js
CHANGED
|
@@ -9,7 +9,7 @@ const View = require("@saltcorn/data/models/view");
|
|
|
9
9
|
const Field = require("@saltcorn/data/models/field");
|
|
10
10
|
const Table = require("@saltcorn/data/models/table");
|
|
11
11
|
const Page = require("@saltcorn/data/models/page");
|
|
12
|
-
const { div, a } = require("@saltcorn/markup/tags");
|
|
12
|
+
const { div, a, iframe, script } = require("@saltcorn/markup/tags");
|
|
13
13
|
const { getState } = require("@saltcorn/data/db/state");
|
|
14
14
|
const User = require("@saltcorn/data/models/user");
|
|
15
15
|
const Workflow = require("@saltcorn/data/models/workflow");
|
|
@@ -41,6 +41,7 @@ const {
|
|
|
41
41
|
const { getActionConfigFields } = require("@saltcorn/data/plugin-helper");
|
|
42
42
|
const Library = require("@saltcorn/data/models/library");
|
|
43
43
|
const path = require("path");
|
|
44
|
+
const fsp = require("fs").promises;
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
47
|
* @type {object}
|
|
@@ -431,6 +432,116 @@ router.post(
|
|
|
431
432
|
);
|
|
432
433
|
|
|
433
434
|
/**
|
|
435
|
+
* open the builder
|
|
436
|
+
* @param {*} req
|
|
437
|
+
* @param {*} res
|
|
438
|
+
* @param {*} page
|
|
439
|
+
*/
|
|
440
|
+
const getEditNormalPage = async (req, res, page) => {
|
|
441
|
+
// set fixed states in page directly for legacy builds
|
|
442
|
+
traverseSync(page.layout, {
|
|
443
|
+
view(s) {
|
|
444
|
+
if (s.state === "fixed" && !s.configuration) {
|
|
445
|
+
const fs = page.fixed_states[s.name];
|
|
446
|
+
if (fs) s.configuration = fs;
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
});
|
|
450
|
+
const options = await pageBuilderData(req, page);
|
|
451
|
+
const builderData = {
|
|
452
|
+
options,
|
|
453
|
+
context: page,
|
|
454
|
+
layout: page.layout,
|
|
455
|
+
mode: "page",
|
|
456
|
+
version_tag: db.connectObj.version_tag,
|
|
457
|
+
};
|
|
458
|
+
res.sendWrap(
|
|
459
|
+
req.__(`%s configuration`, page.name),
|
|
460
|
+
wrap(renderBuilder(builderData, req.csrfToken()), true, req, page)
|
|
461
|
+
);
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* open a file editor with an iframe preview
|
|
466
|
+
* @param {*} req
|
|
467
|
+
* @param {*} res
|
|
468
|
+
* @param {*} page
|
|
469
|
+
*/
|
|
470
|
+
const getEditPageWithHtmlFile = async (req, res, page) => {
|
|
471
|
+
const htmlFile = page.html_file;
|
|
472
|
+
const iframeId = "page_preview_iframe";
|
|
473
|
+
const updateBttnId = "addnUpdBtn";
|
|
474
|
+
const file = await File.findOne(htmlFile);
|
|
475
|
+
if (!file) {
|
|
476
|
+
req.flash("error", req.__("File not found"));
|
|
477
|
+
return res.redirect(`/pageedit`);
|
|
478
|
+
}
|
|
479
|
+
const editForm = new Form({
|
|
480
|
+
action: `/pageedit/edit/${encodeURIComponent(page.name)}`,
|
|
481
|
+
fields: [
|
|
482
|
+
{
|
|
483
|
+
name: "code",
|
|
484
|
+
form_name: "code",
|
|
485
|
+
label: "Code",
|
|
486
|
+
input_type: "code",
|
|
487
|
+
attributes: { mode: "text/html" },
|
|
488
|
+
validator(s) {
|
|
489
|
+
return true;
|
|
490
|
+
},
|
|
491
|
+
},
|
|
492
|
+
],
|
|
493
|
+
values: {
|
|
494
|
+
code: await fsp.readFile(file.location, "utf8"),
|
|
495
|
+
},
|
|
496
|
+
onChange: `document.getElementById('${updateBttnId}').disabled = false;`,
|
|
497
|
+
additionalButtons: [
|
|
498
|
+
{
|
|
499
|
+
label: req.__("Update"),
|
|
500
|
+
id: updateBttnId,
|
|
501
|
+
class: "btn btn-primary",
|
|
502
|
+
onclick: `saveAndContinue(this, () => {
|
|
503
|
+
document.getElementById('${iframeId}').contentWindow.location.reload();
|
|
504
|
+
document.getElementById('${updateBttnId}').disabled = true;
|
|
505
|
+
})`,
|
|
506
|
+
disabled: true,
|
|
507
|
+
},
|
|
508
|
+
],
|
|
509
|
+
submitLabel: req.__("Finish") + " »",
|
|
510
|
+
});
|
|
511
|
+
res.sendWrap(req.__("Edit %s", page.title), {
|
|
512
|
+
above: [
|
|
513
|
+
{
|
|
514
|
+
type: "card",
|
|
515
|
+
title: "Edit",
|
|
516
|
+
titleAjaxIndicator: true,
|
|
517
|
+
contents: [renderForm(editForm, req.csrfToken())],
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
type: "card",
|
|
521
|
+
title: "Preview",
|
|
522
|
+
contents: [
|
|
523
|
+
iframe({
|
|
524
|
+
id: iframeId,
|
|
525
|
+
src: `/files/serve/${encodeURIComponent(htmlFile)}`,
|
|
526
|
+
}),
|
|
527
|
+
script(`
|
|
528
|
+
const iframe = document.getElementById("${iframeId}");
|
|
529
|
+
iframe.onload = () => {
|
|
530
|
+
const _iframe = document.getElementById("${iframeId}");
|
|
531
|
+
if (_iframe.contentWindow.document.body) {
|
|
532
|
+
_iframe.width = _iframe.contentWindow.document.body.scrollWidth;
|
|
533
|
+
_iframe.height = _iframe.contentWindow.document.body.scrollHeight;
|
|
534
|
+
}
|
|
535
|
+
}`),
|
|
536
|
+
],
|
|
537
|
+
},
|
|
538
|
+
],
|
|
539
|
+
});
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* for normal pages, open the builder
|
|
544
|
+
* for pages with a fixed html file, open a file editor with an iframe preview
|
|
434
545
|
* @name get/edit/:pagename
|
|
435
546
|
* @function
|
|
436
547
|
* @memberof module:routes/pageedit~pageeditRouter
|
|
@@ -446,27 +557,8 @@ router.get(
|
|
|
446
557
|
req.flash("error", req.__(`Page %s not found`, pagename));
|
|
447
558
|
res.redirect(`/pageedit`);
|
|
448
559
|
} else {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
view(s) {
|
|
452
|
-
if (s.state === "fixed" && !s.configuration) {
|
|
453
|
-
const fs = page.fixed_states[s.name];
|
|
454
|
-
if (fs) s.configuration = fs;
|
|
455
|
-
}
|
|
456
|
-
},
|
|
457
|
-
});
|
|
458
|
-
const options = await pageBuilderData(req, page);
|
|
459
|
-
const builderData = {
|
|
460
|
-
options,
|
|
461
|
-
context: page,
|
|
462
|
-
layout: page.layout,
|
|
463
|
-
mode: "page",
|
|
464
|
-
version_tag: db.connectObj.version_tag,
|
|
465
|
-
};
|
|
466
|
-
res.sendWrap(
|
|
467
|
-
req.__(`%s configuration`, page.name),
|
|
468
|
-
wrap(renderBuilder(builderData, req.csrfToken()), true, req, page)
|
|
469
|
-
);
|
|
560
|
+
if (!page.html_file) await getEditNormalPage(req, res, page);
|
|
561
|
+
else await getEditPageWithHtmlFile(req, res, page);
|
|
470
562
|
}
|
|
471
563
|
})
|
|
472
564
|
);
|
|
@@ -495,13 +587,33 @@ router.post(
|
|
|
495
587
|
await Page.update(page.id, {
|
|
496
588
|
layout: decodeURIComponent(req.body.layout),
|
|
497
589
|
});
|
|
498
|
-
|
|
499
590
|
req.flash("success", req.__(`Page %s saved`, pagename));
|
|
500
591
|
res.redirect(redirectTarget);
|
|
592
|
+
} else if (req.body.code) {
|
|
593
|
+
try {
|
|
594
|
+
if (!page.html_file) throw new Error(req.__("File not found"));
|
|
595
|
+
const file = await File.findOne(page.html_file);
|
|
596
|
+
if (!file) throw new Error(req.__("File not found"));
|
|
597
|
+
await fsp.writeFile(file.location, req.body.code);
|
|
598
|
+
if (!req.xhr) {
|
|
599
|
+
req.flash("success", req.__(`Page %s saved`, pagename));
|
|
600
|
+
res.redirect(redirectTarget);
|
|
601
|
+
} else res.json({ okay: true });
|
|
602
|
+
} catch (error) {
|
|
603
|
+
getState().log(2, `POST /edit/${pagename}: '${error.message}'`);
|
|
604
|
+
req.flash(
|
|
605
|
+
"error",
|
|
606
|
+
`${req.__("Error")}: ${error.message || req.__("An error occurred")}`
|
|
607
|
+
);
|
|
608
|
+
if (!req.xhr) res.redirect(redirectTarget);
|
|
609
|
+
else res.json({ error: error.message });
|
|
610
|
+
}
|
|
501
611
|
} else {
|
|
612
|
+
getState().log(2, `POST /edit/${pagename}: '${req.body}'`);
|
|
502
613
|
req.flash("error", req.__(`Error processing page`));
|
|
503
614
|
res.redirect(redirectTarget);
|
|
504
615
|
}
|
|
616
|
+
getState().log(5, `POST /edit/${pagename}: Success`);
|
|
505
617
|
})
|
|
506
618
|
);
|
|
507
619
|
|
package/tests/fields.test.js
CHANGED
|
@@ -364,7 +364,43 @@ describe("Field Endpoints", () => {
|
|
|
364
364
|
await request(app)
|
|
365
365
|
.post("/field/show-calculated/books/pagesp1/show")
|
|
366
366
|
.set("Cookie", loginCookie)
|
|
367
|
-
.expect((r) => +r.body >
|
|
367
|
+
.expect((r) => +r.body > 2);
|
|
368
|
+
});
|
|
369
|
+
it("should show calculated with single joinfield", async () => {
|
|
370
|
+
const loginCookie = await getAdminLoginCookie();
|
|
371
|
+
const table = Table.findOne({ name: "patients" });
|
|
372
|
+
await Field.create({
|
|
373
|
+
table,
|
|
374
|
+
label: "pagesp1",
|
|
375
|
+
type: "Integer",
|
|
376
|
+
calculated: true,
|
|
377
|
+
stored: true,
|
|
378
|
+
expression: "favbook.pages+1",
|
|
379
|
+
});
|
|
380
|
+
const app = await getApp({ disableCsrf: true });
|
|
381
|
+
|
|
382
|
+
await request(app)
|
|
383
|
+
.post("/field/show-calculated/patients/pagesp1/show")
|
|
384
|
+
.set("Cookie", loginCookie)
|
|
385
|
+
.expect((r) => +r.body > 2);
|
|
386
|
+
});
|
|
387
|
+
it("should show calculated with double joinfield", async () => {
|
|
388
|
+
const loginCookie = await getAdminLoginCookie();
|
|
389
|
+
const table = Table.findOne({ name: "readings" });
|
|
390
|
+
await Field.create({
|
|
391
|
+
table,
|
|
392
|
+
label: "pagesp1",
|
|
393
|
+
type: "Integer",
|
|
394
|
+
calculated: true,
|
|
395
|
+
stored: true,
|
|
396
|
+
expression: "patient_id.favbook.pages+1",
|
|
397
|
+
});
|
|
398
|
+
const app = await getApp({ disableCsrf: true });
|
|
399
|
+
|
|
400
|
+
await request(app)
|
|
401
|
+
.post("/field/show-calculated/readings/pagesp1/show")
|
|
402
|
+
.set("Cookie", loginCookie)
|
|
403
|
+
.expect((r) => +r.body > 2);
|
|
368
404
|
});
|
|
369
405
|
});
|
|
370
406
|
|
package/tests/page.test.js
CHANGED
|
@@ -16,6 +16,7 @@ const Page = require("@saltcorn/data/models/page");
|
|
|
16
16
|
const File = require("@saltcorn/data/models/file");
|
|
17
17
|
const { existsSync } = require("fs");
|
|
18
18
|
const { join } = require("path");
|
|
19
|
+
const fs = require("fs");
|
|
19
20
|
|
|
20
21
|
let htmlFile = null;
|
|
21
22
|
|
|
@@ -26,24 +27,20 @@ const prepHtmlFiles = async () => {
|
|
|
26
27
|
db.getTenantSchema(),
|
|
27
28
|
folder
|
|
28
29
|
);
|
|
30
|
+
const html = `<html><head><title>Landing page</title></head><body><h1>${content}</h1></body></html>`;
|
|
29
31
|
if (!existsSync(scFolder)) await File.new_folder(folder);
|
|
30
32
|
if (!existsSync(join(scFolder, name))) {
|
|
31
|
-
return await File.from_contents(
|
|
32
|
-
name,
|
|
33
|
-
"text/html",
|
|
34
|
-
`<html><head><title>Landing page</title></head><body><h1>${content}</h1></body></html>`,
|
|
35
|
-
1,
|
|
36
|
-
1,
|
|
37
|
-
folder
|
|
38
|
-
);
|
|
33
|
+
return await File.from_contents(name, "text/html", html, 1, 1, folder);
|
|
39
34
|
} else {
|
|
40
35
|
const file = await File.from_file_on_disk(name, scFolder);
|
|
36
|
+
fs.writeFileSync(file.location, html);
|
|
41
37
|
file.location = File.absPathToServePath(file.location);
|
|
42
38
|
return file;
|
|
43
39
|
}
|
|
44
40
|
};
|
|
45
41
|
htmlFile = await createFile("/", "fixed_page.html", "Land here");
|
|
46
42
|
await createFile("/subfolder", "fixed_page2.html", "Or Land here");
|
|
43
|
+
await createFile("/", "test.html", "page with fixed html");
|
|
47
44
|
};
|
|
48
45
|
|
|
49
46
|
beforeAll(async () => {
|
|
@@ -135,6 +132,11 @@ describe("page create", () => {
|
|
|
135
132
|
|
|
136
133
|
it("does not find the html file for staff or public", async () => {
|
|
137
134
|
const app = await getApp({ disableCsrf: true });
|
|
135
|
+
await request(app)
|
|
136
|
+
.post(`/files/setrole/fixed_page.html`)
|
|
137
|
+
.set("Cookie", await getAdminLoginCookie())
|
|
138
|
+
.send("role=1")
|
|
139
|
+
.expect(toRedirect("/files?dir=."));
|
|
138
140
|
const loginCookie = await getStaffLoginCookie();
|
|
139
141
|
await request(app)
|
|
140
142
|
.get("/page/new_page_with_html_file")
|
|
@@ -247,6 +249,33 @@ describe("pageedit", () => {
|
|
|
247
249
|
.set("Cookie", loginCookie)
|
|
248
250
|
.expect(toInclude("<script>builder.renderBuilder"));
|
|
249
251
|
});
|
|
252
|
+
it("show editor with html file", async () => {
|
|
253
|
+
const app = await getApp({ disableCsrf: true });
|
|
254
|
+
const loginCookie = await getAdminLoginCookie();
|
|
255
|
+
await request(app)
|
|
256
|
+
.get("/pageedit/edit/page_with_html_file")
|
|
257
|
+
.set("Cookie", loginCookie)
|
|
258
|
+
.expect(toInclude(`<textarea mode="text/html"`));
|
|
259
|
+
});
|
|
260
|
+
it("edit editor with html file", async () => {
|
|
261
|
+
const app = await getApp({ disableCsrf: true });
|
|
262
|
+
const loginCookie = await getAdminLoginCookie();
|
|
263
|
+
const newHtml =
|
|
264
|
+
"<html><head><title>title</title></head><body><h1>new html</h1></body</html>";
|
|
265
|
+
await request(app)
|
|
266
|
+
.get("/page/page_with_html_file")
|
|
267
|
+
.set("Cookie", loginCookie)
|
|
268
|
+
.expect(toInclude("page with fixed html"));
|
|
269
|
+
await request(app)
|
|
270
|
+
.post("/pageedit/edit/page_with_html_file")
|
|
271
|
+
.set("Cookie", loginCookie)
|
|
272
|
+
.send("code=" + encodeURIComponent(newHtml))
|
|
273
|
+
.expect(toRedirect("/pageedit"));
|
|
274
|
+
await request(app)
|
|
275
|
+
.get("/page/page_with_html_file")
|
|
276
|
+
.set("Cookie", loginCookie)
|
|
277
|
+
.expect(toInclude("new html"));
|
|
278
|
+
});
|
|
250
279
|
|
|
251
280
|
it("sets root page", async () => {
|
|
252
281
|
const app = await getApp({ disableCsrf: true });
|
package/tests/table.test.js
CHANGED
|
@@ -17,8 +17,12 @@ const db = require("@saltcorn/data/db");
|
|
|
17
17
|
const User = require("@saltcorn/data/models/user");
|
|
18
18
|
const { plugin_with_routes } = require("@saltcorn/data/tests/mocks");
|
|
19
19
|
const { getState } = require("@saltcorn/data/db/state");
|
|
20
|
+
const { sleep } = require("@saltcorn/data/utils");
|
|
20
21
|
|
|
21
|
-
afterAll(
|
|
22
|
+
afterAll(async () => {
|
|
23
|
+
await sleep(200);
|
|
24
|
+
await db.close();
|
|
25
|
+
});
|
|
22
26
|
beforeAll(async () => {
|
|
23
27
|
await resetToFixtures();
|
|
24
28
|
});
|