@saltcorn/server 0.9.0-beta.0 → 0.9.0-beta.10

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,18 +1,18 @@
1
1
  {
2
2
  "name": "@saltcorn/server",
3
- "version": "0.9.0-beta.0",
3
+ "version": "0.9.0-beta.10",
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
- "@saltcorn/base-plugin": "0.9.0-beta.0",
10
- "@saltcorn/builder": "0.9.0-beta.0",
11
- "@saltcorn/data": "0.9.0-beta.0",
12
- "@saltcorn/admin-models": "0.9.0-beta.0",
13
- "@saltcorn/filemanager": "0.9.0-beta.0",
14
- "@saltcorn/markup": "0.9.0-beta.0",
15
- "@saltcorn/sbadmin2": "0.9.0-beta.0",
9
+ "@saltcorn/base-plugin": "0.9.0-beta.10",
10
+ "@saltcorn/builder": "0.9.0-beta.10",
11
+ "@saltcorn/data": "0.9.0-beta.10",
12
+ "@saltcorn/admin-models": "0.9.0-beta.10",
13
+ "@saltcorn/filemanager": "0.9.0-beta.10",
14
+ "@saltcorn/markup": "0.9.0-beta.10",
15
+ "@saltcorn/sbadmin2": "0.9.0-beta.10",
16
16
  "@socket.io/cluster-adapter": "^0.2.1",
17
17
  "@socket.io/sticky": "^1.0.1",
18
18
  "adm-zip": "0.5.10",
@@ -45,6 +45,7 @@
45
45
  "node-fetch": "2.6.9",
46
46
  "node-watch": "^0.7.2",
47
47
  "notp": "2.0.3",
48
+ "npm-registry-fetch": "16.0.0",
48
49
  "passport": "^0.6.0",
49
50
  "passport-custom": "^1.1.1",
50
51
  "passport-http-bearer": "^1.0.1",
@@ -55,7 +56,7 @@
55
56
  "qrcode": "1.5.1",
56
57
  "resize-with-sharp-or-jimp": "0.1.6",
57
58
  "socket.io": "4.6.0",
58
- "systeminformation": "^5.11.12",
59
+ "systeminformation": "^5.21.7",
59
60
  "thirty-two": "1.0.2",
60
61
  "tmp-promise": "^3.0.2",
61
62
  "uuid": "^8.2.0",
@@ -446,3 +446,7 @@ Copyright (c) 2017 Taha Paksu
446
446
  padding: 5px 9px;
447
447
  z-index: 1;
448
448
  }
449
+
450
+ div.builder-config-field {
451
+ margin-top: 0.5rem;
452
+ }
@@ -51,6 +51,7 @@ const nubBy = (prop, xs) => {
51
51
  });
52
52
  };
