@saltcorn/server 0.8.3 → 0.8.5-beta.0

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/locales/en.json CHANGED
@@ -1104,5 +1104,6 @@
1104
1104
  "Tag: %s": "Tag: %s",
1105
1105
  "Tag entry": "Tag entry",
1106
1106
  "Clear": "Clear",
1107
- "Restore a snapshot": "Restore a snapshot"
1107
+ "Restore a snapshot": "Restore a snapshot",
1108
+ "Snapshot restored": "Snapshot restored"
1108
1109
  }
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@saltcorn/server",
3
- "version": "0.8.3",
3
+ "version": "0.8.5-beta.0",
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.3",
10
- "@saltcorn/builder": "0.8.3",
11
- "@saltcorn/data": "0.8.3",
12
- "@saltcorn/admin-models": "0.8.3",
13
- "@saltcorn/filemanager": "0.8.3",
14
- "@saltcorn/markup": "0.8.3",
15
- "@saltcorn/sbadmin2": "0.8.3",
9
+ "@saltcorn/base-plugin": "0.8.5-beta.0",
10
+ "@saltcorn/builder": "0.8.5-beta.0",
11
+ "@saltcorn/data": "0.8.5-beta.0",
12
+ "@saltcorn/admin-models": "0.8.5-beta.0",
13
+ "@saltcorn/filemanager": "0.8.5-beta.0",
14
+ "@saltcorn/markup": "0.8.5-beta.0",
15
+ "@saltcorn/sbadmin2": "0.8.5-beta.0",
16
16
  "@socket.io/cluster-adapter": "^0.2.1",
17
17
  "@socket.io/sticky": "^1.0.1",
18
18
  "adm-zip": "0.5.10",
@@ -352,6 +352,20 @@ function rep_down(e) {
352
352
  apply_form_subset_record(theform, vals1);
353
353
  }
354
354
  }
355
+ //https://stackoverflow.com/a/4835406
356
+ function escapeHtml(text) {
357
+ var map = {
358
+ "&": "&",
359
+ "<": "&lt;",
360
+ ">": "&gt;",
361
+ '"': "&quot;",
362
+ "'": "&#039;",
363
+ };
364
+
365
+ return text.replace(/[&<>"']/g, function (m) {
366
+ return map[m];
367
+ });
368
+ }
355
369
 
356
370
  function reload_on_init() {
357
371
  localStorage.setItem("reload_on_init", true);
@@ -408,18 +422,60 @@ function initialize_page() {
408
422
  });
409
423
  $("[data-inline-edit-dest-url]").click(function () {
410
424
  var url = $(this).attr("data-inline-edit-dest-url");
411
- var current = $(this).children("span.current").html();
425
+ var current =
426
+ $(this).attr("data-inline-edit-current") ||
427
+ $(this).children("span.current").html();
412
428
  var key = $(this).attr("data-inline-edit-field") || "value";
413
429
  var ajax = !!$(this).attr("data-inline-edit-ajax");
414
- $(this).replaceWith(
415
- `<form method="post" action="${url}" ${
416
- ajax ? `onsubmit="inline_ajax_submit(event)"` : ""
417
- }>
430
+ var type = $(this).attr("data-inline-edit-type");
431
+ var is_key = type?.startsWith("Key:");
432
+ const opts = encodeURIComponent(
433
+ JSON.stringify({
434
+ url,
435
+ key,
436
+ ajax,
437
+ current,
438
+ current_label: $(this).attr("data-inline-edit-current-label"),
439
+ type,
440
+ is_key,
441
+ })
442
+ );
443
+ if (is_key) {
444
+ const [tblName, target] = type.replace("Key:", "").split(".");
445
+ $.ajax(`/api/${tblName}`).then((resp) => {
446
+ if (resp.success) {
447
+ const selopts = resp.success.map(
448
+ (r) =>
449
+ `<option ${current == r.id ? `selected ` : ``}value="${
450
+ r.id
451
+ }">${escapeHtml(r[target])}</option>`
452
+ );
453
+ $(this).replaceWith(
454
+ `<form method="post" action="${url}" ${
455
+ ajax ? `onsubmit="inline_ajax_submit(event, '${opts}')"` : ""
456
+ }>
457
+ <input type="hidden" name="_csrf" value="${_sc_globalCsrf}">
458
+ <select name="${key}" value="${current}">${selopts}
459
+ </select>
460
+ <button type="submit" class="btn btn-sm btn-primary">OK</button>
461
+ <button onclick="cancel_inline_edit(event, '${opts}')" type="button" class="btn btn-sm btn-danger"><i class="fas fa-times"></i></button>
462
+ </form>`
463
+ );
464
+ }
465
+ });
466
+ } else
467
+ $(this).replaceWith(
468
+ `<form method="post" action="${url}" ${
469
+ ajax ? `onsubmit="inline_ajax_submit(event, '${opts}')"` : ""
470
+ }>
418
471
  <input type="hidden" name="_csrf" value="${_sc_globalCsrf}">
419
- <input type="text" name="${key}" value="${current}">
472
+ <input type="${
473
+ type === "Integer" || type === "Float" ? "number" : "text"
474
+ }" name="${key}" value="${escapeHtml(current)}">
420
475
  <button type="submit" class="btn btn-sm btn-primary">OK</button>
476
+ <button onclick="cancel_inline_edit(event, '${opts}')" type="button" class="btn btn-sm btn-danger"><i class="fas fa-times"></i></button>
421
477
  </form>`
422
- );
478
+ );
423
479
  });
