@saltcorn/server 0.7.1-beta.3 → 0.7.2-beta.2

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.
@@ -70,10 +70,12 @@ function apply_showif() {
70
70
 
71
71
  var options = data[1][val];
72
72
  var current = e.attr("data-selected");
73
- //console.log(val, options, current,data)
73
+ //console.log({ val, options, current, data });
74
74
  e.empty();
75
75
  (options || []).forEach((o) => {
76
- if (!(o && o.label && o.value)) {
76
+ if (
77
+ !(o && typeof o.label !== "undefined" && typeof o.value !== "undefined")
78
+ ) {
77
79
  if (`${current}` === `${o}`)
78
80
  e.append($("<option selected>" + o + "</option>"));
79
81
  else e.append($("<option>" + o + "</option>"));
@@ -219,6 +221,9 @@ if (localStorage.getItem("reload_on_init")) {
219
221
  location.reload();
220
222
  }
221
223
  function initialize_page() {
224
+ $(".blur-on-enter-keypress").bind("keyup", function (e) {
225
+ if (e.keyCode === 13) e.target.blur();
226
+ });
222
227
  $("form").change(apply_showif);
223
228
  apply_showif();
224
229
  apply_showif();
@@ -310,6 +315,34 @@ function initialize_page() {
310
315
  });
311
316
  $('a[data-bs-toggle="tab"].deeplink').historyTabs();
312
317
  init_bs5_dropdowns();
318
+
319
+ // Initialize Sliders - https://stackoverflow.com/a/31083391
320
+ var sliderSections = document.getElementsByClassName("range-slider");
321
+ for (var x = 0; x < sliderSections.length; x++) {
322
+ var sliders = sliderSections[x].getElementsByTagName("input");
323
+ for (var y = 0; y < sliders.length; y++) {
324
+ if (sliders[y].type === "range") {
325
+ sliders[y].oninput = function () {
326
+ // Get slider values
327
+ var parent = this.parentNode;
328
+ var slides = parent.getElementsByTagName("input");
329
+ var slide1 = parseFloat(slides[0].value);
330
+ var slide2 = parseFloat(slides[1].value);
331
+ // Neither slider will clip the other, so make sure we determine which is larger
332
+ if (slide1 > slide2) {
333
+ var tmp = slide2;
334
+ slide2 = slide1;
335
+ slide1 = tmp;
336
+ }
337
+
338
+ var displayElement = parent.getElementsByClassName("rangeValues")[0];
339
+ displayElement.innerHTML = slide1 + " - " + slide2;
340
+ };
341
+ // Manually trigger event first time to display values
342
+ sliders[y].oninput();
343
+ }
344
+ }
345
+ }
313
346
  }
314
347
 
315
348
  $(initialize_page);
@@ -459,57 +492,8 @@ function tristateClick(nm) {
459
492
  }
460
493
  }
461
494
 
462
- function notifyAlert(note, spin) {
463
- if (Array.isArray(note)) {
464
- note.forEach(notifyAlert);
465
- return;
466
- }
467
- var txt, type;
468
- if (typeof note == "string") {
469
- txt = note;
470
- type = "info";
471
- } else {
472
- txt = note.text;
473
- type = note.type;
474
- }
475
-
476
- $("#alerts-area")
477
- .append(`<div class="alert alert-${type} alert-dismissible fade show ${
478
- spin ? "d-flex align-items-center" : ""
479
- }" role="alert">
480
- ${txt}
481
- ${
482
- spin
483
- ? `<div class="spinner-border ms-auto" role="status" aria-hidden="true"></div>`
484
- : `<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
485
- </button>`
486
- }
487
- </div>`);
488
- }
489
-
490
495
  function ajax_done(res) {
491
- if (res.notify) notifyAlert(res.notify);
492
- if (res.error) notifyAlert({ type: "danger", text: res.error });
493
- if (res.eval_js) eval(res.eval_js);
494
- if (res.reload_page) location.reload(); //TODO notify to cookie if reload or goto
495
- if (res.download) {
496
- const dataurl = `data:${
497
- res.download.mimetype || "application/octet-stream"
498
- };base64,${res.download.blob}`;
499
- fetch(dataurl)
500
- .then((res) => res.blob())
501
- .then((blob) => {
502
- const link = document.createElement("a");
503
- link.href = window.URL.createObjectURL(blob);
504
- if (res.download.filename) link.download = res.download.filename;
505
- else link.target = "_blank";
506
- link.click();
507
- });
508
- }
509
- if (res.goto) {
510
- if (res.target === "_blank") window.open(res.goto, "_blank").focus();
511
- else window.location.href = res.goto;
512
- }
496
+ common_done(res);
513
497
  }
514
498
 
515
499
  function view_post(viewname, route, data, onDone) {
@@ -546,11 +530,6 @@ function globalErrorCatcher(message, source, lineno, colno, error) {
546
530
  });
547
531
  }
548
532
 
549
- function press_store_button(clicked) {
550
- const width = $(clicked).width();
551
- $(clicked).html('<i class="fas fa-spinner fa-spin"></i>').width(width);
552
- }
553
-
554
533
  function ajax_modal(url, opts = {}) {
555
534
  if ($("#scmodal").length === 0) {
556
535
  $("body").append(`<div id="scmodal", class="modal">
@@ -567,6 +546,10 @@ function ajax_modal(url, opts = {}) {
567
546
  </div>
568
547
  </div>
569
548
  </div>`);
549
+ } else if ($("#scmodal").hasClass("show")) {
550
+ var myModalEl = document.getElementById("scmodal");
551
+ var modal = bootstrap.Modal.getInstance(myModalEl);
552
+ modal.dispose();
570
553
  }
571
554
  if (opts.submitReload === false) $("#scmodal").addClass("no-submit-reload");
572
555
  else $("#scmodal").removeClass("no-submit-reload");
@@ -587,6 +570,7 @@ function ajax_modal(url, opts = {}) {
587
570
 
588
571
  function saveAndContinue(e, k) {
589
572
  var form = $(e).closest("form");
573
+ submitWithEmptyAction(form[0]);
590
574
  var url = form.attr("action");
591
575
  var form_data = form.serialize();
592
576
  $.ajax(url, {
@@ -614,6 +598,54 @@ function saveAndContinue(e, k) {
614
598
  return false;
615
599
  }
616
600
 
601
+ function applyViewConfig(e, url) {
602
+ var form = $(e).closest("form");
603
+ var form_data = form.serializeArray();
604
+ const cfg = {};
605
+ form_data.forEach((item) => {
606
+ cfg[item.name] = item.value;
607
+ });
608
+ $.ajax(url, {
609
+ type: "POST",
610
+ dataType: "json",
611
+ contentType: "application/json",
612
+ headers: {
613
+ "CSRF-Token": _sc_globalCsrf,
614
+ },
615
+ data: JSON.stringify(cfg),
616
+ error: function (request) {},
617
+ });
618
+
619
+ return false;
620
+ }
621
+
622
+ const repeaterCopyValuesToForm = (form, editor) => {
623
+ const vs = JSON.parse(editor.getString());
624
+ const allNames = new Set([]);
625
+ const setVal = (k, ix, v) => {
626
+ const $e = form.find(`input[name="${k}_${ix}"]`);
627
+ if ($e.length) $e.val(v);
628
+ else
629
+ form.append(
630
+ `<input type="hidden" name="${k}_${ix}" value="${v}"></input>`
631
+ );
632
+ };
633
+ vs.forEach((v, ix) => {
634
+ Object.entries(v).forEach(([k, v]) => {
635
+ //console.log(ix, k, typeof v, v)
636
+ allNames.add(k);
637
+ if (typeof v === "boolean") setVal(k, ix, v ? "on" : "");
638
+ else setVal(k, ix, v);
639
+ });
640
+ });
641
+ //delete
642
+ [...allNames].forEach((k) => {
643
+ for (let ix = vs.length; ix < vs.length + 20; ix++) {
644
+ $(`input[name=${k}_${ix}]`).remove();
645
+ }
646
+ });
647
+ };
648
+
617
649
  function ajaxSubmitForm(e) {
618
650
  var form = $(e).closest("form");
619
651
  var url = form.attr("action");
@@ -698,31 +730,16 @@ function make_unique_field(
698
730
  type: "GET",
699
731
  success: function (res) {
700
732
  if (res.success) {
701
- const gen_char = (i) => {
702
- switch (char_type) {
703
- case "Lowercase Letters":
704
- return String.fromCharCode("a".charCodeAt(0) + i);
705
- break;
706
- case "Uppercase Letters":
707
- return String.fromCharCode("A".charCodeAt(0) + i);
708
- break;
709
- default:
710
- return i;
711
- break;
712
- }
713
- };
714
- const vals = res.success
715
- .map((o) => o[field_name])
716
- .filter((s) => s.startsWith(value));
717
- if (vals.includes(value) || always_append) {
718
- for (let i = start || 0; i < vals.length + (start || 0) + 2; i++) {
719
- const newname = `${value}${space ? " " : ""}${gen_char(i)}`;
720
- if (!vals.includes(newname)) {
721
- $("#" + id).val(newname);
722
- return;
723
- }
724
- }
725
- }
733
+ unique_field_from_rows(
734
+ res.success,
735
+ id,
736
+ field_name,
737
+ space,
738
+ start,
739
+ always_append,
740
+ char_type,
741
+ value
742
+ );
726
743
  }
727
744
  },
728
745
  }
@@ -830,13 +847,13 @@ const columnSummary = (col) => {
830
847
  if (!col) return "Unknown";
831
848
  switch (col.type) {
832
849
  case "Field":
833
- return `Field ${col.field_name} ${col.fieldview}`;
850
+ return `Field ${col.field_name} ${col.fieldview || ""}`;
834
851
  case "Link":
835
852
  return `Link ${col.link_text}`;
836
853
  case "JoinField":
837
854
  return `Join ${col.join_field}`;
838
855
  case "ViewLink":
839
- return `View ${col.view_label || col.view.split(":")[1] || ""}`;
856
+ return `View link ${col.view_label || col.view.split(":")[1] || ""}`;
840
857
  case "Action":
841
858
  return `Action ${col.action_label || col.action_name}`;
842
859
  case "Aggregation":
package/routes/admin.js CHANGED
@@ -787,7 +787,7 @@ router.get(
787
787
  ? div(
788
788
  { class: "alert alert-success", role: "alert" },
789
789
  i({ class: "fas fa-check-circle fa-lg me-2" }),
790
- h5({ class: "d-inline" }, "No errors detected")
790
+ h5({ class: "d-inline" }, req.__("No errors detected during configuration check"))
791
791
  )
792
792
  : errors.map(mkError)
793
793
  ),
package/routes/api.js CHANGED
@@ -20,6 +20,7 @@ const { error_catcher } = require("./utils.js");
20
20
  //const { mkTable, renderForm, link, post_btn } = require("@saltcorn/markup");
21
21
  const { getState } = require("@saltcorn/data/db/state");
22
22
  const Table = require("@saltcorn/data/models/table");
23
+ const View = require("@saltcorn/data/models/view");
23
24
  //const Field = require("@saltcorn/data/models/field");
24
25
  const Trigger = require("@saltcorn/data/models/trigger");
25
26
  //const load_plugins = require("../load_plugins");
@@ -111,6 +112,40 @@ function accessAllowed(req, user, trigger) {
111
112
  return role <= trigger.min_role;
112
113
  }
113
114
 
115
+ router.post(
116
+ "/viewQuery/:viewName/:queryName",
117
+ error_catcher(async (req, res, next) => {
118
+ let { viewName, queryName } = req.params;
119
+ const view = await View.findOne({ name: viewName });
120
+ if (!view) {
121
+ res.status(404).json({ error: req.__("Not found") });
122
+ return;
123
+ }
124
+ await passport.authenticate(
125
+ "jwt",
126
+ { session: false },
127
+ async function (err, user, info) {
128
+ const role = user && user.id ? user.role_id : 10;
129
+ if (
130
+ role <= view.min_role ||
131
+ (await view.authorise_get({ req, ...view })) // TODO set query to state
132
+ ) {
133
+ const queries = view.queries(false, req);
134
+ if (queries[queryName]) {
135
+ const { args } = req.body;
136
+ const resp = await queries[queryName](...args, true);
137
+ res.json({ success: resp });
138
+ } else {
139
+ res.status(404).json({ error: req.__("Not found") });
140
+ }
141
+ } else {
142
+ res.status(401).json({ error: req.__("Not authorized") });
143
+ }
144
+ }
145
+ )(req, res, next);
146
+ })
147
+ );
148
+
114
149
  router.get(
115
150
  "/:tableName/distinct/:fieldName",
116
151
  //passport.authenticate("api-bearer", { session: false }),
@@ -180,7 +215,7 @@ router.get(
180
215
  }
181
216
 
182
217
  await passport.authenticate(
183
- "api-bearer",
218
+ ["api-bearer", "jwt"],
184
219
  { session: false },
185
220
  async function (err, user, info) {
186
221
  if (accessAllowedRead(req, user, table)) {
package/routes/edit.js CHANGED
@@ -44,7 +44,8 @@ router.post(
44
44
  "error",
45
45
  req.__("Not allowed to write to table %s", table.name)
46
46
  );
47
- if (req.get("referer")) res.redirect(req.get("referer"));
47
+ if (req.xhr) res.send("OK");
48
+ else if (req.get("referer")) res.redirect(req.get("referer"));
48
49
  else res.redirect(redirect || `/list/${table.name}`);
49
50
  })
50
51
  );
package/routes/fields.js CHANGED
@@ -181,6 +181,7 @@ const fieldFlow = (req) =>
181
181
  var attributes = context.attributes || {};
182
182
  attributes.default = context.default;
183
183
  attributes.summary_field = context.summary_field;
184
+ attributes.include_fts = context.include_fts;
184
185
  attributes.on_delete_cascade = context.on_delete_cascade;
185
186
  const {
186
187
  table_id,
@@ -370,6 +371,11 @@ const fieldFlow = (req) =>
370
371
  value: f.name,
371
372
  label: f.label,
372
373
  }));
374
+ const textfields = orderedFields
375
+ .filter(
376
+ (f) => (!f.calculated || f.stored) && f.type?.sql_name === "text"
377
+ )
378
+ .map((f) => f.name);
373
379
  return new Form({
374
380
  fields: [
375
381
  new Field({
@@ -378,6 +384,12 @@ const fieldFlow = (req) =>
378
384
  input_type: "select",
379
385
  options: keyfields,
380
386
  }),
387
+ new Field({
388
+ name: "include_fts",
389
+ label: req.__("Include in full-text search"),
390
+ type: "Bool",
391
+ showIf: { summary_field: textfields },
392
+ }),
381
393
  new Field({
382
394
  name: "on_delete_cascade",
383
395
  label: req.__("On delete cascade"),
package/routes/files.js CHANGED
@@ -9,6 +9,7 @@ const File = require("@saltcorn/data/models/file");
9
9
  const User = require("@saltcorn/data/models/user");
10
10
  const { getState } = require("@saltcorn/data/db/state");
11
11
  const s3storage = require("../s3storage");
12
+ const sharp = require("sharp");
12
13
 
13
14
  const {
14
15
  mkTable,
@@ -43,6 +44,8 @@ const {
43
44
  config_fields_form,
44
45
  save_config_from_form,
45
46
  } = require("../markup/admin");
47
+ const fsp = require("fs").promises;
48
+ const fs = require("fs");
46
49
 
47
50
  /**
48
51
  * @type {object}
@@ -187,6 +190,54 @@ router.get(
187
190
  })
188
191
  );
189
192
 
193
+ /**
194
+ * @name get/resize/:id
195
+ * @function
196
+ * @memberof module:routes/files~filesRouter
197
+ * @function
198
+ */
199
+ router.get(
200
+ "/resize/:id/:width_str",
201
+ error_catcher(async (req, res) => {
202
+ const role = req.user && req.user.id ? req.user.role_id : 10;
203
+ const user_id = req.user && req.user.id;
204
+ const { id, width_str } = req.params;
205
+ let file;
206
+ if (typeof strictParseInt(id) !== "undefined")
207
+ file = await File.findOne({ id });
208
+ else file = await File.findOne({ filename: id });
209
+
210
+ if (!file) {
211
+ res
212
+ .status(404)
213
+ .sendWrap(req.__("Not found"), h1(req.__("File not found")));
214
+ return;
215
+ }
216
+ if (role <= file.min_role_read || (user_id && user_id === file.user_id)) {
217
+ res.type(file.mimetype);
218
+ const cacheability = file.min_role_read === 10 ? "public" : "private";
219
+ res.set("Cache-Control", `${cacheability}, max-age=86400`);
220
+ //TODO s3
221
+ if (file.s3_store) s3storage.serveObject(file, res, false);
222
+ else {
223
+ const width = strictParseInt(width_str);
224
+ if (!width) {
225
+ res.sendFile(file.location);
226
+ return;
227
+ }
228
+ const fnm = `${file.location}_w${width}`;
229
+ if (!fs.existsSync(fnm)) {
230
+ await sharp(file.location).resize({ width }).toFile(fnm);
231
+ }
232
+ res.sendFile(fnm);
233
+ }
234
+ } else {
235
+ req.flash("warning", req.__("Not authorized"));
236
+ res.redirect("/");
237
+ }
238
+ })
239
+ );
240
+
190
241
  /**
191
242
  * @name post/setrole/:id
192
243
  * @function
package/routes/plugins.js CHANGED
@@ -652,16 +652,16 @@ router.get(
652
652
  error_catcher(async (req, res) => {
653
653
  const { plugin } = req.params;
654
654
  const filepath = req.params[0];
655
+ const hasVersion = plugin.includes("@");
655
656
  const location =
656
- getState().plugin_locations[
657
- plugin.includes("@") ? plugin.split("@")[0] : plugin
658
- ];
657
+ getState().plugin_locations[hasVersion ? plugin.split("@")[0] : plugin];
659
658
  if (location) {
660
659
  const safeFile = path
661
660
  .normalize(filepath)
662
661
  .replace(/^(\.\.(\/|\\|$))+/, "");
663
662
  const fullpath = path.join(location, "public", safeFile);
664
- if (fs.existsSync(fullpath)) res.sendFile(fullpath, { maxAge: "1d" });
663
+ if (fs.existsSync(fullpath))
664
+ res.sendFile(fullpath, { maxAge: hasVersion ? "100d" : "1d" });
665
665
  else res.status(404).send(req.__("Not found"));
666
666
  } else {
667
667
  res.status(404).send(req.__("Not found"));
@@ -582,8 +582,11 @@ router.get(
582
582
  return;
583
583
  }
584
584
  const configFlow = await view.get_config_flow(req);
585
+ const hasConfig =
586
+ view.configuration && Object.keys(view.configuration).length > 0;
585
587
  const wfres = await configFlow.run(
586
588
  {
589
+ id: hasConfig ? view.id : undefined,
587
590
  table_id: view.table_id,
588
591
  exttable_name: view.exttable_name,
589
592
  viewname: name,
@@ -704,6 +707,48 @@ router.post(
704
707
  })
705
708
  );
706
709
 
710
+ /**
711
+ * @name post/saveconfig/:id
712
+ * @function
713
+ * @memberof module:routes/viewedit~vieweditRouter
714
+ * @function
715
+ */
716
+ router.post(
717
+ "/saveconfig/:viewname",
718
+ isAdmin,
719
+ error_catcher(async (req, res) => {
720
+ const { viewname } = req.params;
721
+
722
+ if (viewname && req.body) {
723
+ const view = await View.findOne({ name: viewname });
724
+ const configFlow = await view.get_config_flow(req);
725
+ const step = await configFlow.singleStepForm(req.body, req);
726
+ if (step?.renderForm) {
727
+ if (!step.renderForm.hasErrors) {
728
+ let newcfg;
729
+ if (step.contextField)
730
+ newcfg = {
731
+ ...view.configuration,
732
+ [step.contextField]: {
733
+ ...view.configuration?.[step.contextField],
734
+ ...step.renderForm.values,
735
+ },
736
+ };
737
+ else newcfg = { ...view.configuration, ...step.renderForm.values };
738
+ await View.update({ configuration: newcfg }, view.id);
739
+ res.json({ success: "ok" });
740
+ } else {
741
+ res.json({ error: step.renderForm.errorSummary });
742
+ }
743
+ } else {
744
+ res.json({ error: "no form" });
745
+ }
746
+ } else {
747
+ res.json({ error: "no view" });
748
+ }
749
+ })
750
+ );
751
+
707
752
  /**
708
753
  * @name post/setrole/:id
709
754
  * @function
@@ -730,3 +775,12 @@ router.post(
730
775
  res.redirect("/viewedit");
731
776
  })
732
777
  );
778
+
779
+ router.post(
780
+ "/test/inserter",
781
+ isAdmin,
782
+ error_catcher(async (req, res) => {
783
+ const view = await View.create(req.body);
784
+ res.json({ view });
785
+ })
786
+ );
@@ -12,6 +12,7 @@ const {
12
12
  respondJsonWith,
13
13
  } = require("../auth/testhelp");
14
14
  const db = require("@saltcorn/data/db");
15
+ const { sleep } = require("@saltcorn/data/tests/mocks");
15
16
  const fs = require("fs").promises;
16
17
  const File = require("@saltcorn/data/models/file");
17
18
  const User = require("@saltcorn/data/models/user");
@@ -30,7 +31,12 @@ beforeAll(async () => {
30
31
  4
31
32
  );
32
33
  });
33
- afterAll(db.close);
34
+
35
+ afterAll(async () => {
36
+ await sleep(200);
37
+ db.close();
38
+ });
39
+
34
40
  const adminPageContains = (specs) =>
35
41
  it("adminPageContains " + specs.map((s) => s[1]).join(","), async () => {
36
42
  const app = await getApp({ disableCsrf: true });
@@ -456,6 +462,71 @@ describe("actions", () => {
456
462
  .expect(toRedirect("/actions/"));
457
463
  });
458
464
  });
465
+ describe("localizer", () => {
466
+ itShouldRedirectUnauthToLogin("/site-structure/localizer");
467
+ itShouldRedirectUnauthToLogin("/site-structure/localizer/add-lang");
468
+ it("redirects site struct to menu", async () => {
469
+ const app = await getApp({ disableCsrf: true });
470
+ const loginCookie = await getAdminLoginCookie();
471
+ await request(app)
472
+ .get("/site-structure")
473
+ .set("Cookie", loginCookie)
474
+ .expect(toRedirect("/menu"));
475
+ });
476
+ it("shows languages", async () => {
477
+ const app = await getApp({ disableCsrf: true });
478
+ const loginCookie = await getAdminLoginCookie();
479
+ await request(app)
480
+ .get("/site-structure/localizer")
481
+ .set("Cookie", loginCookie)
482
+ .expect(toInclude("Languages"));
483
+ });
484
+ it("shows add language form", async () => {
485
+ const app = await getApp({ disableCsrf: true });
486
+ const loginCookie = await getAdminLoginCookie();
487
+ await request(app)
488
+ .get("/site-structure/localizer/add-lang")
489
+ .set("Cookie", loginCookie)
490
+ .expect(toInclude("Locale identifier short code"));
491
+ });
492
+ it("add language", async () => {
493
+ const app = await getApp({ disableCsrf: true });
494
+ const loginCookie = await getAdminLoginCookie();
495
+ await request(app)
496
+ .post("/site-structure/localizer/save-lang")
497
+ .set("Cookie", loginCookie)
498
+ .send("name=dansk")
499
+ .send("locale=da")
500
+ .expect(toRedirect("/site-structure/localizer/edit/da"));
501
+ });
502
+ it("shows new in languages", async () => {
503
+ const app = await getApp({ disableCsrf: true });
504
+ const loginCookie = await getAdminLoginCookie();
505
+ await request(app)
506
+ .get("/site-structure/localizer")
507
+ .set("Cookie", loginCookie)
508
+ .expect(toInclude("dansk"));
509
+ });
510
+
511
+ it("shows edit language form", async () => {
512
+ const app = await getApp({ disableCsrf: true });
513
+ const loginCookie = await getAdminLoginCookie();
514
+ await request(app)
515
+ .get("/site-structure/localizer/edit/da")
516
+ .set("Cookie", loginCookie)
517
+ .expect(toInclude("Hello world"));
518
+ });
519
+ it("set string language", async () => {
520
+ const app = await getApp({ disableCsrf: true });
521
+ const loginCookie = await getAdminLoginCookie();
522
+ await request(app)
523
+ .post("/site-structure/localizer/save-string/da/Hello%20world")
524
+ .set("Cookie", loginCookie)
525
+ .send("value=Hej+verden")
526
+ .expect(toRedirect("/site-structure/localizer/edit/da"));
527
+ });
528
+ });
529
+
459
530
  /**
460
531
  * Pages tests
461
532
  */
@@ -14,6 +14,7 @@ const load_script = (fnm) => {
14
14
  };
15
15
 
16
16
  load_script("jquery-3.6.0.min.js");
17
+ load_script("saltcorn-common.js");
17
18
  load_script("saltcorn.js");
18
19
 
19
20
  test("updateQueryStringParameter", () => {
@@ -90,7 +90,7 @@ describe("Plugin Endpoints", () => {
90
90
  .expect(toInclude("testfilecontents"));
91
91
  await request(app)
92
92
  .get(
93
- "/plugins/pubdeps/sbadmin2/startbootstrap-sb-admin-2-bs5/4.1.5-beta.0/css/sb-admin-2.min.css"
93
+ "/plugins/pubdeps/sbadmin2/startbootstrap-sb-admin-2-bs5/4.1.5-beta.4/css/sb-admin-2.min.css"
94
94
  )
95
95
  .expect(toInclude("Start Bootstrap"));
96
96
 
@@ -100,7 +100,7 @@ describe("Plugin Endpoints", () => {
100
100
  .expect(toRedirect("/plugins"));
101
101
  await request(app)
102
102
  .get(
103
- "/plugins/pubdeps/sbadmin2/startbootstrap-sb-admin-2-bs5/4.1.5-beta.0/css/sb-admin-2.min.css"
103
+ "/plugins/pubdeps/sbadmin2/startbootstrap-sb-admin-2-bs5/4.1.5-beta.4/css/sb-admin-2.min.css"
104
104
  )
105
105
  .expect(toInclude("Start Bootstrap"));
106
106
  });
@@ -82,7 +82,7 @@ describe("edit view", () => {
82
82
  .post("/view/authoredit")
83
83
  .send("author=Chekov")
84
84
 
85
- .expect(toRedirect("/"));
85
+ .expect(toRedirect("/view/authorlist"));
86
86
  });
87
87
  });
88
88