@saltcorn/server 0.8.8-beta.0 → 0.8.8-beta.2

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.8.8-beta.0",
3
+ "version": "0.8.8-beta.2",
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.8.8-beta.0",
10
- "@saltcorn/builder": "0.8.8-beta.0",
11
- "@saltcorn/data": "0.8.8-beta.0",
12
- "@saltcorn/admin-models": "0.8.8-beta.0",
13
- "@saltcorn/filemanager": "0.8.8-beta.0",
14
- "@saltcorn/markup": "0.8.8-beta.0",
15
- "@saltcorn/sbadmin2": "0.8.8-beta.0",
9
+ "@saltcorn/base-plugin": "0.8.8-beta.2",
10
+ "@saltcorn/builder": "0.8.8-beta.2",
11
+ "@saltcorn/data": "0.8.8-beta.2",
12
+ "@saltcorn/admin-models": "0.8.8-beta.2",
13
+ "@saltcorn/filemanager": "0.8.8-beta.2",
14
+ "@saltcorn/markup": "0.8.8-beta.2",
15
+ "@saltcorn/sbadmin2": "0.8.8-beta.2",
16
16
  "@socket.io/cluster-adapter": "^0.2.1",
17
17
  "@socket.io/sticky": "^1.0.1",
18
18
  "adm-zip": "0.5.10",
