@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/auth/admin.js +9 -5
- package/auth/routes.js +16 -6
- package/errors.js +51 -48
- package/locales/en.json +29 -1
- package/locales/it.json +2 -1
- package/locales/ru.json +42 -6
- package/locales/zh.json +1 -1
- package/markup/admin.js +4 -3
- package/markup/plugin-store.js +5 -5
- package/package.json +7 -7
- package/public/jquery-menu-editor.min.js +1 -1
- package/public/saltcorn-builder.css +75 -0
- package/public/saltcorn-common.js +26 -10
- package/public/saltcorn.css +4 -0
- package/public/saltcorn.js +5 -1
- package/routes/admin.js +387 -96
- package/routes/api.js +9 -1
- package/routes/eventlog.js +24 -22
- package/routes/fields.js +11 -13
- package/routes/files.js +5 -5
- package/routes/homepage.js +60 -60
- package/routes/infoarch.js +6 -3
- package/routes/menu.js +65 -4
- package/routes/packs.js +4 -4
- package/routes/page.js +5 -1
- package/routes/pageedit.js +9 -1
- package/routes/plugins.js +187 -123
- package/routes/search.js +4 -2
- package/routes/settings.js +3 -3
- package/routes/tables.js +191 -190
- package/routes/tenant.js +31 -29
- package/routes/utils.js +4 -0
- package/routes/view.js +18 -1
- package/routes/viewedit.js +78 -70
- package/serve.js +54 -38
- package/tests/admin.test.js +1 -1
- package/tests/api.test.js +17 -0
- package/tests/clientjs.test.js +11 -1
- package/tests/plugins.test.js +1 -1
- package/tests/viewedit.test.js +1 -1
- package/wrapper.js +57 -55
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.__("
|
|
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
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
105
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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.__("
|
|
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
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
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
|
-
|
|
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("
|
|
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 "
|
|
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> ' + req.__("Refresh")
|
|
452
452
|
),
|
|
453
453
|
db.getTenantSchema() === db.connectObj.default_schema &&
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
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> ' +
|
|
461
|
+
req.__("Upgrade installed modules")
|
|
462
|
+
),
|
|
463
463
|
db.getTenantSchema() === db.connectObj.default_schema &&
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
464
|
+
a(
|
|
465
|
+
{
|
|
466
|
+
class: "dropdown-item",
|
|
467
|
+
href: `/plugins/new`,
|
|
468
|
+
},
|
|
469
|
+
'<i class="fas fa-plus"></i> ' + 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.__("
|
|
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.__("
|
|
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
|
-
|
|
568
|
-
|
|
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
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
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.__("
|
|
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
|
|
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
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
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
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
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
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
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.__("
|
|
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
|
|
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.__(`
|
|
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
|
-
|
|
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,
|
package/routes/settings.js
CHANGED
|
@@ -63,9 +63,9 @@ router.get(
|
|
|
63
63
|
href: "/admin",
|
|
64
64
|
}),
|
|
65
65
|
settingsCard({
|
|
66
|
-
title: req.__("
|
|
67
|
-
icon: "fas fa-
|
|
68
|
-
blurb: req.__("
|
|
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({
|