@saltcorn/server 0.7.4-beta.2 → 0.7.4

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/fields.js CHANGED
@@ -19,12 +19,13 @@ const {
19
19
  expressionValidator,
20
20
  get_async_expression_function,
21
21
  get_expression_function,
22
+ freeVariables,
22
23
  } = require("@saltcorn/data/models/expression");
23
24
  const db = require("@saltcorn/data/db");
24
25
 
25
26
  const { isAdmin, error_catcher } = require("./utils.js");
26
27
  const expressionBlurb = require("../markup/expression_blurb");
27
- const { readState } = require("@saltcorn/data/plugin-helper");
28
+ const { readState, add_free_variables_to_joinfields } = require("@saltcorn/data/plugin-helper");
28
29
  const { wizardCardTitle } = require("../markup/forms.js");
29
30
  const FieldRepeat = require("@saltcorn/data/models/fieldrepeat");
30
31
  const { applyAsync } = require("@saltcorn/data/utils");
@@ -621,7 +622,11 @@ router.post(
621
622
  const { formula, tablename, stored } = req.body;
622
623
  const table = await Table.findOne({ name: tablename });
623
624
  const fields = await table.getFields();
624
- const rows = await table.getRows({}, { orderBy: "RANDOM()", limit: 1 });
625
+ const freeVars = freeVariables(formula)
626
+ const joinFields = {}
627
+ if (stored)
628
+ add_free_variables_to_joinfields(freeVars, joinFields, fields)
629
+ const rows = await table.getJoinedRows({ joinFields, orderBy: "RANDOM()", limit: 1 });
625
630
  if (rows.length < 1) return "No rows in table";
626
631
  let result;
627
632
  try {
@@ -661,8 +666,12 @@ router.post(
661
666
  return;
662
667
  }
663
668
  const fields = await table.getFields();
664
- const row = { ...req.body };
665
- readState(row, fields);
669
+ let row = { ...req.body };
670
+ if (!row || Object.keys(row).length === 0) {
671
+ const { id } = req.query
672
+ if (id) row = await table.getRow({ id })
673
+ } else
674
+ readState(row, fields);
666
675
 
667
676
  if (fieldName.includes(".")) {
668
677
  //join field
@@ -694,7 +703,7 @@ router.post(
694
703
  return;
695
704
  }
696
705
  } else {
697
- targetField.type.fieldviews[fieldview];
706
+ fv = targetField.type.fieldviews[fieldview];
698
707
  if (!fv)
699
708
  fv =
700
709
  targetField.type.fieldviews.show ||
@@ -743,7 +752,9 @@ router.post(
743
752
 
744
753
  let result;
745
754
  try {
746
- if (field.stored) {
755
+ if (!field.calculated) {
756
+ result = row[field.name]
757
+ } else if (field.stored) {
747
758
  const f = get_async_expression_function(formula, fields);
748
759
  result = await f(row);
749
760
  } else {
@@ -751,7 +762,9 @@ router.post(
751
762
  result = f(row);
752
763
  }
753
764
  const fv = field.type.fieldviews[fieldview];
754
- res.send(fv.run(result));
765
+ if (!fv)
766
+ res.send(text(result));
767
+ else res.send(fv.run(result));
755
768
  } catch (e) {
756
769
  return res.status(400).send(`Error: ${e.message}`);
757
770
  }
package/routes/index.js CHANGED
@@ -72,6 +72,7 @@ const roleadmin = require("../auth/roleadmin");
72
72
  const scapi = require("./scapi");
73
73
  const tags = require("./tags");
74
74
  const tagentries = require("./tag_entries");
75
+ const dataDiagram = require("./diagram");
75
76
 
76
77
  module.exports =
77
78
  /**
@@ -110,4 +111,5 @@ module.exports =
110
111
  app.use("/scapi", scapi);
111
112
  app.use("/tag", tags);
112
113
  app.use("/tag-entries", tagentries);
114
+ app.use("/diagram", dataDiagram);
113
115
  };
@@ -21,7 +21,7 @@ const { add_to_menu } = require("@saltcorn/admin-models/models/pack");
21
21
  const db = require("@saltcorn/data/db");
22
22
  const { getPageList } = require("./common_lists");
23
23
 
24
- const { isAdmin, error_catcher } = require("./utils.js");
24
+ const { isAdmin, error_catcher, addOnDoneRedirect } = require("./utils.js");
25
25
  const {
26
26
  mkTable,
27
27
  renderForm,
@@ -54,7 +54,7 @@ const pagePropertiesForm = async (req) => {
54
54
  const roles = await User.get_roles();
55
55
 
56
56
  const form = new Form({
57
- action: "/pageedit/edit-properties",
57
+ action: addOnDoneRedirect("/pageedit/edit-properties", req),
58
58
  fields: [
59
59
  new Field({
60
60
  label: req.__("Name"),
@@ -185,9 +185,8 @@ const pageBuilderData = async (req, context) => {
185
185
  const getRootPageForm = (pages, roles, req) => {
186
186
  const form = new Form({
187
187
  action: "/pageedit/set_root_page",
188
- submitLabel: req.__("Save"),
189
- submitButtonClass: "btn-outline-primary",
190
- onChange: "remove_outline(this)",
188
+ noSubmitButton: true,
189
+ onChange: "saveAndContinue(this)",
191
190
  blurb: req.__(
192
191
  "The root page is the page that is served when the user visits the home location (/). This can be set for each user role."
193
192
  ),
@@ -358,7 +357,7 @@ router.post(
358
357
  if (!pageRow.fixed_states) pageRow.fixed_states = {};
359
358
  if (!pageRow.layout) pageRow.layout = {};
360
359
  await Page.create(pageRow);
361
- res.redirect(`/pageedit/edit/${pageRow.name}`);
360
+ res.redirect(addOnDoneRedirect(`/pageedit/edit/${pageRow.name}`, req));
362
361
  }
363
362
  }
364
363
  })
@@ -417,20 +416,23 @@ router.post(
417
416
  error_catcher(async (req, res) => {
418
417
  const { pagename } = req.params;
419
418
 
419
+ let redirectTarget = req.query.on_done_redirect
420
+ ? `/${req.query.on_done_redirect}`
421
+ : "/pageedit";
420
422
  const page = await Page.findOne({ name: pagename });
421
423
  if (!page) {
422
424
  req.flash("error", req.__(`Page %s not found`, pagename));
423
- res.redirect(`/pageedit`);
425
+ res.redirect(redirectTarget);
424
426
  } else if (req.body.layout) {
425
427
  await Page.update(page.id, {
426
428
  layout: decodeURIComponent(req.body.layout),
427
429
  });
428
430
 
429
431
  req.flash("success", req.__(`Page %s saved`, pagename));
430
- res.redirect(`/pageedit`);
432
+ res.redirect(redirectTarget);
431
433
  } else {
432
434
  req.flash("error", req.__(`Error processing page`));
433
- res.redirect(`/pageedit`);
435
+ res.redirect(redirectTarget);
434
436
  }
435
437
  })
436
438
  );
package/routes/plugins.js CHANGED
@@ -455,7 +455,7 @@ const store_actions_dropdown = (req) =>
455
455
  {
456
456
  class: "dropdown-item",
457
457
  href: `/plugins/upgrade`,
458
- onClick: `notifyAlert('Upgrading modules...', true)`,
458
+ onClick: `notifyAlert('${req.__("Upgrading modules...")}', true)`,
459
459
  },
460
460
  '<i class="far fa-arrow-alt-circle-up"></i>&nbsp;' +
461
461
  req.__("Upgrade installed modules")
@@ -551,7 +551,7 @@ router.get(
551
551
  const { name } = req.params;
552
552
  const plugin = await Plugin.findOne({ name: decodeURIComponent(name) });
553
553
  if (!plugin) {
554
- req.flash("warning", "Plugin not found");
554
+ req.flash("warning", req.__("Module not found"));
555
555
  res.redirect("/plugins");
556
556
  return;
557
557
  }
@@ -792,7 +792,7 @@ router.get(
792
792
  pkgjson = require(path.join(mod.location, "package.json"));
793
793
 
794
794
  if (!plugin_db) {
795
- req.flash("warning", "Plugin not found");
795
+ req.flash("warning", "Module not found");
796
796
  res.redirect("/plugins");
797
797
  return;
798
798
  }
@@ -817,7 +817,7 @@ router.get(
817
817
  ),
818
818
  mod.plugin_module.dependencies
819
819
  ? tr(
820
- th(req.__("Plugin dependencies")),
820
+ th(req.__("Module dependencies")),
821
821
  td(
822
822
  mod.plugin_module.dependencies.map((d) =>
823
823
  span({ class: "badge bg-primary me-1" }, d)
@@ -933,7 +933,7 @@ router.get(
933
933
 
934
934
  const plugin = await Plugin.findOne({ name });
935
935
  await plugin.upgrade_version((p, f) => load_plugins.loadPlugin(p, f));
936
- req.flash("success", req.__(`Plugin up-to-date`));
936
+ req.flash("success", req.__(`Module up-to-date`));
937
937
 
938
938
  res.redirect(`/plugins/info/${plugin.name}`);
939
939
  })
@@ -954,7 +954,7 @@ router.post(
954
954
  if (schema !== db.connectObj.default_schema) {
955
955
  req.flash(
956
956
  "error",
957
- req.__(`Only store plugins can be installed on tenant instances`)
957
+ req.__(`Only store modules can be installed on tenant instances`)
958
958
  );
959
959
  res.redirect(`/plugins`);
960
960
  } else {
@@ -963,12 +963,12 @@ router.post(
963
963
  plugin,
964
964
  schema === db.connectObj.default_schema || plugin.source === "github"
965
965
  );
966
- req.flash("success", req.__(`Plugin %s installed`, plugin.name));
966
+ req.flash("success", req.__(`Module %s installed`, plugin.name));
967
967
  res.redirect(`/plugins`);
968
968
  } catch (e) {
969
969
  req.flash("error", `${e.message}`);
970
970
  const form = pluginForm(req, plugin);
971
- res.sendWrap(req.__(`Edit Plugin`), renderForm(form, req.csrfToken()));
971
+ res.sendWrap(req.__(`Edit Module`), renderForm(form, req.csrfToken()));
972
972
  }
973
973
  }
974
974
  })
@@ -988,7 +988,7 @@ router.post(
988
988
 
989
989
  const plugin = await Plugin.findOne({ name: decodeURIComponent(name) });
990
990
  if (!plugin) {
991
- req.flash("warning", "Plugin not found");
991
+ req.flash("warning", "Module not found");
992
992
  res.redirect("/plugins");
993
993
  return;
994
994
  }
@@ -998,11 +998,11 @@ router.post(
998
998
  getState().getConfig("development_mode", false)
999
999
  ) {
1000
1000
  await plugin.delete();
1001
- req.flash("success", req.__(`Plugin %s removed.`, plugin.name));
1001
+ req.flash("success", req.__(`Module %s removed.`, plugin.name));
1002
1002
  } else {
1003
1003
  req.flash(
1004
1004
  "error",
1005
- req.__(`Cannot remove plugin: views %s depend on it`, depviews.join())
1005
+ req.__(`Cannot remove module: views %s depend on it`, depviews.join())
1006
1006
  );
1007
1007
  }
1008
1008
  res.redirect(`/plugins`);
@@ -1025,7 +1025,7 @@ router.post(
1025
1025
  if (!plugin) {
1026
1026
  req.flash(
1027
1027
  "error",
1028
- req.__(`Plugin %s not found`, text(decodeURIComponent(name)))
1028
+ req.__(`Module %s not found`, text(decodeURIComponent(name)))
1029
1029
  );
1030
1030
  res.redirect(`/plugins`);
1031
1031
  return;
@@ -1034,7 +1034,7 @@ router.post(
1034
1034
  if (!isRoot && plugin.unsafe) {
1035
1035
  req.flash(
1036
1036
  "error",
1037
- req.__("Cannot install unsafe plugins on subdomain tenants")
1037
+ req.__("Cannot install unsafe modules on subdomain tenants")
1038
1038
  );
1039
1039
  res.redirect(`/plugins`);
1040
1040
  return;
@@ -1047,14 +1047,14 @@ router.post(
1047
1047
  req.flash(
1048
1048
  "success",
1049
1049
  req.__(
1050
- `Plugin %s installed, please complete configuration.`,
1050
+ `Module %s installed, please complete configuration.`,
1051
1051
  plugin_db.name
1052
1052
  )
1053
1053
  );
1054
1054
  await sleep(1000); // Allow other workers to load this plugin
1055
1055
  res.redirect(`/plugins/configure/${plugin_db.name}`);
1056
1056
  } else {
1057
- req.flash("success", req.__(`Plugin %s installed`, plugin.name));
1057
+ req.flash("success", req.__(`Module %s installed`, plugin.name));
1058
1058
  res.redirect(`/plugins`);
1059
1059
  }
1060
1060
  })
package/routes/tables.js CHANGED
@@ -1013,7 +1013,6 @@ router.get(
1013
1013
  const getRole = (rid) => roles.find((r) => r.id === rid).role;
1014
1014
  const mainCard = await tablesList(rows, req);
1015
1015
  const createCard = div(
1016
- h5(req.__("Create table")),
1017
1016
  a(
1018
1017
  { href: `/table/new`, class: "btn btn-primary mt-1 me-3" },
1019
1018
  i({ class: "fas fa-plus-square me-1" }),
@@ -1029,8 +1028,13 @@ router.get(
1029
1028
  ),
1030
1029
  !db.isSQLite &&
1031
1030
  a(
1032
- { href: `/table/discover`, class: "btn btn-secondary mt-1" },
1031
+ {
1032
+ href: `/table/discover`,
1033
+ class: "btn btn-secondary mt-1",
1034
+ title: req.__("Discover tables that are already in the Database, but not known to Saltcorn"),
1035
+ },
1033
1036
  i({ class: "fas fa-map-signs me-1" }),
1037
+
1034
1038
  req.__("Discover tables")
1035
1039
  )
1036
1040
  );
@@ -105,7 +105,7 @@ router.get(
105
105
  },
106
106
  {
107
107
  type: "card",
108
- title: `Add entries to tag`,
108
+ title: req.__(`Add entries to tag`),
109
109
  contents: buildForm(
110
110
  entry_type,
111
111
  tag_id,
@@ -143,7 +143,7 @@ router.post(
143
143
  const { entry_type, tag_id } = req.params;
144
144
  const { ids } = req.body;
145
145
  if (!ids) {
146
- req.flash("error", req.__("Please select at least on item"));
146
+ req.flash("error", req.__("Please select at least one item"));
147
147
  return res.redirect(`/tag-entries/add/${entry_type}/${tag_id}`);
148
148
  }
149
149
  const fieldName = idField(entry_type);
package/routes/tags.js CHANGED
@@ -6,7 +6,7 @@ const Form = require("@saltcorn/data/models/form");
6
6
  const User = require("@saltcorn/data/models/user");
7
7
 
8
8
  const { isAdmin, error_catcher, csrfField } = require("./utils");
9
- const { send_admin_page } = require("../markup/admin");
9
+ const { send_infoarch_page } = require("../markup/admin");
10
10
 
11
11
  const {
12
12
  mkTable,
@@ -31,34 +31,38 @@ router.get(
31
31
  isAdmin,
32
32
  error_catcher(async (req, res) => {
33
33
  const rows = await Tag.find();
34
- send_admin_page({
34
+ send_infoarch_page({
35
35
  res,
36
36
  req,
37
37
  active_sub: "Tags",
38
- contents: [
39
- mkTable(
40
- [
41
- {
42
- label: req.__("Tagname"),
43
- key: (r) =>
44
- link(`/tag/${r.id || r.name}?show_list=tables`, text(r.name)),
45
- },
38
+ contents: {
39
+ type: "card",
40
+ title: req.__("Tags"),
41
+ contents: [
42
+ mkTable(
43
+ [
44
+ {
45
+ label: req.__("Tagname"),
46
+ key: (r) =>
47
+ link(`/tag/${r.id || r.name}?show_list=tables`, text(r.name)),
48
+ },
49
+ {
50
+ label: req.__("Delete"),
51
+ key: (r) => post_delete_btn(`/tag/delete/${r.id}`, req, r.name),
52
+ },
53
+ ],
54
+ rows,
55
+ {}
56
+ ),
57
+ a(
46
58
  {
47
- label: req.__("Delete"),
48
- key: (r) => post_delete_btn(`/tag/delete/${r.id}`, req, r.name),
59
+ href: `/tag/new`,
60
+ class: "btn btn-primary",
49
61
  },
50
- ],
51
- rows,
52
- {}
53
- ),
54
- a(
55
- {
56
- href: `/tag/new`,
57
- class: "btn btn-primary",
58
- },
59
- req.__("Create tag")
60
- ),
61
- ],
62
+ req.__("Create tag")
63
+ ),
64
+ ],
65
+ },
62
66
  });
63
67
  })
64
68
  );
@@ -199,7 +203,7 @@ router.get(
199
203
  href: `/tag-entries/add/pages/${tag.id}`,
200
204
  class: "btn btn-primary",
201
205
  },
202
- req.__("Add tages")
206
+ req.__("Add pages")
203
207
  ),
204
208
  ],
205
209
  },
@@ -222,7 +226,7 @@ router.get(
222
226
  href: `/tag-entries/add/trigger/${tag.id}`,
223
227
  class: "btn btn-primary",
224
228
  },
225
- req.__("Add trigger")
229
+ req.__("Add triggers")
226
230
  ),
227
231
  ],
228
232
  },
package/routes/utils.js CHANGED
@@ -113,37 +113,62 @@ const get_tenant_from_req = (req) => {
113
113
  };
114
114
 
115
115
  /**
116
+ * middleware to extract the tenant domain and call runWithtenant()
116
117
  * @param {object} req
117
118
  * @param {object} res
118
119
  * @param {function} next
119
120
  */
120
121
  const setTenant = (req, res, next) => {
121
122
  if (db.is_it_multi_tenant()) {
122
- const other_domain = get_other_domain_tenant(req.hostname);
123
- if (other_domain) {
124
- const state = getTenant(other_domain);
125
- if (!state) {
126
- setLanguage(req, res);
127
- next();
128
- } else {
129
- db.runWithTenant(other_domain, () => {
130
- setLanguage(req, res, state);
131
- state.log(5, `${req.method} ${req.originalUrl}`);
123
+ // for a saltcorn mobile request use 'req.user.tenant'
124
+ if (req.smr) {
125
+ if (
126
+ req.user?.tenant &&
127
+ req.user.tenant !== db.connectObj.default_schema
128
+ ) {
129
+ const state = getTenant(req.user.tenant);
130
+ if (!state) {
131
+ setLanguage(req, res);
132
132
  next();
133
- });
133
+ } else {
134
+ db.runWithTenant(req.user.tenant, () => {
135
+ setLanguage(req, res, state);
136
+ state.log(5, `${req.method} ${req.originalUrl}`);
137
+ next();
138
+ });
139
+ }
134
140
  }
135
- } else {
136
- const ten = get_tenant_from_req(req);
137
- const state = getTenant(ten);
138
- if (!state) {
141
+ else {
139
142
  setLanguage(req, res);
140
143
  next();
144
+ }
145
+ } else {
146
+ const other_domain = get_other_domain_tenant(req.hostname);
147
+ if (other_domain) {
148
+ const state = getTenant(other_domain);
149
+ if (!state) {
150
+ setLanguage(req, res);
151
+ next();
152
+ } else {
153
+ db.runWithTenant(other_domain, () => {
154
+ setLanguage(req, res, state);
155
+ state.log(5, `${req.method} ${req.originalUrl}`);
156
+ next();
157
+ });
158
+ }
141
159
  } else {
142
- db.runWithTenant(ten, () => {
143
- setLanguage(req, res, state);
144
- state.log(5, `${req.method} ${req.originalUrl}`);
160
+ const ten = get_tenant_from_req(req);
161
+ const state = getTenant(ten);
162
+ if (!state) {
163
+ setLanguage(req, res);
145
164
  next();
146
- });
165
+ } else {
166
+ db.runWithTenant(ten, () => {
167
+ setLanguage(req, res, state);
168
+ state.log(5, `${req.method} ${req.originalUrl}`);
169
+ next();
170
+ });
171
+ }
147
172
  }
148
173
  }
149
174
  } else {
@@ -232,6 +257,20 @@ const getSessionStore = () => {
232
257
  }
233
258
  };
234
259
 
260
+ /**
261
+ * appends 'req.query.on_done_redirect' to 'oldPath' if it exists
262
+ * @param {string} oldPath path without 'on_done_redirect'
263
+ * @param {any} req express request
264
+ * @returns a new string with or without on_done_redirect=...
265
+ */
266
+ const addOnDoneRedirect = (oldPath, req) => {
267
+ const separator = oldPath.indexOf("?") > -1 ? "&" : "?";
268
+ if (req.query.on_done_redirect) {
269
+ return `${oldPath}${separator}on_done_redirect=${req.query.on_done_redirect}`;
270
+ }
271
+ return oldPath;
272
+ };
273
+
235
274
  module.exports = {
236
275
  sqlsanitize,
237
276
  csrfField,
@@ -243,5 +282,6 @@ module.exports = {
243
282
  getGitRevision,
244
283
  getSessionStore,
245
284
  setTenant,
246
- get_tenant_from_req
285
+ get_tenant_from_req,
286
+ addOnDoneRedirect,
247
287
  };
@@ -16,6 +16,7 @@ const {
16
16
  post_dropdown_item,
17
17
  renderBuilder,
18
18
  settingsDropdown,
19
+ alert
19
20
  } = require("@saltcorn/markup");
20
21
  const {
21
22
  //span,
@@ -30,7 +31,7 @@ const {
30
31
  } = require("@saltcorn/markup/tags");
31
32
 
32
33
  const { getState } = require("@saltcorn/data/db/state");
33
- const { isAdmin, error_catcher } = require("./utils.js");
34
+ const { isAdmin, error_catcher, addOnDoneRedirect } = require("./utils.js");
34
35
  const { setTableRefs, viewsList } = require("./common_lists");
35
36
  const Form = require("@saltcorn/data/models/form");
36
37
  const Field = require("@saltcorn/data/models/field");
@@ -76,6 +77,20 @@ router.get(
76
77
 
77
78
  const viewMarkup = await viewsList(views, req);
78
79
  const tables = await Table.find();
80
+ const viewAccessWarning = view => {
81
+ const table = tables.find(t => t.name === view.table)
82
+ if (!table) return false
83
+ if (table.ownership_field_id || table.ownership_formula) return false
84
+
85
+ return table.min_role_read < view.min_role
86
+ }
87
+ const hasAccessWarning = views.filter(viewAccessWarning)
88
+ const accessWarning = hasAccessWarning.length > 0
89
+ ? alert("danger", `<p>You have views with a role to access lower than the table role to read,
90
+ with no table ownership. In the next version of Saltcorn, this may cause a
91
+ denial of access. Users will need to have table read access to any data displayed.</p>
92
+ Views potentially affected: ${hasAccessWarning.map(v => v.name).join(", ")}`)
93
+ : ''
79
94
  res.sendWrap(req.__(`Views`), {
80
95
  above: [
81
96
  {
@@ -87,17 +102,18 @@ router.get(
87
102
  class: "mt-0",
88
103
  title: req.__("Your views"),
89
104
  contents: [
105
+ accessWarning,
90
106
  viewMarkup,
91
107
  tables.length > 0
92
108
  ? a(
93
- { href: `/viewedit/new`, class: "btn btn-primary" },
94
- req.__("Create view")
95
- )
109
+ { href: `/viewedit/new`, class: "btn btn-primary" },
110
+ req.__("Create view")
111
+ )
96
112
  : p(
97
- req.__(
98
- "You must create at least one table before you can create views."
99
- )
100
- ),
113
+ req.__(
114
+ "You must create at least one table before you can create views."
115
+ )
116
+ ),
101
117
  ],
102
118
  },
103
119
  ],
@@ -129,7 +145,7 @@ const viewForm = async (req, tableOptions, roles, pages, values) => {
129
145
  .map(([k, v]) => k);
130
146
  const slugOptions = await Table.allSlugOptions();
131
147
  return new Form({
132
- action: "/viewedit/save",
148
+ action: addOnDoneRedirect("/viewedit/save", req),
133
149
  submitLabel: req.__("Configure") + " &raquo;",
134
150
  blurb: req.__("First, please give some basic information about the view."),
135
151
  fields: [
@@ -209,15 +225,15 @@ const viewForm = async (req, tableOptions, roles, pages, values) => {
209
225
  }),
210
226
  ...(isEdit
211
227
  ? [
212
- new Field({
213
- name: "viewtemplate",
214
- input_type: "hidden",
215
- }),
216
- new Field({
217
- name: "table_name",
218
- input_type: "hidden",
219
- }),
220
- ]
228
+ new Field({
229
+ name: "viewtemplate",
230
+ input_type: "hidden",
231
+ }),
232
+ new Field({
233
+ name: "table_name",
234
+ input_type: "hidden",
235
+ }),
236
+ ]
221
237
  : []),
222
238
  ],
223
239
  values,
@@ -337,7 +353,6 @@ router.post(
337
353
  const pages = await Page.find();
338
354
  const form = await viewForm(req, tableOptions, roles, pages);
339
355
  const result = form.validate(req.body);
340
-
341
356
  const sendForm = (form) => {
342
357
  res.sendWrap(req.__(`Edit view`), {
343
358
  above: [
@@ -397,7 +412,12 @@ router.post(
397
412
  else v.configuration = {};
398
413
  await View.create(v);
399
414
  }
400
- res.redirect(`/viewedit/config/${encodeURIComponent(v.name)}`);
415
+ res.redirect(
416
+ addOnDoneRedirect(
417
+ `/viewedit/config/${encodeURIComponent(v.name)}`,
418
+ req
419
+ )
420
+ );
401
421
  }
402
422
  } else {
403
423
  sendForm(form);
@@ -146,6 +146,15 @@ describe("pageedit", () => {
146
146
  .send("id=1")
147
147
  .expect(toRedirect("/pageedit/"));
148
148
  });
149
+ it("show builder", async () => {
150
+ const app = await getApp({ disableCsrf: true });
151
+ const loginCookie = await getAdminLoginCookie();
152
+ await request(app)
153
+ .get("/pageedit/edit/a_page")
154
+ .set("Cookie", loginCookie)
155
+ .expect(toInclude("<script>builder.renderBuilder"));
156
+
157
+ });
149
158
 
150
159
  it("sets root page", async () => {
151
160
  const app = await getApp({ disableCsrf: true });
@@ -43,6 +43,22 @@ describe("viewedit edit endpoint", () => {
43
43
  .set("Cookie", loginCookie)
44
44
  .expect(toInclude("author"));
45
45
  });
46
+ it("show list editor", async () => {
47
+ const loginCookie = await getAdminLoginCookie();
48
+ const app = await getApp({ disableCsrf: true });
49
+ await request(app)
50
+ .get("/viewedit/config/authorlist")
51
+ .set("Cookie", loginCookie)
52
+ .expect(toInclude("author"));
53
+ });
54
+ it("show builder", async () => {
55
+ const loginCookie = await getAdminLoginCookie();
56
+ const app = await getApp({ disableCsrf: true });
57
+ await request(app)
58
+ .get("/viewedit/config/authorshow")
59
+ .set("Cookie", loginCookie)
60
+ .expect(toInclude("<script>builder.renderBuilder"));
61
+ });
46
62
  });
47
63
 
48
64
  describe("viewedit new List", () => {