@saltcorn/server 1.0.0-beta.9 → 1.0.0-rc.1

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 CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@saltcorn/server",
3
- "version": "1.0.0-beta.9",
3
+ "version": "1.0.0-rc.1",
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.9",
11
- "@saltcorn/builder": "1.0.0-beta.9",
12
- "@saltcorn/data": "1.0.0-beta.9",
13
- "@saltcorn/admin-models": "1.0.0-beta.9",
14
- "@saltcorn/filemanager": "1.0.0-beta.9",
15
- "@saltcorn/markup": "1.0.0-beta.9",
16
- "@saltcorn/plugins-loader": "1.0.0-beta.9",
17
- "@saltcorn/sbadmin2": "1.0.0-beta.9",
10
+ "@saltcorn/base-plugin": "1.0.0-rc.1",
11
+ "@saltcorn/builder": "1.0.0-rc.1",
12
+ "@saltcorn/data": "1.0.0-rc.1",
13
+ "@saltcorn/admin-models": "1.0.0-rc.1",
14
+ "@saltcorn/filemanager": "1.0.0-rc.1",
15
+ "@saltcorn/markup": "1.0.0-rc.1",
16
+ "@saltcorn/plugins-loader": "1.0.0-rc.1",
17
+ "@saltcorn/sbadmin2": "1.0.0-rc.1",
18
18
  "@socket.io/cluster-adapter": "^0.2.1",
19
19
  "@socket.io/sticky": "^1.0.1",
20
20
  "adm-zip": "0.5.10",
@@ -46,7 +46,7 @@
46
46
  "node-fetch": "2.6.9",
47
47
  "node-watch": "^0.7.2",
48
48
  "notp": "2.0.3",
49
- "npm-registry-fetch": "16.0.0",
49
+ "npm-registry-fetch": "17.1.0",
50
50
  "passport": "^0.6.0",
51
51
  "passport-custom": "^1.1.1",
52
52
  "passport-http-bearer": "^1.0.1",
@@ -55,7 +55,7 @@
55
55
  "pg": "^8.2.1",
56
56
  "pluralize": "^8.0.0",
57
57
  "qrcode": "1.5.1",
58
- "resize-with-sharp-or-jimp": "0.1.7",
58
+ "resize-with-sharp-or-jimp": "0.1.8",
59
59
  "semver": "^7.6.0",
60
60
  "socket.io": "4.6.0",
61
61
  "systeminformation": "^5.21.7",
