@saltcorn/server 0.9.5-beta.2 → 0.9.5-beta.21

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,19 +1,20 @@
1
1
  {
2
2
  "name": "@saltcorn/server",
3
- "version": "0.9.5-beta.2",
3
+ "version": "0.9.5-beta.21",
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.2",
11
- "@saltcorn/builder": "0.9.5-beta.2",
12
- "@saltcorn/data": "0.9.5-beta.2",
13
- "@saltcorn/admin-models": "0.9.5-beta.2",
14
- "@saltcorn/filemanager": "0.9.5-beta.2",
15
- "@saltcorn/markup": "0.9.5-beta.2",
16
- "@saltcorn/sbadmin2": "0.9.5-beta.2",
10
+ "@saltcorn/base-plugin": "0.9.5-beta.21",
11
+ "@saltcorn/builder": "0.9.5-beta.21",
12
+ "@saltcorn/data": "0.9.5-beta.21",
13
+ "@saltcorn/admin-models": "0.9.5-beta.21",
14
+ "@saltcorn/filemanager": "0.9.5-beta.21",
15
+ "@saltcorn/markup": "0.9.5-beta.21",
16
+ "@saltcorn/plugins-loader": "0.9.5-beta.21",
17
+ "@saltcorn/sbadmin2": "0.9.5-beta.21",
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": "26.6.3",
74
- "jest-environment-jsdom": "^26.6.2",
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
- const socket = io({ transports: ["websocket"] });
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 = typeof parent?.saltcorn?.data?.state === "undefined";
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.map((v1) => Object.entries(v1).map(kvToQs).join("&")).join("&")
165
- : `${k}=${v[0] === "$" ? rec[v.substring(1)] : v}`;
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 = typeof parent?.saltcorn?.data?.state === "undefined";
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
- $("[mobile-img-path]").each(async function () {
747
- if (parent.loadEncodedFile) {
748
- const fileId = $(this).attr("mobile-img-path");
749
- const base64Encoded = await parent.loadEncodedFile(fileId);
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.style.backgroundImage = `url("${base64Encoded}")`;
759
+ this.src = base64Encoded;
759
760
  }
760
- }
761
- });
761
+ });
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
+ });
762
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
 
@@ -872,12 +915,31 @@ function initialize_page() {
872
915
  .find(".show[rendered='server-side'][type='success']")
873
916
  .removeClass("show");
874
917
  }, 5000);
918
+ $(".lazy-accoordion").on("show.bs.collapse", function (e) {
919
+ const $e = $(e.target).find("[data-sc-view-source]");
920
+ if ($.trim($e.html()) == "") {
921
+ const url = $e.attr("data-sc-view-source");
922
+ $.ajax(url, {
923
+ headers: {
924
+ pjaxpageload: "true",
925
+ localizedstate: "true", //no admin bar
926
+ },
927
+ success: function (res, textStatus, request) {
928
+ $e.html(res);
929
+ initialize_page();
930
+ },
931
+ error: function (res) {
932
+ notifyAlert({ type: "danger", text: res.responseText });
933
+ },
934
+ });
935
+ }
936
+ });
875
937
  }
876
938
 
877
939
  $(initialize_page);
878
940
 