424
480
  function setExplainer(that) {
425
481
  var id = $(that).attr("id") + "_explainer";
@@ -531,10 +587,33 @@ function initialize_page() {
531
587
 
532
588
  $(initialize_page);
533
589
 
534
- function inline_ajax_submit(e) {
590
+ function cancel_inline_edit(e, opts1) {
591
+ var opts = JSON.parse(decodeURIComponent(opts1 || "") || "{}");
592
+ var form = $(e.target).closest("form");
593
+
594
+ form.replaceWith(`<div
595
+ data-inline-edit-field="${opts.key}"
596
+ ${opts.ajax ? `data-inline-edit-ajax="true"` : ""}
597
+ ${opts.type ? `data-inline-edit-type="${opts.type}"` : ""}
598
+ ${opts.current ? `data-inline-edit-current="${opts.current}"` : ""}
599
+ ${
600
+ opts.current_label
601
+ ? `data-inline-edit-current-label="${opts.current_label}"`
602
+ : ""
603
+ }
604
+ data-inline-edit-dest-url="${opts.url}">
605
+ <span class="current">${opts.current_label || opts.current}</span>
606
+ <i class="editicon fas fa-edit ms-1"></i>
607
+ </div>`);
608
+ initialize_page();
609
+ }
610
+
611
+ function inline_ajax_submit(e, opts1) {
612
+ var opts = JSON.parse(decodeURIComponent(opts1 || "") || "{}");
535
613
  e.preventDefault();
536
614
  var form = $(e.target).closest("form");
537
615
  var form_data = form.serialize();
616
+ var formDataArray = form.serializeArray();
538
617
  var url = form.attr("action");
539
618
  $.ajax(url, {
540
619
  type: "POST",
@@ -543,7 +622,24 @@ function inline_ajax_submit(e) {
543
622
  },
544
623
  data: form_data,
545
624
  success: function (res) {
546
- location.reload();
625
+ if (opts) {
626
+ let rawVal = formDataArray.find((f) => f.name == opts.key).value;
627
+ let val = opts.is_key
628
+ ? form.find("select").find("option:selected").text()
629
+ : rawVal;
630
+
631
+ $(e.target).replaceWith(`<div
632
+ data-inline-edit-field="${opts.key}"
633
+ ${opts.ajax ? `data-inline-edit-ajax="true"` : ""}
634
+ ${opts.type ? `data-inline-edit-type="${opts.type}"` : ""}
635
+ ${opts.current ? `data-inline-edit-current="${rawVal}"` : ""}
636
+ ${opts.current_label ? `data-inline-edit-current-label="${val}"` : ""}
637
+ data-inline-edit-dest-url="${opts.url}">
638
+ <span class="current">${val}</span>
639
+ <i class="editicon fas fa-edit ms-1"></i>
640
+ </div>`);
641
+ initialize_page();
642
+ } else location.reload();
547
643
  },
548
644
  error: function (e) {
549
645
  ajax_done(
package/routes/admin.js CHANGED
@@ -596,7 +596,6 @@ router.get(
596
596
  }.json`
597
597
  );
598
598
  readStream.pipe(res);
599
- res.send(snap.pack);
600
599
  })
601
600
  );
602
601
 
package/routes/api.js CHANGED
@@ -423,11 +423,20 @@ router.post(
423
423
  let hasErrors = false;
424
424
  Object.keys(row).forEach((k) => {
425
425
  const field = fields.find((f) => f.name === k);
426
- if (!field || field.calculated) {
426
+ if (!field && k.includes(".")) {
427
+ const [fnm, jkey] = k.split(".");
428
+ const jfield = fields.find((f) => f.name === fnm);
429
+ if (jfield?.type?.name === "JSON") {
430
+ if (!row[fnm]) row[fnm] = { [jkey]: row[k] };
431
+ else row[fnm][jkey] = row[k];
432
+ delete row[k];
433
+ }
434
+ } else if (!field || field.calculated) {
427
435
  delete row[k];
428
436
  return;
429
437
  }
430
- if (field.type && field.type.validate) {
438
+
439
+ if (field?.type && field.type.validate) {
431
440
  const vres = field.type.validate(field.attributes || {})(row[k]);
432
441
  if (vres.error) {
433
442
  hasErrors = true;