@@ -18,7 +18,7 @@ function monospace_block_click(e) {
18
18
  function copy_monospace_block(e) {
19
19
  let e1 = $(e).next("pre");
20
20
  let e2 = $(e1).next("pre");
21
- if (!e2.length) return navigator.clipboard.writeText($(el).text());
21
+ if (!e2.length) return navigator.clipboard.writeText($(e1).text());
22
22
  const e1t = e1.text();
23
23
  const e2t = e2.text();
24
24
  if (e1t.length > e2t.length) return navigator.clipboard.writeText(e1t);
@@ -63,14 +63,20 @@ function reset_nearest_form(that) {
63
63
 
64
64
  function add_repeater(nm) {
65
65
  var es = $("div.form-repeat.repeat-" + nm);
66
- var e = es.first();
66
+ const ncopy = es.length - 1;
67
+ var e = es.last();
67
68
  var newix = es.length;
68
69
  var newe = $(e).clone();
69
70
  newe.find("[name]").each(function (ix, element) {
70
71
  if ($(element).hasClass("omit-repeater-clone")) $(element).remove();
71
- var newnm = (element.name || "").replace("_0", "_" + newix);
72
- var newid = (element.id || "").replace("_0", "_" + newix);
72
+ const oldnm = element.name || "";
73
+ var newnm = (element.name || "").replace("_" + ncopy, "_" + newix);
74
+ var newid = (element.id || "").replace("_" + ncopy, "_" + newix);
73
75
  $(element).attr("name", newnm).attr("id", newid);
76
+ if (element.tagName === "SELECT") {
77
+ const original = document.getElementsByName(oldnm)[0];
78
+ if (original) element.selectedIndex = original.selectedIndex;
79
+ }
74
80
  });
75
81
  newe.appendTo($("div.repeats-" + nm));
76
82
  newe.find("[data-on-cloned]").each(function (ix, element) {
@@ -80,6 +86,27 @@ function add_repeater(nm) {
80
86
  });
81
87
  }
82
88
 
89
+ function rep_del(e) {
90
+ var myrep = $(e).closest(".form-repeat");
91
+ var ix = myrep.index();
92
+ var parent = myrep.parent();
93
+ myrep.remove();
94
+ parent.children().each(function (childix, element) {
95
+ if (childix > ix) {
96
+ reindex(element, childix, childix - 1);
97
+ }
98
+ });
99
+ }
100
+
101
+ function reindex(element, oldix, newix) {
102
+ $(element).html(
103
+ $(element)
104
+ .html()
105
+ .split("_" + oldix + '"')
106
+ .join("_" + newix + '"')
107
+ );
108
+ }
109
+
83
110
  const _apply_showif_plugins = [];
84
111
 
85
112
  const add_apply_showif_plugin = (p) => {
@@ -115,16 +142,18 @@ function apply_showif() {
115
142
  }
116
143
  if (!e.data("data-closest-form-ns"))
117
144
  e.data("data-closest-form-ns", e.closest(".form-namespace"));
118
- if (to_show(e))
119
- e.show()
120
- .find("input, textarea, button, select, [data-show-if]")
121
- .prop("disabled", e.attr("data-disabled") || false);
122
- else
123
- e.hide()
124
- .find(
125
- "input:enabled, textarea:enabled, button:enabled, select:enabled, [data-show-if]:not([disabled])"
126
- )
127
- .prop("disabled", true);
145
+ if (to_show(e)) {
146
+ e.find("input, textarea, button, select, [data-show-if]").prop(
147
+ "disabled",
148
+ e.attr("data-disabled") || false
149
+ );
150
+ element.style.display = "";
151
+ } else {
152
+ e.find(
153
+ "input:enabled, textarea:enabled, button:enabled, select:enabled, [data-show-if]:not([disabled])"
154
+ ).prop("disabled", true);
155
+ element.style.setProperty("display", "none", "important");
156
+ }
128
157
  } catch (e) {
129
158
  console.error(e);
130
159
  }
@@ -155,8 +184,21 @@ function apply_showif() {
155
184
  var current = e.attr("data-selected") || e.val();
156
185
  //console.log({ field: e.attr("name"), target: data[0], val, current });
157
186
  e.empty();
187
+ //TODO clean repetition in following cose
158
188
  (options || []).forEach((o) => {
159
- if (
189
+ if (o && o.optgroup) {
190
+ const opts = o.options
191
+ .map(
192
+ (innero) =>
193
+ `<option ${
194
+ `${current}` === `${innero.value || innero}` ? "selected " : ""
195
+ }value="${innero.value || innero}">${
196
+ innero.label || innero
197
+ }</option>`
198
+ )
199
+ .join("");
200
+ e.append($(`<optgroup label="${o.label}">` + opts + "</optgroup>"));
201
+ } else if (
160
202
  !(o && typeof o.label !== "undefined" && typeof o.value !== "undefined")
161
203
  ) {
162
204
  if (`${current}` === `${o}`)
@@ -303,25 +345,27 @@ function apply_showif() {
303
345
  ...cache,
304
346
  [qs]: "fetching",
305
347
  });
306
- $.ajax(`/api/${dynwhere.table}?${qs}`).then((resp) => {
307
- if (resp.success) {
308
- if (window._sc_loglevel > 4)
309
- console.log("dynwhere fetch", qs, resp.success);
310
-
311
- activate(resp.success, qs);
312
- const cacheNow = e.prop("data-fetch-options-cache") || {};
313
- e.prop("data-fetch-options-cache", {
314
- ...cacheNow,
315
- [qs]: resp.success,
316
- });
317
- } else {
318
- const cacheNow = e.prop("data-fetch-options-cache") || {};
319
- e.prop("data-fetch-options-cache", {
320
- ...cacheNow,
321
- [qs]: undefined,
322
- });
323
- }
324
- });
348
+ $.ajax(`/api/${dynwhere.table}?${qs}`)
349
+ .then((resp) => {
350
+ if (resp.success) {
351
+ if (window._sc_loglevel > 4)
352
+ console.log("dynwhere fetch", qs, resp.success);
353
+
354
+ activate(resp.success, qs);
355
+ const cacheNow = e.prop("data-fetch-options-cache") || {};
356
+ e.prop("data-fetch-options-cache", {
357
+ ...cacheNow,
358
+ [qs]: resp.success,
359
+ });
360
+ } else {
361
+ const cacheNow = e.prop("data-fetch-options-cache") || {};
362
+ e.prop("data-fetch-options-cache", {
363
+ ...cacheNow,
364
+ [qs]: undefined,
365
+ });
366
+ }
367
+ })
368
+ .fail(checkNetworkError);
325
369
  }
326
370
  });
327
371
  $("[data-filter-table]").each(function (ix, element) {
@@ -530,6 +574,7 @@ function get_form_record(e_in, select_labels) {
530
574
  $(e_in).prop("data-join-values", jvs);
531
575
  apply_showif();
532
576
  },
577
+ error: checkNetworkError,
533
578
  });
534
579
  }
535
580
  $(e_in).prop("data-join-key-values", keyVals);
@@ -558,27 +603,6 @@ function showIfFormulaInputs(e, fml) {
558
603
  }
559
604
  }
560
605
 
561
- function rep_del(e) {
562
- var myrep = $(e).closest(".form-repeat");
563
- var ix = myrep.index();
564
- var parent = myrep.parent();
565
- parent.children().each(function (childix, element) {
566
- if (childix > ix) {
567
- reindex(element, childix, childix - 1);
568
- }
569
- });
570
- myrep.remove();
571
- }
572
-
573
- function reindex(element, oldix, newix) {
574
- $(element).html(
575
- $(element)
576
- .html()
577
- .split("_" + oldix)
578
- .join("_" + newix)
579
- );
580
- }
581
-
582
606
  function get_form_subset_record(e) {
583
607
  const rec = {};
584
608
  e.find("input[name],select[name]").each(function () {
@@ -740,6 +764,42 @@ function doMobileTransforms() {
740
764
  }
741
765
  });
742
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
+
743
803
  $("button").each(function () {
744
804
  for (const [k, v] of Object.entries({ onclick: replacers.onclick })) {
745
805
  for ({ web, mobile } of v) replaceAttr(this, k, v.web, v.mobile);
@@ -894,31 +954,33 @@ function initialize_page() {
894
954
  })
895
955
  );
896
956
  const doAjaxOptionsFetch = (tblName, target) => {
897
- $.ajax(`/api/${tblName}`).then((resp) => {
898
- if (resp.success) {
899
- resp.success.sort((a, b) =>
900
- a[target]?.toLowerCase?.() > b[target]?.toLowerCase?.() ? 1 : -1
901
- );
902
-
903
- const selopts = resp.success.map(
904
- (r) =>
905
- `<option ${current == r.id ? `selected ` : ``}value="${
906
- r.id
907
- }">${escapeHtml(r[target])}</option>`
908
- );
909
- $(this).replaceWith(
910
- `<form method="post" action="${url}" ${
911
- ajax ? `onsubmit="inline_ajax_submit(event, '${opts}')"` : ""
912
- }>
957
+ $.ajax(`/api/${tblName}`)
958
+ .then((resp) => {
959
+ if (resp.success) {
960
+ resp.success.sort((a, b) =>
961
+ a[target]?.toLowerCase?.() > b[target]?.toLowerCase?.() ? 1 : -1
962
+ );
963
+
964
+ const selopts = resp.success.map(
965
+ (r) =>
966
+ `<option ${current == r.id ? `selected ` : ``}value="${
967
+ r.id
968
+ }">${escapeHtml(r[target])}</option>`
969
+ );
970
+ $(this).replaceWith(
971
+ `<form method="post" action="${url}" ${
972
+ ajax ? `onsubmit="inline_ajax_submit(event, '${opts}')"` : ""
973
+ }>
913
974
  <input type="hidden" name="_csrf" value="${_sc_globalCsrf}">
914
975
  <select name="${key}" value="${current}">${selopts}
915
976
  </select>
916
977
  <button type="submit" class="btn btn-sm btn-primary">OK</button>
917
978
  <button onclick="cancel_inline_edit(event, '${opts}')" type="button" class="btn btn-sm btn-danger"><i class="fas fa-times"></i></button>
918
979
  </form>`
919
- );
920
- }
921
- });
980
+ );
981
+ }
982
+ })
983
+ .fail(checkNetworkError);
922
984
  };