53
53
  function apply_showif() {
54
+ const isNode = typeof parent?.saltcorn?.data?.state === "undefined";
54
55
  $("[data-show-if]").each(function (ix, element) {
55
56
  var e = $(element);
56
57
  try {
@@ -78,6 +79,15 @@ function apply_showif() {
78
79
  console.error(e);
79
80
  }
80
81
  });
82
+ $("[data-dyn-href]").each(function (ix, element) {
83
+ const e = $(element);
84
+ const rec = get_form_record(e);
85
+ const href = new Function(
86
+ `{${Object.keys(rec).join(",")}}`,
87
+ "return " + e.attr("data-dyn-href")
88
+ )(rec);
89
+ e.attr("href", href);
90
+ });
81
91
  $("[data-calc-options]").each(function (ix, element) {
82
92
  var e = $(element);
83
93
  var data = JSON.parse(decodeURIComponent(e.attr("data-calc-options")));
@@ -263,10 +273,12 @@ function apply_showif() {
263
273
 
264
274
  if (typeof cache[recS] !== "undefined") {
265
275
  e.html(cache[recS]);
276
+ e.prop("data-source-url-current", recS);
266
277
  activate_onchange_coldef();
267
278
  return;
268
279
  }
269
- ajax_post_json(e.attr("data-source-url"), rec, {
280
+
281
+ const cb = {
270
282
  success: (data) => {
271
283
  e.html(data);
272
284
  const cacheNow = e.prop("data-source-url-cache") || {};
@@ -286,7 +298,11 @@ function apply_showif() {
286
298
  });
287
299
  e.html("");
288
300
  },
289
- });
301
+ };
302
+ if (isNode) ajax_post_json(e.attr("data-source-url"), rec, cb);
303
+ else {
304
+ local_post_json(e.attr("data-source-url"), rec, cb);
305
+ }
290
306
  });
291
307
  const locale =
292
308
  navigator.userLanguage ||
@@ -335,18 +351,21 @@ function splitTargetMatch(elemValue, target, keySpec) {
335
351
  return elemValueShort === target;
336
352
  }
337
353
 
338
- function get_form_record(e, select_labels) {
354
+ function get_form_record(e_in, select_labels) {
339
355
  const rec = {};
340
- e.closest(".form-namespace")
341
- .find("input[name],select[name]")
342
- .each(function () {
343
- const name = $(this).attr("data-fieldname") || $(this).attr("name");
344
- if (select_labels && $(this).prop("tagName").toLowerCase() === "select")
345
- rec[name] = $(this).find("option:selected").text();
346
- else if ($(this).prop("type") === "checkbox")
347
- rec[name] = $(this).prop("checked");
348
- else rec[name] = $(this).val();
349
- });
356
+
357
+ const e = e_in.viewname
358
+ ? $(`form[data-viewname=${e_in.viewname}]`)
359
+ : e_in.closest(".form-namespace");
360
+
361
+ e.find("input[name],select[name],textarea[name]").each(function () {
362
+ const name = $(this).attr("data-fieldname") || $(this).attr("name");
363
+ if (select_labels && $(this).prop("tagName").toLowerCase() === "select")
364
+ rec[name] = $(this).find("option:selected").text();
365
+ else if ($(this).prop("type") === "checkbox")
366
+ rec[name] = $(this).prop("checked");
367
+ else rec[name] = $(this).val();
368
+ });
350
369
  return rec;
351
370
  }
352
371
  function showIfFormulaInputs(e, fml) {
@@ -506,6 +525,11 @@ function initialize_page() {
506
525
  });
507
526
 
508
527
  $("form").change(apply_showif);
528
+ // also change if we select same
529
+ $("form select").on("blur", (e) => {
530
+ if (!e || !e.target) return;
531
+ $(e.target).closest("form").trigger("change");
532
+ });
509
533
  apply_showif();
510
534
  apply_showif();
511
535
  $("[data-inline-edit-dest-url]").each(function () {
@@ -527,6 +551,7 @@ function initialize_page() {
527
551
  var ajax = !!$(this).attr("data-inline-edit-ajax");
528
552
  var type = $(this).attr("data-inline-edit-type");
529
553
  var schema = $(this).attr("data-inline-edit-schema");
554
+ var decimalPlaces = $(this).attr("data-inline-edit-decimal-places");
530
555
  if (schema) {
531
556
  schema = JSON.parse(decodeURIComponent(schema));
532
557
  }
@@ -549,6 +574,7 @@ function initialize_page() {
549
574
  type,
550
575
  is_key,
551
576
  schema,
577
+ ...(decimalPlaces ? { decimalPlaces } : {}),
552
578
  })
553
579
  );
554
580
  const doAjaxOptionsFetch = (tblName, target) => {
@@ -601,7 +627,17 @@ function initialize_page() {
601
627
  }
602
628
  <input type="${
603
629
  type === "Integer" || type === "Float" ? "number" : "text"
604
- }" name="${key}" value="${escapeHtml(current)}">
630
+ }" ${
631
+ type === "Float"
632
+ ? `step="${
633
+ decimalPlaces
634
+ ? Math.round(
635
+ Math.pow(10, -decimalPlaces) * Math.pow(10, decimalPlaces)
636
+ ) / Math.pow(10, decimalPlaces)
637
+ : "any"
638
+ }"`
639
+ : ""
640
+ } name="${key}" value="${escapeHtml(current)}">
605
641
  <button type="submit" class="btn btn-sm btn-primary">OK</button>
606
642
  <button onclick="cancel_inline_edit(event, '${opts}')" type="button" class="btn btn-sm btn-danger"><i class="fas fa-times"></i></button>
607
643
  </form>`
@@ -654,10 +690,13 @@ function initialize_page() {
654
690
  setTimeout(() => {
655
691
  codes.forEach((el) => {
656
692
  //console.log($(el).attr("mode"), el);
693
+ if ($(el).hasClass("codemirror-enabled")) return;
694
+
657
695
  const cm = CodeMirror.fromTextArea(el, {
658
696
  lineNumbers: true,
659
697
  mode: $(el).attr("mode"),
660
698
  });
699
+ $(el).addClass("codemirror-enabled");
661
700
  cm.on(
662
701
  "change",
663
702
  $.debounce(() => {
@@ -768,6 +807,11 @@ function inline_submit_success(e, form, opts) {
768
807
  : ""
769
808
  }
770
809
  ${opts.current_label ? `data-inline-edit-current-label="${val}"` : ""}
810
+ ${
811
+ opts.decimalPlaces
812
+ ? `data-inline-edit-decimal-places="${opts.decimalPlaces}"`
813
+ : ""
814
+ }
771
815
  data-inline-edit-dest-url="${opts.url}">
772
816
  <span class="current">${val}</span>
773
817
  <i class="editicon ${!isNode ? "visible" : ""} fas fa-edit ms-1"></i>
@@ -945,15 +989,26 @@ function emptyAlerts() {
945
989
  $("#toasts-area").html("");
946
990
  }
947
991
 
948
- function press_store_button(clicked) {
992
+ function press_store_button(clicked, keepOld) {
949
993
  let btn = clicked;
950
994
  if ($(clicked).is("form")) btn = $(clicked).find("button[type=submit]");
951
-
995
+ if (keepOld) {
996
+ const oldText = $(btn).html();
997
+ $(btn).data("old-text", oldText);
998
+ }
952
999
  const width = $(btn).width();
953
1000
  $(btn).html('<i class="fas fa-spinner fa-spin"></i>').width(width);
954
1001
  }
955
1002
 
956
- function common_done(res, isWeb = true) {
1003
+ function restore_old_button(btnId) {
1004
+ const btn = $(`#${btnId}`);
1005
+ const oldText = $(btn).data("old-text");
1006
+ btn.html(oldText);
1007
+ btn.css({ width: "" });
1008
+ btn.removeData("old-text");
1009
+ }
1010
+
1011
+ function common_done(res, viewname, isWeb = true) {
957
1012
  const handle = (element, fn) => {
958
1013
  if (Array.isArray(element)) for (const current of element) fn(current);
959
1014
  else fn(element);
@@ -982,6 +1037,18 @@ function common_done(res, isWeb = true) {
982
1037
  });
983
1038
  });