@@ -282,6 +282,10 @@ function ensure_modal_exists_and_closed() {
282
282
  </div>
283
283
  </div>`);
284
284
  } else if ($("#scmodal").hasClass("show")) {
285
+ // remove reload handler added by edit, for when we have popup link
286
+ // in autosave edit in popup
287
+ $("#scmodal").off("hidden.bs.modal");
288
+
285
289
  close_saltcorn_modal();
286
290
  }
287
291
  }
@@ -319,7 +323,9 @@ function ajax_modal(url, opts = {}) {
319
323
  if (title) $("#scmodal .modal-title").html(decodeURIComponent(title));
320
324
  $("#scmodal .modal-body").html(res);
321
325
  $("#scmodal").prop("data-modal-state", url);
322
- new bootstrap.Modal($("#scmodal")).show();
326
+ new bootstrap.Modal($("#scmodal"), {
327
+ focus: false,
328
+ }).show();
323
329
  initialize_page();
324
330
  (opts.onOpen || function () {})(res);
325
331
  $("#scmodal").on("hidden.bs.modal", function (e) {
@@ -669,6 +675,9 @@ function build_mobile_app(button) {
669
675
  form.serializeArray().forEach((item) => {
670
676
  params[item.name] = item.value;
671
677
  });
678
+ params.synchedTables = Array.from($("#synched-tbls-select-id")[0].options)
679
+ .filter((option) => !option.hidden)
680
+ .map((option) => option.value);
672
681
  ajax_post("/admin/build-mobile-app", {
673
682
  data: params,
674
683
  success: (data) => {
@@ -682,6 +691,40 @@ function build_mobile_app(button) {
682
691
  });
683
692
  }
684
693
 
694
+ function move_to_synched() {
695
+ const opts = $("#unsynched-tbls-select-id");
696
+ $("#synched-tbls-select-id").removeAttr("selected");
697
+ for (const selected of opts.val()) {
698
+ const jUnsOpt = $(`[id='${selected}_unsynched_opt']`);
699
+ jUnsOpt.attr("hidden", "true");
700
+ jUnsOpt.removeAttr("selected");
701
+ const jSynOpt = $(`[id='${selected}_synched_opt']`);
702
+ jSynOpt.removeAttr("hidden");
703
+ jSynOpt.removeAttr("selected");
704
+ }
705
+ }
706
+
707
+ function move_to_unsynched() {
708
+ const opts = $("#synched-tbls-select-id");
709
+ $("#unsynched-tbls-select-id").removeAttr("selected");
710
+ for (const selected of opts.val()) {
711
+ const jSynOpt = $(`[id='${selected}_synched_opt']`);
712
+ jSynOpt.attr("hidden", "true");
713
+ jSynOpt.removeAttr("selected");
714
+ const jUnsOpt = $(`[id='${selected}_unsynched_opt']`);
715
+ jUnsOpt.removeAttr("hidden");
716
+ jUnsOpt.removeAttr("selected");
717
+ }
718
+ }
719
+
720
+ function toggle_tbl_sync() {
721
+ if ($("#offlineModeBoxId")[0].checked === true) {
722
+ $("#tblSyncSelectorId").attr("hidden", false);
723
+ } else {
724
+ $("#tblSyncSelectorId").attr("hidden", true);
725
+ }
726
+ }
727
+
685
728
  function join_field_clicked(e, fieldPath) {
686
729
  $("#inputjoin_field").val(fieldPath);
687
730
  apply_showif();
package/routes/actions.js CHANGED
@@ -211,6 +211,7 @@ const triggerForm = async (req, trigger) => {
211
211
  name: "description",
212
212
  label: req.__("Description"),
213
213
  type: "String",
214
+ fieldview: "textarea",
214
215
  sublabel: req.__(
215
216
  "Description allows you to give more information about the action"
216
217
  ),
@@ -400,8 +401,8 @@ router.get(
400
401
  });
401
402
  form.values = trigger.configuration;
402
403
  const events = Trigger.when_options;
403
- const actions = await Trigger.find({
404
- when_trigger: { or: ["API call", "Never"] },
404
+ const actions = Trigger.find({
405
+ when_trigger: {or: ["API call", "Never"]},
405
406
  });
406
407
  const tables = (await Table.find({})).map((t) => ({
407
408
  name: t.name,
@@ -430,7 +431,7 @@ router.get(
430
431
  div(
431
432
  button(
432
433
  { class: "btn btn-primary mt-2", id: "blocklySave" },
433
- "Save"
434
+ req.__("Save")
434
435
  ),
435
436
  renderForm(form, req.csrfToken()),
436
437
  script(
package/routes/admin.js CHANGED
@@ -1491,7 +1491,7 @@ router.get(
1491
1491
  const images = (await File.find({ mime_super: "image" })).filter((image) =>
1492
1492
  image.filename?.endsWith(".png")
1493
1493
  );
1494
-
1494
+ const withSyncInfo = await Table.find({ has_sync_info: true });
1495
1495
  send_admin_page({
1496
1496
  res,
1497
1497
  req,
@@ -1752,7 +1752,6 @@ router.get(
1752
1752
  ),
1753
1753
 
1754
1754
  div(
1755
- // TODO only for some tables?
1756
1755
  { class: "row pb-2" },
1757
1756
  div(
1758
1757
  { class: "col-sm-4" },
@@ -1761,6 +1760,8 @@ router.get(
1761
1760
  id: "offlineModeBoxId",
1762
1761
  class: "form-check-input me-2",
1763
1762
  name: "allowOfflineMode",
1763
+ value: "allowOfflineMode",
1764
+ onClick: "toggle_tbl_sync()",
1764
1765
  checked: true,
1765
1766
  }),
1766
1767
  label(
@@ -1771,6 +1772,98 @@ router.get(
1771
1772
  req.__("Allow offline mode")
1772
1773
  )
1773
1774
  )
1775
+ ),
1776
+ div(
1777
+ {
1778
+ id: "tblSyncSelectorId",
1779
+ class: "row pb-2",
1780
+ },
1781
+ div(
1782
+ label(
1783
+ { class: "form-label fw-bold" },
1784
+ req.__("Table Synchronization")
1785
+ )
1786
+ ),
1787
+ div(
1788
+ { class: "container" },
1789
+ div(
1790
+ { class: "row" },
1791
+ div(
1792
+ { class: "col-sm-4 text-center" },
1793
+ req.__("unsynched")
1794
+ ),
1795
+ div({ class: "col-sm-1" }),
1796
+ div(
1797
+ { class: "col-sm-4 text-center" },
1798
+ req.__("synched")
1799
+ )
1800
+ ),
1801
+ div(
1802
+ { class: "row" },
1803
+ div(
1804
+ { class: "col-sm-4" },
1805
+ select(
1806
+ {
1807
+ id: "unsynched-tbls-select-id",
1808
+ class: "form-control form-select",
1809
+ multiple: true,
1810
+ },
1811
+ withSyncInfo.map((table) =>
1812
+ option({
1813
+ id: `${table.name}_unsynched_opt`,
1814
+ value: table.name,
1815
+ label: table.name,
1816
+ })
1817
+ )
1818
+ )
1819
+ ),
1820
+ div(
1821
+ { class: "col-sm-1 d-flex justify-content-center" },
1822
+ div(
1823
+ div(
1824
+ button(
1825
+ {
1826
+ id: "move-right-btn-id",
1827
+ type: "button",
1828
+ onClick: `move_to_synched()`,
1829
+ class: "btn btn-light pt-1 mb-1",
1830
+ },
1831
+ i({ class: "fas fa-arrow-right" })
1832
+ )
1833
+ ),
1834
+ div(
1835
+ button(
1836
+ {
1837
+ id: "move-left-btn-id",
1838
+ type: "button",
1839
+ onClick: `move_to_unsynched()`,
1840
+ class: "btn btn-light pt-1",
1841
+ },
1842
+ i({ class: "fas fa-arrow-left" })
1843
+ )
1844
+ )
1845
+ )
1846
+ ),
1847
+ div(
1848
+ { class: "col-sm-4" },
1849
+ select(
1850
+ {
1851
+ id: "synched-tbls-select-id",
1852
+ class: "form-control form-select",
1853
+ multiple: true,
1854
+ },
1855
+ withSyncInfo.map((table) =>
1856
+ option({
1857
+ id: `${table.name}_synched_opt`,
1858
+ value: table.name,
1859
+ label: table.name,
1860
+ hidden: "true",
1861
+ })
1862
+ )
1863
+ )
1864
+ )
1865
+ )
1866
+ )
1774
1867
  )
1775
1868
  ),
1776
1869
  button(
@@ -1877,6 +1970,7 @@ router.post(
1877
1970
  serverURL,
1878
1971
  splashPage,
1879
1972
  allowOfflineMode,
1973
+ synchedTables,
1880
1974
  } = req.body;
1881
1975
  if (!androidPlatform && !iOSPlatform) {
1882
1976
  return res.json({
@@ -1928,6 +2022,8 @@ router.post(
1928
2022
  if (serverURL) spawnParams.push("-s", serverURL);
1929
2023
  if (splashPage) spawnParams.push("--splashPage", splashPage);
1930
2024
  if (allowOfflineMode) spawnParams.push("--allowOfflineMode");
2025
+ if (synchedTables?.length > 0)
2026
+ spawnParams.push("--synchedTables", ...synchedTables.map((tbl) => tbl));
1931
2027
  if (
1932
2028
  db.is_it_multi_tenant() &&
1933
2029
  db.getTenantSchema() !== db.connectObj.default_schema
package/routes/fields.js CHANGED
@@ -542,14 +542,6 @@ const fieldFlow = (req) =>
542
542
  type: "Bool",
543
543
  showIf: { summary_field: textfields },
544
544
  }),
545
- /*new Field({
546
- name: "on_delete_cascade",
547
- label: req.__("On delete cascade"),
548
- type: "Bool",
549
- sublabel: req.__(
550
- "If the parent row is deleted, automatically delete the child rows."
551
- ),
552
- }),*/
553
545
  new Field({
554
546
  name: "on_delete",
555
547
  label: req.__("On delete"),
@@ -1063,7 +1055,11 @@ router.post(
1063
1055
  res.send("");
1064
1056
  return;
1065
1057
  }
1066
- const firefox = /firefox/i.test(req.headers["user-agent"]);
1058
+ //const firefox = /firefox/i.test(req.headers["user-agent"]);
1059
+
1060
+ //Chrome 116 changes its behaviour to align with firefox
1061
+ // - disabled inputs do not dispactch click events
1062
+ const firefox = true;
1067
1063
  const fv = fieldviews[fieldview];
1068
1064
  if (!fv && field.type === "Key" && fieldview === "select")
1069
1065
  res.send(
package/routes/menu.js CHANGED
@@ -69,8 +69,8 @@ const menuForm = async (req) => {
69
69
  .filter(([k, v]) => !v.requireRow && !v.disableInBuilder)
70
70
  .map(([k, v]) => k),
71
71
  ];
72
- const triggers = await Trigger.find({
73
- when_trigger: { or: ["API call", "Never"] },
72
+ const triggers = Trigger.find({
73
+ when_trigger: {or: ["API call", "Never"]},
74
74
  });
75
75
  triggers.forEach((tr) => {
76
76
  actions.push(tr.name);
@@ -148,6 +148,13 @@ const menuForm = async (req) => {
148
148
  input_type: "select",
149
149
  options: roles.map((r) => ({ label: r.role, value: r.id })),
150
150
  },
151
+ {
152
+ name: "disable_on_mobile",
153
+ label: req.__("Disable on mobile"),
154
+ type: "Bool",
155
+ class: "item-menu",
156
+ required: false,
157
+ },
151
158
  {
152
159
  name: "url",
153
160
  label: req.__("URL"),
@@ -264,18 +271,18 @@ const menuForm = async (req) => {
264
271
  },
265
272
  attributes: {
266
273
  options: [
267
- { name: "", label: "Link" },
268
- { name: "btn btn-primary", label: "Primary button" },
269
- { name: "btn btn-secondary", label: "Secondary button" },
270
- { name: "btn btn-success", label: "Success button" },
271
- { name: "btn btn-danger", label: "Danger button" },
274
+ { name: "", label: req.__("Link") },
275
+ { name: "btn btn-primary", label: req.__("Primary button") },
276
+ { name: "btn btn-secondary", label: req.__("Secondary button") },
277
+ { name: "btn btn-success", label: req.__("Success button") },
278
+ { name: "btn btn-danger", label: req.__("Danger button") },
272
279
  {
273
280
  name: "btn btn-outline-primary",
274
- label: "Primary outline button",
281
+ label: req.__("Primary outline button"),
275
282
  },
276
283
  {
277
284
  name: "btn btn-outline-secondary",
278
- label: "Secondary outline button",
285
+ label: req.__("Secondary outline button"),
279
286
  },
280
287
  ],
281
288
  },
package/routes/scapi.js CHANGED
@@ -101,7 +101,7 @@ router.get(
101
101
  { session: false },
102
102
  async function (err, user, info) {
103
103
  if (accessAllowedRead(req, user)) {
104
- const views = await View.find({});
104
+ const views = await View.find({}, { cached: true });
105
105
 
106
106
  res.json({ success: views });
107
107
  } else {