923
985
  if (type === "JSON" && schema && schema.type.startsWith("Key to ")) {
924
986
  const tblName = schema.type.replace("Key to ", "");
@@ -1097,7 +1159,8 @@ function initialize_page() {
1097
1159
  initialize_page();
1098
1160
  },
1099
1161
  error: function (res) {
1100
- notifyAlert({ type: "danger", text: res.responseText });
1162
+ if (!checkNetworkError(res))
1163
+ notifyAlert({ type: "danger", text: res.responseText });
1101
1164
  if ($e.html() === "Loading...") $e.html("");
1102
1165
  },
1103
1166
  });
@@ -1172,9 +1235,10 @@ function inline_ajax_submit(e, opts1) {
1172
1235
  inline_submit_success(e, form, opts);
1173
1236
  },
1174
1237
  error: function (e) {
1175
- ajax_done(
1176
- e.responseJSON || { error: "Unknown error: " + e.responseText }
1177
- );
1238
+ if (!checkNetworkError(e))
1239
+ ajax_done(
1240
+ e.responseJSON || { error: "Unknown error: " + e.responseText }
1241
+ );
1178
1242
  },
1179
1243
  });
1180
1244
  }
@@ -1217,6 +1281,7 @@ function enable_codemirror(f) {
1217
1281
  dataType: "script",
1218
1282
  cache: true,
1219
1283
  success: f,
1284
+ error: checkNetworkError,
1220
1285
  });