879
941
  function cancel_inline_edit(e, opts1) {
880
- const isNode = typeof parent?.saltcorn?.data?.state === "undefined";
942
+ const isNode = getIsNode();
881
943
  var opts = JSON.parse(decodeURIComponent(opts1 || "") || "{}");
882
944
  var form = $(e.target).closest("form");
883
945
  form.replaceWith(opts.resetHtml);
@@ -885,7 +947,7 @@ function cancel_inline_edit(e, opts1) {
885
947
  }
886
948
 
887
949
  function inline_submit_success(e, form, opts) {
888
- const isNode = typeof parent?.saltcorn?.data?.state === "undefined";
950
+ const isNode = getIsNode();
889
951
  const formDataArray = form.serializeArray();
890
952
  if (opts) {
891
953
  let fdEntry = formDataArray.find((f) => f.name == opts.key);
@@ -1025,6 +1087,15 @@ function tristateClick(e, required) {
1025
1087
  }
1026
1088
  }
1027
1089
 
1090
+ function getIsNode() {
1091
+ try {
1092
+ return typeof parent?.saltcorn?.data?.state === "undefined";
1093
+ } catch (e) {
1094
+ //probably in an iframe
1095
+ return true;
1096
+ }
1097
+ }
1098
+
1028
1099
  function buildToast(txt, type, spin) {
1029
1100
  const realtype = type === "error" ? "danger" : type;
1030
1101
  const icon =
@@ -1035,7 +1106,7 @@ function buildToast(txt, type, spin) {
1035
1106
  : realtype === "warning"
1036
1107
  ? "fa-exclamation-triangle"
1037
1108
  : "";
1038
- const isNode = typeof parent?.saltcorn?.data?.state === "undefined";
1109
+ const isNode = getIsNode();
1039
1110
  const rndid = `tab${Math.floor(Math.random() * 16777215).toString(16)}`;
1040
1111
  return {
1041
1112
  id: rndid,
@@ -1167,8 +1238,10 @@ async function common_done(res, viewname, isWeb = true) {
1167
1238
  await handle(res.notify_success, (text) =>
1168
1239
  notifyAlert({ type: "success", text: text })
1169
1240
  );
1170
- if (res.set_fields && viewname) {
1171
- const form = $(`form[data-viewname="${viewname}"]`);
1241
+ if (res.set_fields && (viewname || res.set_fields._viewname)) {
1242
+ const form = $(
1243
+ `form[data-viewname="${res.set_fields._viewname || viewname}"]`
1244
+ );
1172
1245
  if (form.length === 0 && set_state_fields) {
1173
1246
  // assume this is a filter
1174
1247
  set_state_fields(
@@ -1178,6 +1251,7 @@ async function common_done(res, viewname, isWeb = true) {
1178
1251
  );
1179
1252
  } else {
1180
1253
  Object.keys(res.set_fields).forEach((k) => {
1254
+ if (k === "_viewname") return;
1181
1255
  const input = form.find(
1182
1256
  `input[name=${k}], textarea[name=${k}], select[name=${k}]`
1183
1257
  );
@@ -1186,6 +1260,7 @@ async function common_done(res, viewname, isWeb = true) {
1186
1260
  form.append(
1187
1261
  `<input type="hidden" name="id" value="${res.set_fields[k]}">`
1188
1262
  );
1263
+ reloadEmbeddedEditOwnViews(form, res.set_fields[k]);
1189
1264
  return;
1190
1265
  }
1191
1266
  if (input.attr("type") === "checkbox")
@@ -1250,6 +1325,28 @@ async function common_done(res, viewname, isWeb = true) {
1250
1325
  }
1251
1326
  }
1252
1327
 
1328
+ function reloadEmbeddedEditOwnViews(form, id) {
1329
+ form.find("div[sc-load-on-assign-id]").each(function () {
1330
+ const $e = $(this);
1331
+ const viewname = $e.attr("sc-load-on-assign-id");
1332
+ const newUrl = `/view/${viewname}?id=${id}`;
1333
+ $.ajax(newUrl, {
1334
+ headers: {
1335
+ pjaxpageload: "true",
1336
+ localizedstate: "true", //no admin bar
1337
+ },
1338
+ success: function (res, textStatus, request) {
1339
+ const newE = `<div class="d-inline" data-sc-embed-viewname="${viewname}" data-sc-view-source="${newUrl}">${res}</div>`;
1340
+ $e.replaceWith(newE);
1341
+ initialize_page();
1342
+ },
1343
+ error: function (res) {
1344
+ notifyAlert({ type: "danger", text: res.responseText });
1345
+ },
1346
+ });
1347
+ });
1348
+ }
1349
+
1253
1350
  const repeaterCopyValuesToForm = (form, editor, noTriggerChange) => {
1254
1351
  const vs = JSON.parse(editor.getString());
1255
1352
 
@@ -1542,3 +1639,55 @@ function set_readonly_select(e) {
1542
1639
  const option = options.find((o) => o.value == e.target.value);
1543
1640
  if (option) $disp.val(option.label);
1544
1641
  }
1642
+
1643
+ function close_saltcorn_modal() {
1644
+ $("#scmodal").off("hidden.bs.modal");
1645
+ var myModalEl = document.getElementById("scmodal");
1646
+ if (!myModalEl) return;
1647
+ var modal = bootstrap.Modal.getInstance(myModalEl);
1648
+ if (modal) {
1649
+ if (modal.hide) modal.hide();
1650
+ if (modal.dispose) modal.dispose();
1651
+ }
1652
+ }
1653
+
1654
+ function reload_embedded_view(viewname, new_query_string) {
1655
+ const isNode = getIsNode();
1656
+ const updater = ($e, res) => {
1657
+ $e.html(res);
1658
+ initialize_page();
1659
+ };
1660
+ if (window._sc_loglevel > 4)
1661
+ console.log(
1662
+ "reload_embedded_view",
1663
+ viewname,
1664
+ "found",
1665
+ $(`[data-sc-embed-viewname="${viewname}"]`).length
1666
+ );
1667
+ $(`[data-sc-embed-viewname="${viewname}"]`).each(function () {
1668
+ const $e = $(this);
1669
+ let url = $e.attr("data-sc-local-state") || $e.attr("data-sc-view-source");
1670
+ if (!url) return;
1671
+ if (new_query_string) {
1672
+ url = url.split("?")[0] + "?" + new_query_string;
1673
+ }
1674
+ if (isNode) {
1675
+ $.ajax(url, {
1676
+ headers: {
1677
+ pjaxpageload: "true",
1678
+ localizedstate: "true", //no admin bar
1679
+ },
1680
+ success: function (res, textStatus, request) {
1681
+ updater($e, res);
1682
+ },
1683
+ error: function (res) {
1684
+ notifyAlert({ type: "danger", text: res.responseText });
1685
+ },
1686
+ });
1687
+ } else {
1688
+ runUrl(url).then((html) => {
1689
+ updater($e, html);
1690
+ });
1691
+ }
1692
+ });
1693
+ }
@@ -502,3 +502,7 @@ tr[onclick] {
502
502
  .editStarRating i.fa-star {
503
503
  color: unset;
504
504
  }
505
+
506
+ .modal-header {
507
+ justify-content: space-between;
508
+ }
@@ -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").html(resp.responseText || resp.statusText);
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", true);
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";
@@ -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, { configuration: form.values });
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;