@saltcorn/server 0.8.6-beta.4 → 0.8.6-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 +51 -34
- package/public/saltcorn.css +17 -0
- package/routes/admin.js +3 -0
- package/routes/api.js +4 -27
- package/routes/viewedit.js +19 -4
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "0.8.6-beta.
|
|
3
|
+
"version": "0.8.6-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
|
-
"@saltcorn/base-plugin": "0.8.6-beta.
|
|
10
|
-
"@saltcorn/builder": "0.8.6-beta.
|
|
11
|
-
"@saltcorn/data": "0.8.6-beta.
|
|
12
|
-
"@saltcorn/admin-models": "0.8.6-beta.
|
|
13
|
-
"@saltcorn/filemanager": "0.8.6-beta.
|
|
14
|
-
"@saltcorn/markup": "0.8.6-beta.
|
|
15
|
-
"@saltcorn/sbadmin2": "0.8.6-beta.
|
|
9
|
+
"@saltcorn/base-plugin": "0.8.6-beta.6",
|
|
10
|
+
"@saltcorn/builder": "0.8.6-beta.6",
|
|
11
|
+
"@saltcorn/data": "0.8.6-beta.6",
|
|
12
|
+
"@saltcorn/admin-models": "0.8.6-beta.6",
|
|
13
|
+
"@saltcorn/filemanager": "0.8.6-beta.6",
|
|
14
|
+
"@saltcorn/markup": "0.8.6-beta.6",
|
|
15
|
+
"@saltcorn/sbadmin2": "0.8.6-beta.6",
|
|
16
16
|
"@socket.io/cluster-adapter": "^0.2.1",
|
|
17
17
|
"@socket.io/sticky": "^1.0.1",
|
|
18
18
|
"adm-zip": "0.5.10",
|
|
@@ -435,6 +435,7 @@ function reload_on_init() {
|
|
|
435
435
|
localStorage.setItem("reload_on_init", true);
|
|
436
436
|
}
|
|
437
437
|
function initialize_page() {
|
|
438
|
+
const isNode = typeof parent?.saltcorn?.data?.state === "undefined";
|
|
438
439
|
//console.log("init page");
|
|
439
440
|
$(".blur-on-enter-keypress").bind("keyup", function (e) {
|
|
440
441
|
if (e.keyCode === 13) e.target.blur();
|
|
@@ -480,7 +481,9 @@ function initialize_page() {
|
|
|
480
481
|
if ($(this).find(".editicon").length === 0) {
|
|
481
482
|
var current = $(this).html();
|
|
482
483
|
$(this).html(
|
|
483
|
-
`<span class="current">${current}</span><i class="editicon
|
|
484
|
+
`<span class="current">${current}</span><i class="editicon ${
|
|
485
|
+
!isNode ? "visible" : ""
|
|
486
|
+
} fas fa-edit ms-1"></i>`
|
|
484
487
|
);
|
|
485
488
|
}
|
|
486
489
|
});
|
|
@@ -546,12 +549,20 @@ function initialize_page() {
|
|
|
546
549
|
} else
|
|
547
550
|
$(this).replaceWith(
|
|
548
551
|
`<form method="post" action="${url}" ${
|
|
549
|
-
ajax
|
|
552
|
+
ajax
|
|
553
|
+
? `onsubmit="inline_${
|
|
554
|
+
isNode ? "ajax" : "local"
|
|
555
|
+
}_submit(event, '${opts}')"`
|
|
556
|
+
: ""
|
|
550
557
|
}>
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
558
|
+
${
|
|
559
|
+
isNode
|
|
560
|
+
? `<input type="hidden" name="_csrf" value="${_sc_globalCsrf}"></input>`
|
|
561
|
+
: ""
|
|
562
|
+
}
|
|
563
|
+
<input type="${
|
|
564
|
+
type === "Integer" || type === "Float" ? "number" : "text"
|
|
565
|
+
}" name="${key}" value="${escapeHtml(current)}">
|
|
555
566
|
<button type="submit" class="btn btn-sm btn-primary">OK</button>
|
|
556
567
|
<button onclick="cancel_inline_edit(event, '${opts}')" type="button" class="btn btn-sm btn-danger"><i class="fas fa-times"></i></button>
|
|
557
568
|
</form>`
|
|
@@ -641,6 +652,7 @@ function initialize_page() {
|
|
|
641
652
|
$(initialize_page);
|
|
642
653
|
|
|
643
654
|
function cancel_inline_edit(e, opts1) {
|
|
655
|
+
const isNode = typeof parent?.saltcorn?.data?.state === "undefined";
|
|
644
656
|
var opts = JSON.parse(decodeURIComponent(opts1 || "") || "{}");
|
|
645
657
|
var form = $(e.target).closest("form");
|
|
646
658
|
var json_fk_opt;
|
|
@@ -668,17 +680,47 @@ function cancel_inline_edit(e, opts1) {
|
|
|
668
680
|
<span class="current">${
|
|
669
681
|
json_fk_opt || opts.current_label || opts.current
|
|
670
682
|
}</span>
|
|
671
|
-
<i class="editicon fas fa-edit ms-1"></i>
|
|
683
|
+
<i class="editicon ${!isNode ? "visible" : ""} fas fa-edit ms-1"></i>
|
|
672
684
|
</div>`);
|
|
673
685
|
initialize_page();
|
|
674
686
|
}
|
|
675
687
|
|
|
688
|
+
function inline_submit_success(e, form, opts) {
|
|
689
|
+
const isNode = typeof parent?.saltcorn?.data?.state === "undefined";
|
|
690
|
+
const formDataArray = form.serializeArray();
|
|
691
|
+
if (opts) {
|
|
692
|
+
let rawVal = formDataArray.find((f) => f.name == opts.key).value;
|
|
693
|
+
let val =
|
|
694
|
+
opts.is_key || (opts.schema && opts.schema.type.startsWith("Key to "))
|
|
695
|
+
? form.find("select").find("option:selected").text()
|
|
696
|
+
: rawVal;
|
|
697
|
+
|
|
698
|
+
$(e.target).replaceWith(`<div
|
|
699
|
+
data-inline-edit-field="${opts.key}"
|
|
700
|
+
${opts.ajax ? `data-inline-edit-ajax="true"` : ""}
|
|
701
|
+
${opts.type ? `data-inline-edit-type="${opts.type}"` : ""}
|
|
702
|
+
${opts.current ? `data-inline-edit-current="${rawVal}"` : ""}
|
|
703
|
+
${
|
|
704
|
+
opts.schema
|
|
705
|
+
? `data-inline-edit-schema="${encodeURIComponent(
|
|
706
|
+
JSON.stringify(opts.schema)
|
|
707
|
+
)}"`
|
|
708
|
+
: ""
|
|
709
|
+
}
|
|
710
|
+
${opts.current_label ? `data-inline-edit-current-label="${val}"` : ""}
|
|
711
|
+
data-inline-edit-dest-url="${opts.url}">
|
|
712
|
+
<span class="current">${val}</span>
|
|
713
|
+
<i class="editicon ${!isNode ? "visible" : ""} fas fa-edit ms-1"></i>
|
|
714
|
+
</div>`);
|
|
715
|
+
initialize_page();
|
|
716
|
+
} else location.reload();
|
|
717
|
+
}
|
|
718
|
+
|
|
676
719
|
function inline_ajax_submit(e, opts1) {
|
|
677
720
|
var opts = JSON.parse(decodeURIComponent(opts1 || "") || "{}");
|
|
678
721
|
e.preventDefault();
|
|
679
722
|
var form = $(e.target).closest("form");
|
|
680
723
|
var form_data = form.serialize();
|
|
681
|
-
var formDataArray = form.serializeArray();
|
|
682
724
|
var url = form.attr("action");
|
|
683
725
|
$.ajax(url, {
|
|
684
726
|
type: "POST",
|
|
@@ -687,32 +729,7 @@ function inline_ajax_submit(e, opts1) {
|
|
|
687
729
|
},
|
|
688
730
|
data: form_data,
|
|
689
731
|
success: function (res) {
|
|
690
|
-
|
|
691
|
-
let rawVal = formDataArray.find((f) => f.name == opts.key).value;
|
|
692
|
-
let val =
|
|
693
|
-
opts.is_key || (opts.schema && opts.schema.type.startsWith("Key to "))
|
|
694
|
-
? form.find("select").find("option:selected").text()
|
|
695
|
-
: rawVal;
|
|
696
|
-
|
|
697
|
-
$(e.target).replaceWith(`<div
|
|
698
|
-
data-inline-edit-field="${opts.key}"
|
|
699
|
-
${opts.ajax ? `data-inline-edit-ajax="true"` : ""}
|
|
700
|
-
${opts.type ? `data-inline-edit-type="${opts.type}"` : ""}
|
|
701
|
-
${opts.current ? `data-inline-edit-current="${rawVal}"` : ""}
|
|
702
|
-
${
|
|
703
|
-
opts.schema
|
|
704
|
-
? `data-inline-edit-schema="${encodeURIComponent(
|
|
705
|
-
JSON.stringify(opts.schema)
|
|
706
|
-
)}"`
|
|
707
|
-
: ""
|
|
708
|
-
}
|
|
709
|
-
${opts.current_label ? `data-inline-edit-current-label="${val}"` : ""}
|
|
710
|
-
data-inline-edit-dest-url="${opts.url}">
|
|
711
|
-
<span class="current">${val}</span>
|
|
712
|
-
<i class="editicon fas fa-edit ms-1"></i>
|
|
713
|
-
</div>`);
|
|
714
|
-
initialize_page();
|
|
715
|
-
} else location.reload();
|
|
732
|
+
inline_submit_success(e, form, opts);
|
|
716
733
|
},
|
|
717
734
|
error: function (e) {
|
|
718
735
|
ajax_done(
|
package/public/saltcorn.css
CHANGED
|
@@ -402,3 +402,20 @@ table.table-inner-grid td {
|
|
|
402
402
|
div.unread-notify {
|
|
403
403
|
border-left: 4px solid green;
|
|
404
404
|
}
|
|
405
|
+
|
|
406
|
+
.mobile-data-inline-edit {
|
|
407
|
+
position: relative;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.mobile-data-inline-edit::after {
|
|
411
|
+
content: "";
|
|
412
|
+
position: absolute;
|
|
413
|
+
top: -25%;
|
|
414
|
+
left: 0%;
|
|
415
|
+
width: 100%;
|
|
416
|
+
height: 150%;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.mt-6 {
|
|
420
|
+
margin-top: 5rem;
|
|
421
|
+
}
|
package/routes/admin.js
CHANGED
package/routes/api.js
CHANGED
|
@@ -19,6 +19,7 @@ const Router = require("express-promise-router");
|
|
|
19
19
|
const { error_catcher } = require("./utils.js");
|
|
20
20
|
//const { mkTable, renderForm, link, post_btn } = require("@saltcorn/markup");
|
|
21
21
|
const { getState } = require("@saltcorn/data/db/state");
|
|
22
|
+
const { prepare_update_row } = require("@saltcorn/data/web-mobile-commons");
|
|
22
23
|
const Table = require("@saltcorn/data/models/table");
|
|
23
24
|
const View = require("@saltcorn/data/models/view");
|
|
24
25
|
//const Field = require("@saltcorn/data/models/field");
|
|
@@ -460,39 +461,15 @@ router.post(
|
|
|
460
461
|
return;
|
|
461
462
|
}
|
|
462
463
|
await passport.authenticate(
|
|
463
|
-
"api-bearer",
|
|
464
|
+
["api-bearer", "jwt"],
|
|
464
465
|
{ session: false },
|
|
465
466
|
async function (err, user, info) {
|
|
466
467
|
if (accessAllowedWrite(req, user, table)) {
|
|
467
468
|
const { _versions, ...row } = req.body;
|
|
468
469
|
const fields = table.getFields();
|
|
469
470
|
readState(row, fields, req);
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
for (const k of Object.keys(row)) {
|
|
473
|
-
const field = fields.find((f) => f.name === k);
|
|
474
|
-
if (!field && k.includes(".")) {
|
|
475
|
-
const [fnm, jkey] = k.split(".");
|
|
476
|
-
const jfield = fields.find((f) => f.name === fnm);
|
|
477
|
-
if (jfield?.type?.name === "JSON") {
|
|
478
|
-
if (typeof row[fnm] === "undefined") {
|
|
479
|
-
const dbrow = await table.getRow({ [table.pk_name]: id });
|
|
480
|
-
row[fnm] = dbrow[fnm] || {};
|
|
481
|
-
}
|
|
482
|
-
row[fnm][jkey] = row[k];
|
|
483
|
-
delete row[k];
|
|
484
|
-
}
|
|
485
|
-
} else if (!field || field.calculated) {
|
|
486
|
-
delete row[k];
|
|
487
|
-
} else if (field?.type && field.type.validate) {
|
|
488
|
-
const vres = field.type.validate(field.attributes || {})(row[k]);
|
|
489
|
-
if (vres.error) {
|
|
490
|
-
hasErrors = true;
|
|
491
|
-
errors.push(`${k}: ${vres.error}`);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
if (hasErrors) {
|
|
471
|
+
const errors = await prepare_update_row(table, row, id);
|
|
472
|
+
if (errors.length > 0) {
|
|
496
473
|
getState().log(
|
|
497
474
|
2,
|
|
498
475
|
`API POST ${table.name} error: ${errors.join(", ")}`
|
package/routes/viewedit.js
CHANGED
|
@@ -493,14 +493,22 @@ router.post(
|
|
|
493
493
|
* @param {object} res
|
|
494
494
|
* @returns {void}
|
|
495
495
|
*/
|
|
496
|
-
const respondWorkflow = (view, wf, wfres, req, res) => {
|
|
496
|
+
const respondWorkflow = (view, wf, wfres, req, res, table) => {
|
|
497
497
|
const wrap = (contents, noCard, previewURL) => ({
|
|
498
498
|
above: [
|
|
499
499
|
{
|
|
500
500
|
type: "breadcrumbs",
|
|
501
501
|
crumbs: [
|
|
502
502
|
{ text: req.__("Views"), href: "/viewedit" },
|
|
503
|
-
{
|
|
503
|
+
{
|
|
504
|
+
href: `/view/${view.name}`,
|
|
505
|
+
text: view.name,
|
|
506
|
+
postLinkText: `[${view.viewtemplate}${
|
|
507
|
+
table
|
|
508
|
+
? ` on ${a({ href: `/table/` + table.name }, table.name)}`
|
|
509
|
+
: ""
|
|
510
|
+
}]`,
|
|
511
|
+
},
|
|
504
512
|
{ workflow: wf, step: wfres },
|
|
505
513
|
],
|
|
506
514
|
},
|
|
@@ -584,6 +592,9 @@ router.get(
|
|
|
584
592
|
(view.configuration?.columns || []).forEach((c) => {
|
|
585
593
|
c._columndef = JSON.stringify(c);
|
|
586
594
|
});
|
|
595
|
+
let table;
|
|
596
|
+
if (view.table_id) table = Table.findOne({ id: view.table_id });
|
|
597
|
+
if (view.exttable_name) table = Table.findOne({ name: view.exttable_name });
|
|
587
598
|
const configFlow = await view.get_config_flow(req);
|
|
588
599
|
const hasConfig =
|
|
589
600
|
view.configuration && Object.keys(view.configuration).length > 0;
|
|
@@ -598,7 +609,7 @@ router.get(
|
|
|
598
609
|
},
|
|
599
610
|
req
|
|
600
611
|
);
|
|
601
|
-
respondWorkflow(view, configFlow, wfres, req, res);
|
|
612
|
+
respondWorkflow(view, configFlow, wfres, req, res, table);
|
|
602
613
|
})
|
|
603
614
|
);
|
|
604
615
|
|
|
@@ -617,7 +628,11 @@ router.post(
|
|
|
617
628
|
const view = await View.findOne({ name });
|
|
618
629
|
const configFlow = await view.get_config_flow(req);
|
|
619
630
|
const wfres = await configFlow.run(req.body, req);
|
|
620
|
-
|
|
631
|
+
|
|
632
|
+
let table;
|
|
633
|
+
if (view.table_id) table = Table.findOne({ id: view.table_id });
|
|
634
|
+
if (view.exttable_name) table = Table.findOne({ name: view.exttable_name });
|
|
635
|
+
respondWorkflow(view, configFlow, wfres, req, res, table);
|
|
621
636
|
})
|
|
622
637
|
);
|
|
623
638
|
|