984
1039
  }
1040
+ if (res.set_fields && viewname) {
1041
+ Object.keys(res.set_fields).forEach((k) => {
1042
+ const form = $(`form[data-viewname=${viewname}]`);
1043
+ const input = form.find(
1044
+ `input[name=${k}], textarea[name=${k}], select[name=${k}]`
1045
+ );
1046
+ if (input.attr("type") === "checkbox")
1047
+ input.prop("checked", res.set_fields[k]);
1048
+ else input.val(res.set_fields[k]);
1049
+ input.trigger("set_form_field");
1050
+ });
1051
+ }
985
1052
  if (res.goto && !isWeb)
986
1053
  // TODO ch
987
1054
  notifyAlert({
@@ -997,6 +1064,7 @@ function common_done(res, isWeb = true) {
997
1064
  if (
998
1065
  prev.origin === next.origin &&
999
1066
  prev.pathname === next.pathname &&
1067
+ prev.searchParams.toString() === next.searchParams.toString() &&
1000
1068
  next.hash !== prev.hash
1001
1069
  )
1002
1070
  location.reload();
@@ -472,3 +472,17 @@ div.unread-notify {
472
472
  cursor: pointer;
473
473
  text-decoration: underline;
474
474
  }
475
+
476
+ table.help-md thead {
477
+ border-bottom: 1px solid black;
478
+ }
479
+
480
+ table.help-md {
481
+ margin-bottom: 1em;
482
+ }
483
+
484
+ table.help-md td:nth-child(2),
485
+ table.help-md th:nth-child(2) {
486
+ padding-left: 10px;
487
+ padding-right: 10px;
488
+ }
@@ -198,8 +198,8 @@ function clear_state(omit_fields_str, e) {
198
198
  pjax_to(newUrl, e);
199
199
  }
200
200
 
201
- function ajax_done(res) {
202
- common_done(res);
201
+ function ajax_done(res, viewname) {
202
+ common_done(res, viewname);
203
203
  }
204
204
 
205
205
  function view_post(viewname, route, data, onDone, sendState) {
@@ -220,7 +220,7 @@ function view_post(viewname, route, data, onDone, sendState) {
220
220
  })
221
221
  .done(function (res) {
222
222
  if (onDone) onDone(res);
223
- ajax_done(res);
223
+ ajax_done(res, viewname);
224
224
  })
225
225
  .fail(function (res) {
226
226
  notifyAlert({ type: "danger", text: res.responseText });
@@ -340,6 +340,28 @@ function ajax_modal(url, opts = {}) {
340
340
  $("body").css("overflow", "");
341
341
  });
342
342
  },
343
+ ...(opts.onError
344
+ ? {
345
+ error: opts.onError,
346
+ }
347
+ : {}),
348
+ });
349
+ }
350
+
351
+ function selectVersionError(res, btnId) {
352
+ notifyAlert({
353
+ type: "danger",
354
+ text: res.responseJSON?.error || "unknown error",
355
+ });
356
+ restore_old_button(btnId);
357
+ }
358
+
359
+ function submitWithAjax(e) {
360
+ saveAndContinue(e, (res) => {
361
+ if (res && res.responseJSON && res.responseJSON.url_when_done)
362
+ window.location.href = res.responseJSON.url_when_done;
363
+ if (res && res.responseJSON && res.responseJSON.error)
364
+ notifyAlert({ type: "danger", text: res.responseJSON.error });
343
365
  });
344
366
  }
345
367
 
@@ -368,6 +390,9 @@ function saveAndContinue(e, k) {
368
390
  if (res.notify) {
369
391
  notifyAlert(res.notify);
370
392
  }
393
+ if (res.reload_page) {
394
+ location.reload(); //TODO notify to cookie if reload or goto
395
+ }
371
396
  },
372
397
  error: function (request) {
373
398
  var ct = request.getResponseHeader("content-type") || "";
@@ -388,8 +413,8 @@ function saveAndContinue(e, k) {
388
413
  }
389
414
  ajax_indicate_error(e, request);
390
415
  },
391
- complete: function () {
392
- if (k) k();
416
+ complete: function (res) {
417
+ if (k) k(res);
393
418
  },
394
419
  });
