@saltcorn/server 0.8.9 → 0.9.0-beta.0
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/help/Table constraints.tmd +23 -0
- package/help/Table formula constraint.tmd +43 -0
- package/help/index.js +42 -0
- package/markup/expression_blurb.js +4 -127
- package/package.json +10 -8
- package/routes/admin.js +19 -0
- package/routes/api.js +1 -1
- package/routes/fields.js +2 -1
- package/routes/tables.js +18 -8
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Table constraints in Saltcorn are used to impose constraints on the data that
|
|
2
|
+
can be held in individual rows or to alter the performance characteristics of
|
|
3
|
+
the table.
|
|
4
|
+
|
|
5
|
+
There are three types of table constraints:
|
|
6
|
+
|
|
7
|
+
A __unique constraint__ can be used to impose a restriction that a combination
|
|
8
|
+
of fields is unique
|
|
9
|
+
across the whole table. For instance, if you have a table for people and you
|
|
10
|
+
mark `name` and `age` as jointly unique using a unique constraint then you cannot
|
|
11
|
+
have two rows with the same name and age; but you could have two rows with the
|
|
12
|
+
same name.
|
|
13
|
+
|
|
14
|
+
A __formula constraint__ is used to impose restrictions on the content of
|
|
15
|
+
each row which can use several Fields. For instance if you have from and to
|
|
16
|
+
date fields, you can use the formula constraint to ensure that the to date is
|
|
17
|
+
always after the from date.
|
|
18
|
+
|
|
19
|
+
An __index__ does not put any limitations or constraints
|
|
20
|
+
on the table data. It adds an index to the table to accelerate queries from
|
|
21
|
+
individual fields, at the expense of using more disk space. You should put an
|
|
22
|
+
index on fields in large tables that are frequently queried either through
|
|
23
|
+
filters or aggregations.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
The constraint formula should be a JavaScript expression which evaluates to a
|
|
2
|
+
boolean (true or false). If the formula evaluates to false then the row is not
|
|
3
|
+
valid and will not be accepted in the table. If you are editing an existing row
|
|
4
|
+
then the edit will not be accepted. The supplied error message text will be shown
|
|
5
|
+
to the user.
|
|
6
|
+
|
|
7
|
+
Some examples:
|
|
8
|
+
|
|
9
|
+
{{# for (const fml of table.getFormulaExamples("Bool")) { }} * `{{= fml}}`
|
|
10
|
+
{{# } }}
|
|
11
|
+
|
|
12
|
+
This formula can use any of the fields in table {{= table.name }} as variables:
|
|
13
|
+
|
|
14
|
+
| Field | Variable name | Type |
|
|
15
|
+
| ----- | ------------- | ---- |
|
|
16
|
+
{{# for (const field of table.fields) { }} | {{= field.label }} | `{{= field.name }}` | {{= field.pretty_type }} |
|
|
17
|
+
{{# } }}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
{{# if(table.fields.some(f=>f.is_fkey)) { }}
|
|
23
|
+
|
|
24
|
+
You can also use join fields on related tables. These are accessed with the dot object access
|
|
25
|
+
notation, in the form:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
{key field}.{field on referenced table}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The first-order join fields you can use in the constraint formula are:
|
|
32
|
+
|
|
33
|
+
{{# for (const field of table.fields.filter(f=>f.is_fkey && f.reftable_name)) { }}
|
|
34
|
+
{{# const reftable = Table.findOne( field.reftable_name); }}
|
|
35
|
+
* Through {{=field.label}} key field: {{= table.fields.map(jf=>`\`${field.name}.${jf.name}\``).join(", ") }}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
{{# } }}
|
|
39
|
+
|
|
40
|
+
If you use join fields, Saltcorn is not able to create a constraint in the SQL database. In that case, it will not check existing
|
|
41
|
+
rows, and it will also not be able to enforce constraints involving the primary key value on newly created rows.
|
|
42
|
+
|
|
43
|
+
{{# } }}
|
package/help/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const Table = require("@saltcorn/data/models/table");
|
|
2
|
+
const File = require("@saltcorn/data/models/file");
|
|
3
|
+
const _ = require("underscore");
|
|
4
|
+
const fs = require("fs").promises;
|
|
5
|
+
const MarkdownIt = require("markdown-it"),
|
|
6
|
+
md = new MarkdownIt();
|
|
7
|
+
|
|
8
|
+
const { pre } = require("@saltcorn/markup/tags");
|
|
9
|
+
|
|
10
|
+
const get_md_file = async (topic) => {
|
|
11
|
+
try {
|
|
12
|
+
const fp = require.resolve(`./${File.normalise(topic)}.tmd`);
|
|
13
|
+
const fileBuf = await fs.readFile(fp);
|
|
14
|
+
return fileBuf.toString();
|
|
15
|
+
} catch (e) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
_.templateSettings = {
|
|
21
|
+
evaluate: /\{\{#(.+?)\}\}/g,
|
|
22
|
+
interpolate: /\{\{=(.+?)\}\}/g,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const get_help_markup = async (topic, query, req) => {
|
|
26
|
+
try {
|
|
27
|
+
const context = { user: req.user, Table };
|
|
28
|
+
if (query.table) {
|
|
29
|
+
context.table = Table.findOne({ name: query.table });
|
|
30
|
+
}
|
|
31
|
+
const mdTemplate = await get_md_file(topic);
|
|
32
|
+
if (!mdTemplate) return { markup: "Topic not found" };
|
|
33
|
+
const template = _.template(mdTemplate);
|
|
34
|
+
const mdTopic = template(context);
|
|
35
|
+
const markup = md.render(mdTopic);
|
|
36
|
+
return { markup };
|
|
37
|
+
} catch (e) {
|
|
38
|
+
return { markup: pre(e.toString()) };
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
module.exports = { get_help_markup };
|
|
@@ -22,144 +22,21 @@ const toJsType = (type) =>
|
|
|
22
22
|
Color: "string",
|
|
23
23
|
}[type] || type);
|
|
24
24
|
|
|
25
|
-
/**
|
|
26
|
-
* @param {*} type
|
|
27
|
-
* @param {object[]} fields
|
|
28
|
-
* @returns {string[]}
|
|
29
|
-
*/
|
|
30
|
-
const intExamples = (type, fields) => {
|
|
31
|
-
const boolFields = fields.filter((f) => f.type && f.type.name === "Bool");
|
|
32
|
-
const intFields = fields.filter((f) => f.type && f.type.name === "Integer");
|
|
33
|
-
const exs = ["3"];
|
|
34
|
-
if (boolFields.length > 0) {
|
|
35
|
-
const b = is.one_of(boolFields).generate();
|
|
36
|
-
exs.push(`${b.name} ? 6 : 9`);
|
|
37
|
-
}
|
|
38
|
-
if (intFields.length > 0) {
|
|
39
|
-
const b = is.one_of(intFields).generate();
|
|
40
|
-
exs.push(`${b.name} + 5`);
|
|
41
|
-
}
|
|
42
|
-
return exs;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* @param {*} type
|
|
47
|
-
* @param {object[]} fields
|
|
48
|
-
* @returns {string[]}
|
|
49
|
-
*/
|
|
50
|
-
const colorExamples = (type, fields) => {
|
|
51
|
-
const boolFields = fields.filter((f) => f.type && f.type.name === "Bool");
|
|
52
|
-
const exs = [`"#06ab6d1"`];
|
|
53
|
-
if (boolFields.length > 0) {
|
|
54
|
-
const b = is.one_of(boolFields).generate();
|
|
55
|
-
exs.push(`${b.name} ? "#000000" : "#ffffff"`);
|
|
56
|
-
}
|
|
57
|
-
return exs;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* @param {*} type
|
|
62
|
-
* @param {object[]} fields
|
|
63
|
-
* @returns {string[]}
|
|
64
|
-
*/
|
|
65
|
-
const stringExamples = (type, fields) => {
|
|
66
|
-
const boolFields = fields.filter((f) => f.type && f.type.name === "Bool");
|
|
67
|
-
const strFields = fields.filter((f) => f.type && f.type.name === "String");
|
|
68
|
-
const exs = [`"Hello world!"`];
|
|
69
|
-
if (boolFields.length > 0) {
|
|
70
|
-
const b = is.one_of(boolFields).generate();
|
|
71
|
-
exs.push(`${b.name} ? "Squish" : "Squash"`);
|
|
72
|
-
}
|
|
73
|
-
if (strFields.length > 0) {
|
|
74
|
-
const b = is.one_of(strFields).generate();
|
|
75
|
-
exs.push(`${b.name}.toUpperCase()`);
|
|
76
|
-
}
|
|
77
|
-
return exs;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* @param {*} type
|
|
82
|
-
* @param {object[]} fields
|
|
83
|
-
* @returns {string[]}
|
|
84
|
-
*/
|
|
85
|
-
const floatExamples = (type, fields) => {
|
|
86
|
-
const boolFields = fields.filter((f) => f.type && f.type.name === "Bool");
|
|
87
|
-
const numFields = fields.filter(
|
|
88
|
-
(f) => f.type && (f.type.name === "Integer" || f.type.name === "Float")
|
|
89
|
-
);
|
|
90
|
-
const exs = ["3.14"];
|
|
91
|
-
if (boolFields.length > 0) {
|
|
92
|
-
const b = is.one_of(boolFields).generate();
|
|
93
|
-
exs.push(`${b.name} ? 2.78 : 99`);
|
|
94
|
-
}
|
|
95
|
-
if (numFields.length > 0) {
|
|
96
|
-
const b = is.one_of(numFields).generate();
|
|
97
|
-
exs.push(`Math.pow(${b.name}, 2)`);
|
|
98
|
-
}
|
|
99
|
-
if (numFields.length > 1) {
|
|
100
|
-
const n1 = numFields[0];
|
|
101
|
-
const n2 = numFields[1];
|
|
102
|
-
exs.push(
|
|
103
|
-
`${n1.name}>${n2.name} ? Math.sqrt(${n1.name}) : ${n1.name}*${n2.name}`
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
return exs;
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* @param {*} type
|
|
111
|
-
* @param {object[]} fields
|
|
112
|
-
* @returns {string[]}
|
|
113
|
-
*/
|
|
114
|
-
const boolExamples = (type, fields) => {
|
|
115
|
-
const boolFields = fields.filter((f) => f.type && f.type.name === "Bool");
|
|
116
|
-
const numFields = fields.filter(
|
|
117
|
-
(f) => (f.type && f.type.name === "Integer") || f.type.name === "Float"
|
|
118
|
-
);
|
|
119
|
-
const exs = ["true"];
|
|
120
|
-
if (boolFields.length > 0) {
|
|
121
|
-
const b = is.one_of(boolFields).generate();
|
|
122
|
-
exs.push(`!${b.name}`);
|
|
123
|
-
}
|
|
124
|
-
if (boolFields.length > 1) {
|
|
125
|
-
const b1 = boolFields[0];
|
|
126
|
-
const b2 = boolFields[1];
|
|
127
|
-
exs.push(`${b1.name} && ${b2.name}`);
|
|
128
|
-
}
|
|
129
|
-
if (numFields.length > 0) {
|
|
130
|
-
const b = is.one_of(numFields).generate();
|
|
131
|
-
exs.push(`${b.name}<3`);
|
|
132
|
-
}
|
|
133
|
-
if (numFields.length > 1) {
|
|
134
|
-
const n1 = numFields[0];
|
|
135
|
-
const n2 = numFields[1];
|
|
136
|
-
exs.push(`${n1.name}>${n2.name}`);
|
|
137
|
-
}
|
|
138
|
-
return exs;
|
|
139
|
-
};
|
|
140
|
-
|
|
141
25
|
/**
|
|
142
26
|
* @param {string} type
|
|
143
27
|
* @param {*} stored
|
|
144
|
-
* @param {
|
|
28
|
+
* @param {Table} table
|
|
145
29
|
* @param {object} req
|
|
146
30
|
* @returns {p[]}
|
|
147
31
|
*/
|
|
148
|
-
const expressionBlurb = (type, stored,
|
|
32
|
+
const expressionBlurb = (type, stored, table, req) => {
|
|
33
|
+
const allFields = table.fields;
|
|
149
34
|
const fields = allFields.filter((f) => !f.calculated);
|
|
150
35
|
const funs = getState().functions;
|
|
151
36
|
const funNames = Object.entries(funs)
|
|
152
37
|
.filter(([k, v]) => !(!stored && v.isAsync))
|
|
153
38
|
.map(([k, v]) => k);
|
|
154
|
-
const examples = (
|
|
155
|
-
{
|
|
156
|
-
Integer: () => intExamples(type, fields),
|
|
157
|
-
Float: () => floatExamples(type, fields),
|
|
158
|
-
Bool: () => boolExamples(type, fields),
|
|
159
|
-
Color: () => colorExamples(type, fields),
|
|
160
|
-
String: () => stringExamples(type, fields),
|
|
161
|
-
}[type] || (() => [])
|
|
162
|
-
)();
|
|
39
|
+
const examples = table.getFormulaExamples(type);
|
|
163
40
|
return [
|
|
164
41
|
p(
|
|
165
42
|
req.__(
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-beta.0",
|
|
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
|
-
"@saltcorn/base-plugin": "0.
|
|
10
|
-
"@saltcorn/builder": "0.
|
|
11
|
-
"@saltcorn/data": "0.
|
|
12
|
-
"@saltcorn/admin-models": "0.
|
|
13
|
-
"@saltcorn/filemanager": "0.
|
|
14
|
-
"@saltcorn/markup": "0.
|
|
15
|
-
"@saltcorn/sbadmin2": "0.
|
|
9
|
+
"@saltcorn/base-plugin": "0.9.0-beta.0",
|
|
10
|
+
"@saltcorn/builder": "0.9.0-beta.0",
|
|
11
|
+
"@saltcorn/data": "0.9.0-beta.0",
|
|
12
|
+
"@saltcorn/admin-models": "0.9.0-beta.0",
|
|
13
|
+
"@saltcorn/filemanager": "0.9.0-beta.0",
|
|
14
|
+
"@saltcorn/markup": "0.9.0-beta.0",
|
|
15
|
+
"@saltcorn/sbadmin2": "0.9.0-beta.0",
|
|
16
16
|
"@socket.io/cluster-adapter": "^0.2.1",
|
|
17
17
|
"@socket.io/sticky": "^1.0.1",
|
|
18
18
|
"adm-zip": "0.5.10",
|
|
@@ -32,11 +32,13 @@
|
|
|
32
32
|
"express-session": "^1.17.1",
|
|
33
33
|
"greenlock": "^4.0.4",
|
|
34
34
|
"greenlock-express": "^4.0.3",
|
|
35
|
+
"underscore": "1.13.6",
|
|
35
36
|
"helmet": "^3.23.3",
|
|
36
37
|
"i18n": "^0.15.1",
|
|
37
38
|
"imapflow": "1.0.123",
|
|
38
39
|
"jsonwebtoken": "^9.0.0",
|
|
39
40
|
"live-plugin-manager": "^0.17.1",
|
|
41
|
+
"markdown-it": "^13.0.2",
|
|
40
42
|
"moment": "^2.29.4",
|
|
41
43
|
"multer": "1.4.5-lts.1",
|
|
42
44
|
"multer-s3": "^2.10.0",
|
package/routes/admin.js
CHANGED
|
@@ -56,6 +56,7 @@ const {
|
|
|
56
56
|
li,
|
|
57
57
|
ol,
|
|
58
58
|
script,
|
|
59
|
+
text,
|
|
59
60
|
domReady,
|
|
60
61
|
} = require("@saltcorn/markup/tags");
|
|
61
62
|
const db = require("@saltcorn/data/db");
|
|
@@ -104,6 +105,7 @@ const Page = require("@saltcorn/data/models/page");
|
|
|
104
105
|
const { getSafeSaltcornCmd } = require("@saltcorn/data/utils");
|
|
105
106
|
const stream = require("stream");
|
|
106
107
|
const Crash = require("@saltcorn/data/models/crash");
|
|
108
|
+
const { get_help_markup } = require("../help/index.js");
|
|
107
109
|
|
|
108
110
|
const router = new Router();
|
|
109
111
|
module.exports = router;
|
|
@@ -240,6 +242,22 @@ router.get(
|
|
|
240
242
|
})
|
|
241
243
|
);
|
|
242
244
|
|
|
245
|
+
/**
|
|
246
|
+
* @name get/send-test-email
|
|
247
|
+
* @function
|
|
248
|
+
* @memberof module:routes/admin~routes/adminRouter
|
|
249
|
+
*/
|
|
250
|
+
router.get(
|
|
251
|
+
"/help/:topic",
|
|
252
|
+
isAdmin,
|
|
253
|
+
error_catcher(async (req, res) => {
|
|
254
|
+
const { topic } = req.params;
|
|
255
|
+
const { markup } = await get_help_markup(topic, req.query, req);
|
|
256
|
+
|
|
257
|
+
res.sendWrap(`Help: ${topic}`, { above: [markup] });
|
|
258
|
+
})
|
|
259
|
+
);
|
|
260
|
+
|
|
243
261
|
/**
|
|
244
262
|
* @name get/backup
|
|
245
263
|
* @function
|
|
@@ -538,6 +556,7 @@ router.get(
|
|
|
538
556
|
error_catcher(async (req, res) => {
|
|
539
557
|
const { type, name } = req.params;
|
|
540
558
|
const snaps = await Snapshot.entity_history(type, name);
|
|
559
|
+
res.set("Page-Title", `Restore ${text(name)}`);
|
|
541
560
|
res.send(
|
|
542
561
|
mkTable(
|
|
543
562
|
[
|
package/routes/api.js
CHANGED
|
@@ -140,7 +140,7 @@ router.post(
|
|
|
140
140
|
const view = await View.findOne({ name: viewName });
|
|
141
141
|
const db = require("@saltcorn/data/db");
|
|
142
142
|
if (!view) {
|
|
143
|
-
getState().log(3, `API viewQuery ${
|
|
143
|
+
getState().log(3, `API viewQuery ${viewName} not found`);
|
|
144
144
|
res.status(404).json({
|
|
145
145
|
error: req.__("View %s not found", viewName),
|
|
146
146
|
view: viewName,
|
package/routes/fields.js
CHANGED
|
@@ -165,6 +165,7 @@ const fieldForm = async (req, fkey_opts, existing_names, id, hasData) => {
|
|
|
165
165
|
name: "protected",
|
|
166
166
|
sublabel: req.__("Set role to access"),
|
|
167
167
|
type: "Bool",
|
|
168
|
+
showIf: { calculated: false },
|
|
168
169
|
}),
|
|
169
170
|
{
|
|
170
171
|
label: req.__("Minimum role to write"),
|
|
@@ -460,7 +461,7 @@ const fieldFlow = (req) =>
|
|
|
460
461
|
html: expressionBlurb(
|
|
461
462
|
context.type,
|
|
462
463
|
context.stored,
|
|
463
|
-
|
|
464
|
+
table,
|
|
464
465
|
req
|
|
465
466
|
),
|
|
466
467
|
},
|
package/routes/tables.js
CHANGED
|
@@ -1378,6 +1378,12 @@ router.get(
|
|
|
1378
1378
|
link(`/table/add-constraint/${id}/Formula`, req.__("Formula")),
|
|
1379
1379
|
" | ",
|
|
1380
1380
|
link(`/table/add-constraint/${id}/Index`, req.__("Index")),
|
|
1381
|
+
a(
|
|
1382
|
+
{
|
|
1383
|
+
href: `javascript:ajax_modal('/admin/help/Table%20constraints?table=${table.name}')`,
|
|
1384
|
+
},
|
|
1385
|
+
i({ class: "fas fa-question-circle ms-1" })
|
|
1386
|
+
),
|
|
1381
1387
|
],
|
|
1382
1388
|
},
|
|
1383
1389
|
],
|
|
@@ -1392,11 +1398,11 @@ router.get(
|
|
|
1392
1398
|
* @param {object[]} fields
|
|
1393
1399
|
* @returns {Form}
|
|
1394
1400
|
*/
|
|
1395
|
-
const constraintForm = (req,
|
|
1401
|
+
const constraintForm = (req, table, fields, type) => {
|
|
1396
1402
|
switch (type) {
|
|
1397
1403
|
case "Formula":
|
|
1398
1404
|
return new Form({
|
|
1399
|
-
action: `/table/add-constraint/${
|
|
1405
|
+
action: `/table/add-constraint/${table.id}/${type}`,
|
|
1400
1406
|
|
|
1401
1407
|
fields: [
|
|
1402
1408
|
{
|
|
@@ -1405,6 +1411,10 @@ const constraintForm = (req, table_id, fields, type) => {
|
|
|
1405
1411
|
validator: expressionValidator,
|
|
1406
1412
|
type: "String",
|
|
1407
1413
|
class: "validate-expression",
|
|
1414
|
+
help: {
|
|
1415
|
+
topic: "Table formula constraint",
|
|
1416
|
+
context: { table: table.name },
|
|
1417
|
+
},
|
|
1408
1418
|
sublabel:
|
|
1409
1419
|
req.__(
|
|
1410
1420
|
"Formula must evaluate to true for valid rows. In scope: "
|
|
@@ -1417,14 +1427,14 @@ const constraintForm = (req, table_id, fields, type) => {
|
|
|
1417
1427
|
{
|
|
1418
1428
|
name: "errormsg",
|
|
1419
1429
|
label: "Error message",
|
|
1420
|
-
sublabel: "Shown the user if formula is false",
|
|
1430
|
+
sublabel: "Shown to the user if formula is false",
|
|
1421
1431
|
type: "String",
|
|
1422
1432
|
},
|
|
1423
1433
|
],
|
|
1424
1434
|
});
|
|
1425
1435
|
case "Unique":
|
|
1426
1436
|
return new Form({
|
|
1427
|
-
action: `/table/add-constraint/${
|
|
1437
|
+
action: `/table/add-constraint/${table.id}/${type}`,
|
|
1428
1438
|
blurb: req.__(
|
|
1429
1439
|
"Tick the boxes for the fields that should be jointly unique"
|
|
1430
1440
|
),
|
|
@@ -1437,14 +1447,14 @@ const constraintForm = (req, table_id, fields, type) => {
|
|
|
1437
1447
|
{
|
|
1438
1448
|
name: "errormsg",
|
|
1439
1449
|
label: "Error message",
|
|
1440
|
-
sublabel: "Shown the user if joint uniqueness is violated",
|
|
1450
|
+
sublabel: "Shown to the user if joint uniqueness is violated",
|
|
1441
1451
|
type: "String",
|
|
1442
1452
|
},
|
|
1443
1453
|
],
|
|
1444
1454
|
});
|
|
1445
1455
|
case "Index":
|
|
1446
1456
|
return new Form({
|
|
1447
|
-
action: `/table/add-constraint/${
|
|
1457
|
+
action: `/table/add-constraint/${table.id}/${type}`,
|
|
1448
1458
|
blurb: req.__(
|
|
1449
1459
|
"Choose the field to be indexed. This make searching the table faster."
|
|
1450
1460
|
),
|
|
@@ -1483,7 +1493,7 @@ router.get(
|
|
|
1483
1493
|
return;
|
|
1484
1494
|
}
|
|
1485
1495
|
const fields = table.getFields();
|
|
1486
|
-
const form = constraintForm(req, table
|
|
1496
|
+
const form = constraintForm(req, table, fields, type);
|
|
1487
1497
|
res.sendWrap(req.__(`Add constraint to %s`, table.name), {
|
|
1488
1498
|
above: [
|
|
1489
1499
|
{
|
|
@@ -1527,7 +1537,7 @@ router.post(
|
|
|
1527
1537
|
return;
|
|
1528
1538
|
}
|
|
1529
1539
|
const fields = table.getFields();
|
|
1530
|
-
const form = constraintForm(req, table
|
|
1540
|
+
const form = constraintForm(req, table, fields, type);
|
|
1531
1541
|
form.validate(req.body);
|
|
1532
1542
|
if (form.hasErrors) req.flash("error", req.__("An error occurred"));
|
|
1533
1543
|
else {
|