@saltcorn/server 1.0.0-beta.14 → 1.0.0-beta.15

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/load_plugins.js CHANGED
@@ -173,7 +173,7 @@ const loadAllPlugins = async (force) => {
173
173
  }
174
174
  }
175
175
  await getState().refreshUserLayouts();
176
- await getState().refresh(true);
176
+ await getState().refresh(true, true);
177
177
  if (!isRoot()) reloadAuthFromRoot();
178
178
  };
179
179
 
package/locales/en.json CHANGED
@@ -1472,5 +1472,6 @@
1472
1472
  "Minimum user role required to create a new tenant<div class=\"alert alert-danger fst-normal\" role=\"alert\" data-show-if=\"showIfFormulaInputs($('select[name=role_to_create_tenant]'), '+role_to_create_tenant>1')\">Giving non-trusted users access to create tenants is a security risk and not recommended.</div>": "Minimum user role required to create a new tenant<div class=\"alert alert-danger fst-normal\" role=\"alert\" data-show-if=\"showIfFormulaInputs($('select[name=role_to_create_tenant]'), '+role_to_create_tenant>1')\">Giving non-trusted users access to create tenants is a security risk and not recommended.</div>",
1473
1473
  "Select tag": "Select tag",
1474
1474
  "Invalid build directory path": "Invalid build directory path",
1475
- "Invalid build directory name": "Invalid build directory name"
1476
- }
1475
+ "Invalid build directory name": "Invalid build directory name",
1476
+ "clean node_modules": "clean node_modules"
1477
+ }
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@saltcorn/server",
3
- "version": "1.0.0-beta.14",
3
+ "version": "1.0.0-beta.15",
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.14",
11
- "@saltcorn/builder": "1.0.0-beta.14",
12
- "@saltcorn/data": "1.0.0-beta.14",
13
- "@saltcorn/admin-models": "1.0.0-beta.14",
14
- "@saltcorn/filemanager": "1.0.0-beta.14",
15
- "@saltcorn/markup": "1.0.0-beta.14",
16
- "@saltcorn/plugins-loader": "1.0.0-beta.14",
17
- "@saltcorn/sbadmin2": "1.0.0-beta.14",
10
+ "@saltcorn/base-plugin": "1.0.0-beta.15",
11
+ "@saltcorn/builder": "1.0.0-beta.15",
12
+ "@saltcorn/data": "1.0.0-beta.15",
13
+ "@saltcorn/admin-models": "1.0.0-beta.15",
14
+ "@saltcorn/filemanager": "1.0.0-beta.15",
15
+ "@saltcorn/markup": "1.0.0-beta.15",
16
+ "@saltcorn/plugins-loader": "1.0.0-beta.15",
17
+ "@saltcorn/sbadmin2": "1.0.0-beta.15",
18
18
  "@socket.io/cluster-adapter": "^0.2.1",
19
19
  "@socket.io/sticky": "^1.0.1",
20
20
  "adm-zip": "0.5.10",