395
420
 
@@ -410,7 +435,8 @@ function updateMatchingRows(e, viewname) {
410
435
  }
411
436
  }
412
437
 
413
- function applyViewConfig(e, url, k) {
438
+ function applyViewConfig(e, url, k, event) {
439
+ if (event && event.target && event.target.id === "myEditor_icon") return;
414
440
  var form = $(e).closest("form");
415
441
  var form_data = form.serializeArray();
416
442
  const cfg = {};
@@ -491,7 +517,7 @@ function ajaxSubmitForm(e) {
491
517
  var no_reload = $("#scmodal").hasClass("no-submit-reload");
492
518
  $("#scmodal").modal("hide");
493
519
  if (!no_reload) location.reload();
494
- else common_done(res);
520
+ else common_done(res, form.attr("data-viewname"));
495
521
  },
496
522
  error: function (request) {
497
523
  var title = request.getResponseHeader("Page-Title");
package/routes/actions.js CHANGED
@@ -174,8 +174,9 @@ const triggerForm = async (req, trigger) => {
174
174
  attributes: {
175
175
  explainers: {
176
176
  Often: req.__("Every 5 minutes"),
177
- Never:
178
- req.__("Not scheduled but can be run as an action from a button click"),
177
+ Never: req.__(
178
+ "Not scheduled but can be run as an action from a button click"
179
+ ),
179
180
  },
180
181
  },
181
182
  },
@@ -201,6 +202,7 @@ const triggerForm = async (req, trigger) => {
201
202
  label: req.__("Action"),
202
203
  type: "String",
203
204
  required: true,
205
+ help: { topic: "Actions" },
204
206
  attributes: {
205
207
  calcOptions: ["when_trigger", action_options],
206
208
  },
@@ -402,7 +404,7 @@ router.get(
402
404
  form.values = trigger.configuration;
403
405
  const events = Trigger.when_options;
404
406
  const actions = Trigger.find({
405
- when_trigger: {or: ["API call", "Never"]},
407
+ when_trigger: { or: ["API call", "Never"] },
406
408
  });
407
409
  const tables = (await Table.find({})).map((t) => ({
408
410
  name: t.name,