@saltcorn/server 0.7.4-beta.1 → 0.7.4-beta.3

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.
@@ -86,8 +86,7 @@ function apply_showif() {
86
86
  } else {
87
87
  e.append(
88
88
  $(
89
- `<option ${
90
- `${current}` === `${o.value}` ? "selected" : ""
89
+ `<option ${`${current}` === `${o.value}` ? "selected" : ""
91
90
  } value="${o.value}">${o.label}</option>`
92
91
  )
93
92
  );
@@ -118,15 +117,13 @@ function apply_showif() {
118
117
  resp.success.forEach((r) => {
119
118
  e.append(
120
119
  $(
121
- `<option ${
122
- `${current}` === `${r[dynwhere.refname]}` ? "selected" : ""
123
- } value="${r[dynwhere.refname]}">${
124
- dynwhere.label_formula
125
- ? new Function(
126
- `{${Object.keys(r).join(",")}}`,
127
- "return " + dynwhere.label_formula
128
- )(r)
129
- : r[dynwhere.summary_field]
120
+ `<option ${`${current}` === `${r[dynwhere.refname]}` ? "selected" : ""
121
+ } value="${r[dynwhere.refname]}">${dynwhere.label_formula
122
+ ? new Function(
123
+ `{${Object.keys(r).join(",")}}`,
124
+ "return " + dynwhere.label_formula
125
+ )(r)
126
+ : r[dynwhere.summary_field]
130
127
  }</option>`
131
128
  )
132
129
  );
@@ -466,16 +463,14 @@ function notifyAlert(note, spin) {
466
463
  }
467
464
 
468
465
  $("#alerts-area")
469
- .append(`<div class="alert alert-${type} alert-dismissible fade show ${
470
- spin ? "d-flex align-items-center" : ""
471
- }" role="alert">
466
+ .append(`<div class="alert alert-${type} alert-dismissible fade show ${spin ? "d-flex align-items-center" : ""
467
+ }" role="alert">
472
468
  ${txt}
473
- ${
474
- spin
475
- ? `<div class="spinner-border ms-auto" role="status" aria-hidden="true"></div>`
476
- : `<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
469
+ ${spin
470
+ ? `<div class="spinner-border ms-auto" role="status" aria-hidden="true"></div>`
471
+ : `<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
477
472
  </button>`
478
- }
473
+ }
479
474
  </div>`);
480
475
  }
481
476
 
@@ -492,9 +487,8 @@ function common_done(res, isWeb = true) {
492
487
  (isWeb ? location : parent.location).reload(); //TODO notify to cookie if reload or goto
493
488
  }
494
489
  if (res.download) {
495
- const dataurl = `data:${
496
- res.download.mimetype || "application/octet-stream"
497
- };base64,${res.download.blob}`;
490
+ const dataurl = `data:${res.download.mimetype || "application/octet-stream"
491
+ };base64,${res.download.blob}`;
498
492
  fetch(dataurl)
499
493
  .then((res) => res.blob())
500
494
  .then((blob) => {
@@ -515,6 +509,9 @@ function common_done(res, isWeb = true) {
515
509
  if (res.target === "_blank") window.open(res.goto, "_blank").focus();
516
510
  else window.location.href = res.goto;
517
511
  }
512
+ if (res.popup) {
513
+ ajax_modal(res.popup)
514
+ }
518
515
  }
519
516
 
520
517
  const repeaterCopyValuesToForm = (form, editor, noTriggerChange) => {
@@ -523,10 +520,11 @@ const repeaterCopyValuesToForm = (form, editor, noTriggerChange) => {
523
520
  const setVal = (k, ix, v) => {
524
521
  const $e = form.find(`input[name="${k}_${ix}"]`);
525
522
  if ($e.length) $e.val(v);
526
- else
527
- form.append(
528
- `<input type="hidden" data-repeater-ix="${ix}" name="${k}_${ix}" value="${v}"></input>`
529
- );
523
+ else {
524
+ const $ne = $(`<input type="hidden" data-repeater-ix="${ix}" name="${k}_${ix}"></input>`);
525
+ $ne.val(v);
526
+ form.append($ne);
527
+ }
530
528
  };
531
529
  vs.forEach((v, ix) => {
532
530
  Object.entries(v).forEach(([k, v]) => {
@@ -649,9 +647,9 @@ function room_older(viewname, room_id, btn) {
649
647
  function init_room(viewname, room_id) {
650
648
  const socket = parent?.config?.server_path
651
649
  ? io(parent.config.server_path, {
652
- query: `jwt=${localStorage.getItem("auth_jwt")}`,
653
- transports: ["websocket"],
654
- })
650
+ query: `jwt=${localStorage.getItem("auth_jwt")}`,
651
+ transports: ["websocket"],
652
+ })
655
653
  : io({ transports: ["websocket"] });
656
654
 
657
655
  socket.emit("join_room", [viewname, room_id]);
@@ -323,4 +323,27 @@ table.table-inner-grid, table.table-inner-grid th, table.table-inner-grid td {
323
323
 
324
324
  .CodeMirror {
325
325
  resize: vertical;
326
- }
326
+ }
327
+
328
+ /* copied from bootstrap and adjusted to show the arrow on the left */
329
+ .card .card-header-left-collapse[data-bs-toggle=collapse] {
330
+ text-decoration: none;
331
+ position: relative;
332
+ padding: 0.75rem 3.25rem 0.75rem 1.25rem;
333
+ }
334
+ .card .card-header-left-collapse[data-bs-toggle=collapse]::before {
335
+ position: absolute;
336
+ left: 0;
337
+ top: 0;
338
+ line-height: 51px;
339
+ font-weight: 900;
340
+ content: "\f107";
341
+ font-family: "Font Awesome 5 Free";
342
+ color: #d1d3e2;
343
+ }
344
+ .card .card-header-left-collapse[data-bs-toggle=collapse].collapsed {
345
+ border-radius: 0.35rem;
346
+ }
347
+ .card .card-header-left-collapse[data-bs-toggle=collapse].collapsed::before {
348
+ content: "\f105";
349
+ }
@@ -51,12 +51,19 @@ function removeQueryStringParameter(uri1, key) {
51
51
  return uri + hash;
52
52
  }
53
53
 
54
+ function get_current_state_url() {
55
+ let $modal = $("#scmodal");
56
+ if ($modal.length === 0 || !$modal.hasClass("show"))
57
+ return window.location.href;
58
+ else return $modal.prop("data-modal-state");
59
+ }
60
+
54
61
  function select_id(id) {
55
- pjax_to(updateQueryStringParameter(window.location.href, "id", id));
62
+ pjax_to(updateQueryStringParameter(get_current_state_url(), "id", id));
56
63
  }
57
64
 
58
65
  function set_state_field(key, value) {
59
- pjax_to(updateQueryStringParameter(window.location.href, key, value));
66
+ pjax_to(updateQueryStringParameter(get_current_state_url(), key, value));
60
67
  }
61
68
 
62
69
  function check_state_field(that) {
@@ -65,13 +72,13 @@ function check_state_field(that) {
65
72
  const value = that.value;
66
73
  var separator = window.location.href.indexOf("?") !== -1 ? "&" : "?";
67
74
  let dest;
68
- if (checked) dest = window.location.href + `${separator}${name}=${value}`;
69
- else dest = window.location.href.replace(`${name}=${value}`, "");
75
+ if (checked) dest = get_current_state_url() + `${separator}${name}=${value}`;
76
+ else dest = get_current_state_url().replace(`${name}=${value}`, "");
70
77
  pjax_to(dest.replace("&&", "&").replace("?&", "?"));
71
78
  }
72
79
 
73
80
  function set_state_fields(kvs) {
74
- var newhref = window.location.href;
81
+ var newhref = get_current_state_url();
75
82
  Object.entries(kvs).forEach((kv) => {
76
83
  if (kv[1].unset && kv[1].unset === true)
77
84
  newhref = removeQueryStringParameter(newhref, kv[0]);
@@ -80,7 +87,7 @@ function set_state_fields(kvs) {
80
87
  pjax_to(newhref.replace("&&", "&").replace("?&", "?"));
81
88
  }
82
89
  function unset_state_field(key) {
83
- pjax_to(removeQueryStringParameter(window.location.href, key));
90
+ pjax_to(removeQueryStringParameter(get_current_state_url(), key));
84
91
  }
85
92
 
86
93
  let loadPage = true;
@@ -93,7 +100,11 @@ $(function () {
93
100
  });
94
101
 
95
102
  function pjax_to(href) {
96
- if (!$("#page-inner-content").length) window.location.href = href;
103
+ let $modal = $("#scmodal");
104
+ const inModal = $modal.length && $modal.hasClass("show")
105
+ let $dest = inModal ? $("#scmodal .modal-body") : $("#page-inner-content");
106
+
107
+ if (!$dest.length) window.location.href = href;
97
108
  else {
98
109
  loadPage = false;
99
110
  $.ajax(href, {
@@ -101,18 +112,21 @@ function pjax_to(href) {
101
112
  pjaxpageload: "true",
102
113
  },
103
114
  success: function (res, textStatus, request) {
104
- window.history.pushState({ url: href }, "", href);
115
+ if (!inModal) window.history.pushState({ url: href }, "", href);
105
116
  setTimeout(() => {
106
117
  loadPage = true;
107
118
  }, 0);
108
- if (res.includes("<!--SCPT:")) {
119
+ if (!inModal && res.includes("<!--SCPT:")) {
109
120
  const start = res.indexOf("<!--SCPT:");
110
121
  const end = res.indexOf("-->", start);
111
122
  document.title = res.substring(start + 9, end);
112
123
  }
113
- $("#page-inner-content").html(res);
124
+ $dest.html(res);
114
125
  initialize_page();
115
126
  },
127
+ error: function (res) {
128
+ notifyAlert({ type: "danger", text: res.responseText });
129
+ }
116
130
  });
117
131
  }
118
132
  }
@@ -120,8 +134,24 @@ function pjax_to(href) {
120
134
  function href_to(href) {
121
135
  window.location.href = href;
122
136
  }
123
- function clear_state() {
124
- pjax_to(window.location.href.split("?")[0]);
137
+ function clear_state(omit_fields_str) {
138
+ let newUrl = get_current_state_url().split("?")[0]
139
+ const hash = get_current_state_url().split("#")[1]
140
+ if (omit_fields_str) {
141
+ const omit_fields = omit_fields_str.split(',').map(s => s.trim())
142
+ let qs = (get_current_state_url().split("?")[1] || "").split("#")[0]
143
+ let params = new URLSearchParams(qs);
144
+ newUrl = newUrl + '?'
145
+ omit_fields.forEach(f => {
146
+ if (params.get(f))
147
+ newUrl = updateQueryStringParameter(newUrl, f, params.get(f));
148
+ })
149
+
150
+ }
151
+ if (hash)
152
+ newUrl += '#' + hash;
153
+
154
+ pjax_to(newUrl);
125
155
  }
126
156
 
127
157
  function ajax_done(res) {
@@ -143,6 +173,8 @@ function view_post(viewname, route, data, onDone) {
143
173
  }).done(function (res) {
144
174
  if (onDone) onDone(res);
145
175
  ajax_done(res);
176
+ }).fail(function (res) {
177
+ notifyAlert({ type: "danger", text: res.responseText });
146
178
  });
147
179
  }
148
180
  var logged_errors = [];
@@ -208,11 +240,12 @@ function ajax_modal(url, opts = {}) {
208
240
  var title = request.getResponseHeader("Page-Title");
209
241
  if (title) $("#scmodal .modal-title").html(decodeURIComponent(title));
210
242
  $("#scmodal .modal-body").html(res);
243
+ $("#scmodal").prop("data-modal-state", url);
211
244
  new bootstrap.Modal($("#scmodal")).show();
212
245
  initialize_page();
213
- (opts.onOpen || function () {})(res);
246
+ (opts.onOpen || function () { })(res);
214
247
  $("#scmodal").on("hidden.bs.modal", function (e) {
215
- (opts.onClose || function () {})(res);
248
+ (opts.onClose || function () { })(res);
216
249
  $("body").css("overflow", "");
217
250
  });
218
251
  },
@@ -264,7 +297,7 @@ function applyViewConfig(e, url, k) {
264
297
  "CSRF-Token": _sc_globalCsrf,
265
298
  },
266
299
  data: JSON.stringify(cfg),
267
- error: function (request) {},
300
+ error: function (request) { },
268
301
  success: function (res) {
269
302
  k && k(res);
270
303
  },
@@ -444,16 +477,16 @@ Copyright (c) 2015 Jeff Green
444
477
  stateObject,
445
478
  document.title,
446
479
  window.location.pathname +
447
- window.location.search +
448
- $(this).attr("href")
480
+ window.location.search +
481
+ $(this).attr("href")
449
482
  );
450
483
  } else {
451
484
  window.history.replaceState(
452
485
  stateObject,
453
486
  document.title,
454
487
  window.location.pathname +
455
- window.location.search +
456
- $(this).attr("href")
488
+ window.location.search +
489
+ $(this).attr("href")
457
490
  );
458
491
  }
459
492
  });
@@ -466,3 +499,7 @@ Copyright (c) 2015 Jeff Green
466
499
  });
467
500
  };
468
501
  })(jQuery);
502
+
503
+ // Copyright (c) 2011 Marcus Ekwall, http://writeless.se/
504
+ // https://github.com/mekwall/jquery-throttle
505
+ (function (a) { var b = a.jQuery || a.me || (a.me = {}), i = function (e, f, g, h, c, a) { f || (f = 100); var d = !1, j = !1, i = typeof g === "function", l = function (a, b) { d = setTimeout(function () { d = !1; if (h || c) e.apply(a, b), c && (j = +new Date); i && g.apply(a, b) }, f) }, k = function () { if (!d || a) { if (!d && !h && (!c || +new Date - j > f)) e.apply(this, arguments), c && (j = +new Date); (a || !c) && clearTimeout(d); l(this, arguments) } }; if (b.guid) k.guid = e.guid = e.guid || b.guid++; return k }; b.throttle = i; b.debounce = function (a, b, g, h, c) { return i(a, b, g, h, c, !0) } })(this);
package/routes/actions.js CHANGED
@@ -8,6 +8,7 @@ const Router = require("express-promise-router");
8
8
  const { isAdmin, error_catcher, get_base_url } = require("./utils.js");
9
9
  const { getState } = require("@saltcorn/data/db/state");
10
10
  const Trigger = require("@saltcorn/data/models/trigger");
11
+ const { getTriggerList } = require("./common_lists");
11
12
 
12
13
  /**
13
14
  * @type {object}
@@ -97,45 +98,7 @@ router.get(
97
98
  type: "card",
98
99
  title: req.__("Triggers"),
99
100
  contents: div(
100
- mkTable(
101
- [
102
- { label: req.__("Name"), key: "name" },
103
- { label: req.__("Action"), key: "action" },
104
- {
105
- label: req.__("Table or Channel"),
106
- key: (r) => r.table_name || r.channel,
107
- },
108
- {
109
- label: req.__("When"),
110
- key: (a) =>
111
- a.when_trigger === "API call"
112
- ? `API: ${base_url}api/action/${a.name}`
113
- : a.when_trigger,
114
- },
115
- {
116
- label: req.__("Test run"),
117
- key: (r) =>
118
- r.table_id
119
- ? ""
120
- : link(`/actions/testrun/${r.id}`, req.__("Test run")),
121
- },
122
- {
123
- label: req.__("Edit"),
124
- key: (r) => link(`/actions/edit/${r.id}`, req.__("Edit")),
125
- },
126
- {
127
- label: req.__("Configure"),
128
- key: (r) =>
129
- link(`/actions/configure/${r.id}`, req.__("Configure")),
130
- },
131
- {
132
- label: req.__("Delete"),
133
- key: (r) => post_delete_btn(`/actions/delete/${r.id}`, req),
134
- },
135
- ],
136
- triggers,
137
- { hover: true }
138
- ),
101
+ getTriggerList(triggers, req),
139
102
  link("/actions/new", req.__("Add trigger"))
140
103
  ),
141
104
  },
package/routes/admin.js CHANGED
@@ -390,7 +390,7 @@ router.get(
390
390
  renderForm(backupForm, req.csrfToken()),
391
391
  a(
392
392
  { href: "/admin/auto-backup-list" },
393
- "Restore/download automated backups &raquo;"
393
+ req.__("Restore/download automated backups &raquo;")
394
394
  ),
395
395
  script(
396
396
  domReady(
@@ -406,13 +406,13 @@ router.get(
406
406
  contents: div(
407
407
  p(
408
408
  i(
409
- "Snapshots store your application structure and definition, without the table data. Individual views and pages can be restored from snapshots from the <a href='/viewedit'>view</a> or <a href='/pageedit'>pages</a> overviews (\"Restore\" from individual page or view dropdowns)."
409
+ req.__("Snapshots store your application structure and definition, without the table data. Individual views and pages can be restored from snapshots from the <a href='/viewedit'>view</a> or <a href='/pageedit'>pages</a> overviews (\"Restore\" from individual page or view dropdowns).")
410
410
  )
411
411
  ),
412
412
  renderForm(aSnapshotForm, req.csrfToken()),
413
413
  a(
414
414
  { href: "/admin/snapshot-list" },
415
- "List/download snapshots &raquo;"
415
+ req.__("List/download snapshots &raquo;")
416
416
  )
417
417
  ),
418
418
  },
@@ -472,16 +472,16 @@ router.get(
472
472
  title: req.__("Restoring automated backup"),
473
473
  contents: div(
474
474
  ol(
475
- li("Download one of the backups above"),
475
+ li(req.__("Download one of the backups above")),
476
476
  li(
477
- a({ href: "/admin/clear-all" }, "Clear this application"),
477
+ a({ href: "/admin/clear-all" }, req.__("Clear this application")),
478
478
  " ",
479
- "(tick all boxes)"
479
+ req.__("(tick all boxes)")
480
480
  ),
481
481
  li(
482
- "When prompted to create the first user, click the link to restore a backup"
482
+ req.__("When prompted to create the first user, click the link to restore a backup")
483
483
  ),
484
- li("Select the downloaded backup file")
484
+ li(req.__("Select the downloaded backup file"))
485
485
  )
486
486
  ),
487
487
  },
@@ -551,7 +551,7 @@ router.get(
551
551
  mkTable(
552
552
  [
553
553
  {
554
- label: "When",
554
+ label: req.__("When"),
555
555
  key: (r) =>
556
556
  `${localeDateTime(r.created)} (${moment(r.created).fromNow()})`,
557
557
  },
@@ -618,7 +618,7 @@ const autoBackupForm = (req) =>
618
618
  noSubmitButton: true,
619
619
  additionalButtons: [
620
620
  {
621
- label: "Backup now",
621
+ label: req.__("Backup now"),
622
622
  id: "btnBackupNow",
623
623
  class: "btn btn-outline-secondary",
624
624
  onclick: "ajax_post('/admin/auto-backup-now')",
@@ -671,7 +671,7 @@ const snapshotForm = (req) =>
671
671
  noSubmitButton: true,
672
672
  additionalButtons: [
673
673
  {
674
- label: "Snapshot now",
674
+ label: req.__("Snapshot now"),
675
675
  id: "btnSnapNow",
676
676
  class: "btn btn-outline-secondary",
677
677
  onclick: "ajax_post('/admin/snapshot-now')",
@@ -808,7 +808,6 @@ router.get(
808
808
  " ",
809
809
  req.__("Configuration check")
810
810
  ),
811
-
812
811
  hr(),
813
812
 
814
813
  a(
@@ -945,7 +944,7 @@ router.post(
945
944
  });
946
945
  child.on("exit", function (code, signal) {
947
946
  res.end(
948
- `Upgrade done (if it was available) with code ${code}.\n\nPress the BACK button in your browser, then RELOAD the page.`
947
+ req.__(`Upgrade done (if it was available) with code ${code}.\n\nPress the BACK button in your browser, then RELOAD the page.`)
949
948
  );
950
949
  setTimeout(() => {
951
950
  if (process.send) process.send("RestartServer");
@@ -1193,7 +1192,7 @@ router.get(
1193
1192
  })
1194
1193
  );
1195
1194
  /**
1196
- * /confiuration-check
1195
+ * /configuration-check
1197
1196
  */
1198
1197
  router.get(
1199
1198
  "/configuration-check",
@@ -1576,7 +1575,7 @@ router.post(
1576
1575
  {
1577
1576
  type: "card",
1578
1577
  title: req.__("Build Result"),
1579
- contents: div("The build was successfully"),
1578
+ contents: div(req.__("The build was successfully")),
1580
1579
  },
1581
1580
  files.length > 0 ? app_files_table(files, req) : "",
1582
1581
  ],
@@ -1588,7 +1587,7 @@ router.post(
1588
1587
  type: "card",
1589
1588
  title: req.__("Build Result"),
1590
1589
  contents: div(
1591
- "Unable to build the app:",
1590
+ req.__("Unable to build the app:"),
1592
1591
  pre(code(childOutputs.join("<br/>")))
1593
1592
  ),
1594
1593
  },
@@ -1604,7 +1603,7 @@ router.post(
1604
1603
  type: "card",
1605
1604
  title: req.__("Build Result"),
1606
1605
  contents: div(
1607
- p("Unable to build the app:"),
1606
+ p(req.__("Unable to build the app:")),
1608
1607
  pre(code(message)),
1609
1608
  pre(code(stack))
1610
1609
  ),
package/routes/api.js CHANGED
@@ -71,8 +71,8 @@ function accessAllowedRead(req, user, table) {
71
71
  req.user && req.user.id
72
72
  ? req.user.role_id
73
73
  : user && user.role_id
74
- ? user.role_id
75
- : 10;
74
+ ? user.role_id
75
+ : 10;
76
76
 
77
77
  return role <= table.min_role_read;
78
78
  }
@@ -89,8 +89,8 @@ function accessAllowedWrite(req, user, table) {
89
89
  req.user && req.user.id
90
90
  ? req.user.role_id
91
91
  : user && user.role_id
92
- ? user.role_id
93
- : 10;
92
+ ? user.role_id
93
+ : 10;
94
94
 
95
95
  return role <= table.min_role_write;
96
96
  }
@@ -106,8 +106,8 @@ function accessAllowed(req, user, trigger) {
106
106
  req.user && req.user.id
107
107
  ? req.user.role_id
108
108
  : user && user.role_id
109
- ? user.role_id
110
- : 10;
109
+ ? user.role_id
110
+ : 10;
111
111
 
112
112
  return role <= trigger.min_role;
113
113
  }
@@ -247,6 +247,7 @@ router.get(
247
247
  fields: tbl_fields,
248
248
  approximate: !!approximate,
249
249
  state: req_query,
250
+ table
250
251
  });
251
252
  rows = await table.getRows(qstate);
252
253
  } else {