@saltcorn/server 0.9.6-beta.8 → 0.9.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/app.js +9 -2
- package/auth/admin.js +51 -52
- package/auth/roleadmin.js +6 -2
- package/auth/routes.js +28 -10
- package/auth/testhelp.js +86 -0
- package/help/Field label.tmd +11 -0
- package/help/Field types.tmd +39 -0
- package/help/Inclusion Formula.tmd +38 -0
- package/help/Ownership field.tmd +76 -0
- package/help/Ownership formula.tmd +75 -0
- package/help/Table roles.tmd +20 -0
- package/help/User groups.tmd +35 -0
- package/help/User roles.tmd +30 -0
- package/load_plugins.js +28 -4
- package/locales/en.json +28 -1
- package/locales/it.json +3 -2
- package/markup/forms.js +5 -1
- package/package.json +9 -9
- package/public/log_viewer_utils.js +32 -0
- package/public/mermaid.min.js +705 -306
- package/public/saltcorn-builder.css +23 -0
- package/public/saltcorn-common.js +195 -71
- package/public/saltcorn.css +72 -0
- package/public/saltcorn.js +78 -0
- package/restart_watcher.js +1 -0
- package/routes/actions.js +27 -0
- package/routes/admin.js +180 -66
- package/routes/api.js +6 -0
- package/routes/common_lists.js +42 -32
- package/routes/fields.js +9 -1
- package/routes/homepage.js +2 -0
- package/routes/menu.js +69 -4
- package/routes/notifications.js +90 -10
- package/routes/pageedit.js +18 -13
- package/routes/plugins.js +5 -1
- package/routes/search.js +10 -4
- package/routes/tables.js +47 -27
- package/routes/tenant.js +4 -15
- package/routes/utils.js +20 -6
- package/routes/viewedit.js +11 -7
- package/serve.js +27 -5
- package/tests/edit.test.js +426 -0
- package/tests/fields.test.js +21 -0
- package/tests/filter.test.js +68 -0
- package/tests/page.test.js +2 -2
- package/tests/sync.test.js +59 -0
- package/wrapper.js +4 -1
|
@@ -509,3 +509,26 @@ div.builder-config-field {
|
|
|
509
509
|
border: 1px solid black;
|
|
510
510
|
margin-top: 2px;
|
|
511
511
|
}
|
|
512
|
+
|
|
513
|
+
div.componets-and-library-accordion {
|
|
514
|
+
padding-right: 0 !important;
|
|
515
|
+
}
|
|
516
|
+
.builder-left-shrunk .componets-and-library-accordion {
|
|
517
|
+
min-height: 0 !important;
|
|
518
|
+
padding-right: 0;
|
|
519
|
+
}
|
|
520
|
+
.toolbox-card .builder-layers {
|
|
521
|
+
min-height: 200px;
|
|
522
|
+
overflow-y: auto;
|
|
523
|
+
max-height: max-content !important;
|
|
524
|
+
}
|
|
525
|
+
.toolbox-card:nth-child(2) {
|
|
526
|
+
margin-bottom: 0px;
|
|
527
|
+
}
|
|
528
|
+
#builder-main-canvas {
|
|
529
|
+
height: calc(100dvh - 50px) !important;
|
|
530
|
+
min-height: 600px;
|
|
531
|
+
}
|
|
532
|
+
#builder-main-canvas.h-100 {
|
|
533
|
+
height: 100% !important;
|
|
534
|
+
}
|
|
@@ -8,6 +8,23 @@ jQuery.fn.swapWith = function (to) {
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
function monospace_block_click(e) {
|
|
12
|
+
let e1 = $(e).next("pre");
|
|
13
|
+
let mine = $(e).html();
|
|
14
|
+
$(e).html($(e1).html());
|
|
15
|
+
$(e1).html(mine);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function copy_monospace_block(e) {
|
|
19
|
+
let e1 = $(e).next("pre");
|
|
20
|
+
let e2 = $(e1).next("pre");
|
|
21
|
+
if (!e2.length) return navigator.clipboard.writeText($(el).text());
|
|
22
|
+
const e1t = e1.text();
|
|
23
|
+
const e2t = e2.text();
|
|
24
|
+
if (e1t.length > e2t.length) return navigator.clipboard.writeText(e1t);
|
|
25
|
+
else return navigator.clipboard.writeText(e2t);
|
|
26
|
+
}
|
|
27
|
+
|
|
11
28
|
function setScreenInfoCookie() {
|
|
12
29
|
document.cookie = `_sc_screen_info_=${JSON.stringify({
|
|
13
30
|
width: window.screen.width,
|
|
@@ -190,7 +207,8 @@ function apply_showif() {
|
|
|
190
207
|
else qss.push(`dereference=${dynwhere.dereference}`);
|
|
191
208
|
}
|
|
192
209
|
const qs = qss.join("&");
|
|
193
|
-
|
|
210
|
+
let current = e.attr("data-selected");
|
|
211
|
+
if (current === "null") current = null;
|
|
194
212
|
e.change(function (ec) {
|
|
195
213
|
e.attr("data-selected", ec.target.value);
|
|
196
214
|
});
|
|
@@ -199,12 +217,14 @@ function apply_showif() {
|
|
|
199
217
|
if (currentOptionsSet === qs) return;
|
|
200
218
|
|
|
201
219
|
const activate = (success, qs) => {
|
|
220
|
+
//re-fetch current, because it may have changed
|
|
221
|
+
let current = e.attr("data-selected");
|
|
222
|
+
if (current === "null") current = null;
|
|
202
223
|
if (e.prop("data-fetch-options-current-set") === qs) return;
|
|
203
224
|
e.empty();
|
|
204
225
|
e.prop("data-fetch-options-current-set", qs);
|
|
205
226
|
const toAppend = [];
|
|
206
|
-
|
|
207
|
-
toAppend.push({ label: dynwhere.neutral_label || "", value: "" });
|
|
227
|
+
|
|
208
228
|
let currentDataOption = undefined;
|
|
209
229
|
const dataOptions = [];
|
|
210
230
|
//console.log(success);
|
|
@@ -235,13 +255,24 @@ function apply_showif() {
|
|
|
235
255
|
? 1
|
|
236
256
|
: -1
|
|
237
257
|
);
|
|
258
|
+
if (!dynwhere.required)
|
|
259
|
+
toAppend.unshift({ label: dynwhere.neutral_label || "", value: "" });
|
|
260
|
+
if (dynwhere.required && dynwhere.placeholder)
|
|
261
|
+
toAppend.unshift({
|
|
262
|
+
disabled: true,
|
|
263
|
+
label: dynwhere.placeholder,
|
|
264
|
+
value: "",
|
|
265
|
+
selected: !current,
|
|
266
|
+
});
|
|
238
267
|
e.html(
|
|
239
268
|
toAppend
|
|
240
269
|
.map(
|
|
241
|
-
({ label, value, selected }) =>
|
|
270
|
+
({ label, value, selected, disabled }) =>
|
|
242
271
|
`<option${selected ? ` selected` : ""}${
|
|
243
|
-
|
|
244
|
-
}
|
|
272
|
+
disabled ? ` disabled` : ""
|
|
273
|
+
}${typeof value !== "undefined" ? ` value="${value}"` : ""}>${
|
|
274
|
+
label || ""
|
|
275
|
+
}</option>`
|
|
245
276
|
)
|
|
246
277
|
.join("")
|
|
247
278
|
);
|
|
@@ -624,6 +655,138 @@ function escapeHtml(text) {
|
|
|
624
655
|
function reload_on_init() {
|
|
625
656
|
localStorage.setItem("reload_on_init", true);
|
|
626
657
|
}
|
|
658
|
+
|
|
659
|
+
function doMobileTransforms() {
|
|
660
|
+
const replaceAttr = (el, attr, web, mobile) => {
|
|
661
|
+
const jThis = $(el);
|
|
662
|
+
const skip = jThis.attr("skip-mobile-adjust");
|
|
663
|
+
if (!skip) {
|
|
664
|
+
const attrVal = jThis.attr(attr);
|
|
665
|
+
if (attrVal?.includes(web)) {
|
|
666
|
+
jThis.attr(attr, attrVal.replace(web, mobile));
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
const replacers = {
|
|
672
|
+
href: [
|
|
673
|
+
{
|
|
674
|
+
web: "javascript:history.back()",
|
|
675
|
+
mobile: "javascript:parent.goBack()",
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
web: "javascript:ajax_modal",
|
|
679
|
+
mobile: "javascript:mobile_modal",
|
|
680
|
+
},
|
|
681
|
+
],
|
|
682
|
+
onclick: [
|
|
683
|
+
{
|
|
684
|
+
web: "history.back()",
|
|
685
|
+
mobile: "parent.goBack()",
|
|
686
|
+
},
|
|
687
|
+
{
|
|
688
|
+
web: "ajax_modal",
|
|
689
|
+
mobile: "mobile_modal",
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
web: "ajax_post_",
|
|
693
|
+
mobile: "local_post_",
|
|
694
|
+
},
|
|
695
|
+
],
|
|
696
|
+
};
|
|
697
|
+
|
|
698
|
+
$("a").each(function () {
|
|
699
|
+
let path = $(this).attr("href") || "";
|
|
700
|
+
if (path.startsWith("http")) {
|
|
701
|
+
const url = new URL(path);
|
|
702
|
+
path = `${url.pathname}${url.search}`;
|
|
703
|
+
}
|
|
704
|
+
if (path.startsWith("/view/") || path.startsWith("/page/")) {
|
|
705
|
+
const jThis = $(this);
|
|
706
|
+
const skip = jThis.attr("skip-mobile-adjust");
|
|
707
|
+
if (!skip) {
|
|
708
|
+
jThis.removeAttr("href");
|
|
709
|
+
jThis.attr("onclick", `execLink('${path}')`);
|
|
710
|
+
if (jThis.find("i,img").length === 0 && !jThis.css("color")) {
|
|
711
|
+
jThis.css(
|
|
712
|
+
"color",
|
|
713
|
+
"rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1))"
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
} else if (path.includes("/files/serve/")) {
|
|
718
|
+
const tokens = path.split("/files/serve/");
|
|
719
|
+
if (tokens.length > 1)
|
|
720
|
+
$(this).attr("href", `javascript:openFile('${tokens[1]}')`);
|
|
721
|
+
} else if (path.includes("/files/download/")) {
|
|
722
|
+
const tokens = path.split("/files/download/");
|
|
723
|
+
if (tokens.length > 1)
|
|
724
|
+
$(this).attr(
|
|
725
|
+
"href",
|
|
726
|
+
`javascript:notifyAlert('File donwloads are not supported.')`
|
|
727
|
+
);
|
|
728
|
+
} else {
|
|
729
|
+
for (const [k, v] of Object.entries(replacers)) {
|
|
730
|
+
for ({ web, mobile } of v) replaceAttr(this, k, web, mobile);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
$("button").each(function () {
|
|
736
|
+
for (const [k, v] of Object.entries({ onclick: replacers.onclick })) {
|
|
737
|
+
for ({ web, mobile } of v) replaceAttr(this, k, v.web, v.mobile);
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
$("[mobile-img-path]").each(async function () {
|
|
742
|
+
if (parent.loadEncodedFile) {
|
|
743
|
+
const fileId = $(this).attr("mobile-img-path");
|
|
744
|
+
const base64Encoded = await parent.loadEncodedFile(fileId);
|
|
745
|
+
this.src = base64Encoded;
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
$("[mobile-bg-img-path]").each(async function () {
|
|
750
|
+
if (parent.loadEncodedFile) {
|
|
751
|
+
const fileId = $(this).attr("mobile-bg-img-path");
|
|
752
|
+
if (fileId) {
|
|
753
|
+
const base64Encoded = await parent.loadEncodedFile(fileId);
|
|
754
|
+
this.style.backgroundImage = `url("${base64Encoded}")`;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
$("img:not([mobile-img-path]):not([mobile-bg-img-path])").each(
|
|
760
|
+
async function () {
|
|
761
|
+
if (parent.loadEncodedFile) {
|
|
762
|
+
const jThis = $(this);
|
|
763
|
+
const src = jThis.attr("src");
|
|
764
|
+
if (src?.includes("/files/serve/")) {
|
|
765
|
+
const tokens = src.split("/files/serve/");
|
|
766
|
+
if (tokens.length > 1) {
|
|
767
|
+
const fileId = tokens[1];
|
|
768
|
+
const base64Encoded = await parent.loadEncodedFile(fileId);
|
|
769
|
+
this.src = base64Encoded;
|
|
770
|
+
}
|
|
771
|
+
} else if (src?.includes("/files/resize/")) {
|
|
772
|
+
const tokens = src.split("/files/resize/");
|
|
773
|
+
if (tokens.length > 1) {
|
|
774
|
+
const idAndDims = tokens[1].split("/");
|
|
775
|
+
const width = idAndDims[0];
|
|
776
|
+
const height = idAndDims.length > 2 ? idAndDims[1] : undefined;
|
|
777
|
+
const fileId = idAndDims[idAndDims.length - 1];
|
|
778
|
+
const style = { width: `${width || 50}px` };
|
|
779
|
+
if (height > 0) style.height = `${height}px`;
|
|
780
|
+
const base64Encoded = await parent.loadEncodedFile(fileId);
|
|
781
|
+
this.src = base64Encoded;
|
|
782
|
+
jThis.css(style);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
|
|
627
790
|
function initialize_page() {
|
|
628
791
|
if (window._sc_locale && window.dayjs) dayjs.locale(window._sc_locale);
|
|
629
792
|
const isNode = getIsNode();
|
|
@@ -798,58 +961,7 @@ function initialize_page() {
|
|
|
798
961
|
</form>`
|
|
799
962
|
);
|
|
800
963
|
});
|
|
801
|
-
if (!isNode)
|
|
802
|
-
$("[mobile-img-path]").each(async function () {
|
|
803
|
-
if (parent.loadEncodedFile) {
|
|
804
|
-
const fileId = $(this).attr("mobile-img-path");
|
|
805
|
-
const base64Encoded = await parent.loadEncodedFile(fileId);
|
|
806
|
-
this.src = base64Encoded;
|
|
807
|
-
}
|
|
808
|
-
});
|
|
809
|
-
|
|
810
|
-
$("[mobile-bg-img-path]").each(async function () {
|
|
811
|
-
if (parent.loadEncodedFile) {
|
|
812
|
-
const fileId = $(this).attr("mobile-bg-img-path");
|
|
813
|
-
if (fileId) {
|
|
814
|
-
const base64Encoded = await parent.loadEncodedFile(fileId);
|
|
815
|
-
this.style.backgroundImage = `url("${base64Encoded}")`;
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
});
|
|
819
|
-
|
|
820
|
-
$("a").each(function () {
|
|
821
|
-
let path = $(this).attr("href") || "";
|
|
822
|
-
if (path.startsWith("http")) {
|
|
823
|
-
const url = new URL(path);
|
|
824
|
-
path = `${url.pathname}${url.search}`;
|
|
825
|
-
}
|
|
826
|
-
if (path.startsWith("/view/")) {
|
|
827
|
-
const jThis = $(this);
|
|
828
|
-
const skip = jThis.attr("skip-mobile-adjust");
|
|
829
|
-
if (!skip) {
|
|
830
|
-
jThis.attr("href", `javascript:execLink('${path}')`);
|
|
831
|
-
if (jThis.find("i,img").length === 0 && !jThis.css("color")) {
|
|
832
|
-
jThis.css(
|
|
833
|
-
"color",
|
|
834
|
-
"rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1))"
|
|
835
|
-
);
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
});
|
|
840
|
-
|
|
841
|
-
$("img").each(async function () {
|
|
842
|
-
if (parent.loadEncodedFile) {
|
|
843
|
-
const jThis = $(this);
|
|
844
|
-
const src = jThis.attr("src");
|
|
845
|
-
if (src?.startsWith("/files/serve/")) {
|
|
846
|
-
const fileId = src.replace("/files/serve/", "");
|
|
847
|
-
const base64Encoded = await parent.loadEncodedFile(fileId);
|
|
848
|
-
this.src = base64Encoded;
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
});
|
|
852
|
-
}
|
|
964
|
+
if (!isNode) doMobileTransforms();
|
|
853
965
|
function setExplainer(that) {
|
|
854
966
|
var id = $(that).attr("id") + "_explainer";
|
|
855
967
|
|
|
@@ -1285,10 +1397,12 @@ async function common_done(res, viewnameOrElem, isWeb = true) {
|
|
|
1285
1397
|
}
|
|
1286
1398
|
};
|
|
1287
1399
|
if (res.notify) await handle(res.notify, notifyAlert);
|
|
1288
|
-
if (res.error)
|
|
1400
|
+
if (res.error) {
|
|
1401
|
+
if (window._sc_loglevel > 4) console.trace("error response", res.error);
|
|
1289
1402
|
await handle(res.error, (text) =>
|
|
1290
1403
|
notifyAlert({ type: "danger", text: text })
|
|
1291
1404
|
);
|
|
1405
|
+
}
|
|
1292
1406
|
if (res.notify_success)
|
|
1293
1407
|
await handle(res.notify_success, (text) =>
|
|
1294
1408
|
notifyAlert({ type: "success", text: text })
|
|
@@ -1322,6 +1436,10 @@ async function common_done(res, viewnameOrElem, isWeb = true) {
|
|
|
1322
1436
|
if (input.attr("type") === "checkbox")
|
|
1323
1437
|
input.prop("checked", res.set_fields[k]);
|
|
1324
1438
|
else input.val(res.set_fields[k]);
|
|
1439
|
+
if (input.attr("data-selected")) {
|
|
1440
|
+
input.attr("data-selected", res.set_fields[k]);
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1325
1443
|
input.trigger("set_form_field");
|
|
1326
1444
|
});
|
|
1327
1445
|
}
|
|
@@ -1355,15 +1473,15 @@ async function common_done(res, viewnameOrElem, isWeb = true) {
|
|
|
1355
1473
|
});
|
|
1356
1474
|
}
|
|
1357
1475
|
if (res.eval_js) await handle(res.eval_js, eval_it);
|
|
1358
|
-
|
|
1359
|
-
if (res.goto && !isWeb)
|
|
1360
|
-
// TODO ch
|
|
1361
|
-
notifyAlert({
|
|
1362
|
-
type: "danger",
|
|
1363
|
-
text: "Goto is not supported in a mobile deployment.",
|
|
1364
|
-
});
|
|
1365
1476
|
else if (res.goto) {
|
|
1366
|
-
if (
|
|
1477
|
+
if (!isWeb) {
|
|
1478
|
+
const next = new URL(res.goto, "http://localhost");
|
|
1479
|
+
const pathname = next.pathname;
|
|
1480
|
+
if (pathname.startsWith("/view/") || pathname.startsWith("/page/")) {
|
|
1481
|
+
const route = `get${pathname}${next.search ? "?" + next.search : ""}`;
|
|
1482
|
+
await parent.handleRoute(route);
|
|
1483
|
+
} else parent.cordova.InAppBrowser.open(res.goto, "_system");
|
|
1484
|
+
} else if (res.target === "_blank") window.open(res.goto, "_blank").focus();
|
|
1367
1485
|
else {
|
|
1368
1486
|
const prev = new URL(window.location.href);
|
|
1369
1487
|
const next = new URL(res.goto, prev.origin);
|
|
@@ -1484,10 +1602,10 @@ const columnSummary = (col) => {
|
|
|
1484
1602
|
};
|
|
1485
1603
|
|
|
1486
1604
|
function submitWithEmptyAction(form) {
|
|
1487
|
-
var formAction = form.action;
|
|
1488
|
-
form.action
|
|
1605
|
+
var formAction = form.getAttribute("action");
|
|
1606
|
+
form.setAttribute("action", "javascript:void(0)");
|
|
1489
1607
|
form.submit();
|
|
1490
|
-
form.action
|
|
1608
|
+
form.setAttribute("action", formAction);
|
|
1491
1609
|
}
|
|
1492
1610
|
|
|
1493
1611
|
function unique_field_from_rows(
|
|
@@ -1711,7 +1829,13 @@ function close_saltcorn_modal() {
|
|
|
1711
1829
|
function reload_embedded_view(viewname, new_query_string) {
|
|
1712
1830
|
const isNode = getIsNode();
|
|
1713
1831
|
const updater = ($e, res) => {
|
|
1714
|
-
$e.
|
|
1832
|
+
const localState = $e.attr("data-sc-local-state");
|
|
1833
|
+
const parent = $e.parent();
|
|
1834
|
+
$e.replaceWith(res);
|
|
1835
|
+
if (localState && !new_query_string) {
|
|
1836
|
+
const newE = parent.find(`[data-sc-embed-viewname="${viewname}"]`);
|
|
1837
|
+
newE.attr("data-sc-local-state", localState);
|
|
1838
|
+
}
|
|
1715
1839
|
initialize_page();
|
|
1716
1840
|
};
|
|
1717
1841
|
if (window._sc_loglevel > 4)
|
package/public/saltcorn.css
CHANGED
|
@@ -514,3 +514,75 @@ ul.katetree {
|
|
|
514
514
|
ul.katetree details ul {
|
|
515
515
|
list-style-type: none;
|
|
516
516
|
}
|
|
517
|
+
|
|
518
|
+
pre.monospace-block {
|
|
519
|
+
font-family: monospace;
|
|
520
|
+
color: unset;
|
|
521
|
+
background: unset;
|
|
522
|
+
padding: unset;
|
|
523
|
+
border-radius: unset;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
.d-none-prefer {
|
|
527
|
+
display: none;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
button.monospace-copy-btn:has(+ pre.monospace-block:hover) {
|
|
531
|
+
display: block !important ;
|
|
532
|
+
}
|
|
533
|
+
button.monospace-copy-btn:hover {
|
|
534
|
+
display: block !important ;
|
|
535
|
+
}
|
|
536
|
+
button.monospace-copy-btn {
|
|
537
|
+
position: absolute;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
#page-inner-content.sbadmin2-theme .table.table-card-rows {
|
|
541
|
+
border-spacing: 0px 8px;
|
|
542
|
+
border-collapse: separate;
|
|
543
|
+
}
|
|
544
|
+
#page-inner-content.sbadmin2-theme .table.table-card-rows tbody {
|
|
545
|
+
transform: translateY(8px);
|
|
546
|
+
}
|
|
547
|
+
#page-inner-content.sbadmin2-theme .table.table-card-rows tr {
|
|
548
|
+
border-radius: 6px;
|
|
549
|
+
}
|
|
550
|
+
#page-inner-content.sbadmin2-theme
|
|
551
|
+
.table-hover.table-card-rows
|
|
552
|
+
> tbody
|
|
553
|
+
> tr:hover
|
|
554
|
+
> * {
|
|
555
|
+
--tblr-table-bg-state: transparent !important;
|
|
556
|
+
--bs-table-accent-bg: transparent !important;
|
|
557
|
+
color: var(--bs-table-hover-color);
|
|
558
|
+
background-color: var(--bs-table-hover-bg);
|
|
559
|
+
}
|
|
560
|
+
#page-inner-content.sbadmin2-theme .table.table-card-rows thead th {
|
|
561
|
+
background-color: #eaecf4;
|
|
562
|
+
border-block: 1px solid #d3d3d3 !important;
|
|
563
|
+
padding: 18px 15px;
|
|
564
|
+
font-weight: 600;
|
|
565
|
+
}
|
|
566
|
+
#page-inner-content.sbadmin2-theme .table.table-card-rows thead th:first-child {
|
|
567
|
+
border-left: 1px solid #d3d3d3 !important;
|
|
568
|
+
border-radius: 6px 0 0 6px;
|
|
569
|
+
}
|
|
570
|
+
#page-inner-content.sbadmin2-theme .table.table-card-rows thead th:last-child {
|
|
571
|
+
border-right: 1px #d3d3d3 !important;
|
|
572
|
+
border-radius: 0 6px 6px 0;
|
|
573
|
+
}
|
|
574
|
+
#page-inner-content.sbadmin2-theme .table.table-card-rows tbody td {
|
|
575
|
+
border-block: 1px solid #e3e6f0 !important;
|
|
576
|
+
position: relative;
|
|
577
|
+
z-index: 11;
|
|
578
|
+
padding: 15px 15px;
|
|
579
|
+
background-color: #fff;
|
|
580
|
+
}
|
|
581
|
+
#page-inner-content.sbadmin2-theme .table.table-card-rows tbody td:first-child {
|
|
582
|
+
border-left: 1px solid #e3e6f0 !important;
|
|
583
|
+
border-radius: 6px 0 0 6px;
|
|
584
|
+
}
|
|
585
|
+
#page-inner-content.sbadmin2-theme .table.table-card-rows tbody td:last-child {
|
|
586
|
+
border-right: 1px #e3e6f0 !important;
|
|
587
|
+
border-radius: 0 6px 6px 0;
|
|
588
|
+
}
|
package/public/saltcorn.js
CHANGED
|
@@ -1034,6 +1034,84 @@ function execLink(path) {
|
|
|
1034
1034
|
window.location.href = `${location.origin}${path}`;
|
|
1035
1035
|
}
|
|
1036
1036
|
|
|
1037
|
+
let defferedPrompt;
|
|
1038
|
+
window.addEventListener("beforeinstallprompt", (e) => {
|
|
1039
|
+
e.preventDefault();
|
|
1040
|
+
defferedPrompt = e;
|
|
1041
|
+
});
|
|
1042
|
+
|
|
1043
|
+
function isAndroidMobile() {
|
|
1044
|
+
const ua = navigator.userAgent || navigator.vendor || window.opera;
|
|
1045
|
+
return /android/i.test(ua) && /mobile/i.test(ua);
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
function validatePWAManifest(manifest) {
|
|
1049
|
+
const errors = [];
|
|
1050
|
+
if (!manifest) errors.push("The manifest.json file is missing. ");
|
|
1051
|
+
else {
|
|
1052
|
+
if (!manifest.icons || manifest.icons.length === 0)
|
|
1053
|
+
errors.push("At least one icon is required");
|
|
1054
|
+
else if (
|
|
1055
|
+
manifest.icons.length > 0 &&
|
|
1056
|
+
!manifest.icons.some((icon) => {
|
|
1057
|
+
const sizes = icon.sizes.split("x");
|
|
1058
|
+
const x = parseInt(sizes[0]);
|
|
1059
|
+
const y = parseInt(sizes[1]);
|
|
1060
|
+
return x === y && x >= 144;
|
|
1061
|
+
})
|
|
1062
|
+
) {
|
|
1063
|
+
errors.push(
|
|
1064
|
+
"At least one square icon of size 144x144 or larger is required"
|
|
1065
|
+
);
|
|
1066
|
+
}
|
|
1067
|
+
if (isAndroidMobile() && manifest.display === "browser") {
|
|
1068
|
+
errors.push(
|
|
1069
|
+
"The display property 'browser' may not work on mobile devices"
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
return errors;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
function supportsBeforeInstallPrompt() {
|
|
1077
|
+
return "onbeforeinstallprompt" in window;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
function installPWA() {
|
|
1081
|
+
if (defferedPrompt) defferedPrompt.prompt();
|
|
1082
|
+
else if (!supportsBeforeInstallPrompt()) {
|
|
1083
|
+
notifyAlert({
|
|
1084
|
+
type: "danger",
|
|
1085
|
+
text:
|
|
1086
|
+
"It looks like your browser doesn’t support this feature. " +
|
|
1087
|
+
"Please try the standard installation method provided by your browser, or switch to a different browser.",
|
|
1088
|
+
});
|
|
1089
|
+
} else {
|
|
1090
|
+
const manifestUrl = `${window.location.origin}/notifications/manifest.json`;
|
|
1091
|
+
notifyAlert({
|
|
1092
|
+
type: "danger",
|
|
1093
|
+
text:
|
|
1094
|
+
"Unable to install the app. " +
|
|
1095
|
+
"Please check if the app is already installed or " +
|
|
1096
|
+
`inspect your manifest.json <a href="${manifestUrl}?pretty=true" target="_blank">here</a>`,
|
|
1097
|
+
});
|
|
1098
|
+
$.ajax(manifestUrl, {
|
|
1099
|
+
success: (res) => {
|
|
1100
|
+
const errors = validatePWAManifest(res);
|
|
1101
|
+
if (errors.length > 0)
|
|
1102
|
+
notifyAlert({
|
|
1103
|
+
type: "warning",
|
|
1104
|
+
text: `${errors.join(", ")}`,
|
|
1105
|
+
});
|
|
1106
|
+
},
|
|
1107
|
+
error: (res) => {
|
|
1108
|
+
console.log("Error fetching manifest.json");
|
|
1109
|
+
console.log(res);
|
|
1110
|
+
},
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1037
1115
|
(() => {
|
|
1038
1116
|
const e = document.querySelector("[data-sidebar-toggler]");
|
|
1039
1117
|
let closed = localStorage.getItem("sidebarClosed") === "true";
|
package/restart_watcher.js
CHANGED
package/routes/actions.js
CHANGED
|
@@ -375,6 +375,7 @@ router.get(
|
|
|
375
375
|
|
|
376
376
|
const form = await triggerForm(req, trigger);
|
|
377
377
|
form.values = trigger;
|
|
378
|
+
form.onChange = `saveAndContinue(this)`;
|
|
378
379
|
send_events_page({
|
|
379
380
|
res,
|
|
380
381
|
req,
|
|
@@ -383,6 +384,7 @@ router.get(
|
|
|
383
384
|
contents: {
|
|
384
385
|
type: "card",
|
|
385
386
|
title: req.__("Edit trigger %s", id),
|
|
387
|
+
titleAjaxIndicator: true,
|
|
386
388
|
contents: renderForm(form, req.csrfToken()),
|
|
387
389
|
},
|
|
388
390
|
});
|
|
@@ -464,6 +466,10 @@ router.post(
|
|
|
464
466
|
...form.values.configuration,
|
|
465
467
|
};
|
|
466
468
|
await Trigger.update(trigger.id, form.values); //{configuration: form.values});
|
|
469
|
+
if (req.xhr) {
|
|
470
|
+
res.json({ success: "ok" });
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
467
473
|
req.flash("success", req.__("Action information saved"));
|
|
468
474
|
res.redirect(`/actions/`);
|
|
469
475
|
}
|
|
@@ -881,3 +887,24 @@ router.get(
|
|
|
881
887
|
}
|
|
882
888
|
})
|
|
883
889
|
);
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* @name post/clone/:id
|
|
893
|
+
* @function
|
|
894
|
+
* @memberof module:routes/actions~actionsRouter
|
|
895
|
+
* @function
|
|
896
|
+
*/
|
|
897
|
+
router.post(
|
|
898
|
+
"/clone/:id",
|
|
899
|
+
isAdmin,
|
|
900
|
+
error_catcher(async (req, res) => {
|
|
901
|
+
const { id } = req.params;
|
|
902
|
+
const trig = await Trigger.findOne({ id });
|
|
903
|
+
const newtrig = await trig.clone();
|
|
904
|
+
req.flash(
|
|
905
|
+
"success",
|
|
906
|
+
req.__("Trigger %s duplicated as %s", trig.name, newtrig.name)
|
|
907
|
+
);
|
|
908
|
+
res.redirect(`/actions`);
|
|
909
|
+
})
|
|
910
|
+
);
|