1221
1286
  }
1222
1287
  function tristateClick(e, required) {
@@ -1336,10 +1401,14 @@ function notifyAlert(note, spin) {
1336
1401
  if (typeof note == "string") {
1337
1402
  txt = note;
1338
1403
  type = "info";
1339
- } else {
1404
+ } else if (note.text) {
1340
1405
  txt = note.text;
1341
- type = note.type;
1406
+ type = note.type || "info";
1407
+ } else {
1408
+ type = "info";
1409
+ txt = JSON.stringify(note, null, 2);
1342
1410
  }
1411
+
1343
1412
  const { id, html } = buildToast(txt, type, spin);
1344
1413
  let $modal = $("#scmodal");
1345
1414
  if ($modal.length && $modal.hasClass("show"))
@@ -1524,7 +1593,8 @@ function reloadEmbeddedEditOwnViews(form, id) {
1524
1593
  initialize_page();
1525
1594
  },
1526
1595
  error: function (res) {
1527
- notifyAlert({ type: "danger", text: res.responseText });
1596
+ if (!checkNetworkError(res))
1597
+ notifyAlert({ type: "danger", text: res.responseText });
1528
1598
  },
1529
1599
  });
1530
1600
  });
@@ -1757,24 +1827,26 @@ function is_paging_param(key) {
1757
1827
  return key.endsWith("_page") || key.endsWith("_pagesize");
1758
1828
  }
