@saltcorn/server 0.9.5-beta.2 → 0.9.5-beta.20
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/auth/routes.js +54 -7
- package/errors.js +1 -0
- package/help/Cordova Builder.tmd +13 -0
- package/load_plugins.js +89 -144
- package/locales/en.json +30 -1
- package/locales/ru.json +1134 -1101
- package/package.json +16 -13
- package/public/log_viewer_utils.js +17 -1
- package/public/saltcorn-common.js +154 -24
- package/public/saltcorn.css +4 -0
- package/public/saltcorn.js +67 -46
- package/restart_watcher.js +2 -0
- package/routes/actions.js +17 -1
- package/routes/admin.js +389 -20
- package/routes/api.js +4 -1
- package/routes/common_lists.js +1 -1
- package/routes/fields.js +13 -8
- package/routes/homepage.js +6 -3
- package/routes/menu.js +12 -3
- package/routes/pageedit.js +1 -1
- package/routes/plugins.js +265 -29
- package/routes/search.js +28 -2
- package/routes/tables.js +4 -0
- package/serve.js +1 -1
- package/tests/page.test.js +11 -1
package/package.json
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "0.9.5-beta.
|
|
3
|
+
"version": "0.9.5-beta.20",
|
|
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.5-beta.
|
|
11
|
-
"@saltcorn/builder": "0.9.5-beta.
|
|
12
|
-
"@saltcorn/data": "0.9.5-beta.
|
|
13
|
-
"@saltcorn/admin-models": "0.9.5-beta.
|
|
14
|
-
"@saltcorn/filemanager": "0.9.5-beta.
|
|
15
|
-
"@saltcorn/markup": "0.9.5-beta.
|
|
16
|
-
"@saltcorn/
|
|
10
|
+
"@saltcorn/base-plugin": "0.9.5-beta.20",
|
|
11
|
+
"@saltcorn/builder": "0.9.5-beta.20",
|
|
12
|
+
"@saltcorn/data": "0.9.5-beta.20",
|
|
13
|
+
"@saltcorn/admin-models": "0.9.5-beta.20",
|
|
14
|
+
"@saltcorn/filemanager": "0.9.5-beta.20",
|
|
15
|
+
"@saltcorn/markup": "0.9.5-beta.20",
|
|
16
|
+
"@saltcorn/plugins-loader": "0.9.5-beta.20",
|
|
17
|
+
"@saltcorn/sbadmin2": "0.9.5-beta.20",
|
|
17
18
|
"@socket.io/cluster-adapter": "^0.2.1",
|
|
18
19
|
"@socket.io/sticky": "^1.0.1",
|
|
19
20
|
"adm-zip": "0.5.10",
|
|
@@ -26,6 +27,7 @@
|
|
|
26
27
|
"cors": "2.8.5",
|
|
27
28
|
"csurf": "^1.11.0",
|
|
28
29
|
"csv-stringify": "^5.5.0",
|
|
30
|
+
"dockerode": "~4.0.2",
|
|
29
31
|
"express": "^4.17.1",
|
|
30
32
|
"express-fileupload": "^1.1.8",
|
|
31
33
|
"express-promise-router": "^3.0.3",
|
|
@@ -37,7 +39,6 @@
|
|
|
37
39
|
"i18n": "^0.15.1",
|
|
38
40
|
"imapflow": "1.0.123",
|
|
39
41
|
"jsonwebtoken": "^9.0.0",
|
|
40
|
-
"live-plugin-manager": "^0.17.1",
|
|
41
42
|
"markdown-it": "^13.0.2",
|
|
42
43
|
"moment": "^2.29.4",
|
|
43
44
|
"multer": "1.4.5-lts.1",
|
|
@@ -70,8 +71,8 @@
|
|
|
70
71
|
},
|
|
71
72
|
"repository": "github:saltcorn/saltcorn",
|
|
72
73
|
"devDependencies": {
|
|
73
|
-
"jest": "
|
|
74
|
-
"jest-environment-jsdom": "
|
|
74
|
+
"jest": "^28.1.3",
|
|
75
|
+
"jest-environment-jsdom": "28.1.3",
|
|
75
76
|
"supertest": "^6.3.3"
|
|
76
77
|
},
|
|
77
78
|
"scripts": {
|
|
@@ -84,11 +85,13 @@
|
|
|
84
85
|
"testEnvironment": "node",
|
|
85
86
|
"testPathIgnorePatterns": [
|
|
86
87
|
"/node_modules/",
|
|
87
|
-
"/plugin_packages/"
|
|
88
|
+
"/plugin_packages/",
|
|
89
|
+
"/plugins_folder/"
|
|
88
90
|
],
|
|
89
91
|
"coveragePathIgnorePatterns": [
|
|
90
92
|
"/node_modules/",
|
|
91
|
-
"/plugin_packages/"
|
|
93
|
+
"/plugin_packages/",
|
|
94
|
+
"/plugins_folder/"
|
|
92
95
|
],
|
|
93
96
|
"moduleNameMapper": {
|
|
94
97
|
"@saltcorn/sqlite/(.*)": "<rootDir>/../sqlite/dist/$1",
|
|
@@ -131,7 +131,23 @@ var logViewerHelpers = (() => {
|
|
|
131
131
|
|
|
132
132
|
return {
|
|
133
133
|
init_log_socket: () => {
|
|
134
|
-
|
|
134
|
+
let socket = null;
|
|
135
|
+
setTimeout(() => {
|
|
136
|
+
if (socket === null || socket.disconnected) {
|
|
137
|
+
notifyAlert({
|
|
138
|
+
type: "danger",
|
|
139
|
+
text: "Unable to connect to the server",
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}, 5000);
|
|
143
|
+
try {
|
|
144
|
+
socket = io({ transports: ["websocket"] });
|
|
145
|
+
} catch (e) {
|
|
146
|
+
notifyAlert({
|
|
147
|
+
type: "danger",
|
|
148
|
+
text: "Unable to connect to the server " + e.message,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
135
151
|
startTrackingMsg();
|
|
136
152
|
socket.on("connect", () => handleConnect(socket));
|
|
137
153
|
socket.on("disconnect", handleDisconnect);
|
|
@@ -76,7 +76,7 @@ function valid_js_var_name(s) {
|
|
|
76
76
|
return !!s.match(/^[a-zA-Z_$][a-zA-Z_$0-9]*$/);
|
|
77
77
|
}
|
|
78
78
|
function apply_showif() {
|
|
79
|
-
const isNode =
|
|
79
|
+
const isNode = getIsNode();
|
|
80
80
|
$("[data-show-if]").each(function (ix, element) {
|
|
81
81
|
var e = $(element);
|
|
82
82
|
try {
|
|
@@ -159,10 +159,18 @@ function apply_showif() {
|
|
|
159
159
|
decodeURIComponent(e.attr("data-fetch-options"))
|
|
160
160
|
);
|
|
161
161
|
if (window._sc_loglevel > 4) console.log("dynwhere", dynwhere);
|
|
162
|
-
const kvToQs = ([k, v]) => {
|
|
162
|
+
const kvToQs = ([k, v], is_or) => {
|
|
163
163
|
return k === "or" && Array.isArray(v)
|
|
164
|
-
? v
|
|
165
|
-
|
|
164
|
+
? v
|
|
165
|
+
.map((v1) =>
|
|
166
|
+
Object.entries(v1)
|
|
167
|
+
.map((kv) => kvToQs(kv, true))
|
|
168
|
+
.join("&")
|
|
169
|
+
)
|
|
170
|
+
.join("&")
|
|
171
|
+
: `${k}=${v[0] === "$" ? rec[v.substring(1)] : v}${
|
|
172
|
+
is_or ? "&_or_field=" + k : ""
|
|
173
|
+
}`;
|
|
166
174
|
};
|
|
167
175
|
const qss = Object.entries(dynwhere.whereParsed).map(kvToQs);
|
|
168
176
|
if (dynwhere.dereference) {
|
|
@@ -571,7 +579,7 @@ function reload_on_init() {
|
|
|
571
579
|
}
|
|
572
580
|
function initialize_page() {
|
|
573
581
|
if (window._sc_locale && window.dayjs) dayjs.locale(window._sc_locale);
|
|
574
|
-
const isNode =
|
|
582
|
+
const isNode = getIsNode();
|
|
575
583
|
//console.log("init page");
|
|
576
584
|
$(".blur-on-enter-keypress").bind("keyup", function (e) {
|
|
577
585
|
if (e.keyCode === 13) e.target.blur();
|
|
@@ -743,23 +751,58 @@ function initialize_page() {
|
|
|
743
751
|
</form>`
|
|
744
752
|
);
|
|
745
753
|
});
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
this.src = base64Encoded;
|
|
751
|
-
}
|
|
752
|
-
});
|
|
753
|
-
$("[mobile-bg-img-path]").each(async function () {
|
|
754
|
-
if (parent.loadEncodedFile) {
|
|
755
|
-
const fileId = $(this).attr("mobile-bg-img-path");
|
|
756
|
-
if (fileId) {
|
|
754
|
+
if (!isNode) {
|
|
755
|
+
$("[mobile-img-path]").each(async function () {
|
|
756
|
+
if (parent.loadEncodedFile) {
|
|
757
|
+
const fileId = $(this).attr("mobile-img-path");
|
|
757
758
|
const base64Encoded = await parent.loadEncodedFile(fileId);
|
|
758
|
-
this.
|
|
759
|
+
this.src = base64Encoded;
|
|
759
760
|
}
|
|
760
|
-
}
|
|
761
|
-
});
|
|
761
|
+
});
|
|
762
762
|
|
|
763
|
+
$("[mobile-bg-img-path]").each(async function () {
|
|
764
|
+
if (parent.loadEncodedFile) {
|
|
765
|
+
const fileId = $(this).attr("mobile-bg-img-path");
|
|
766
|
+
if (fileId) {
|
|
767
|
+
const base64Encoded = await parent.loadEncodedFile(fileId);
|
|
768
|
+
this.style.backgroundImage = `url("${base64Encoded}")`;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
$("a").each(function () {
|
|
774
|
+
let path = $(this).attr("href") || "";
|
|
775
|
+
if (path.startsWith("http")) {
|
|
776
|
+
const url = new URL(path);
|
|
777
|
+
path = `${url.pathname}${url.search}`;
|
|
778
|
+
}
|
|
779
|
+
if (path.startsWith("/view/")) {
|
|
780
|
+
const jThis = $(this);
|
|
781
|
+
const skip = jThis.attr("skip-mobile-adjust");
|
|
782
|
+
if (!skip) {
|
|
783
|
+
jThis.attr("href", `javascript:execLink('${path}')`);
|
|
784
|
+
if (jThis.find("i,img").length === 0 && !jThis.css("color")) {
|
|
785
|
+
jThis.css(
|
|
786
|
+
"color",
|
|
787
|
+
"rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1))"
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
$("img").each(async function () {
|
|
795
|
+
if (parent.loadEncodedFile) {
|
|
796
|
+
const jThis = $(this);
|
|
797
|
+
const src = jThis.attr("src");
|
|
798
|
+
if (src?.startsWith("/files/serve/")) {
|
|
799
|
+
const fileId = src.replace("/files/serve/", "");
|
|
800
|
+
const base64Encoded = await parent.loadEncodedFile(fileId);
|
|
801
|
+
this.src = base64Encoded;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
}
|
|
763
806
|
function setExplainer(that) {
|
|
764
807
|
var id = $(that).attr("id") + "_explainer";
|
|
765
808
|
|
|
@@ -877,7 +920,7 @@ function initialize_page() {
|
|
|
877
920
|
$(initialize_page);
|
|
878
921
|
|
|
879
922
|
function cancel_inline_edit(e, opts1) {
|
|
880
|
-
const isNode =
|
|
923
|
+
const isNode = getIsNode();
|
|
881
924
|
var opts = JSON.parse(decodeURIComponent(opts1 || "") || "{}");
|
|
882
925
|
var form = $(e.target).closest("form");
|
|
883
926
|
form.replaceWith(opts.resetHtml);
|
|
@@ -885,7 +928,7 @@ function cancel_inline_edit(e, opts1) {
|
|
|
885
928
|
}
|
|
886
929
|
|
|
887
930
|
function inline_submit_success(e, form, opts) {
|
|
888
|
-
const isNode =
|
|
931
|
+
const isNode = getIsNode();
|
|
889
932
|
const formDataArray = form.serializeArray();
|
|
890
933
|
if (opts) {
|
|
891
934
|
let fdEntry = formDataArray.find((f) => f.name == opts.key);
|
|
@@ -1025,6 +1068,15 @@ function tristateClick(e, required) {
|
|
|
1025
1068
|
}
|
|
1026
1069
|
}
|
|
1027
1070
|
|
|
1071
|
+
function getIsNode() {
|
|
1072
|
+
try {
|
|
1073
|
+
return typeof parent?.saltcorn?.data?.state === "undefined";
|
|
1074
|
+
} catch (e) {
|
|
1075
|
+
//probably in an iframe
|
|
1076
|
+
return true;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1028
1080
|
function buildToast(txt, type, spin) {
|
|
1029
1081
|
const realtype = type === "error" ? "danger" : type;
|
|
1030
1082
|
const icon =
|
|
@@ -1035,7 +1087,7 @@ function buildToast(txt, type, spin) {
|
|
|
1035
1087
|
: realtype === "warning"
|
|
1036
1088
|
? "fa-exclamation-triangle"
|
|
1037
1089
|
: "";
|
|
1038
|
-
const isNode =
|
|
1090
|
+
const isNode = getIsNode();
|
|
1039
1091
|
const rndid = `tab${Math.floor(Math.random() * 16777215).toString(16)}`;
|
|
1040
1092
|
return {
|
|
1041
1093
|
id: rndid,
|
|
@@ -1167,8 +1219,10 @@ async function common_done(res, viewname, isWeb = true) {
|
|
|
1167
1219
|
await handle(res.notify_success, (text) =>
|
|
1168
1220
|
notifyAlert({ type: "success", text: text })
|
|
1169
1221
|
);
|
|
1170
|
-
if (res.set_fields && viewname) {
|
|
1171
|
-
const form = $(
|
|
1222
|
+
if (res.set_fields && (viewname || res.set_fields._viewname)) {
|
|
1223
|
+
const form = $(
|
|
1224
|
+
`form[data-viewname="${res.set_fields._viewname || viewname}"]`
|
|
1225
|
+
);
|
|
1172
1226
|
if (form.length === 0 && set_state_fields) {
|
|
1173
1227
|
// assume this is a filter
|
|
1174
1228
|
set_state_fields(
|
|
@@ -1178,6 +1232,7 @@ async function common_done(res, viewname, isWeb = true) {
|
|
|
1178
1232
|
);
|
|
1179
1233
|
} else {
|
|
1180
1234
|
Object.keys(res.set_fields).forEach((k) => {
|
|
1235
|
+
if (k === "_viewname") return;
|
|
1181
1236
|
const input = form.find(
|
|
1182
1237
|
`input[name=${k}], textarea[name=${k}], select[name=${k}]`
|
|
1183
1238
|
);
|
|
@@ -1186,6 +1241,7 @@ async function common_done(res, viewname, isWeb = true) {
|
|
|
1186
1241
|
form.append(
|
|
1187
1242
|
`<input type="hidden" name="id" value="${res.set_fields[k]}">`
|
|
1188
1243
|
);
|
|
1244
|
+
reloadEmbeddedEditOwnViews(form, res.set_fields[k]);
|
|
1189
1245
|
return;
|
|
1190
1246
|
}
|
|
1191
1247
|
if (input.attr("type") === "checkbox")
|
|
@@ -1250,6 +1306,28 @@ async function common_done(res, viewname, isWeb = true) {
|
|
|
1250
1306
|
}
|
|
1251
1307
|
}
|
|
1252
1308
|
|
|
1309
|
+
function reloadEmbeddedEditOwnViews(form, id) {
|
|
1310
|
+
form.find("div[sc-load-on-assign-id]").each(function () {
|
|
1311
|
+
const $e = $(this);
|
|
1312
|
+
const viewname = $e.attr("sc-load-on-assign-id");
|
|
1313
|
+
const newUrl = `/view/${viewname}?id=${id}`;
|
|
1314
|
+
$.ajax(newUrl, {
|
|
1315
|
+
headers: {
|
|
1316
|
+
pjaxpageload: "true",
|
|
1317
|
+
localizedstate: "true", //no admin bar
|
|
1318
|
+
},
|
|
1319
|
+
success: function (res, textStatus, request) {
|
|
1320
|
+
const newE = `<div class="d-inline" data-sc-embed-viewname="${viewname}" data-sc-view-source="${newUrl}">${res}</div>`;
|
|
1321
|
+
$e.replaceWith(newE);
|
|
1322
|
+
initialize_page();
|
|
1323
|
+
},
|
|
1324
|
+
error: function (res) {
|
|
1325
|
+
notifyAlert({ type: "danger", text: res.responseText });
|
|
1326
|
+
},
|
|
1327
|
+
});
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1253
1331
|
const repeaterCopyValuesToForm = (form, editor, noTriggerChange) => {
|
|
1254
1332
|
const vs = JSON.parse(editor.getString());
|
|
1255
1333
|
|
|
@@ -1542,3 +1620,55 @@ function set_readonly_select(e) {
|
|
|
1542
1620
|
const option = options.find((o) => o.value == e.target.value);
|
|
1543
1621
|
if (option) $disp.val(option.label);
|
|
1544
1622
|
}
|
|
1623
|
+
|
|
1624
|
+
function close_saltcorn_modal() {
|
|
1625
|
+
$("#scmodal").off("hidden.bs.modal");
|
|
1626
|
+
var myModalEl = document.getElementById("scmodal");
|
|
1627
|
+
if (!myModalEl) return;
|
|
1628
|
+
var modal = bootstrap.Modal.getInstance(myModalEl);
|
|
1629
|
+
if (modal) {
|
|
1630
|
+
if (modal.hide) modal.hide();
|
|
1631
|
+
if (modal.dispose) modal.dispose();
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
function reload_embedded_view(viewname, new_query_string) {
|
|
1636
|
+
const isNode = getIsNode();
|
|
1637
|
+
const updater = ($e, res) => {
|
|
1638
|
+
$e.html(res);
|
|
1639
|
+
initialize_page();
|
|
1640
|
+
};
|
|
1641
|
+
if (window._sc_loglevel > 4)
|
|
1642
|
+
console.log(
|
|
1643
|
+
"reload_embedded_view",
|
|
1644
|
+
viewname,
|
|
1645
|
+
"found",
|
|
1646
|
+
$(`[data-sc-embed-viewname="${viewname}"]`).length
|
|
1647
|
+
);
|
|
1648
|
+
$(`[data-sc-embed-viewname="${viewname}"]`).each(function () {
|
|
1649
|
+
const $e = $(this);
|
|
1650
|
+
let url = $e.attr("data-sc-local-state") || $e.attr("data-sc-view-source");
|
|
1651
|
+
if (!url) return;
|
|
1652
|
+
if (new_query_string) {
|
|
1653
|
+
url = url.split("?")[0] + "?" + new_query_string;
|
|
1654
|
+
}
|
|
1655
|
+
if (isNode) {
|
|
1656
|
+
$.ajax(url, {
|
|
1657
|
+
headers: {
|
|
1658
|
+
pjaxpageload: "true",
|
|
1659
|
+
localizedstate: "true", //no admin bar
|
|
1660
|
+
},
|
|
1661
|
+
success: function (res, textStatus, request) {
|
|
1662
|
+
updater($e, res);
|
|
1663
|
+
},
|
|
1664
|
+
error: function (res) {
|
|
1665
|
+
notifyAlert({ type: "danger", text: res.responseText });
|
|
1666
|
+
},
|
|
1667
|
+
});
|
|
1668
|
+
} else {
|
|
1669
|
+
runUrl(url).then((html) => {
|
|
1670
|
+
updater($e, html);
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
});
|
|
1674
|
+
}
|
package/public/saltcorn.css
CHANGED
package/public/saltcorn.js
CHANGED
|
@@ -154,37 +154,6 @@ $(function () {
|
|
|
154
154
|
});
|
|
155
155
|
});
|
|
156
156
|
|
|
157
|
-
function reload_embedded_view(viewname, new_query_string) {
|
|
158
|
-
if (window._sc_loglevel > 4)
|
|
159
|
-
console.log(
|
|
160
|
-
"reload_embedded_view",
|
|
161
|
-
viewname,
|
|
162
|
-
"found",
|
|
163
|
-
$(`[data-sc-embed-viewname="${viewname}"]`).length
|
|
164
|
-
);
|
|
165
|
-
$(`[data-sc-embed-viewname="${viewname}"]`).each(function () {
|
|
166
|
-
const $e = $(this);
|
|
167
|
-
let url = $e.attr("data-sc-local-state") || $e.attr("data-sc-view-source");
|
|
168
|
-
if (!url) return;
|
|
169
|
-
if (new_query_string) {
|
|
170
|
-
url = url.split("?")[0] + "?" + new_query_string;
|
|
171
|
-
}
|
|
172
|
-
$.ajax(url, {
|
|
173
|
-
headers: {
|
|
174
|
-
pjaxpageload: "true",
|
|
175
|
-
localizedstate: "true", //no admin bar
|
|
176
|
-
},
|
|
177
|
-
success: function (res, textStatus, request) {
|
|
178
|
-
$e.html(res);
|
|
179
|
-
initialize_page();
|
|
180
|
-
},
|
|
181
|
-
error: function (res) {
|
|
182
|
-
notifyAlert({ type: "danger", text: res.responseText });
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
|
|
188
157
|
function pjax_to(href, e) {
|
|
189
158
|
let $modal = $("#scmodal");
|
|
190
159
|
const inModal = $modal.length && $modal.hasClass("show");
|
|
@@ -323,17 +292,6 @@ function globalErrorCatcher(message, source, lineno, colno, error) {
|
|
|
323
292
|
});
|
|
324
293
|
}
|
|
325
294
|
|
|
326
|
-
function close_saltcorn_modal() {
|
|
327
|
-
$("#scmodal").off("hidden.bs.modal");
|
|
328
|
-
var myModalEl = document.getElementById("scmodal");
|
|
329
|
-
if (!myModalEl) return;
|
|
330
|
-
var modal = bootstrap.Modal.getInstance(myModalEl);
|
|
331
|
-
if (modal) {
|
|
332
|
-
if (modal.hide) modal.hide();
|
|
333
|
-
if (modal.dispose) modal.dispose();
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
295
|
function ensure_modal_exists_and_closed() {
|
|
338
296
|
if ($("#scmodal").length === 0) {
|
|
339
297
|
$("body").append(`<div id="scmodal" class="modal">
|
|
@@ -450,7 +408,14 @@ function saveAndContinueAsync(e) {
|
|
|
450
408
|
});
|
|
451
409
|
}
|
|
452
410
|
|
|
453
|
-
function saveAndContinue(e, k) {
|
|
411
|
+
function saveAndContinue(e, k, event) {
|
|
412
|
+
if (
|
|
413
|
+
event &&
|
|
414
|
+
event.target &&
|
|
415
|
+
event.target.classList &&
|
|
416
|
+
event.target.classList.contains("no-form-change")
|
|
417
|
+
)
|
|
418
|
+
return;
|
|
454
419
|
var form = $(e).closest("form");
|
|
455
420
|
const valres = form[0].reportValidity();
|
|
456
421
|
if (!valres) return;
|
|
@@ -471,6 +436,7 @@ function saveAndContinue(e, k) {
|
|
|
471
436
|
form.append(
|
|
472
437
|
`<input type="hidden" class="form-control " name="id" value="${res.id}">`
|
|
473
438
|
);
|
|
439
|
+
reloadEmbeddedEditOwnViews(form, res.id);
|
|
474
440
|
}
|
|
475
441
|
common_done(res, form.attr("data-viewname"));
|
|
476
442
|
},
|
|
@@ -515,6 +481,7 @@ function applyViewConfig(e, url, k, event) {
|
|
|
515
481
|
cfg[item.name] = item.value;
|
|
516
482
|
});
|
|
517
483
|
ajax_indicator(true, e);
|
|
484
|
+
window.savingViewConfig = true;
|
|
518
485
|
$.ajax(url, {
|
|
519
486
|
type: "POST",
|
|
520
487
|
dataType: "json",
|
|
@@ -524,9 +491,11 @@ function applyViewConfig(e, url, k, event) {
|
|
|
524
491
|
},
|
|
525
492
|
data: JSON.stringify(cfg),
|
|
526
493
|
error: function (request) {
|
|
494
|
+
window.savingViewConfig = false;
|
|
527
495
|
ajax_indicate_error(e, request);
|
|
528
496
|
},
|
|
529
497
|
success: function (res) {
|
|
498
|
+
window.savingViewConfig = false;
|
|
530
499
|
ajax_indicator(false);
|
|
531
500
|
k && k(res);
|
|
532
501
|
!k && updateViewPreview();
|
|
@@ -549,10 +518,12 @@ function updateViewPreview() {
|
|
|
549
518
|
},
|
|
550
519
|
|
|
551
520
|
error: function (resp) {
|
|
552
|
-
$("#viewcfg-preview-error")
|
|
521
|
+
$("#viewcfg-preview-error")
|
|
522
|
+
.show()
|
|
523
|
+
.html(resp.responseText || resp.statusText);
|
|
553
524
|
},
|
|
554
525
|
success: function (res) {
|
|
555
|
-
$("#viewcfg-preview-error").html("");
|
|
526
|
+
$("#viewcfg-preview-error").hide().html("");
|
|
556
527
|
$preview.css({ opacity: 1.0 });
|
|
557
528
|
|
|
558
529
|
//disable functions preview migght try to call
|
|
@@ -821,6 +792,17 @@ function build_mobile_app(button) {
|
|
|
821
792
|
params.includedPlugins = Array.from(pluginsSelect.options)
|
|
822
793
|
.filter((option) => !option.hidden)
|
|
823
794
|
.map((option) => option.value);
|
|
795
|
+
|
|
796
|
+
if (
|
|
797
|
+
params.useDocker &&
|
|
798
|
+
!cordovaBuilderAvailable &&
|
|
799
|
+
!confirm(
|
|
800
|
+
"Docker is selected but the Cordova builder seems not to be installed. " +
|
|
801
|
+
"Do you really want to continue?"
|
|
802
|
+
)
|
|
803
|
+
) {
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
824
806
|
ajax_post("/admin/build-mobile-app", {
|
|
825
807
|
data: params,
|
|
826
808
|
success: (data) => {
|
|
@@ -834,6 +816,41 @@ function build_mobile_app(button) {
|
|
|
834
816
|
});
|
|
835
817
|
}
|
|
836
818
|
|
|
819
|
+
function pull_cordova_builder() {
|
|
820
|
+
ajax_post("/admin/mobile-app/pull-cordova-builder", {
|
|
821
|
+
success: () => {
|
|
822
|
+
notifyAlert(
|
|
823
|
+
"Pulling the the cordova-builder. " +
|
|
824
|
+
"To see the progress, open the logs viewer with the System logging verbosity set to 'All'."
|
|
825
|
+
);
|
|
826
|
+
},
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
function check_cordova_builder() {
|
|
831
|
+
$.ajax("/admin/mobile-app/check-cordova-builder", {
|
|
832
|
+
type: "GET",
|
|
833
|
+
success: function (res) {
|
|
834
|
+
cordovaBuilderAvailable = !!res.installed;
|
|
835
|
+
if (cordovaBuilderAvailable) {
|
|
836
|
+
$("#dockerBuilderStatusId").html(
|
|
837
|
+
`<span>
|
|
838
|
+
installed<i class="ps-2 fas fa-check text-success"></i>
|
|
839
|
+
</span>
|
|
840
|
+
`
|
|
841
|
+
);
|
|
842
|
+
} else {
|
|
843
|
+
$("#dockerBuilderStatusId").html(
|
|
844
|
+
`<span>
|
|
845
|
+
not available<i class="ps-2 fas fa-times text-danger"></i>
|
|
846
|
+
</span>
|
|
847
|
+
`
|
|
848
|
+
);
|
|
849
|
+
}
|
|
850
|
+
},
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
|
|
837
854
|
function move_to_synched() {
|
|
838
855
|
const opts = $("#unsynched-tbls-select-id");
|
|
839
856
|
$("#synched-tbls-select-id").removeAttr("selected");
|
|
@@ -897,7 +914,7 @@ function toggle_tbl_sync() {
|
|
|
897
914
|
function toggle_android_platform() {
|
|
898
915
|
if ($("#androidCheckboxId")[0].checked === true) {
|
|
899
916
|
$("#dockerCheckboxId").attr("hidden", false);
|
|
900
|
-
$("#dockerCheckboxId").attr("checked",
|
|
917
|
+
$("#dockerCheckboxId").attr("checked", cordovaBuilderAvailable);
|
|
901
918
|
$("#dockerLabelId").removeClass("d-none");
|
|
902
919
|
} else {
|
|
903
920
|
$("#dockerCheckboxId").attr("hidden", true);
|
|
@@ -916,6 +933,10 @@ function join_field_clicked(e, fieldPath) {
|
|
|
916
933
|
apply_showif();
|
|
917
934
|
}
|
|
918
935
|
|
|
936
|
+
function execLink(path) {
|
|
937
|
+
window.location.href = `${location.origin}${path}`;
|
|
938
|
+
}
|
|
939
|
+
|
|
919
940
|
(() => {
|
|
920
941
|
const e = document.querySelector("[data-sidebar-toggler]");
|
|
921
942
|
let closed = localStorage.getItem("sidebarClosed") === "true";
|
package/restart_watcher.js
CHANGED
|
@@ -16,6 +16,7 @@ const { eachTenant } = require("@saltcorn/admin-models/models/tenant");
|
|
|
16
16
|
const relevantPackages = [
|
|
17
17
|
"db-common",
|
|
18
18
|
"common-code",
|
|
19
|
+
"plugins-loader",
|
|
19
20
|
"postgres",
|
|
20
21
|
"saltcorn-data",
|
|
21
22
|
"saltcorn-builder",
|
|
@@ -37,6 +38,7 @@ const excludePatterns = [
|
|
|
37
38
|
/\.docs/,
|
|
38
39
|
/migrations/,
|
|
39
40
|
/.*test.js/,
|
|
41
|
+
/.*test.ts/,
|
|
40
42
|
];
|
|
41
43
|
|
|
42
44
|
/**
|
package/routes/actions.js
CHANGED
|
@@ -307,6 +307,14 @@ const triggerForm = async (req, trigger) => {
|
|
|
307
307
|
showIf: { when_trigger: ["API call"] },
|
|
308
308
|
options: roleOptions,
|
|
309
309
|
},
|
|
310
|
+
{
|
|
311
|
+
name: "_raw_output",
|
|
312
|
+
label: "Raw Output",
|
|
313
|
+
parent_field: "configuration",
|
|
314
|
+
sublabel: req.__("Do not wrap response in a success object"),
|
|
315
|
+
type: "Bool",
|
|
316
|
+
showIf: { when_trigger: ["API call"] },
|
|
317
|
+
},
|
|
310
318
|
],
|
|
311
319
|
});
|
|
312
320
|
// if (trigger) {
|
|
@@ -450,6 +458,11 @@ router.post(
|
|
|
450
458
|
},
|
|
451
459
|
});
|
|
452
460
|
} else {
|
|
461
|
+
if (form.values.configuration)
|
|
462
|
+
form.values.configuration = {
|
|
463
|
+
...trigger.configuration,
|
|
464
|
+
...form.values.configuration,
|
|
465
|
+
};
|
|
453
466
|
await Trigger.update(trigger.id, form.values); //{configuration: form.values});
|
|
454
467
|
req.flash("success", req.__("Action information saved"));
|
|
455
468
|
res.redirect(`/actions/`);
|
|
@@ -662,6 +675,7 @@ router.get(
|
|
|
662
675
|
onChange: "saveAndContinue(this)",
|
|
663
676
|
submitLabel: req.__("Done"),
|
|
664
677
|
fields: cfgFields,
|
|
678
|
+
...(action.configFormOptions || {}),
|
|
665
679
|
});
|
|
666
680
|
// populate form values
|
|
667
681
|
form.values = trigger.configuration;
|
|
@@ -729,7 +743,9 @@ router.post(
|
|
|
729
743
|
},
|
|
730
744
|
});
|
|
731
745
|
} else {
|
|
732
|
-
await Trigger.update(trigger.id, {
|
|
746
|
+
await Trigger.update(trigger.id, {
|
|
747
|
+
configuration: { ...trigger.configuration, ...form.values },
|
|
748
|
+
});
|
|
733
749
|
if (req.xhr) {
|
|
734
750
|
res.json({ success: "ok" });
|
|
735
751
|
return;
|