@saltcorn/server 0.8.7 → 0.8.8-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 +20 -16
- package/auth/routes.js +18 -13
- package/locales/en.json +45 -1
- package/locales/ru.json +145 -100
- package/locales/si.json +1197 -0
- package/package.json +8 -8
- package/public/diagram_utils.js +21 -1
- package/public/saltcorn-common.js +40 -19
- package/public/saltcorn.js +11 -5
- package/routes/actions.js +4 -3
- package/routes/admin.js +2 -0
- package/routes/common_lists.js +34 -19
- package/routes/diagram.js +214 -199
- package/routes/fields.js +118 -7
- package/routes/index.js +2 -0
- package/routes/menu.js +16 -9
- package/routes/models.js +492 -0
- package/routes/page.js +10 -6
- package/routes/tables.js +67 -41
- package/routes/view.js +10 -6
- package/routes/viewedit.js +27 -5
- package/tests/view.test.js +217 -0
package/routes/diagram.js
CHANGED
|
@@ -102,228 +102,243 @@ router.get(
|
|
|
102
102
|
title: req.__(`Application diagram`),
|
|
103
103
|
contents: [
|
|
104
104
|
div(
|
|
105
|
-
{ class: "
|
|
106
|
-
// New dropdown
|
|
107
|
-
button(
|
|
108
|
-
{
|
|
109
|
-
type: "button",
|
|
110
|
-
class: "btn btn-primary m-2 rounded",
|
|
111
|
-
"data-bs-toggle": "dropdown",
|
|
112
|
-
"aria-expanded": false,
|
|
113
|
-
},
|
|
114
|
-
"New",
|
|
115
|
-
i({ class: "fas fa-plus-square ms-2" })
|
|
116
|
-
),
|
|
117
|
-
|
|
105
|
+
{ class: "d-flex justify-content-between" },
|
|
118
106
|
div(
|
|
119
|
-
{
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
req.__("View")
|
|
131
|
-
)
|
|
107
|
+
{ class: "btn-group" },
|
|
108
|
+
// New dropdown
|
|
109
|
+
button(
|
|
110
|
+
{
|
|
111
|
+
type: "button",
|
|
112
|
+
class: "btn btn-primary m-2 rounded",
|
|
113
|
+
"data-bs-toggle": "dropdown",
|
|
114
|
+
"aria-expanded": false,
|
|
115
|
+
},
|
|
116
|
+
"New",
|
|
117
|
+
i({ class: "fas fa-plus-square ms-2" })
|
|
132
118
|
),
|
|
133
|
-
|
|
119
|
+
|
|
134
120
|
div(
|
|
135
|
-
{
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
121
|
+
{
|
|
122
|
+
class: "dropdown-menu",
|
|
123
|
+
},
|
|
124
|
+
// New View
|
|
125
|
+
div(
|
|
126
|
+
{ class: "m-3" },
|
|
127
|
+
|
|
128
|
+
a(
|
|
129
|
+
{
|
|
130
|
+
href: "/viewedit/new?on_done_redirect=diagram",
|
|
131
|
+
},
|
|
132
|
+
req.__("View")
|
|
133
|
+
)
|
|
134
|
+
),
|
|
135
|
+
// New Page
|
|
136
|
+
div(
|
|
137
|
+
{ class: "m-3" },
|
|
138
|
+
a(
|
|
139
|
+
{
|
|
140
|
+
href: "/pageedit/new?on_done_redirect=diagram",
|
|
141
|
+
},
|
|
142
|
+
req.__("Page")
|
|
143
|
+
)
|
|
144
|
+
),
|
|
145
|
+
// New Table
|
|
146
|
+
div(
|
|
147
|
+
{ class: "m-3" },
|
|
148
|
+
a(
|
|
149
|
+
{
|
|
150
|
+
href: "/table/new",
|
|
151
|
+
},
|
|
152
|
+
req.__("Table")
|
|
153
|
+
)
|
|
154
|
+
),
|
|
155
|
+
// New Trigger
|
|
156
|
+
div(
|
|
157
|
+
{ class: "m-3" },
|
|
158
|
+
a(
|
|
159
|
+
{
|
|
160
|
+
href: "/actions/new?on_done_redirect=diagram",
|
|
161
|
+
},
|
|
162
|
+
req.__("Trigger")
|
|
163
|
+
)
|
|
141
164
|
)
|
|
142
165
|
),
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
{
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
)
|
|
166
|
+
// Entity type filter dropdown
|
|
167
|
+
button(
|
|
168
|
+
{
|
|
169
|
+
type: "button",
|
|
170
|
+
class: "btn btn-primary m-2 rounded",
|
|
171
|
+
"data-bs-toggle": "dropdown",
|
|
172
|
+
"aria-expanded": false,
|
|
173
|
+
},
|
|
174
|
+
req.__("All entities")
|
|
152
175
|
),
|
|
153
|
-
// New Trigger
|
|
154
176
|
div(
|
|
155
|
-
{
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
{
|
|
176
|
-
class: "dropdown-menu",
|
|
177
|
-
},
|
|
178
|
-
// Views checkbox
|
|
179
|
-
div(
|
|
180
|
-
{ class: "m-3 form-check" },
|
|
181
|
-
label(
|
|
182
|
-
{ class: "form-check-label", for: "showViewsId" },
|
|
183
|
-
req.__("Views")
|
|
177
|
+
{
|
|
178
|
+
class: "dropdown-menu",
|
|
179
|
+
},
|
|
180
|
+
// Views checkbox
|
|
181
|
+
div(
|
|
182
|
+
{ class: "m-3 form-check" },
|
|
183
|
+
label(
|
|
184
|
+
{ class: "form-check-label", for: "showViewsId" },
|
|
185
|
+
req.__("Views")
|
|
186
|
+
),
|
|
187
|
+
input({
|
|
188
|
+
type: "checkbox",
|
|
189
|
+
class: "form-check-input",
|
|
190
|
+
id: "showViewsId",
|
|
191
|
+
checked: true,
|
|
192
|
+
name: "show_views",
|
|
193
|
+
value: "true",
|
|
194
|
+
onclick: "toggleEntityFilter('views'); reloadCy();",
|
|
195
|
+
autocomplete: "off",
|
|
196
|
+
})
|
|
184
197
|
),
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
class: "form-check
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
198
|
+
// Pages checkbox
|
|
199
|
+
div(
|
|
200
|
+
{ class: "m-3 form-check" },
|
|
201
|
+
label(
|
|
202
|
+
{ class: "form-check-label", for: "showPagesId" },
|
|
203
|
+
req.__("Pages")
|
|
204
|
+
),
|
|
205
|
+
input({
|
|
206
|
+
type: "checkbox",
|
|
207
|
+
class: "form-check-input",
|
|
208
|
+
id: "showPagesId",
|
|
209
|
+
name: "show_pages",
|
|
210
|
+
value: "true",
|
|
211
|
+
checked: true,
|
|
212
|
+
onclick: "toggleEntityFilter('pages'); reloadCy();",
|
|
213
|
+
autocomplete: "off",
|
|
214
|
+
})
|
|
202
215
|
),
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
class: "form-check
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
216
|
+
// Tables checkbox
|
|
217
|
+
div(
|
|
218
|
+
{ class: "m-3 form-check" },
|
|
219
|
+
label(
|
|
220
|
+
{ class: "form-check-label", for: "showTablesId" },
|
|
221
|
+
req.__("Tables")
|
|
222
|
+
),
|
|
223
|
+
input({
|
|
224
|
+
type: "checkbox",
|
|
225
|
+
class: "form-check-input",
|
|
226
|
+
id: "showTablesId",
|
|
227
|
+
name: "show_tables",
|
|
228
|
+
value: "true",
|
|
229
|
+
checked: true,
|
|
230
|
+
onclick: "toggleEntityFilter('tables'); reloadCy();",
|
|
231
|
+
autocomplete: "off",
|
|
232
|
+
})
|
|
220
233
|
),
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
class: "form-check
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
234
|
+
// Trigger checkbox
|
|
235
|
+
div(
|
|
236
|
+
{ class: "m-3 form-check" },
|
|
237
|
+
label(
|
|
238
|
+
{ class: "form-check-label", for: "showTriggerId" },
|
|
239
|
+
req.__("Triggers")
|
|
240
|
+
),
|
|
241
|
+
input({
|
|
242
|
+
type: "checkbox",
|
|
243
|
+
class: "form-check-input",
|
|
244
|
+
id: "showTriggerId",
|
|
245
|
+
name: "show_trigger",
|
|
246
|
+
value: "true",
|
|
247
|
+
checked: true,
|
|
248
|
+
onclick: "toggleEntityFilter('trigger'); reloadCy();",
|
|
249
|
+
autocomplete: "off",
|
|
250
|
+
})
|
|
251
|
+
)
|
|
231
252
|
),
|
|
232
|
-
//
|
|
233
|
-
|
|
234
|
-
{
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
class: "form-check-input",
|
|
242
|
-
id: "showTriggerId",
|
|
243
|
-
name: "show_trigger",
|
|
244
|
-
value: "true",
|
|
245
|
-
checked: true,
|
|
246
|
-
onclick: "toggleEntityFilter('trigger'); reloadCy();",
|
|
247
|
-
autocomplete: "off",
|
|
248
|
-
})
|
|
249
|
-
)
|
|
250
|
-
),
|
|
251
|
-
// Tags filter dropdown
|
|
252
|
-
button(
|
|
253
|
-
{
|
|
254
|
-
type: "button",
|
|
255
|
-
class: "btn btn-primary m-2 rounded",
|
|
256
|
-
"data-bs-toggle": "dropdown",
|
|
257
|
-
"aria-expanded": false,
|
|
258
|
-
},
|
|
259
|
-
req.__("Tags")
|
|
260
|
-
),
|
|
261
|
-
div(
|
|
262
|
-
{
|
|
263
|
-
class: "dropdown-menu",
|
|
264
|
-
},
|
|
265
|
-
// no tags checkbox
|
|
266
|
-
div(
|
|
267
|
-
{ class: "m-3 form-check" },
|
|
268
|
-
label(
|
|
269
|
-
{ class: "form-check-label", for: "noTagsId" },
|
|
270
|
-
req.__("no tags")
|
|
271
|
-
),
|
|
272
|
-
input({
|
|
273
|
-
type: "checkbox",
|
|
274
|
-
class: "form-check-input",
|
|
275
|
-
id: "noTagsId",
|
|
276
|
-
name: "no_tags",
|
|
277
|
-
value: "true",
|
|
278
|
-
checked: true,
|
|
279
|
-
onclick: "toggleTagFilterMode(); reloadCy();",
|
|
280
|
-
autocomplete: "off",
|
|
281
|
-
})
|
|
253
|
+
// Tags filter dropdown
|
|
254
|
+
button(
|
|
255
|
+
{
|
|
256
|
+
type: "button",
|
|
257
|
+
class: "btn btn-primary m-2 rounded",
|
|
258
|
+
"data-bs-toggle": "dropdown",
|
|
259
|
+
"aria-expanded": false,
|
|
260
|
+
},
|
|
261
|
+
req.__("Tags")
|
|
282
262
|
),
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
263
|
+
div(
|
|
264
|
+
{
|
|
265
|
+
class: "dropdown-menu",
|
|
266
|
+
},
|
|
267
|
+
// no tags checkbox
|
|
268
|
+
div(
|
|
286
269
|
{ class: "m-3 form-check" },
|
|
287
270
|
label(
|
|
288
|
-
{
|
|
289
|
-
|
|
290
|
-
id: `tagFilter_label_${tag.name}`,
|
|
291
|
-
style: "opacity: 0.5;",
|
|
292
|
-
for: inputId,
|
|
293
|
-
},
|
|
294
|
-
tag.name
|
|
271
|
+
{ class: "form-check-label", for: "noTagsId" },
|
|
272
|
+
req.__("no tags")
|
|
295
273
|
),
|
|
296
274
|
input({
|
|
297
275
|
type: "checkbox",
|
|
298
276
|
class: "form-check-input",
|
|
299
|
-
id:
|
|
300
|
-
name: "
|
|
301
|
-
value:
|
|
302
|
-
checked:
|
|
303
|
-
onclick:
|
|
277
|
+
id: "noTagsId",
|
|
278
|
+
name: "no_tags",
|
|
279
|
+
value: "true",
|
|
280
|
+
checked: true,
|
|
281
|
+
onclick: "toggleTagFilterMode(); reloadCy();",
|
|
304
282
|
autocomplete: "off",
|
|
305
283
|
})
|
|
306
|
-
)
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
284
|
+
),
|
|
285
|
+
tags.map((tag) => {
|
|
286
|
+
const inputId = `tagFilter_box_${tag.name}_id`;
|
|
287
|
+
return div(
|
|
288
|
+
{ class: "m-3 form-check" },
|
|
289
|
+
label(
|
|
290
|
+
{
|
|
291
|
+
class: "form-check-label",
|
|
292
|
+
id: `tagFilter_label_${tag.name}`,
|
|
293
|
+
style: "opacity: 0.5;",
|
|
294
|
+
for: inputId,
|
|
295
|
+
},
|
|
296
|
+
tag.name
|
|
297
|
+
),
|
|
298
|
+
input({
|
|
299
|
+
type: "checkbox",
|
|
300
|
+
class: "form-check-input",
|
|
301
|
+
id: inputId,
|
|
302
|
+
name: "choice",
|
|
303
|
+
value: tag.id,
|
|
304
|
+
checked: false,
|
|
305
|
+
onclick: `toggleTagFilter(${tag.id}); reloadCy();`,
|
|
306
|
+
autocomplete: "off",
|
|
307
|
+
})
|
|
308
|
+
);
|
|
309
|
+
}),
|
|
310
|
+
div(
|
|
311
|
+
{ class: "m-3" },
|
|
312
|
+
a(
|
|
313
|
+
{
|
|
314
|
+
href: "/tag/new",
|
|
315
|
+
},
|
|
316
|
+
req.__("Add tag"),
|
|
317
|
+
i({ class: "fas fa-plus ms-2" })
|
|
318
|
+
)
|
|
316
319
|
)
|
|
320
|
+
),
|
|
321
|
+
// refresh button
|
|
322
|
+
button(
|
|
323
|
+
{
|
|
324
|
+
type: "button",
|
|
325
|
+
class: "btn btn-primary m-2 rounded",
|
|
326
|
+
onclick: "reloadCy(true);",
|
|
327
|
+
},
|
|
328
|
+
i({ class: "fas fa-sync-alt" })
|
|
317
329
|
)
|
|
318
330
|
),
|
|
319
|
-
//
|
|
320
|
-
|
|
321
|
-
{
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
331
|
+
// screenshot button
|
|
332
|
+
div(
|
|
333
|
+
{ class: "ad-screenshot-panel" },
|
|
334
|
+
button(
|
|
335
|
+
{
|
|
336
|
+
type: "button",
|
|
337
|
+
class: "btn btn-primary m-2 rounded",
|
|
338
|
+
onclick: "takePicture()",
|
|
339
|
+
},
|
|
340
|
+
i({ class: "fas fa-camera" })
|
|
341
|
+
)
|
|
327
342
|
)
|
|
328
343
|
),
|
|
329
344
|
div({ id: "cy" }),
|
package/routes/fields.js
CHANGED
|
@@ -65,6 +65,10 @@ const fieldForm = async (req, fkey_opts, existing_names, id, hasData) => {
|
|
|
65
65
|
isPrimary = !!field.primary_key;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
+
const roleOptions = (await User.get_roles()).map((r) => ({
|
|
69
|
+
value: r.id,
|
|
70
|
+
label: r.role,
|
|
71
|
+
}));
|
|
68
72
|
return new Form({
|
|
69
73
|
action: "/field",
|
|
70
74
|
validator: (vs) => {
|
|
@@ -140,6 +144,13 @@ const fieldForm = async (req, fkey_opts, existing_names, id, hasData) => {
|
|
|
140
144
|
showIf: { calculated: false },
|
|
141
145
|
type: "Bool",
|
|
142
146
|
}),
|
|
147
|
+
new Field({
|
|
148
|
+
label: req.__("Error message"),
|
|
149
|
+
name: "unique_error_msg",
|
|
150
|
+
sublabel: req.__("Error shown to user if uniqueness is violated"),
|
|
151
|
+
showIf: { calculated: false, is_unique: true },
|
|
152
|
+
type: "String",
|
|
153
|
+
}),
|
|
143
154
|
|
|
144
155
|
new Field({
|
|
145
156
|
label: req.__("Stored"),
|
|
@@ -149,6 +160,22 @@ const fieldForm = async (req, fkey_opts, existing_names, id, hasData) => {
|
|
|
149
160
|
disabled: !!id,
|
|
150
161
|
showIf: { calculated: true },
|
|
151
162
|
}),
|
|
163
|
+
new Field({
|
|
164
|
+
label: req.__("Protected"),
|
|
165
|
+
name: "protected",
|
|
166
|
+
sublabel: req.__("Set role to access"),
|
|
167
|
+
type: "Bool",
|
|
168
|
+
}),
|
|
169
|
+
{
|
|
170
|
+
label: req.__("Minimum role to write"),
|
|
171
|
+
name: "min_role_write",
|
|
172
|
+
input_type: "select",
|
|
173
|
+
sublabel: req.__(
|
|
174
|
+
"User must have this role or higher to update or create field values"
|
|
175
|
+
),
|
|
176
|
+
options: roleOptions,
|
|
177
|
+
showIf: { protected: true },
|
|
178
|
+
},
|
|
152
179
|
],
|
|
153
180
|
});
|
|
154
181
|
};
|
|
@@ -199,6 +226,9 @@ const fieldFlow = (req) =>
|
|
|
199
226
|
attributes.include_fts = context.include_fts;
|
|
200
227
|
attributes.on_delete_cascade = context.on_delete_cascade;
|
|
201
228
|
attributes.on_delete = context.on_delete;
|
|
229
|
+
attributes.unique_error_msg = context.unique_error_msg;
|
|
230
|
+
if (context.protected) attributes.min_role_write = context.min_role_write;
|
|
231
|
+
else attributes.min_role_write = undefined;
|
|
202
232
|
const {
|
|
203
233
|
table_id,
|
|
204
234
|
name,
|
|
@@ -206,10 +236,18 @@ const fieldFlow = (req) =>
|
|
|
206
236
|
required,
|
|
207
237
|
is_unique,
|
|
208
238
|
calculated,
|
|
209
|
-
expression,
|
|
210
239
|
stored,
|
|
211
240
|
description,
|
|
212
241
|
} = context;
|
|
242
|
+
let expression = context.expression;
|
|
243
|
+
if (context.expression_type === "Model prediction") {
|
|
244
|
+
const { model, model_instance, model_output } = context;
|
|
245
|
+
expression = `${model}(${
|
|
246
|
+
model_instance && model_instance !== "Default"
|
|
247
|
+
? `"${model_instance}",`
|
|
248
|
+
: ""
|
|
249
|
+
}row).${model_output}`;
|
|
250
|
+
}
|
|
213
251
|
const { reftable_name, type } = calcFieldType(context.type);
|
|
214
252
|
const fldRow = {
|
|
215
253
|
table_id,
|
|
@@ -280,6 +318,7 @@ const fieldFlow = (req) =>
|
|
|
280
318
|
if (context.type === "Key" && context.reftable_name) {
|
|
281
319
|
form.values.type = `Key to ${context.reftable_name}`;
|
|
282
320
|
}
|
|
321
|
+
if (context.min_role_write) context.protected = true;
|
|
283
322
|
return form;
|
|
284
323
|
},
|
|
285
324
|
},
|
|
@@ -360,9 +399,72 @@ const fieldFlow = (req) =>
|
|
|
360
399
|
form: async (context) => {
|
|
361
400
|
const table = Table.findOne({ id: context.table_id });
|
|
362
401
|
const fields = table.getFields();
|
|
402
|
+
const models = await table.get_models();
|
|
403
|
+
const instance_options = {};
|
|
404
|
+
const output_options = {};
|
|
405
|
+
for (const model of models) {
|
|
406
|
+
instance_options[model.name] = ["Default"];
|
|
407
|
+
const instances = await model.get_instances();
|
|
408
|
+
instance_options[model.name].push(...instances.map((i) => i.name));
|
|
409
|
+
|
|
410
|
+
const outputs = await applyAsync(
|
|
411
|
+
model.templateObj.prediction_outputs || [],
|
|
412
|
+
{ table, configuration: model.configuration }
|
|
413
|
+
);
|
|
414
|
+
output_options[model.name] = outputs.map((o) => o.name);
|
|
415
|
+
}
|
|
363
416
|
return new Form({
|
|
364
|
-
blurb: expressionBlurb(context.type, context.stored, fields, req),
|
|
365
417
|
fields: [
|
|
418
|
+
{
|
|
419
|
+
name: "expression_type",
|
|
420
|
+
label: "Formula type",
|
|
421
|
+
input_type: "select",
|
|
422
|
+
options: [
|
|
423
|
+
"JavaScript expression",
|
|
424
|
+
...(models.length ? ["Model prediction"] : []),
|
|
425
|
+
],
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
name: "model",
|
|
429
|
+
label: req.__("Model"),
|
|
430
|
+
input_type: "select",
|
|
431
|
+
options: models.map((m) => m.name),
|
|
432
|
+
showIf: { expression_type: "Model prediction" },
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
name: "model_instance",
|
|
436
|
+
label: req.__("Model instance"),
|
|
437
|
+
type: "String",
|
|
438
|
+
required: true,
|
|
439
|
+
attributes: {
|
|
440
|
+
calcOptions: ["model", instance_options],
|
|
441
|
+
},
|
|
442
|
+
showIf: { expression_type: "Model prediction" },
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
name: "model_output",
|
|
446
|
+
label: req.__("Prediction output"),
|
|
447
|
+
type: "String",
|
|
448
|
+
required: true,
|
|
449
|
+
attributes: {
|
|
450
|
+
calcOptions: ["model", output_options],
|
|
451
|
+
},
|
|
452
|
+
showIf: { expression_type: "Model prediction" },
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
input_type: "custom_html",
|
|
456
|
+
name: "expr_blurb",
|
|
457
|
+
label: " ",
|
|
458
|
+
showIf: { expression_type: "JavaScript expression" },
|
|
459
|
+
attributes: {
|
|
460
|
+
html: expressionBlurb(
|
|
461
|
+
context.type,
|
|
462
|
+
context.stored,
|
|
463
|
+
fields,
|
|
464
|
+
req
|
|
465
|
+
),
|
|
466
|
+
},
|
|
467
|
+
},
|
|
366
468
|
new Field({
|
|
367
469
|
name: "expression",
|
|
368
470
|
label: req.__("Formula"),
|
|
@@ -370,10 +472,12 @@ const fieldFlow = (req) =>
|
|
|
370
472
|
type: "String",
|
|
371
473
|
class: "validate-expression",
|
|
372
474
|
validator: expressionValidator,
|
|
475
|
+
showIf: { expression_type: "JavaScript expression" },
|
|
373
476
|
}),
|
|
374
477
|
new Field({
|
|
375
478
|
name: "test_btn",
|
|
376
479
|
label: req.__("Test"),
|
|
480
|
+
showIf: { expression_type: "JavaScript expression" },
|
|
377
481
|
// todo sublabel
|
|
378
482
|
input_type: "custom_html",
|
|
379
483
|
attributes: {
|
|
@@ -455,10 +559,12 @@ const fieldFlow = (req) =>
|
|
|
455
559
|
attributes: {
|
|
456
560
|
explainers: {
|
|
457
561
|
Fail: req.__("Prevent any deletion of parent rows"),
|
|
458
|
-
Cascade:
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
562
|
+
Cascade: req.__(
|
|
563
|
+
"If the parent row is deleted, automatically delete the child rows."
|
|
564
|
+
),
|
|
565
|
+
"Set null": req.__(
|
|
566
|
+
"If the parent row is deleted, set key fields on child rows to null"
|
|
567
|
+
),
|
|
462
568
|
},
|
|
463
569
|
},
|
|
464
570
|
sublabel: req.__(
|
|
@@ -720,6 +826,7 @@ router.post(
|
|
|
720
826
|
} is: <pre>${JSON.stringify(result)}</pre>`
|
|
721
827
|
);
|
|
722
828
|
} catch (e) {
|
|
829
|
+
console.error(e);
|
|
723
830
|
return res.send(
|
|
724
831
|
`Error on running on row with id=${rows[0].id}: ${e.message}`
|
|
725
832
|
);
|
|
@@ -956,7 +1063,11 @@ router.post(
|
|
|
956
1063
|
res.send("");
|
|
957
1064
|
return;
|
|
958
1065
|
}
|
|
959
|
-
const firefox = /firefox/i.test(req.headers["user-agent"]);
|
|
1066
|
+
//const firefox = /firefox/i.test(req.headers["user-agent"]);
|
|
1067
|
+
|
|
1068
|
+
//Chrome 116 changes its behaviour to align with firefox
|
|
1069
|
+
// - disabled inputs do not dispactch click events
|
|
1070
|
+
const firefox = true;
|
|
960
1071
|
const fv = fieldviews[fieldview];
|
|
961
1072
|
if (!fv && field.type === "Key" && fieldview === "select")
|
|
962
1073
|
res.send(
|
package/routes/index.js
CHANGED
|
@@ -17,6 +17,7 @@ const eventlog = require("./eventlog");
|
|
|
17
17
|
const infoarch = require("./infoarch");
|
|
18
18
|
const events = require("./events");
|
|
19
19
|
const tenant = require("./tenant");
|
|
20
|
+
const models = require("./models");
|
|
20
21
|
const library = require("./library");
|
|
21
22
|
const settings = require("./settings");
|
|
22
23
|
const plugins = require("./plugins");
|
|
@@ -54,6 +55,7 @@ module.exports =
|
|
|
54
55
|
app.use("/crashlog", crashlog);
|
|
55
56
|
app.use("/events", events);
|
|
56
57
|
app.use("/page", page);
|
|
58
|
+
app.use("/models", models);
|
|
57
59
|
app.use("/settings", settings);
|
|
58
60
|
app.use("/pageedit", pageedit);
|
|
59
61
|
app.use("/actions", actions);
|