1759
1829
  function check_saltcorn_notifications() {
1760
- $.ajax(`/notifications/count-unread`).then((resp) => {
1761
- if (resp.success) {
1762
- const n = resp.success;
1763
- const menu_item = $(`a.notify-menu-item`);
1764
-
1765
- menu_item.html(
1766
- `<i class="fa-fw mr-05 fas fa-bell"></i>Notifications (${n})`
1767
- );
1768
- $(".user-nav-section").html(
1769
- `<i class="fa-fw mr-05 fas fa-user"></i>User (${n})`
1770
- );
1771
- $(".user-nav-section-with-span").html(
1772
- `<i class="fa-fw mr-05 fas fa-user"></i><span>User (${n})</span>`
1773
- );
1774
- window.update_theme_notification_count &&
1775
- window.update_theme_notification_count(n);
1776
- }
1777
- });
1830
+ $.ajax(`/notifications/count-unread`)
1831
+ .then((resp) => {
1832
+ if (resp.success) {
1833
+ const n = resp.success;
1834
+ const menu_item = $(`a.notify-menu-item`);
1835
+
1836
+ menu_item.html(
1837
+ `<i class="fa-fw mr-05 fas fa-bell"></i>Notifications (${n})`
1838
+ );
1839
+ $(".user-nav-section").html(
1840
+ `<i class="fa-fw mr-05 fas fa-user"></i>User (${n})`
1841
+ );
1842
+ $(".user-nav-section-with-span").html(
1843
+ `<i class="fa-fw mr-05 fas fa-user"></i><span>User (${n})</span>`
1844
+ );
1845
+ window.update_theme_notification_count &&
1846
+ window.update_theme_notification_count(n);
1847
+ }
1848
+ })
1849
+ .fail(checkNetworkError);
1778
1850
  }
1779
1851
 
1780
1852
  function disable_inactive_tab_inputs(id) {
@@ -1834,6 +1906,8 @@ function close_saltcorn_modal() {
1834
1906
  }
1835
1907
  }
1836
1908
 
1909
+ let _sc_currently_reloading;
1910
+
1837
1911
  function reload_embedded_view(viewname, new_query_string) {
1838
1912
  const isNode = getIsNode();
1839
1913
  const updater = ($e, res) => {
@@ -1861,16 +1935,21 @@ function reload_embedded_view(viewname, new_query_string) {
1861
1935
  url = url.split("?")[0] + "?" + new_query_string;
1862
1936
  }
1863
1937
  if (isNode) {
1938
+ if (url === _sc_currently_reloading) return;
1939
+ _sc_currently_reloading = url;
1864
1940
  $.ajax(url, {
1865
1941
  headers: {
1866
1942
  pjaxpageload: "true",
1867
1943
  localizedstate: "true", //no admin bar
1868
1944
  },
1869
1945
  success: function (res, textStatus, request) {
1946
+ _sc_currently_reloading = null;
1870
1947
  updater($e, res);
1871
1948
  },
1872
1949
  error: function (res) {
1873
- notifyAlert({ type: "danger", text: res.responseText });
1950
+ _sc_currently_reloading = null;
1951
+ if (!checkNetworkError(res))
1952
+ notifyAlert({ type: "danger", text: res.responseText });
1874
1953
  },
1875
1954
  });
1876
1955
  } else {
@@ -1880,3 +1959,19 @@ function reload_embedded_view(viewname, new_query_string) {
1880
1959
  }
1881
1960
  });
1882
1961
  }
1962
+
1963
+ function update_time_of_week(nm) {
1964
+ return function () {
1965
+ const day = $(`#input${nm}__day`).val();
1966
+ const flat = document.querySelector(`#input${nm}__time`)._flatpickr;
1967
+
1968
+ const time = flat.selectedDates?.[0];
1969
+ let s;
1970
+ if (time) {
1971
+ const m = time.getMinutes();
1972
+
1973
+ s = `${day} ${time.getHours()} ${m < 10 ? `0${m}` : m}`;
1974
+ } else s = day;
1975
+ $(`#inputh${nm}`).val(s).trigger("change");
1976
+ };
1977
+ }
@@ -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
+ }