@saltcorn/server 1.1.0-beta.1 → 1.1.0-beta.11

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/roleadmin.js CHANGED
@@ -56,7 +56,11 @@ const editRoleLayoutForm = (role, layouts, layout_by_role, req) => {
56
56
  },
57
57
  csrfField(req),
58
58
  select(
59
- { name: "layout", onchange: "form.submit()" },
59
+ {
60
+ name: "layout",
61
+ onchange: "form.submit()",
62
+ class: "form-select form-select-sm w-unset d-inline",
63
+ },
60
64
  layouts.map((layout, ix) =>
61
65
  option(
62
66
  {
@@ -88,7 +92,11 @@ const editRole2FAPolicyForm = (role, twofa_policy_by_role, req) =>
88
92
  },
89
93
  csrfField(req),
90
94
  select(
91
- { name: "policy", onchange: "form.submit()" },
95
+ {
96
+ name: "policy",
97
+ onchange: "form.submit()",
98
+ class: "form-select form-select-sm w-unset d-inline",
99
+ },
92
100
  ["Optional", "Disabled", "Mandatory"].map((p) =>
93
101
  option({ selected: twofa_policy_by_role[role.id] === p }, p)
94
102
  )
package/locales/en.json CHANGED
@@ -1493,5 +1493,6 @@
1493
1493
  "You must be logged in to share": "You must be logged in to share",
1494
1494
  "Fluid layout": "Fluid layout",
1495
1495
  "Request fluid layout from theme for a wider display for this page": "Request fluid layout from theme for a wider display for this page",
1496
- "Location of view to create new row": "Location of view to create new row"
1496
+ "Location of view to create new row": "Location of view to create new row",
1497
+ "Default locale": "Default locale"
1497
1498
  }
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@saltcorn/server",
3
- "version": "1.1.0-beta.1",
3
+ "version": "1.1.0-beta.11",
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.1.0-beta.1",
11
- "@saltcorn/builder": "1.1.0-beta.1",
12
- "@saltcorn/data": "1.1.0-beta.1",
13
- "@saltcorn/admin-models": "1.1.0-beta.1",
14
- "@saltcorn/filemanager": "1.1.0-beta.1",
15
- "@saltcorn/markup": "1.1.0-beta.1",
16
- "@saltcorn/plugins-loader": "1.1.0-beta.1",
17
- "@saltcorn/sbadmin2": "1.1.0-beta.1",
10
+ "@saltcorn/base-plugin": "1.1.0-beta.11",
11
+ "@saltcorn/builder": "1.1.0-beta.11",
12
+ "@saltcorn/data": "1.1.0-beta.11",
13
+ "@saltcorn/admin-models": "1.1.0-beta.11",
14
+ "@saltcorn/filemanager": "1.1.0-beta.11",
15
+ "@saltcorn/markup": "1.1.0-beta.11",
16
+ "@saltcorn/plugins-loader": "1.1.0-beta.11",
17
+ "@saltcorn/sbadmin2": "1.1.0-beta.11",
18
18
  "@socket.io/cluster-adapter": "^0.2.1",
19
19
  "@socket.io/sticky": "^1.0.1",
20
20
  "adm-zip": "0.5.10",
@@ -348,3 +348,36 @@ div.CodeMirror-dragcursors {
348
348
 
349
349
  /* Help users use markselection to safely style text background */
350
350
  span.CodeMirror-selectedtext { background: none; }
351
+
352
+ /* Port of TextMate's Blackboard theme */
353
+
354
+ .cm-s-blackboard.CodeMirror { background: #0C1021; color: #F8F8F8; }
355
+ .cm-s-blackboard div.CodeMirror-selected { background: #253B76; }
356
+ .cm-s-blackboard .CodeMirror-line::selection, .cm-s-blackboard .CodeMirror-line > span::selection, .cm-s-blackboard .CodeMirror-line > span > span::selection { background: rgba(37, 59, 118, .99); }
357
+ .cm-s-blackboard .CodeMirror-line::-moz-selection, .cm-s-blackboard .CodeMirror-line > span::-moz-selection, .cm-s-blackboard .CodeMirror-line > span > span::-moz-selection { background: rgba(37, 59, 118, .99); }
358
+ .cm-s-blackboard .CodeMirror-gutters { background: #0C1021; border-right: 0; }
359
+ .cm-s-blackboard .CodeMirror-guttermarker { color: #FBDE2D; }
360
+ .cm-s-blackboard .CodeMirror-guttermarker-subtle { color: #888; }
361
+ .cm-s-blackboard .CodeMirror-linenumber { color: #888; }
362
+ .cm-s-blackboard .CodeMirror-cursor { border-left: 1px solid #A7A7A7; }
363
+
364
+ .cm-s-blackboard .cm-keyword { color: #FBDE2D; }
365
+ .cm-s-blackboard .cm-atom { color: #D8FA3C; }
366
+ .cm-s-blackboard .cm-number { color: #D8FA3C; }
367
+ .cm-s-blackboard .cm-def { color: #8DA6CE; }
368
+ .cm-s-blackboard .cm-variable { color: #FF6400; }
369
+ .cm-s-blackboard .cm-operator { color: #FBDE2D; }
370
+ .cm-s-blackboard .cm-comment { color: #AEAEAE; }
371
+ .cm-s-blackboard .cm-string { color: #61CE3C; }
372
+ .cm-s-blackboard .cm-string-2 { color: #61CE3C; }
373
+ .cm-s-blackboard .cm-meta { color: #D8FA3C; }
374
+ .cm-s-blackboard .cm-builtin { color: #8DA6CE; }
375
+ .cm-s-blackboard .cm-tag { color: #8DA6CE; }
376
+ .cm-s-blackboard .cm-attribute { color: #8DA6CE; }
377
+ .cm-s-blackboard .cm-header { color: #FF6400; }
378
+ .cm-s-blackboard .cm-hr { color: #AEAEAE; }
379
+ .cm-s-blackboard .cm-link { color: #8DA6CE; }
380
+ .cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; }
381
+
382
+ .cm-s-blackboard .CodeMirror-activeline-background { background: #3C3636; }
383
+ .cm-s-blackboard .CodeMirror-matchingbracket { outline:1px solid grey;color:white !important; }
@@ -28,7 +28,7 @@ function flatpickerEditor(cell, onRendered, success, cancel, editorParams) {
28
28
  enableTime: !dayOnly,
29
29
  dateFormat: dayOnly ? "Y-m-d" : "Z",
30
30
  time_24hr: true,
31
- locale: "en", // global variable with locale 'en', 'fr', ...
31
+ locale: window._sc_locale || "en",
32
32
  defaultDate,
33
33
  onClose: function (selectedDates, dateStr, instance) {
34
34
  evt = window.event;
@@ -1064,11 +1064,12 @@ function initialize_page() {
1064
1064
  codes.forEach((el) => {
1065
1065
  //console.log($(el).attr("mode"), el);
1066
1066
  if ($(el).hasClass("codemirror-enabled")) return;
1067
-
1068
- const cm = CodeMirror.fromTextArea(el, {
1067
+ const cmOpts = {
1069
1068
  lineNumbers: true,
1070
1069
  mode: $(el).attr("mode"),
1071
- });
1070
+ };
1071
+ if (_sc_lightmode === "dark") cmOpts.theme = "blackboard";
1072
+ const cm = CodeMirror.fromTextArea(el, cmOpts);
1072
1073
  $(el).addClass("codemirror-enabled");
1073
1074
  cm.on(
1074
1075
  "change",
@@ -1550,7 +1551,7 @@ async function common_done(res, viewnameOrElem, isWeb = true) {
1550
1551
  });
1551
1552
  }
1552
1553
  if (res.eval_js) await handle(res.eval_js, eval_it);
1553
- else if (res.goto) {
1554
+ if (res.goto) {
1554
1555
  if (!isWeb) {
1555
1556
  const next = new URL(res.goto, "http://localhost");
1556
1557
  const pathname = next.pathname;
@@ -85,18 +85,15 @@ div[data-inline-edit-dest-url]:hover .editicon {
85
85
  border-left: none;
86
86
  border-color: #95a5a6;
87
87
  padding-left: 0.3rem;
88
- background-color: #ffffff;
89
88
  }
90
89
 
91
90
  .search-bar input[type="search"] {
92
91
  border-color: #95a5a6;
93
92
  padding-left: 0.3rem;
94
- background-color: #ffffff;
95
93
  }
96
94
 
97
95
  .search-bar button.search-bar {
98
96
  border-color: #95a5a6;
99
- background-color: #ffffff;
100
97
  border-left: 1px solid #95a5a6 !important;
101
98
  border-top: 1px solid #95a5a6 !important;
102
99
  border-bottom: 1px solid #95a5a6 !important;
@@ -358,7 +355,7 @@ table.table-inner-grid td {
358
355
  }
359
356
 
360
357
  .w-unset {
361
- width: unset;
358
+ width: unset !important;
362
359
  }
363
360
 
364
361
  .preview-text {
package/routes/admin.js CHANGED
@@ -155,6 +155,7 @@ admin_config_route({
155
155
  field_names: [
156
156
  "site_name",
157
157
  "timezone",
158
+ "default_locale",
158
159
  "base_url",
159
160
  ...(getConfigFile() ? ["multitenancy_enabled"] : []),
160
161
  { section_header: "Logo image" },
@@ -534,6 +535,7 @@ router.get(
534
535
  {},
535
536
  { orderBy: "created", orderDesc: true, fields: ["id", "created", "hash"] }
536
537
  );
538
+ const locale = getState().getConfig("default_locale", "en");
537
539
  send_admin_page({
538
540
  res,
539
541
  req,
@@ -555,9 +557,11 @@ router.get(
555
557
  )}`,
556
558
  target: "_blank",
557
559
  },
558
- `${localeDateTime(snap.created)} (${moment(
559
- snap.created
560
- ).fromNow()})`
560
+ `${localeDateTime(
561
+ snap.created,
562
+ {},
563
+ locale
564
+ )} (${moment(snap.created).fromNow()})`
561
565
  )
562
566
  )
563
567
  )
@@ -595,6 +599,7 @@ router.get(
595
599
  error_catcher(async (req, res) => {
596
600
  const { type, name } = req.params;
597
601
  const snaps = await Snapshot.entity_history(type, name);
602
+ const locale = getState().getConfig("default_locale", "en");
598
603
  res.set("Page-Title", `Restore ${text(name)}`);
599
604
  res.send(
600
605
  mkTable(
@@ -602,7 +607,9 @@ router.get(
602
607
  {
603
608
  label: req.__("When"),
604
609
  key: (r) =>
605
- `${localeDateTime(r.created)} (${moment(r.created).fromNow()})`,
610
+ `${localeDateTime(r.created, {}, locale)} (${moment(
611
+ r.created
612
+ ).fromNow()})`,
606
613
  },
607
614
 
608
615
  {
@@ -1741,8 +1748,8 @@ router.post(
1741
1748
 
1742
1749
  let altname = await tenant_letsencrypt_name(subdomain);
1743
1750
 
1744
- if (!altname || domain) {
1745
- req.json({ error: "Set Base URL for both tenant and root first." });
1751
+ if (!altname || !domain) {
1752
+ res.json({ error: "Set Base URL for both tenant and root first." });
1746
1753
  return;
1747
1754
  }
1748
1755
 
@@ -1759,13 +1766,14 @@ router.post(
1759
1766
 
1760
1767
  await greenlock.sites.add({
1761
1768
  subject: altname,
1769
+ altnames: [altname],
1762
1770
  });
1763
1771
  // letsencrypt
1764
1772
  const tenant_letsencrypt_sites = getState().getConfig(
1765
1773
  "tenant_letsencrypt_sites",
1766
1774
  []
1767
1775
  );
1768
- await getState().setConfig(tenant_letsencrypt_sites, [
1776
+ await getState().setConfig("tenant_letsencrypt_sites", [
1769
1777
  altname,
1770
1778
  ...tenant_letsencrypt_sites,
1771
1779
  ]);
@@ -1775,12 +1783,10 @@ router.post(
1775
1783
  notify: "Certificate added, please restart server",
1776
1784
  });
1777
1785
  } catch (e) {
1778
- req.flash("error", e.message);
1779
- res.redirect("/useradmin/ssl");
1786
+ res.json({ error: e.message });
1780
1787
  }
1781
1788
  } else {
1782
- req.flash("error", req.__("Not possible for tenant"));
1783
- res.redirect("/useradmin/ssl");
1789
+ res.json({ error: req.__("Not possible for tenant") });
1784
1790
  }
1785
1791
  })
1786
1792
  );
@@ -1849,7 +1855,7 @@ router.post(
1849
1855
  "tenant_letsencrypt_sites",
1850
1856
  []
1851
1857
  );
1852
- await getState().setConfig(tenant_letsencrypt_sites, [
1858
+ await getState().setConfig("tenant_letsencrypt_sites", [
1853
1859
  ...altnames,
1854
1860
  ...tenant_letsencrypt_sites,
1855
1861
  ]);
@@ -424,6 +424,7 @@ router.get(
424
424
  error_catcher(async (req, res) => {
425
425
  const { id } = req.params;
426
426
  const ev = await EventLog.findOneWithUser(id);
427
+ const locale = getState().getConfig("default_locale", "en");
427
428
  send_events_page({
428
429
  res,
429
430
  req,
@@ -435,7 +436,10 @@ router.get(
435
436
  table(
436
437
  { class: "table eventlog" },
437
438
  tbody(
438
- tr(th(req.__("When")), td(localeDateTime(ev.occur_at))),
439
+ tr(
440
+ th(req.__("When")),
441
+ td(localeDateTime(ev.occur_at, {}, locale))
442
+ ),
439
443
  tr(th(req.__("Type")), td(ev.event_type)),
440
444
  tr(th(req.__("Channel")), td(ev.channel)),
441
445
  tr(th(req.__("User")), td(ev.email))
@@ -549,7 +549,14 @@ const no_views_logged_in = async (req, res) => {
549
549
  * @returns {Promise<boolean>}
550
550
  */
551
551
  const get_config_response = async (role_id, res, req) => {
552
- const wrap = async (contents, homeCfg, title, description, no_menu) => {
552
+ const wrap = async (
553
+ contents,
554
+ homeCfg,
555
+ title,
556
+ description,
557
+ no_menu,
558
+ requestFluidLayout
559
+ ) => {
553
560
  if (contents.html_file) await sendHtmlFile(req, res, contents.html_file);
554
561
  else
555
562
  res.sendWrap(
@@ -558,6 +565,7 @@ const get_config_response = async (role_id, res, req) => {
558
565
  description: description || "",
559
566
  bodyClass: "page_" + db.sqlsanitize(homeCfg),
560
567
  no_menu,
568
+ requestFluidLayout,
561
569
  },
562
570
  contents
563
571
  );
@@ -578,7 +586,8 @@ const get_config_response = async (role_id, res, req) => {
578
586
  homeCfg,
579
587
  db_page.title,
580
588
  db_page.description,
581
- db_page.attributes?.no_menu
589
+ db_page.attributes?.no_menu,
590
+ db_page.attributes?.request_fluid_layout
582
591
  );
583
592
  else {
584
593
  const group = PageGroup.findOne({ name: homeCfg });
@@ -592,7 +601,8 @@ const get_config_response = async (role_id, res, req) => {
592
601
  homeCfg,
593
602
  eligible.title,
594
603
  eligible.description,
595
- eligible.attributes?.no_menu
604
+ eligible.attributes?.no_menu,
605
+ eligible.attributes?.request_fluid_layout
596
606
  );
597
607
  } else wrap(req.__("%s has no eligible page", group.name), homeCfg);
598
608
  } else res.redirect(homeCfg);
package/routes/list.js CHANGED
@@ -26,6 +26,7 @@ const {
26
26
  const Table = require("@saltcorn/data/models/table");
27
27
  const { isAdmin, error_catcher } = require("./utils");
28
28
  const moment = require("moment");
29
+ const { getState } = require("@saltcorn/data/db/state");
29
30
 
30
31
  /**
31
32
  * @type {object}
@@ -270,6 +271,7 @@ router.get(
270
271
  res.sendWrap(
271
272
  {
272
273
  title: req.__(`%s data table`, table.name),
274
+ requestFluidLayout: true,
273
275
  headers: [
274
276
  //jsgrid - grid editor external component
275
277
  {
@@ -426,7 +428,13 @@ router.get(
426
428
  ),
427
429
  div({ id: "jsGridNotify" }),
428
430
 
429
- div({ id: "jsGrid" })
431
+ div({
432
+ id: "jsGrid",
433
+ class:
434
+ getState().getLightDarkMode(req.user) === "dark"
435
+ ? "table-dark"
436
+ : undefined,
437
+ })
430
438
  ),
431
439
  },
432
440
  ],
package/routes/tenant.js CHANGED
@@ -58,6 +58,7 @@ const {
58
58
  save_config_from_form,
59
59
  } = require("../markup/admin.js");
60
60
  const { getConfig } = require("@saltcorn/data/models/config");
61
+ const path = require("path");
61
62
  //const {quote} = require("@saltcorn/db-common");
62
63
  // todo add button backup / restore for particular tenant (available in admin tenants screens)
63
64
  //const {
@@ -318,7 +319,53 @@ router.post(
318
319
  if (hasTemplate) {
319
320
  new_url_create += "auth/create_first_user";
320
321
  }
321
-
322
+ const letsencrypt = getState().getConfig("letsencrypt", false);
323
+ if (letsencrypt) {
324
+ let altname = await tenant_letsencrypt_name(subdomain);
325
+ const tenant_letsencrypt_sites = getState().getConfig(
326
+ "tenant_letsencrypt_sites",
327
+ []
328
+ );
329
+ const has_cert = tenant_letsencrypt_sites.includes(altname);
330
+ if (!has_cert) {
331
+ const file_store = db.connectObj.file_store;
332
+ const admin_users = await User.find(
333
+ { role_id: 1 },
334
+ { orderBy: "id" }
335
+ );
336
+ // greenlock logic
337
+ const Greenlock = require("greenlock");
338
+ const greenlock = Greenlock.create({
339
+ packageRoot: path.resolve(__dirname, ".."),
340
+ configDir: path.join(file_store, "greenlock.d"),
341
+ maintainerEmail: admin_users[0].email,
342
+ });
343
+
344
+ await greenlock.sites.add({
345
+ subject: altname,
346
+ altnames: [altname],
347
+ });
348
+ // letsencrypt
349
+ const tenant_letsencrypt_sites = getState().getConfig(
350
+ "tenant_letsencrypt_sites",
351
+ []
352
+ );
353
+ await getState().setConfig("tenant_letsencrypt_sites", [
354
+ altname,
355
+ ...tenant_letsencrypt_sites,
356
+ ]);
357
+ if (req.user?.role_id === 1) {
358
+ req.flash(
359
+ "success",
360
+ req.__(
361
+ "Tenant created. Certificate will be acquired on first visit."
362
+ )
363
+ );
364
+ res.redirect("/tenant/list");
365
+ return;
366
+ }
367
+ }
368
+ }
322
369
  res.sendWrap(
323
370
  req.__("Create application"),
324
371
  div(
@@ -374,6 +421,7 @@ router.get(
374
421
  return;
375
422
  }
376
423
  const tens = await db.select("_sc_tenants");
424
+ const locale = getState().getConfig("default_locale", "en");
377
425
  send_infoarch_page({
378
426
  res,
379
427
  req,
@@ -400,7 +448,8 @@ router.get(
400
448
  },
401
449
  {
402
450
  label: req.__("Created"),
403
- key: (r) => (r.created ? localeDateTime(r.created) : ""),
451
+ key: (r) =>
452
+ r.created ? localeDateTime(r.created, {}, locale) : "",
404
453
  },
405
454
  {
406
455
  label: req.__("Information"),
@@ -628,7 +677,7 @@ router.get(
628
677
  []
629
678
  );
630
679
  const has_cert = tenant_letsencrypt_sites.includes(altname);
631
-
680
+
632
681
  // get list of files
633
682
  let files;
634
683
  await db.runWithTenant(subdomain, async () => {
@@ -161,10 +161,10 @@ describe("Stable versioning install", () => {
161
161
  name: "@christianhugoch/empty_sc_test_plugin",
162
162
  });
163
163
  expect(dbPlugin).not.toBe(null);
164
- expect(dbPlugin.version).toBe("0.0.1");
164
+ expect(dbPlugin.version).toBe("0.1.0");
165
165
  });
166
166
 
167
- it("installs a fixed version", async () => {
167
+ it("installs and upgrades a fixed version", async () => {
168
168
  const loadAndSaveNewPlugin = load_plugins.loadAndSaveNewPlugin;
169
169
  await loadAndSaveNewPlugin(
170
170
  new Plugin({
@@ -178,7 +178,7 @@ describe("Stable versioning install", () => {
178
178
  name: "@christianhugoch/empty_sc_test_plugin",
179
179
  });
180
180
  expect(dbPlugin).not.toBe(null);
181
- expect(dbPlugin.version).toBe("0.0.1");
181
+ expect(dbPlugin.version).toBe("0.1.0");
182
182
  });
183
183
 
184
184
  it("installs and downgrades a fixed version", async () => {
@@ -188,7 +188,7 @@ describe("Stable versioning install", () => {
188
188
  name: "@christianhugoch/empty_sc_test_plugin",
189
189
  location: "@christianhugoch/empty_sc_test_plugin",
190
190
  source: "npm",
191
- version: "0.0.6",
191
+ version: "0.2.0",
192
192
  }),
193
193
  true
194
194
  );
@@ -196,7 +196,7 @@ describe("Stable versioning install", () => {
196
196
  name: "@christianhugoch/empty_sc_test_plugin",
197
197
  });
198
198
  expect(dbPlugin).not.toBe(null);
199
- expect(dbPlugin.version).toBe("0.0.1");
199
+ expect(dbPlugin.version).toBe("0.1.0");
200
200
  });
201
201
  });
202
202
 
@@ -245,7 +245,7 @@ describe("Stable versioning upgrade", () => {
245
245
  expect(newPlugin.version).toBe("0.0.3");
246
246
  });
247
247
 
248
- it("upgrades to latest with downgrade", async () => {
248
+ it("upgrades to latest with downgrade to supported", async () => {
249
249
  const loadAndSaveNewPlugin = load_plugins.loadAndSaveNewPlugin;
250
250
  await loadAndSaveNewPlugin(
251
251
  new Plugin({
@@ -276,7 +276,7 @@ describe("Stable versioning upgrade", () => {
276
276
  name: "@christianhugoch/empty_sc_test_plugin",
277
277
  });
278
278
  expect(newPlugin).not.toBe(null);
279
- expect(newPlugin.version).toBe("0.0.1");
279
+ expect(newPlugin.version).toBe("0.1.0");
280
280
  });
281
281
 
282
282
  it("upgrades to fixed version", async () => {
@@ -313,7 +313,7 @@ describe("Stable versioning upgrade", () => {
313
313
  expect(newPlugin.version).toBe("0.0.3");
314
314
  });
315
315
 
316
- it("upgrades to fixed version with downgrade", async () => {
316
+ it("upgrades to fixed version with downgrade to supported", async () => {
317
317
  const loadAndSaveNewPlugin = load_plugins.loadAndSaveNewPlugin;
318
318
  await loadAndSaveNewPlugin(
319
319
  new Plugin({
@@ -336,7 +336,7 @@ describe("Stable versioning upgrade", () => {
336
336
  name: "@christianhugoch/empty_sc_test_plugin",
337
337
  location: "@christianhugoch/empty_sc_test_plugin",
338
338
  source: "npm",
339
- version: "0.0.6",
339
+ version: "0.2.0",
340
340
  }),
341
341
  true
342
342
  );
@@ -344,6 +344,6 @@ describe("Stable versioning upgrade", () => {
344
344
  name: "@christianhugoch/empty_sc_test_plugin",
345
345
  });
346
346
  expect(newPlugin).not.toBe(null);
347
- expect(newPlugin.version).toBe("0.0.1");
347
+ expect(newPlugin.version).toBe("0.1.0");
348
348
  });
349
349
  });
@@ -365,7 +365,7 @@ describe("Upgrade plugin to supported version", () => {
365
365
  expect(upgradedPlugin.version).toBe("0.0.3");
366
366
  });
367
367
 
368
- it("upgrades to the most current fixed version", async () => {
368
+ it("upgrades to latest as fixed version", async () => {
369
369
  const oldPlugin = await setupPluginVersion(
370
370
  "@christianhugoch/empty_sc_test_plugin_two",
371
371
  "0.0.1"
@@ -389,7 +389,7 @@ describe("Upgrade plugin to supported version", () => {
389
389
  expect(upgradedPlugin.version).toBe("0.0.3");
390
390
  });
391
391
 
392
- it("upgrades with a downgrade of the latest version", async () => {
392
+ it("upgrades with a downgrade of latest", async () => {
393
393
  const oldPlugin = await setupPluginVersion(
394
394
  "@christianhugoch/empty_sc_test_plugin",
395
395
  "0.0.1"
@@ -404,10 +404,10 @@ describe("Upgrade plugin to supported version", () => {
404
404
  const upgradedPlugin = await Plugin.findOne({
405
405
  name: "@christianhugoch/empty_sc_test_plugin",
406
406
  });
407
- expect(upgradedPlugin.version).toBe("0.0.1");
407
+ expect(upgradedPlugin.version).toBe("0.1.0");
408
408
  });
409
409
 
410
- it("upgrades with a downgrade of the most current fixed version", async () => {
410
+ it("upgrades with a downgrade of latest as fixed version", async () => {
411
411
  const oldPlugin = await setupPluginVersion(
412
412
  "@christianhugoch/empty_sc_test_plugin",
413
413
  "0.0.1"
@@ -421,13 +421,13 @@ describe("Upgrade plugin to supported version", () => {
421
421
  "@christianhugoch/empty_sc_test_plugin"
422
422
  )}`
423
423
  )
424
- .send("version=0.1.0")
424
+ .send("version=0.2.0")
425
425
  .set("Cookie", loginCookie)
426
426
  .expect(toRedirect("/plugins"));
427
427
  const upgradedPlugin = await Plugin.findOne({
428
428
  name: "@christianhugoch/empty_sc_test_plugin",
429
429
  });
430
- expect(upgradedPlugin.version).toBe("0.0.1");
430
+ expect(upgradedPlugin.version).toBe("0.1.0");
431
431
  });
432
432
  });
433
433
 
package/wrapper.js CHANGED
@@ -193,7 +193,9 @@ const get_headers = (req, version_tag, description, extras = []) => {
193
193
  state.logLevel
194
194
  }, _sc_globalCsrf = "${req.csrfToken()}", _sc_version_tag = "${version_tag}"${
195
195
  locale ? `, _sc_locale = "${locale}"` : ""
196
- };</script>`,
196
+ }, _sc_lightmode = ${JSON.stringify(
197
+ state.getLightDarkMode?.(req.user) || "light"
198
+ )};</script>`,
197
199
  },
198
200
  { css: `/static_assets/${version_tag}/saltcorn.css` },
199
201
  { script: `/static_assets/${version_tag}/saltcorn-common.js` },