@saltcorn/server 0.7.3-beta.7 → 0.7.4-beta.1

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/routes/plugins.js CHANGED
@@ -79,7 +79,7 @@ const pluginForm = (req, plugin) => {
79
79
  label: req.__("Name"),
80
80
  name: "name",
81
81
  input_type: "text",
82
- sublabel: req.__("Plugin name"),
82
+ sublabel: req.__("Module name"),
83
83
  }),
84
84
  new Field({
85
85
  label: req.__("Source"),
@@ -88,11 +88,11 @@ const pluginForm = (req, plugin) => {
88
88
  required: true,
89
89
  attributes: { options: "npm,local,github,git" },
90
90
  sublabel: req.__(
91
- "Source of plugin for install. Few options:" +
92
- "npm - download from npm repository," +
93
- "local - get from local file system," +
94
- "github - download from github," +
95
- "git - get from git"
91
+ "Source of module for install. Few options:" +
92
+ "npm - download from npm repository," +
93
+ "local - get from local file system," +
94
+ "github - download from github," +
95
+ "git - get from git"
96
96
  ),
97
97
  }),
98
98
  new Field({
@@ -101,19 +101,19 @@ const pluginForm = (req, plugin) => {
101
101
  input_type: "text",
102
102
  sublabel: req.__(
103
103
  "For npm - name of npm package, e.g. @saltcorn/html or saltcorn-gantt, check at npmjs.com, " +
104
- "for local - absolute path to plugin folder in file system, e.g.C:\\gitsrc\\any-bootstrap-theme\\, " +
105
- "for github - name of github project."
104
+ "for local - absolute path to module folder in file system, e.g. C:\\gitsrc\\any-bootstrap-theme\\, " +
105
+ "for github - name of github project."
106
106
  ),
107
107
  }),
108
108
  ...(schema === db.connectObj.default_schema
109
109
  ? [
110
- new Field({
111
- label: req.__("Version"),
112
- name: "version",
113
- input_type: "text",
114
- sublabel: req.__("Version of plugin, latest is default value"),
115
- }),
116
- ]
110
+ new Field({
111
+ label: req.__("Version"),
112
+ name: "version",
113
+ input_type: "text",
114
+ sublabel: req.__("Version of module, latest is default value"),
115
+ }),
116
+ ]
117
117
  : []),
118
118
  new Field({
119
119
  label: req.__("Private SSH key"),
@@ -257,7 +257,7 @@ const store_item_html = (req) => (item) => ({
257
257
  title: item.name,
258
258
  contents: div(
259
259
  div(
260
- item.plugin && badge(req.__("Plugin")),
260
+ item.plugin && badge(req.__("Module")),
261
261
  item.pack && badge(req.__("Pack")),
262
262
  item.has_theme && badge(req.__("Theme")),
263
263
  item.has_auth && badge(req.__("Authentication")),
@@ -269,72 +269,72 @@ const store_item_html = (req) => (item) => ({
269
269
  div(item.description || ""),
270
270
  item.documentation_link
271
271
  ? div(
272
- a(
273
- { href: item.documentation_link, target: "_blank" },
274
- req.__("Documentation")
275
- )
272
+ a(
273
+ { href: item.documentation_link, target: "_blank" },
274
+ req.__("Documentation")
276
275
  )
276
+ )
277
277
  : ""
278
278
  ),
279
279
  footer: div(
280
280
  div(
281
281
  !item.installed &&
282
- item.plugin &&
283
- post_btn(
284
- `/plugins/install/${encodeURIComponent(item.name)}`,
285
- req.__("Install"),
286
- req.csrfToken(),
287
- {
288
- klass: "store-install",
289
- small: true,
290
- onClick: "press_store_button(this)",
291
- }
292
- ),
282
+ item.plugin &&
283
+ post_btn(
284
+ `/plugins/install/${encodeURIComponent(item.name)}`,
285
+ req.__("Install"),
286
+ req.csrfToken(),
287
+ {
288
+ klass: "store-install",
289
+ small: true,
290
+ onClick: "press_store_button(this)",
291
+ }
292
+ ),
293
293
  !item.installed &&
294
- item.pack &&
295
- post_btn(
296
- `/packs/install-named/${encodeURIComponent(item.name)}`,
297
- req.__("Install"),
298
- req.csrfToken(),
299
- {
300
- klass: "store-install",
301
- small: true,
302
- onClick: "press_store_button(this)",
303
- }
304
- ),
294
+ item.pack &&
295
+ post_btn(
296
+ `/packs/install-named/${encodeURIComponent(item.name)}`,
297
+ req.__("Install"),
298
+ req.csrfToken(),
299
+ {
300
+ klass: "store-install",
301
+ small: true,
302
+ onClick: "press_store_button(this)",
303
+ }
304
+ ),
305
305
 
306
306
  item.installed && item.plugin && cfg_link(req, item),
307
307
  item.installed && item.plugin && info_link(req, item),
308
308
 
309
309
  item.installed &&
310
- item.pack &&
311
- post_btn(
312
- `/packs/uninstall/${encodeURIComponent(item.name)}`,
313
- req.__("Uninstall"),
314
- req.csrfToken(),
315
- {
316
- klass: "store-install",
317
- small: true,
318
- btnClass: "btn-danger",
319
- formClass: "d-inline",
320
- onClick: "press_store_button(this)",
321
- }
322
- ),
310
+ item.pack &&
311
+ post_btn(
312
+ `/packs/uninstall/${encodeURIComponent(item.name)}`,
313
+ req.__("Uninstall"),
314
+ req.csrfToken(),
315
+ {
316
+ klass: "store-install",
317
+ small: true,
318
+ btnClass: "btn-danger",
319
+ formClass: "d-inline",
320
+ onClick: "press_store_button(this)",
321
+ }
322
+ ),
323
323
  item.installed &&
324
- item.plugin &&
325
- item.name !== "base" &&
326
- post_btn(
327
- `/plugins/delete/${encodeURIComponent(item.name)}`,
328
- req.__("Remove"),
329
- req.csrfToken(),
330
- {
331
- klass: "store-install",
332
- small: true,
333
- btnClass: "btn-danger",
334
- formClass: "d-inline",
335
- onClick: "press_store_button(this)",
336
- }
337
- )
324
+ item.plugin &&
325
+ item.name !== "base" &&
326
+ post_btn(
327
+ `/plugins/delete/${encodeURIComponent(item.name)}`,
328
+ req.__("Remove"),
329
+ req.csrfToken(),
330
+ {
331
+ klass: "store-install",
332
+ small: true,
333
+ btnClass: "btn-danger",
334
+ formClass: "d-inline",
335
+ onClick: "press_store_button(this)",
336
+ }
337
+ )
338
338
  )
339
339
  ),
340
340
  });
@@ -354,7 +354,7 @@ const storeNavPills = (req) => {
354
354
  "nav-link",
355
355
  (req.query.set === txt.toLowerCase() ||
356
356
  (txt === "All" && !req.query.set)) &&
357
- "active",
357
+ "active",
358
358
  ],
359
359
  },
360
360
  req.__(txt)
@@ -363,7 +363,7 @@ const storeNavPills = (req) => {
363
363
  return ul(
364
364
  { class: "nav nav-pills plugin-section" },
365
365
  link("All"),
366
- link("Plugins"),
366
+ link("Modules"),
367
367
  link("Packs"),
368
368
  link("Themes"),
369
369
  link("Installed")
@@ -407,7 +407,7 @@ const satisfy_q = (p, q) => {
407
407
  */
408
408
  const filter_items_set = (items, query) => {
409
409
  switch (query.set) {
410
- case "plugins":
410
+ case "modules":
411
411
  return items.filter((item) => item.plugin && !item.has_theme);
412
412
  case "packs":
413
413
  return items.filter((item) => item.pack);
@@ -451,23 +451,23 @@ const store_actions_dropdown = (req) =>
451
451
  '<i class="fas fa-sync"></i>&nbsp;' + req.__("Refresh")
452
452
  ),
453
453
  db.getTenantSchema() === db.connectObj.default_schema &&
454
- a(
455
- {
456
- class: "dropdown-item",
457
- href: `/plugins/upgrade`,
458
- onClick: `notifyAlert('Upgrading plugins...', true)`,
459
- },
460
- '<i class="far fa-arrow-alt-circle-up"></i>&nbsp;' +
461
- req.__("Upgrade installed plugins")
462
- ),
454
+ a(
455
+ {
456
+ class: "dropdown-item",
457
+ href: `/plugins/upgrade`,
458
+ onClick: `notifyAlert('Upgrading modules...', true)`,
459
+ },
460
+ '<i class="far fa-arrow-alt-circle-up"></i>&nbsp;' +
461
+ req.__("Upgrade installed modules")
462
+ ),
463
463
  db.getTenantSchema() === db.connectObj.default_schema &&
464
- a(
465
- {
466
- class: "dropdown-item",
467
- href: `/plugins/new`,
468
- },
469
- '<i class="fas fa-plus"></i>&nbsp;' + req.__("Add another plugin")
470
- ),
464
+ a(
465
+ {
466
+ class: "dropdown-item",
467
+ href: `/plugins/new`,
468
+ },
469
+ '<i class="fas fa-plus"></i>&nbsp;' + req.__("Add another module")
470
+ ),
471
471
 
472
472
  a(
473
473
  {
@@ -501,7 +501,7 @@ const plugin_store_html = (items, req) => {
501
501
  type: "breadcrumbs",
502
502
  crumbs: [
503
503
  { text: req.__("Settings"), href: "/settings" },
504
- { text: req.__("Plugin and pack store") },
504
+ { text: req.__("Module store") },
505
505
  ],
506
506
  },
507
507
  {
@@ -534,7 +534,7 @@ router.get(
534
534
  error_catcher(async (req, res) => {
535
535
  const items = await get_store_items();
536
536
  const relevant_items = filter_items(items, req.query);
537
- res.sendWrap(req.__("Plugins"), plugin_store_html(relevant_items, req));
537
+ res.sendWrap(req.__("Module store"), plugin_store_html(relevant_items, req));
538
538
  })
539
539
  );
540
540
 
@@ -561,12 +561,29 @@ router.get(
561
561
  }
562
562
  const flow = module.configuration_workflow();
563
563
  flow.action = `/plugins/configure/${encodeURIComponent(plugin.name)}`;
564
+ flow.autoSave = true;
565
+ flow.saveURL = `/plugins/saveconfig/${encodeURIComponent(plugin.name)}`;
564
566
  const wfres = await flow.run(plugin.configuration || {});
567
+ if (module.layout) {
568
+ wfres.renderForm.additionalButtons = [
569
+ ...(wfres.renderForm.additionalButtons || []),
570
+ {
571
+ label: "Reload page to see changes",
572
+ id: "btnReloadNow",
573
+ class: "btn btn-outline-secondary",
574
+ onclick: "location.reload()",
575
+ },
576
+ ];
577
+ wfres.renderForm.onChange = `${wfres.renderForm.onChange || ""
578
+ };$('#btnReloadNow').removeClass('btn-outline-secondary').addClass('btn-secondary')`;
579
+ }
565
580
 
566
- res.sendWrap(
567
- req.__(`Configure %s Plugin`, plugin.name),
568
- renderForm(wfres.renderForm, req.csrfToken())
569
- );
581
+ res.sendWrap(req.__(`Configure %s Plugin`, plugin.name), {
582
+ type: "card",
583
+ class: "mt-0",
584
+ title: req.__(`Configure %s Plugin`, plugin.name),
585
+ contents: renderForm(wfres.renderForm, req.csrfToken()),
586
+ });
570
587
  })
571
588
  );
572
589
 
@@ -588,13 +605,30 @@ router.post(
588
605
  }
589
606
  const flow = module.configuration_workflow();
590
607
  flow.action = `/plugins/configure/${encodeURIComponent(plugin.name)}`;
608
+ flow.autoSave = true;
609
+ flow.saveURL = `/plugins/saveconfig/${encodeURIComponent(plugin.name)}`;
591
610
  const wfres = await flow.run(req.body);
592
- if (wfres.renderForm)
593
- res.sendWrap(
594
- req.__(`Configure %s Plugin`, plugin.name),
595
- renderForm(wfres.renderForm, req.csrfToken())
596
- );
597
- else {
611
+ if (wfres.renderForm) {
612
+ if (module.layout) {
613
+ wfres.renderForm.additionalButtons = [
614
+ ...(wfres.renderForm.additionalButtons || []),
615
+ {
616
+ label: "Reload page to see changes",
617
+ id: "btnReloadNow",
618
+ class: "btn btn-outline-secondary",
619
+ onclick: "location.reload()",
620
+ },
621
+ ];
622
+ wfres.renderForm.onChange = `${wfres.renderForm.onChange || ""
623
+ };$('#btnReloadNow').removeClass('btn-outline-secondary').addClass('btn-secondary')`;
624
+ }
625
+ res.sendWrap(req.__(`Configure %s Plugin`, plugin.name), {
626
+ type: "card",
627
+ class: "mt-0",
628
+ title: req.__(`Configure %s Plugin`, plugin.name),
629
+ contents: renderForm(wfres.renderForm, req.csrfToken()),
630
+ });
631
+ } else {
598
632
  plugin.configuration = wfres;
599
633
  await plugin.upsert();
600
634
  await load_plugins.loadPlugin(plugin);
@@ -606,12 +640,42 @@ router.post(
606
640
  refresh_plugin_cfg: plugin.name,
607
641
  tenant: db.getTenantSchema(),
608
642
  });
609
- await sleep(500); // Allow other workers to reload this plugin
643
+ if (module.layout) await sleep(500); // Allow other workers to reload this plugin
610
644
  res.redirect("/plugins");
611
645
  }
612
646
  })
613
647
  );
614
648
 
649
+ router.post(
650
+ "/saveconfig/:name",
651
+ isAdmin,
652
+ error_catcher(async (req, res) => {
653
+ const { name } = req.params;
654
+ const plugin = await Plugin.findOne({ name: decodeURIComponent(name) });
655
+ let module = getState().plugins[plugin.name];
656
+ if (!module) {
657
+ module = getState().plugins[getState().plugin_module_names[plugin.name]];
658
+ }
659
+ const flow = module.configuration_workflow();
660
+ const step = await flow.singleStepForm(req.body, req);
661
+ if (step?.renderForm) {
662
+ if (!step.renderForm.hasErrors) {
663
+ plugin.configuration = {
664
+ ...plugin.configuration,
665
+ ...step.renderForm.values,
666
+ };
667
+ await plugin.upsert();
668
+ await load_plugins.loadPlugin(plugin);
669
+ process.send &&
670
+ process.send({
671
+ refresh_plugin_cfg: plugin.name,
672
+ tenant: db.getTenantSchema(),
673
+ });
674
+ res.json({ success: "ok" });
675
+ }
676
+ }
677
+ })
678
+ );
615
679
  /**
616
680
  * @name get/new
617
681
  * @function
@@ -628,13 +692,13 @@ router.get(
628
692
  type: "breadcrumbs",
629
693
  crumbs: [
630
694
  { text: req.__("Settings"), href: "/settings" },
631
- { text: req.__("Plugin and pack store"), href: "/plugins" },
695
+ { text: req.__("Module store"), href: "/plugins" },
632
696
  { text: req.__("New") },
633
697
  ],
634
698
  },
635
699
  {
636
700
  type: "card",
637
- title: req.__(`Add plugin`),
701
+ title: req.__(`Add module`),
638
702
  contents: renderForm(pluginForm(req), req.csrfToken()),
639
703
  },
640
704
  ],
@@ -742,35 +806,35 @@ router.get(
742
806
  latest || "",
743
807
  can_update
744
808
  ? a(
745
- {
746
- href: `/plugins/upgrade-plugin/${plugin_db.name}`,
747
- class: "btn btn-primary btn-sm ms-2",
748
- },
749
- req.__("Upgrade")
750
- )
809
+ {
810
+ href: `/plugins/upgrade-plugin/${plugin_db.name}`,
811
+ class: "btn btn-primary btn-sm ms-2",
812
+ },
813
+ req.__("Upgrade")
814
+ )
751
815
  : ""
752
816
  )
753
817
  ),
754
818
  mod.plugin_module.dependencies
755
819
  ? tr(
756
- th(req.__("Plugin dependencies")),
757
- td(
758
- mod.plugin_module.dependencies.map((d) =>
759
- span({ class: "badge bg-primary me-1" }, d)
760
- )
820
+ th(req.__("Plugin dependencies")),
821
+ td(
822
+ mod.plugin_module.dependencies.map((d) =>
823
+ span({ class: "badge bg-primary me-1" }, d)
761
824
  )
762
825
  )
826
+ )
763
827
  : null,
764
828
  store_item && store_item.documentation_link
765
829
  ? tr(
766
- th(req.__("Documentation")),
767
- td(
768
- link(
769
- store_item.documentation_link,
770
- store_item.documentation_link
771
- )
830
+ th(req.__("Documentation")),
831
+ td(
832
+ link(
833
+ store_item.documentation_link,
834
+ store_item.documentation_link
772
835
  )
773
836
  )
837
+ )
774
838
  : null,
775
839
  pkgjson && pkgjson.repository
776
840
  ? tr(th(req.__("Repository")), td(showRepository(pkgjson.repository)))
@@ -795,13 +859,13 @@ router.get(
795
859
  type: "breadcrumbs",
796
860
  crumbs: [
797
861
  { text: req.__("Settings"), href: "/settings" },
798
- { text: req.__("Plugin and pack store"), href: "/plugins" },
862
+ { text: req.__("Module store"), href: "/plugins" },
799
863
  { text: plugin_db.name },
800
864
  ],
801
865
  },
802
866
  {
803
867
  type: "card",
804
- title: req.__(`%s plugin information`, plugin_db.name),
868
+ title: req.__(`%s module information`, plugin_db.name),
805
869
  contents: p(store_item.description) + infoTable,
806
870
  },
807
871
  ...cards,
@@ -847,7 +911,7 @@ router.get(
847
911
  for (const plugin of installed_plugins) {
848
912
  await plugin.upgrade_version((p, f) => load_plugins.loadPlugin(p, f));
849
913
  }
850
- req.flash("success", req.__(`Plugins up-to-date`));
914
+ req.flash("success", req.__(`Modules up-to-date`));
851
915
  await restart_tenant(loadAllPlugins);
852
916
  process.send &&
853
917
  process.send({ restart_tenant: true, tenant: db.getTenantSchema() });
package/routes/search.js CHANGED
@@ -55,7 +55,8 @@ const searchConfigForm = (tables, views, req) => {
55
55
  );
56
56
  return new Form({
57
57
  action: "/search/config",
58
- submitLabel: req.__("Save"),
58
+ noSubmitButton: true,
59
+ onChange: `saveAndContinue(this)`,
59
60
  blurb:
60
61
  blurb1 +
61
62
  (tbls_noviews.length > 0
@@ -111,7 +112,8 @@ router.post(
111
112
 
112
113
  if (result.success) {
113
114
  await getState().setConfig("globalSearch", result.success);
114
- res.redirect("/search/config");
115
+ if (!req.xhr) res.redirect("/search/config");
116
+ else res.json({ success: "ok" });
115
117
  } else {
116
118
  send_infoarch_page({
117
119
  res,
@@ -63,9 +63,9 @@ router.get(
63
63
  href: "/admin",
64
64
  }),
65
65
  settingsCard({
66
- title: req.__("Plugins"),
67
- icon: "fas fa-plug",
68
- blurb: req.__("Plugin and pack installation and control"),
66
+ title: req.__("Modules"),
67
+ icon: "fas fa-cubes",
68
+ blurb: req.__("Module installation and control"),
69
69
  href: "/plugins",
70
70
  }),
71
71
  settingsCard({