@@ -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);
@@ -225,8 +225,10 @@ function ajax_done(res, viewname) {
225
225
  function spin_action_link(e) {
226
226
  const $e = $(e);
227
227
  const width = $e.width();
228
+ const height = $e.height();
229
+
228
230
  $e.attr("data-innerhtml-prespin", $e.html());
229
- $e.html('<i class="fas fa-spinner fa-spin"></i>').width(width);
231
+ $e.html('<i class="fas fa-spinner fa-spin"></i>').width(width).height(height);
230
232
  }
231
233
 
232
234
  function reset_spinners() {
@@ -870,7 +872,7 @@ function build_mobile_app(button) {
870
872
 
871
873
  if (
872
874
  params.useDocker &&
873
- !cordovaBuilderAvailable &&
875
+ !window.cordovaBuilderAvailable &&
874
876
  !confirm(
875
877
  "Docker is selected but the Cordova builder seems not to be installed. " +
876
878
  "Do you really want to continue?"
@@ -878,6 +880,21 @@ function build_mobile_app(button) {
878
880
  ) {
879
881
  return;
880
882
  }
883
+
884
+ const notSupportedPlugins = params.includedPlugins.filter(
885
+ (plugin) => !window.pluginsReadyForMobile.includes(plugin)
886
+ );
887
+ if (
888
+ notSupportedPlugins.length > 0 &&
889
+ !confirm(
890
+ `It seems that the plugins '${notSupportedPlugins.join(
891
+ ", "
892
+ )}' are not ready for mobile. Do you really want to continue?`
893
+ )
894
+ ) {
895
+ return;
896
+ }
897
+
881
898
  ajax_post("/admin/build-mobile-app", {
882
899
  data: params,
883
900
  success: (data) => {
@@ -949,8 +966,8 @@ function check_cordova_builder() {
949
966
  $.ajax("/admin/mobile-app/check-cordova-builder", {
950
967
  type: "GET",
951
968
  success: function (res) {
952
- cordovaBuilderAvailable = !!res.installed;
953
- if (cordovaBuilderAvailable) {
969
+ window.cordovaBuilderAvailable = !!res.installed;
970
+ if (window.cordovaBuilderAvailable) {
954
971
  $("#dockerBuilderStatusId").html(
955
972
  `<span>
956
973
  installed<i class="ps-2 fas fa-check text-success"></i>
@@ -1044,7 +1061,7 @@ function toggle_tbl_sync() {
1044
1061
  function toggle_android_platform() {
1045
1062
  if ($("#androidCheckboxId")[0].checked === true) {
1046
1063
  $("#dockerCheckboxId").attr("hidden", false);
1047
- $("#dockerCheckboxId").attr("checked", cordovaBuilderAvailable);
1064
+ $("#dockerCheckboxId").attr("checked", window.cordovaBuilderAvailable);
1048
1065
  $("#dockerLabelId").removeClass("d-none");
1049
1066
  } else {
1050
1067
  $("#dockerCheckboxId").attr("hidden", true);
package/routes/actions.js CHANGED
@@ -154,10 +154,12 @@ const triggerForm = async (req, trigger) => {
154
154
  .filter(([k, v]) => v.hasChannel)
155
155
  .map(([k, v]) => k);
156
156
 
157
- const allActions = Trigger.action_options(false);
157
+ const allActions = Trigger.action_options({ notRequireRow: false });
158
158
  const table_triggers = ["Insert", "Update", "Delete", "Validate"];
159
159
  const action_options = {};
160
- const actionsNotRequiringRow = Trigger.action_options(true);
160
+ const actionsNotRequiringRow = Trigger.action_options({
161
+ notRequireRow: true,
162
+ });
161
163
 
162
164
  Trigger.when_options.forEach((t) => {
163
165
  if (table_triggers.includes(t)) action_options[t] = allActions;
package/routes/admin.js CHANGED
@@ -1281,6 +1281,7 @@ router.get(
1281
1281
  throw new Error(req.__("Unable to fetch versions"));
1282
1282
  const versions = Object.keys(pkgInfo.versions);
1283
1283
  if (versions.length === 0) throw new Error(req.__("No versions found"));
1284
+ const tags = pkgInfo["dist-tags"] || {};
1284
1285
  res.set("Page-Title", req.__("%s versions", "Saltcorn"));
1285
1286
  let selected = packagejson.version;
1286
1287
  res.send(
@@ -1290,6 +1291,7 @@ router.get(
1290
1291
  method: "post",
1291
1292
  },
1292
1293
  input({ type: "hidden", name: "_csrf", value: req.csrfToken() }),
1294
+ // version select
1293
1295
  div(
1294
1296
  { class: "form-group" },
1295
1297
  label(
@@ -1315,6 +1317,37 @@ router.get(
1315
1317
  )
1316
1318
  )
1317
1319
  ),
1320
+ // tag select
1321
+ div(
1322
+ { class: "form-group" },
1323
+ label(
1324
+ {
1325
+ for: "tag_select",
1326
+ class: "form-label fw-bold",
1327
+ },
1328
+ req.__("Tags")
1329
+ ),
1330
+ select(
1331
+ {
1332
+ id: "tag_select",
1333
+ class: "form-control form-select",
1334
+ },
1335
+ option({
1336
+ id: "empty_opt",
1337
+ value: "",
1338
+ label: req.__("Select tag"),
1339
+ selected: true,
1340
+ }),
1341
+ Object.keys(tags).map((tag) =>
1342
+ option({
1343
+ id: `${tag}_opt`,
1344
+ value: tags[tag],
1345
+ label: `${tag} (${tags[tag]})`,
1346
+ })
1347
+ )
1348
+ )
1349
+ ),
1350
+ // deep clean checkbox
1318
1351
  div(
1319
1352
  { class: "form-group" },
1320
1353
  input({
@@ -1351,7 +1384,18 @@ router.get(
1351
1384
  req.__("Install")
1352
1385
  )
1353
1386
  )
1354
- )
1387
+ ) +
1388
+ script(
1389
+ domReady(`
1390
+ document.getElementById('tag_select').addEventListener('change', () => {
1391
+ const version = document.getElementById('tag_select').value;
1392
+ if (version) document.getElementById('version_select').value = version;
1393
+ });
1394
+ document.getElementById('version_select').addEventListener('change', () => {
1395
+ document.getElementById('tag_select').value = '';
1396
+ });
1397
+ `)
1398
+ )
1355
1399
  );
1356
1400
  } catch (error) {
1357
1401
  getState().log(
@@ -1780,8 +1824,8 @@ router.get(
1780
1824
  });
1781
1825
  })
1782
1826
  );
1783
- const buildDialogScript = (cordovaBuilderAvailable) => {
1784
- return `<script>
1827
+ const buildDialogScript = (cordovaBuilderAvailable) =>
1828
+ `<script>
1785
1829
  var cordovaBuilderAvailable = ${cordovaBuilderAvailable};
1786
1830
  function showEntrySelect(type) {
1787
1831
  for( const currentType of ["view", "page", "pagegroup"]) {
@@ -1807,7 +1851,6 @@ const buildDialogScript = (cordovaBuilderAvailable) => {
1807
1851
  notifyAlert("Building the app, please wait.", true)
1808
1852
  }
1809
1853
  </script>`;
1810
- };
1811
1854
 
1812
1855
  const imageAvailable = async () => {
1813
1856
  try {
@@ -1865,6 +1908,9 @@ router.get(
1865
1908
  const plugins = (await Plugin.find()).filter(
1866
1909
  (plugin) => ["base", "sbadmin2"].indexOf(plugin.name) < 0
1867
1910
  );
1911
+ const pluginsReadyForMobile = plugins
1912
+ .filter((plugin) => plugin.ready_for_mobile())
1913
+ .map((plugin) => plugin.name);
1868
1914
  const builderSettings =
1869
1915
  getState().getConfig("mobile_builder_settings") || {};
1870
1916
  const dockerAvailable = await imageAvailable();
@@ -1879,6 +1925,11 @@ router.get(
1879
1925
  {
1880
1926
  headerTag: buildDialogScript(dockerAvailable),
1881
1927
  },
1928
+ {
1929
+ headerTag: `<script>var pluginsReadyForMobile = ${JSON.stringify(
1930
+ pluginsReadyForMobile
1931
+ )}</script>`,
1932
+ },
1882
1933
  ],
1883
1934
  contents: {
1884
1935
  above: [
package/routes/menu.js CHANGED
@@ -269,6 +269,9 @@ const menuForm = async (req) => {
269
269
  name: "icon",
270
270
  class: "item-menu",
271
271
  input_type: "hidden",
272
+ showIf: {
273
+ type: ["View", "Page", "Page Group", "Link", "Header", "Action"],
274
+ },
272
275
  },
273
276
  {
274
277
  name: "tooltip",
@@ -183,6 +183,12 @@ const pageBuilderData = async (req, context) => {
183
183
  });
184
184
  }
185
185
  }
186
+ const actionsNotRequiringRow = Trigger.action_options({
187
+ notRequireRow: true,
188
+ apiNeverTriggers: true,
189
+ builtInLabel: "Page Actions",
190
+ builtIns: ["GoBack"],
191
+ });
186
192
  const library = (await Library.find({})).filter((l) => l.suitableFor("page"));
187
193
  const fixed_state_fields = {};
188
194
  for (const view of views) {
@@ -228,7 +234,7 @@ const pageBuilderData = async (req, context) => {
228
234
  images,
229
235
  pages,
230
236
  page_groups,
231
- actions,
237
+ actions: actionsNotRequiringRow,
232
238
  builtInActions: ["GoBack"],
233
239
  library,
234
240
  min_role: context.min_role,
package/routes/tables.js CHANGED
@@ -670,7 +670,10 @@ router.get(
670
670
  * @param {string} lbl
671
671
  * @returns {string}
672
672
  */
673
- const badge = (col, lbl) => `<span class="badge bg-${col}">${lbl}</span>&nbsp;`;
673
+ const badge = (col, lbl, title) =>
674
+ `<span ${
675
+ title ? `title="${title}" ` : ""
676
+ }class="badge bg-${col}">${lbl}</span>&nbsp;`;
674
677
 
675
678
  /**
676
679
  * @param {object} f
@@ -708,8 +711,11 @@ const attribBadges = (f) => {
708
711
  ].includes(k)
709
712
  )
710
713
  return;
711
- if(Array.isArray(v) && !v.length) return;
712
- if (v || v === 0) s += badge("secondary", k);
714
+ if (Array.isArray(v) && !v.length) return;
715
+ const title = ["string", "number", "boolean"].includes(typeof v)
716
+ ? `${v}`
717
+ : null;
718
+ if (v || v === 0) s += badge("secondary", k, title);
713
719
  });
714
720
  }
715
721
  return s;