@saltcorn/server 1.0.0-beta.17 → 1.0.0-beta.19
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/help/Aggregation where formula.tmd +11 -0
- package/help/Calculated fields.tmd +28 -0
- package/help/Protected fields.tmd +4 -0
- package/help/Snapshots.tmd +19 -0
- package/help/Table history.tmd +42 -0
- package/load_plugins.js +9 -1
- package/locales/en.json +4 -2
- package/locales/pl.json +407 -85
- package/package.json +9 -9
- package/public/saltcorn-common.js +42 -0
- package/public/saltcorn.css +17 -0
- package/public/saltcorn.js +1 -0
- package/routes/admin.js +67 -5
- package/routes/fields.js +9 -0
- package/routes/plugins.js +8 -6
- package/routes/tables.js +4 -1
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.19",
|
|
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": "1.0.0-beta.
|
|
11
|
-
"@saltcorn/builder": "1.0.0-beta.
|
|
12
|
-
"@saltcorn/data": "1.0.0-beta.
|
|
13
|
-
"@saltcorn/admin-models": "1.0.0-beta.
|
|
14
|
-
"@saltcorn/filemanager": "1.0.0-beta.
|
|
15
|
-
"@saltcorn/markup": "1.0.0-beta.
|
|
16
|
-
"@saltcorn/plugins-loader": "1.0.0-beta.
|
|
17
|
-
"@saltcorn/sbadmin2": "1.0.0-beta.
|
|
10
|
+
"@saltcorn/base-plugin": "1.0.0-beta.19",
|
|
11
|
+
"@saltcorn/builder": "1.0.0-beta.19",
|
|
12
|
+
"@saltcorn/data": "1.0.0-beta.19",
|
|
13
|
+
"@saltcorn/admin-models": "1.0.0-beta.19",
|
|
14
|
+
"@saltcorn/filemanager": "1.0.0-beta.19",
|
|
15
|
+
"@saltcorn/markup": "1.0.0-beta.19",
|
|
16
|
+
"@saltcorn/plugins-loader": "1.0.0-beta.19",
|
|
17
|
+
"@saltcorn/sbadmin2": "1.0.0-beta.19",
|
|
18
18
|
"@socket.io/cluster-adapter": "^0.2.1",
|
|
19
19
|
"@socket.io/sticky": "^1.0.1",
|
|
20
20
|
"adm-zip": "0.5.10",
|
|
@@ -764,6 +764,42 @@ function doMobileTransforms() {
|
|
|
764
764
|
}
|
|
765
765
|
});
|
|
766
766
|
|
|
767
|
+
$("[mobile-youtube-video]").each(function () {
|
|
768
|
+
const jThis = $(this);
|
|
769
|
+
const src = jThis.attr("src");
|
|
770
|
+
if (src) {
|
|
771
|
+
const rndid = `m-video-${Math.floor(Math.random() * 16777215).toString(
|
|
772
|
+
16
|
|
773
|
+
)}`;
|
|
774
|
+
const url = new URL(src);
|
|
775
|
+
const path = url.pathname;
|
|
776
|
+
const imageId = path.split("/").pop();
|
|
777
|
+
const thumbnailContainer = document.createElement("div");
|
|
778
|
+
thumbnailContainer.className = "mobile-thumbnail-container";
|
|
779
|
+
thumbnailContainer.id = rndid;
|
|
780
|
+
const img = document.createElement("img");
|
|
781
|
+
img.src = `https://img.youtube.com/vi/${imageId}/0.jpg`;
|
|
782
|
+
img.style = "width: 100%; max-width: 600px;";
|
|
783
|
+
img.id = rndid;
|
|
784
|
+
img.setAttribute(
|
|
785
|
+
"onclick",
|
|
786
|
+
`openInAppBrowser('${src.replace(
|
|
787
|
+
"com/embed",
|
|
788
|
+
"com/watch"
|
|
789
|
+
)}', '${rndid}')`
|
|
790
|
+
);
|
|
791
|
+
thumbnailContainer.appendChild(img);
|
|
792
|
+
const spinner = document.createElement("div");
|
|
793
|
+
spinner.className = "mobile-thumbnail-spinner-overlay";
|
|
794
|
+
const spinnerInner = document.createElement("div");
|
|
795
|
+
spinnerInner.className = "d-none spinner-border text-light";
|
|
796
|
+
spinnerInner.setAttribute("role", "status");
|
|
797
|
+
spinner.appendChild(spinnerInner);
|
|
798
|
+
thumbnailContainer.appendChild(spinner);
|
|
799
|
+
jThis.replaceWith(thumbnailContainer);
|
|
800
|
+
}
|
|
801
|
+
});
|
|
802
|
+
|
|
767
803
|
$("button").each(function () {
|
|
768
804
|
for (const [k, v] of Object.entries({ onclick: replacers.onclick })) {
|
|
769
805
|
for ({ web, mobile } of v) replaceAttr(this, k, v.web, v.mobile);
|
|
@@ -1870,6 +1906,8 @@ function close_saltcorn_modal() {
|
|
|
1870
1906
|
}
|
|
1871
1907
|
}
|
|
1872
1908
|
|
|
1909
|
+
let _sc_currently_reloading;
|
|
1910
|
+
|
|
1873
1911
|
function reload_embedded_view(viewname, new_query_string) {
|
|
1874
1912
|
const isNode = getIsNode();
|
|
1875
1913
|
const updater = ($e, res) => {
|
|
@@ -1897,15 +1935,19 @@ function reload_embedded_view(viewname, new_query_string) {
|
|
|
1897
1935
|
url = url.split("?")[0] + "?" + new_query_string;
|
|
1898
1936
|
}
|
|
1899
1937
|
if (isNode) {
|
|
1938
|
+
if (url === _sc_currently_reloading) return;
|
|
1939
|
+
_sc_currently_reloading = url;
|
|
1900
1940
|
$.ajax(url, {
|
|
1901
1941
|
headers: {
|
|
1902
1942
|
pjaxpageload: "true",
|
|
1903
1943
|
localizedstate: "true", //no admin bar
|
|
1904
1944
|
},
|
|
1905
1945
|
success: function (res, textStatus, request) {
|
|
1946
|
+
_sc_currently_reloading = null;
|
|
1906
1947
|
updater($e, res);
|
|
1907
1948
|
},
|
|
1908
1949
|
error: function (res) {
|
|
1950
|
+
_sc_currently_reloading = null;
|
|
1909
1951
|
if (!checkNetworkError(res))
|
|
1910
1952
|
notifyAlert({ type: "danger", text: res.responseText });
|
|
1911
1953
|
},
|
package/public/saltcorn.css
CHANGED
|
@@ -590,3 +590,20 @@ button.monospace-copy-btn {
|
|
|
590
590
|
.custom-file-label {
|
|
591
591
|
margin-left: 10px;
|
|
592
592
|
}
|
|
593
|
+
|
|
594
|
+
.mobile-thumbnail-container {
|
|
595
|
+
position: relative;
|
|
596
|
+
display: inline-block;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
.mobile-thumbnail-spinner-overlay {
|
|
600
|
+
position: absolute;
|
|
601
|
+
top: 50%;
|
|
602
|
+
left: 50%;
|
|
603
|
+
transform: translate(-50%, -50%);
|
|
604
|
+
z-index: 10;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
.mobile-thumbnail-container img {
|
|
608
|
+
display: block;
|
|
609
|
+
}
|
package/public/saltcorn.js
CHANGED
package/routes/admin.js
CHANGED
|
@@ -378,7 +378,9 @@ router.get(
|
|
|
378
378
|
: { type: "blank", contents: "" },
|
|
379
379
|
{
|
|
380
380
|
type: "card",
|
|
381
|
-
title:
|
|
381
|
+
title:
|
|
382
|
+
req.__("Snapshots") +
|
|
383
|
+
`<a href="javascript:ajax_modal('/admin/help/Snapshots?')"><i class="fas fa-question-circle ms-1"></i></a>`,
|
|
382
384
|
titleAjaxIndicator: true,
|
|
383
385
|
contents: div(
|
|
384
386
|
p(
|
|
@@ -1266,6 +1268,50 @@ const pullCordovaBuilder = (req, res) => {
|
|
|
1266
1268
|
});
|
|
1267
1269
|
};
|
|
1268
1270
|
|
|
1271
|
+
const tryInstallSdNotify = (req, res) => {
|
|
1272
|
+
const child = spawn("npm", ["install", "-g", "sd-notify"], {
|
|
1273
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1274
|
+
});
|
|
1275
|
+
return new Promise((resolve, reject) => {
|
|
1276
|
+
child.stdout.on("data", (data) => {
|
|
1277
|
+
res.write(data);
|
|
1278
|
+
});
|
|
1279
|
+
child.stderr?.on("data", (data) => {
|
|
1280
|
+
res.write(data);
|
|
1281
|
+
});
|
|
1282
|
+
child.on("exit", function (code, signal) {
|
|
1283
|
+
resolve(code);
|
|
1284
|
+
});
|
|
1285
|
+
child.on("error", (msg) => {
|
|
1286
|
+
const message = msg.message ? msg.message : msg.code;
|
|
1287
|
+
res.write(req.__("Error: ") + message + "\n");
|
|
1288
|
+
resolve(msg.code);
|
|
1289
|
+
});
|
|
1290
|
+
});
|
|
1291
|
+
};
|
|
1292
|
+
|
|
1293
|
+
const pruneDocker = (req, res) => {
|
|
1294
|
+
const child = spawn("docker", ["image", "prune", "-f"], {
|
|
1295
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1296
|
+
});
|
|
1297
|
+
return new Promise((resolve, reject) => {
|
|
1298
|
+
child.stdout.on("data", (data) => {
|
|
1299
|
+
res.write(data);
|
|
1300
|
+
});
|
|
1301
|
+
child.stderr?.on("data", (data) => {
|
|
1302
|
+
res.write(data);
|
|
1303
|
+
});
|
|
1304
|
+
child.on("exit", function (code, signal) {
|
|
1305
|
+
resolve(code);
|
|
1306
|
+
});
|
|
1307
|
+
child.on("error", (msg) => {
|
|
1308
|
+
const message = msg.message ? msg.message : msg.code;
|
|
1309
|
+
res.write(req.__("Error: ") + message + "\n");
|
|
1310
|
+
resolve(msg.code);
|
|
1311
|
+
});
|
|
1312
|
+
});
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1269
1315
|
/*
|
|
1270
1316
|
* fetch available saltcorn versions and show a dialog to select one
|
|
1271
1317
|
*/
|
|
@@ -1449,10 +1495,26 @@ const doInstall = async (req, res, version, deepClean, runPull) => {
|
|
|
1449
1495
|
res.write(data);
|
|
1450
1496
|
});
|
|
1451
1497
|
child.on("exit", async function (code, signal) {
|
|
1452
|
-
if (code === 0
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1498
|
+
if (code === 0) {
|
|
1499
|
+
if (deepClean) {
|
|
1500
|
+
res.write(req.__("Installing sd-notify") + "\n");
|
|
1501
|
+
const sdNotifyCode = await tryInstallSdNotify(req, res);
|
|
1502
|
+
res.write(
|
|
1503
|
+
req.__("sd-notify install done with code %s", sdNotifyCode) + "\n"
|
|
1504
|
+
);
|
|
1505
|
+
}
|
|
1506
|
+
if (runPull) {
|
|
1507
|
+
res.write(
|
|
1508
|
+
req.__("Pulling the cordova-builder docker image...") + "\n"
|
|
1509
|
+
);
|
|
1510
|
+
const pullCode = await pullCordovaBuilder(req, res);
|
|
1511
|
+
res.write(req.__("Pull done with code %s", pullCode) + "\n");
|
|
1512
|
+
if (pullCode === 0) {
|
|
1513
|
+
res.write(req.__("Pruning docker...") + "\n");
|
|
1514
|
+
const pruneCode = await pruneDocker(req, res);
|
|
1515
|
+
res.write(req.__("Prune done with code %s", pruneCode) + "\n");
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1456
1518
|
}
|
|
1457
1519
|
res.end(
|
|
1458
1520
|
version === "latest"
|
package/routes/fields.js
CHANGED
|
@@ -136,6 +136,9 @@ const fieldForm = async (req, fkey_opts, existing_names, id, hasData) => {
|
|
|
136
136
|
sublabel: req.__("Calculated from other fields with a formula"),
|
|
137
137
|
type: "Bool",
|
|
138
138
|
disabled: !!id,
|
|
139
|
+
help: {
|
|
140
|
+
topic: "Calculated fields",
|
|
141
|
+
},
|
|
139
142
|
}),
|
|
140
143
|
new Field({
|
|
141
144
|
label: req.__("Required"),
|
|
@@ -169,6 +172,9 @@ const fieldForm = async (req, fkey_opts, existing_names, id, hasData) => {
|
|
|
169
172
|
type: "Bool",
|
|
170
173
|
disabled: !!id,
|
|
171
174
|
showIf: { calculated: true },
|
|
175
|
+
help: {
|
|
176
|
+
topic: "Calculated fields",
|
|
177
|
+
},
|
|
172
178
|
}),
|
|
173
179
|
new Field({
|
|
174
180
|
label: req.__("Protected"),
|
|
@@ -176,6 +182,9 @@ const fieldForm = async (req, fkey_opts, existing_names, id, hasData) => {
|
|
|
176
182
|
sublabel: req.__("Set role to access"),
|
|
177
183
|
type: "Bool",
|
|
178
184
|
showIf: { calculated: false },
|
|
185
|
+
help: {
|
|
186
|
+
topic: "Protected fields",
|
|
187
|
+
},
|
|
179
188
|
}),
|
|
180
189
|
{
|
|
181
190
|
label: req.__("Minimum role to write"),
|
package/routes/plugins.js
CHANGED
|
@@ -1235,14 +1235,16 @@ router.get(
|
|
|
1235
1235
|
let latest =
|
|
1236
1236
|
update_permitted &&
|
|
1237
1237
|
(await get_latest_npm_version(plugin_db.location, 1000));
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1238
|
+
let engineInfos = await load_plugins.getEngineInfos(plugin_db); // with cache
|
|
1239
|
+
let forceFetch = true;
|
|
1240
|
+
if (latest && !engineInfos[latest]) {
|
|
1241
|
+
engineInfos = await load_plugins.getEngineInfos(plugin_db, forceFetch);
|
|
1242
|
+
forceFetch = false;
|
|
1243
|
+
}
|
|
1244
|
+
if (latest && !isVersionSupported(latest, engineInfos)) {
|
|
1243
1245
|
latest = supportedVersion(
|
|
1244
1246
|
latest,
|
|
1245
|
-
await load_plugins.getEngineInfos(plugin_db,
|
|
1247
|
+
await load_plugins.getEngineInfos(plugin_db, forceFetch)
|
|
1246
1248
|
);
|
|
1247
1249
|
}
|
|
1248
1250
|
const can_update = update_permitted && latest && mod.version !== latest;
|
package/routes/tables.js
CHANGED
|
@@ -192,6 +192,9 @@ const tableForm = async (table, req) => {
|
|
|
192
192
|
"if(!this.checked && !confirm('Are you sure? This will delete all history')) {this.checked = true; return false}",
|
|
193
193
|
},
|
|
194
194
|
type: "Bool",
|
|
195
|
+
help: {
|
|
196
|
+
topic: "Table history",
|
|
197
|
+
},
|
|
195
198
|
},
|
|
196
199
|
...(table.name === "users"
|
|
197
200
|
? []
|
|
@@ -798,7 +801,7 @@ router.get(
|
|
|
798
801
|
key: (r) => attribBadges(r),
|
|
799
802
|
},
|
|
800
803
|
{ label: req.__("Variable name"), key: (t) => code(t.name) },
|
|
801
|
-
...(table.external
|
|
804
|
+
...(table.external
|
|
802
805
|
? []
|
|
803
806
|
: [
|
|
804
807
|
{
|