@saltcorn/server 0.8.0-beta.3 → 0.8.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/app.js +7 -6
- package/auth/admin.js +226 -217
- package/auth/index.js +20 -20
- package/auth/roleadmin.js +2 -9
- package/auth/routes.js +193 -139
- package/auth/testhelp.js +62 -55
- package/fixture_persons.js +1 -1
- package/index.js +22 -22
- package/locales/en.json +3 -1
- package/locales/ru.json +25 -19
- package/markup/admin.js +86 -53
- package/markup/blockly.js +1 -1
- package/markup/expression_blurb.js +15 -15
- package/markup/forms.js +21 -22
- package/markup/index.js +20 -20
- package/markup/plugin-store.js +4 -4
- package/package.json +8 -8
- package/public/diagram_utils.js +22 -9
- package/public/saltcorn.css +6 -0
- package/restart_watcher.js +157 -157
- package/routes/actions.js +4 -11
- package/routes/admin.js +8 -5
- package/routes/api.js +9 -9
- package/routes/common_lists.js +127 -130
- package/routes/delete.js +2 -2
- package/routes/edit.js +1 -1
- package/routes/fields.js +4 -2
- package/routes/files.js +112 -94
- package/routes/homepage.js +1 -1
- package/routes/infoarch.js +1 -1
- package/routes/list.js +6 -5
- package/routes/packs.js +1 -2
- package/routes/pageedit.js +1 -1
- package/routes/tables.js +172 -165
- package/routes/tag_entries.js +1 -1
- package/routes/utils.js +3 -1
- package/routes/view.js +9 -2
- package/s3storage.js +6 -7
- package/serve.js +35 -31
- package/systemd.js +23 -21
- package/wrapper.js +44 -45
package/auth/testhelp.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @module auth/testhelp
|
|
4
4
|
* @subcategory auth
|
|
5
5
|
*/
|
|
6
|
+
/*global it, expect*/
|
|
6
7
|
const request = require("supertest");
|
|
7
8
|
const app = require("../app");
|
|
8
9
|
const getApp = require("../app");
|
|
@@ -10,8 +11,8 @@ const fixtures = require("@saltcorn/data/db/fixtures");
|
|
|
10
11
|
const reset = require("@saltcorn/data/db/reset_schema");
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
-
* @param {string} loc
|
|
14
|
+
*
|
|
15
|
+
* @param {string} loc
|
|
15
16
|
* @returns {void}
|
|
16
17
|
* @throws {Error}
|
|
17
18
|
*/
|
|
@@ -27,62 +28,68 @@ const toRedirect = (loc) => (res) => {
|
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
|
-
*
|
|
31
|
-
* @param {number} txt
|
|
32
|
-
* @param {number} expCode
|
|
31
|
+
*
|
|
32
|
+
* @param {number} txt
|
|
33
|
+
* @param {number} expCode
|
|
33
34
|
* @returns {void}
|
|
34
35
|
* @throws {Error}
|
|
35
36
|
*/
|
|
36
|
-
const toInclude =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
};
|
|
37
|
+
const toInclude =
|
|
38
|
+
(txt, expCode = 200) =>
|
|
39
|
+
(res) => {
|
|
40
|
+
if (res.statusCode !== expCode) {
|
|
41
|
+
console.log(res.text);
|
|
42
|
+
throw new Error(
|
|
43
|
+
`Expected status ${expCode} when lookinng for "${txt}", received ${res.statusCode}`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!res.text.includes(txt)) {
|
|
48
|
+
console.log(res.text);
|
|
49
|
+
throw new Error(`Expected text ${txt} not found`);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
49
52
|
|
|
50
53
|
/**
|
|
51
|
-
*
|
|
52
|
-
* @param {number} expCode
|
|
54
|
+
*
|
|
55
|
+
* @param {number} expCode
|
|
53
56
|
* @returns {void}
|
|
54
57
|
* @throws {Error}
|
|
55
58
|
*/
|
|
56
|
-
const toSucceed =
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
};
|
|
59
|
+
const toSucceed =
|
|
60
|
+
(expCode = 200) =>
|
|
61
|
+
(res) => {
|
|
62
|
+
if (res.statusCode !== expCode) {
|
|
63
|
+
console.log(res.text);
|
|
64
|
+
throw new Error(`Expected status ${expCode}, received ${res.statusCode}`);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
62
67
|
|
|
63
68
|
/**
|
|
64
|
-
*
|
|
65
|
-
* @param {number} txt
|
|
66
|
-
* @param {number} expCode
|
|
69
|
+
*
|
|
70
|
+
* @param {number} txt
|
|
71
|
+
* @param {number} expCode
|
|
67
72
|
* @returns {void}
|
|
68
73
|
* @throws {Error}
|
|
69
|
-
*/
|
|
70
|
-
const toNotInclude =
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
};
|
|
74
|
+
*/
|
|
75
|
+
const toNotInclude =
|
|
76
|
+
(txt, expCode = 200) =>
|
|
77
|
+
(res) => {
|
|
78
|
+
if (res.statusCode !== expCode) {
|
|
79
|
+
console.log(res.text);
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Expected status ${expCode} when not lookinng for "${txt}", received ${res.statusCode}`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (res.text.includes(txt)) {
|
|
86
|
+
console.log(res.text);
|
|
87
|
+
throw new Error(`Expected text ${txt} to be absent, but was present`);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
83
90
|
|
|
84
91
|
/**
|
|
85
|
-
*
|
|
92
|
+
*
|
|
86
93
|
* @returns {Promise<void>}
|
|
87
94
|
*/
|
|
88
95
|
const getStaffLoginCookie = async () => {
|
|
@@ -96,7 +103,7 @@ const getStaffLoginCookie = async () => {
|
|
|
96
103
|
};
|
|
97
104
|
|
|
98
105
|
/**
|
|
99
|
-
*
|
|
106
|
+
*
|
|
100
107
|
* @returns {Promise<void>}
|
|
101
108
|
*/
|
|
102
109
|
const getAdminLoginCookie = async () => {
|
|
@@ -111,9 +118,9 @@ const getAdminLoginCookie = async () => {
|
|
|
111
118
|
};
|
|
112
119
|
|
|
113
120
|
/**
|
|
114
|
-
*
|
|
115
|
-
* @param {string} path
|
|
116
|
-
* @param {string} dest
|
|
121
|
+
*
|
|
122
|
+
* @param {string} path
|
|
123
|
+
* @param {string} dest
|
|
117
124
|
* @returns {void}
|
|
118
125
|
*/
|
|
119
126
|
const itShouldRedirectUnauthToLogin = (path, dest) => {
|
|
@@ -137,8 +144,8 @@ const resetToFixtures = async () => {
|
|
|
137
144
|
};
|
|
138
145
|
|
|
139
146
|
/**
|
|
140
|
-
*
|
|
141
|
-
* @param {*} pred
|
|
147
|
+
*
|
|
148
|
+
* @param {*} pred
|
|
142
149
|
* @returns {void}
|
|
143
150
|
* @throws {Error}
|
|
144
151
|
*/
|
|
@@ -155,9 +162,9 @@ const succeedJsonWith = (pred) => (res) => {
|
|
|
155
162
|
};
|
|
156
163
|
|
|
157
164
|
/**
|
|
158
|
-
*
|
|
159
|
-
* @param {number} code
|
|
160
|
-
* @param {number} pred
|
|
165
|
+
*
|
|
166
|
+
* @param {number} code
|
|
167
|
+
* @param {number} pred
|
|
161
168
|
* @returns {void}
|
|
162
169
|
* @throws {Error}
|
|
163
170
|
*/
|
|
@@ -174,8 +181,8 @@ const respondJsonWith = (code, pred) => (res) => {
|
|
|
174
181
|
};
|
|
175
182
|
|
|
176
183
|
/**
|
|
177
|
-
*
|
|
178
|
-
* @param {object} res
|
|
184
|
+
*
|
|
185
|
+
* @param {object} res
|
|
179
186
|
* @returns {void}
|
|
180
187
|
* @throws {Error}
|
|
181
188
|
*/
|
package/fixture_persons.js
CHANGED
|
@@ -13,7 +13,7 @@ const basePlugin = require("@saltcorn/base-plugin");
|
|
|
13
13
|
getState().registerPlugin("base", basePlugin);
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* @param {object[]} vs
|
|
16
|
+
* @param {object[]} vs
|
|
17
17
|
* @returns {object}
|
|
18
18
|
*/
|
|
19
19
|
const rndElem = (vs) => vs[Math.floor(Math.random() * vs.length)];
|
package/index.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
// for the jsdoc documentation
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
* @category server
|
|
5
|
-
* @module server/index
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* All files and sub-modules in the saltcorn-markup package.
|
|
10
|
-
* @namespace server_overview
|
|
11
|
-
* @property {module:auth/index~auth_overview} auth
|
|
12
|
-
* @property {module:markup/index~markup_overview} markup
|
|
13
|
-
* @property {module:routes/index~routes_overview} routes
|
|
14
|
-
*
|
|
15
|
-
* @property {module:app} app
|
|
16
|
-
* @property {module:errors} errors
|
|
17
|
-
* @property {module:load_plugins} load_plugins
|
|
18
|
-
* @property {module:serve} serve
|
|
19
|
-
* @property {module:systemd} systemd
|
|
20
|
-
* @property {module:wrapper} wrapper
|
|
21
|
-
* @category server
|
|
22
|
-
*/
|
|
1
|
+
// for the jsdoc documentation
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* @category server
|
|
5
|
+
* @module server/index
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* All files and sub-modules in the saltcorn-markup package.
|
|
10
|
+
* @namespace server_overview
|
|
11
|
+
* @property {module:auth/index~auth_overview} auth
|
|
12
|
+
* @property {module:markup/index~markup_overview} markup
|
|
13
|
+
* @property {module:routes/index~routes_overview} routes
|
|
14
|
+
*
|
|
15
|
+
* @property {module:app} app
|
|
16
|
+
* @property {module:errors} errors
|
|
17
|
+
* @property {module:load_plugins} load_plugins
|
|
18
|
+
* @property {module:serve} serve
|
|
19
|
+
* @property {module:systemd} systemd
|
|
20
|
+
* @property {module:wrapper} wrapper
|
|
21
|
+
* @category server
|
|
22
|
+
*/
|
package/locales/en.json
CHANGED
|
@@ -1055,5 +1055,7 @@
|
|
|
1055
1055
|
"Specifies a filter for what file types the user can pick from the file input dialog box. Example is `text/csv,audio/*,video/*,image/*`": "Specifies a filter for what file types the user can pick from the file input dialog box. Example is `text/csv,audio/*,video/*,image/*`",
|
|
1056
1056
|
"Default Files accept filter": "Default Files accept filter",
|
|
1057
1057
|
"Specifies a default filter for what file types the user can pick from the file input dialog box. Example is `.doc, text/csv,audio/*,video/*,image/*`": "Specifies a default filter for what file types the user can pick from the file input dialog box. Example is `.doc, text/csv,audio/*,video/*,image/*`",
|
|
1058
|
-
"Destination page": "Destination page"
|
|
1058
|
+
"Destination page": "Destination page",
|
|
1059
|
+
"Module Store endpoint": "Module Store endpoint",
|
|
1060
|
+
"Authentication settings updated": "Authentication settings updated"
|
|
1059
1061
|
}
|
package/locales/ru.json
CHANGED
|
@@ -920,28 +920,34 @@
|
|
|
920
920
|
"Permissions settings": "Настройки разрешений",
|
|
921
921
|
"Permissions": "Разрешения",
|
|
922
922
|
"Permissions settings updated": "Настройки разрешений обновлены",
|
|
923
|
-
"Upload file(s)": "
|
|
924
|
-
"Split paste": "
|
|
925
|
-
"Separate paste content into separate inputs": "
|
|
926
|
-
"Preview": "
|
|
927
|
-
"Create new row": "
|
|
928
|
-
"Descending?": "
|
|
929
|
-
"Only include rows where this formula is true. ": "
|
|
930
|
-
"Use %s to access current user ID": "
|
|
931
|
-
"Formula value": "
|
|
932
|
-
"Units": "
|
|
923
|
+
"Upload file(s)": "Загрузка файл(ов)",
|
|
924
|
+
"Split paste": "Раздельная вставка",
|
|
925
|
+
"Separate paste content into separate inputs": "Разделять выставляемый конент на отдельные элементы",
|
|
926
|
+
"Preview": "Превью",
|
|
927
|
+
"Create new row": "Создать новую строку",
|
|
928
|
+
"Descending?": "В обратном порядке?",
|
|
929
|
+
"Only include rows where this formula is true. ": "Включать только строки, для который формула возвращает true. ",
|
|
930
|
+
"Use %s to access current user ID": "Использовать %s для доступа к ID пользователя",
|
|
931
|
+
"Formula value": "Значение формулы",
|
|
932
|
+
"Units": "Единицы",
|
|
933
933
|
"%s view - %s on %s": "%s view - %s on %s",
|
|
934
|
-
"Password Repeat": "
|
|
935
|
-
"Remember me": "
|
|
936
|
-
"Files accept filter ": "Files accept filter ",
|
|
934
|
+
"Password Repeat": "Повторите пароль",
|
|
935
|
+
"Remember me": "Запомнить меня",
|
|
937
936
|
"Specifies a filter for what file types the user can pick from the file input dialog box. Example is `text/csv,audio/*,video/*,image/*`": "Specifies a filter for what file types the user can pick from the file input dialog box. Example is `text/csv,audio/*,video/*,image/*`",
|
|
938
|
-
"Home Page by Role": "
|
|
939
|
-
"Files accept filter": "
|
|
940
|
-
"Specify how to create a new row": "
|
|
941
|
-
"Cascade delete to file": "
|
|
937
|
+
"Home Page by Role": "Домашняя страница в соответствие с ролью",
|
|
938
|
+
"Files accept filter": "Фильтр типов файлов при загрузке",
|
|
939
|
+
"Specify how to create a new row": "Укажите как создавать новую строку",
|
|
940
|
+
"Cascade delete to file": "Каскадное удаление к файлу",
|
|
942
941
|
"Deleting a row will also delete the file referenced by this field": "Deleting a row will also delete the file referenced by this field",
|
|
943
942
|
"Specifies a filter for what file types the user can pick from the file input dialog box. Example is `.doc,audio/*,video/*,image/*`": "Specifies a filter for what file types the user can pick from the file input dialog box. Example is `.doc,audio/*,video/*,image/*`",
|
|
944
|
-
"Default Files accept filter": "Default Files accept filter",
|
|
945
943
|
"Specifies a default filter for what file types the user can pick from the file input dialog box. Example is `.doc, text/csv,audio/*,video/*,image/*`": "Specifies a default filter for what file types the user can pick from the file input dialog box. Example is `.doc, text/csv,audio/*,video/*,image/*`",
|
|
946
|
-
"No file found": "
|
|
944
|
+
"No file found": "Файл не найден",
|
|
945
|
+
"Default File accept filter": "Фильтр типов файлов для загрузки",
|
|
946
|
+
"File upload debug": "Флаг отладки загрузки файлов",
|
|
947
|
+
"Turn on to debug file upload in express-fileupload.": "Turn on to debug file upload in express-fileupload.",
|
|
948
|
+
"File upload size limit in bytes": "Ограничение на размер файла при загрузке (в байтах)",
|
|
949
|
+
"Defines in bytes limit for upload files in express-fileupload.": "Defines in bytes limit for upload files in express-fileupload.",
|
|
950
|
+
"File upload timeout": "Таймаут загрузки файлов",
|
|
951
|
+
"Defines how long to wait for data before aborting for express-fileupload. Set to 0 if you want to turn off timeout checks. ": "Defines how long to wait for data before aborting for express-fileupload. Set to 0 if you want to turn off timeout checks. ",
|
|
952
|
+
"Files settings": "Настройки Файлов"
|
|
947
953
|
}
|
package/markup/admin.js
CHANGED
|
@@ -68,14 +68,40 @@ const restore_backup = (csrf, inner, action = `/admin/restore`) =>
|
|
|
68
68
|
* @param {*} opts.req
|
|
69
69
|
* @returns {object}
|
|
70
70
|
*/
|
|
71
|
-
const add_edit_bar = ({
|
|
71
|
+
const add_edit_bar = ({
|
|
72
|
+
role,
|
|
73
|
+
title,
|
|
74
|
+
contents,
|
|
75
|
+
what,
|
|
76
|
+
url,
|
|
77
|
+
req,
|
|
78
|
+
viewtemplate,
|
|
79
|
+
table,
|
|
80
|
+
cfgUrl,
|
|
81
|
+
}) => {
|
|
72
82
|
if (role > 1 && req && req.xhr) return { above: [contents] }; //make sure not put in card
|
|
73
83
|
if (role > 1) return contents;
|
|
84
|
+
let viewSpec = "";
|
|
85
|
+
if (viewtemplate) viewSpec = viewtemplate;
|
|
86
|
+
if (table) {
|
|
87
|
+
const tbl = Table.findOne(table);
|
|
88
|
+
if (tbl)
|
|
89
|
+
viewSpec = `${viewSpec} on <a href="/table/${table}">${tbl.name}</a>`;
|
|
90
|
+
}
|
|
91
|
+
|
|
74
92
|
const bar = div(
|
|
75
93
|
{ class: "alert alert-light d-print-none admin-edit-bar" },
|
|
76
94
|
title,
|
|
77
|
-
what && span({ class: "ms-1 badge bg-primary" }, what),
|
|
78
|
-
a({ class: "ms-
|
|
95
|
+
what && span({ class: "ms-1 me-2 badge bg-primary" }, what),
|
|
96
|
+
a({ class: "ms-2", href: url }, "Edit ", i({ class: "fas fa-edit" })),
|
|
97
|
+
cfgUrl
|
|
98
|
+
? a(
|
|
99
|
+
{ class: "ms-1 me-3", href: cfgUrl },
|
|
100
|
+
"Configure ",
|
|
101
|
+
i({ class: "fas fa-cog" })
|
|
102
|
+
)
|
|
103
|
+
: "",
|
|
104
|
+
viewSpec
|
|
79
105
|
);
|
|
80
106
|
|
|
81
107
|
if (contents.above) {
|
|
@@ -113,35 +139,35 @@ const send_settings_page = ({
|
|
|
113
139
|
const pillCard = no_nav_pills
|
|
114
140
|
? []
|
|
115
141
|
: [
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
142
|
+
{
|
|
143
|
+
type: "card",
|
|
144
|
+
class: "mt-0",
|
|
145
|
+
contents: div(
|
|
146
|
+
{ class: "d-flex" },
|
|
147
|
+
ul(
|
|
148
|
+
{ class: "nav nav-pills plugin-section" },
|
|
149
|
+
sub_sections.map(({ text, href }) =>
|
|
150
|
+
li(
|
|
151
|
+
{ class: "nav-item" },
|
|
152
|
+
a(
|
|
153
|
+
{
|
|
154
|
+
href,
|
|
155
|
+
class: ["nav-link", active_sub === text && "active"],
|
|
156
|
+
},
|
|
157
|
+
req.__(text)
|
|
158
|
+
)
|
|
132
159
|
)
|
|
133
160
|
)
|
|
134
161
|
)
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
];
|
|
162
|
+
),
|
|
163
|
+
},
|
|
164
|
+
];
|
|
139
165
|
// headers
|
|
140
166
|
const title = headers
|
|
141
167
|
? {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
168
|
+
title: req.__(active_sub),
|
|
169
|
+
headers,
|
|
170
|
+
}
|
|
145
171
|
: req.__(active_sub);
|
|
146
172
|
res.sendWrap(title, {
|
|
147
173
|
above: [
|
|
@@ -158,10 +184,10 @@ const send_settings_page = ({
|
|
|
158
184
|
},
|
|
159
185
|
...(sub2_page
|
|
160
186
|
? [
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
187
|
+
{
|
|
188
|
+
text: sub2_page,
|
|
189
|
+
},
|
|
190
|
+
]
|
|
165
191
|
: []),
|
|
166
192
|
],
|
|
167
193
|
},
|
|
@@ -190,9 +216,9 @@ const send_infoarch_page = (args) => {
|
|
|
190
216
|
{ text: "Languages", href: "/site-structure/localizer" },
|
|
191
217
|
...(tenant_list
|
|
192
218
|
? [
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
219
|
+
{ text: "Tenants", href: "/tenant/list" },
|
|
220
|
+
{ text: "Multitenancy", href: "/tenant/settings" },
|
|
221
|
+
]
|
|
196
222
|
: []),
|
|
197
223
|
{ text: "Tags", href: "/tag" },
|
|
198
224
|
{ text: "Diagram", href: "/diagram" },
|
|
@@ -318,7 +344,7 @@ const viewAttributes = async (key) => {
|
|
|
318
344
|
const flash_restart_if_required = (cfgForm, req) => {
|
|
319
345
|
let restart = false;
|
|
320
346
|
cfgForm.fields.forEach((f) => {
|
|
321
|
-
if (configTypes[f.name]
|
|
347
|
+
if (configTypes[f.name]?.restart_required) {
|
|
322
348
|
const current = getState().getConfig(f.name);
|
|
323
349
|
if (current !== cfgForm.values[f.name]) restart = true;
|
|
324
350
|
}
|
|
@@ -335,8 +361,8 @@ const flash_restart = (req) => {
|
|
|
335
361
|
req.flash(
|
|
336
362
|
"warning",
|
|
337
363
|
req.__(`Restart required for changes to take effect.`) +
|
|
338
|
-
|
|
339
|
-
|
|
364
|
+
" " +
|
|
365
|
+
a({ href: "/admin/system" }, req.__("Restart here"))
|
|
340
366
|
);
|
|
341
367
|
};
|
|
342
368
|
|
|
@@ -358,8 +384,24 @@ const config_fields_form = async ({
|
|
|
358
384
|
const state = getState();
|
|
359
385
|
const fields = [];
|
|
360
386
|
const tenant = db.getTenantSchema();
|
|
361
|
-
|
|
387
|
+
const roleAttribs = {
|
|
388
|
+
options: (await User.get_roles()).map((r) => ({
|
|
389
|
+
label: r.role,
|
|
390
|
+
name: `${r.id}`,
|
|
391
|
+
})),
|
|
392
|
+
};
|
|
393
|
+
const getTenants = async () => {
|
|
394
|
+
const tens = await db.select("_sc_tenants");
|
|
395
|
+
return { options: tens.map((t) => t.subdomain) };
|
|
396
|
+
};
|
|
362
397
|
for (const name of field_names) {
|
|
398
|
+
if (typeof name === "object" && name.section_header) {
|
|
399
|
+
fields.push({
|
|
400
|
+
input_type: "section_header",
|
|
401
|
+
label: name.section_header,
|
|
402
|
+
});
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
363
405
|
values[name] = state.getConfig(name);
|
|
364
406
|
// console.log(`config field name: %s`,name);
|
|
365
407
|
if (configTypes[name].root_only && tenant !== db.connectObj.default_schema)
|
|
@@ -369,16 +411,7 @@ const config_fields_form = async ({
|
|
|
369
411
|
const isTenant = configTypes[name].type === "Tenant";
|
|
370
412
|
const label = configTypes[name].label || name;
|
|
371
413
|
const sublabel = configTypes[name].sublabel || configTypes[name].blurb;
|
|
372
|
-
|
|
373
|
-
options: (await User.get_roles()).map((r) => ({
|
|
374
|
-
label: r.role,
|
|
375
|
-
name: `${r.id}`,
|
|
376
|
-
})),
|
|
377
|
-
};
|
|
378
|
-
const getTenants = async () => {
|
|
379
|
-
const tens = await db.select("_sc_tenants");
|
|
380
|
-
return { options: tens.map((t) => t.subdomain) };
|
|
381
|
-
};
|
|
414
|
+
|
|
382
415
|
fields.push({
|
|
383
416
|
name,
|
|
384
417
|
...configTypes[name],
|
|
@@ -389,16 +422,16 @@ const config_fields_form = async ({
|
|
|
389
422
|
isView || isRole || isTenant
|
|
390
423
|
? "String"
|
|
391
424
|
: configTypes[name].input_type
|
|
392
|
-
|
|
393
|
-
|
|
425
|
+
? undefined
|
|
426
|
+
: configTypes[name].type,
|
|
394
427
|
input_type: configTypes[name].input_type,
|
|
395
428
|
attributes: isView
|
|
396
429
|
? await viewAttributes(name)
|
|
397
430
|
: isRole
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
431
|
+
? roleAttribs
|
|
432
|
+
: isTenant
|
|
433
|
+
? await getTenants()
|
|
434
|
+
: configTypes[name].attributes,
|
|
402
435
|
});
|
|
403
436
|
}
|
|
404
437
|
const form = new Form({
|
package/markup/blockly.js
CHANGED
|
@@ -9,7 +9,7 @@ const { contract, is } = require("contractis");
|
|
|
9
9
|
const { getState } = require("@saltcorn/data/db/state");
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* @param {*} type
|
|
12
|
+
* @param {*} type
|
|
13
13
|
* @returns {*}
|
|
14
14
|
*/
|
|
15
15
|
const toJsType = (type) =>
|
|
@@ -23,8 +23,8 @@ const toJsType = (type) =>
|
|
|
23
23
|
}[type] || type);
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* @param {*} type
|
|
27
|
-
* @param {object[]} fields
|
|
26
|
+
* @param {*} type
|
|
27
|
+
* @param {object[]} fields
|
|
28
28
|
* @returns {string[]}
|
|
29
29
|
*/
|
|
30
30
|
const intExamples = (type, fields) => {
|
|
@@ -43,8 +43,8 @@ const intExamples = (type, fields) => {
|
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
* @param {*} type
|
|
47
|
-
* @param {object[]} fields
|
|
46
|
+
* @param {*} type
|
|
47
|
+
* @param {object[]} fields
|
|
48
48
|
* @returns {string[]}
|
|
49
49
|
*/
|
|
50
50
|
const colorExamples = (type, fields) => {
|
|
@@ -58,8 +58,8 @@ const colorExamples = (type, fields) => {
|
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
|
-
* @param {*} type
|
|
62
|
-
* @param {object[]} fields
|
|
61
|
+
* @param {*} type
|
|
62
|
+
* @param {object[]} fields
|
|
63
63
|
* @returns {string[]}
|
|
64
64
|
*/
|
|
65
65
|
const stringExamples = (type, fields) => {
|
|
@@ -78,8 +78,8 @@ const stringExamples = (type, fields) => {
|
|
|
78
78
|
};
|
|
79
79
|
|
|
80
80
|
/**
|
|
81
|
-
* @param {*} type
|
|
82
|
-
* @param {object[]} fields
|
|
81
|
+
* @param {*} type
|
|
82
|
+
* @param {object[]} fields
|
|
83
83
|
* @returns {string[]}
|
|
84
84
|
*/
|
|
85
85
|
const floatExamples = (type, fields) => {
|
|
@@ -107,8 +107,8 @@ const floatExamples = (type, fields) => {
|
|
|
107
107
|
};
|
|
108
108
|
|
|
109
109
|
/**
|
|
110
|
-
* @param {*} type
|
|
111
|
-
* @param {object[]} fields
|
|
110
|
+
* @param {*} type
|
|
111
|
+
* @param {object[]} fields
|
|
112
112
|
* @returns {string[]}
|
|
113
113
|
*/
|
|
114
114
|
const boolExamples = (type, fields) => {
|
|
@@ -139,10 +139,10 @@ const boolExamples = (type, fields) => {
|
|
|
139
139
|
};
|
|
140
140
|
|
|
141
141
|
/**
|
|
142
|
-
* @param {string} type
|
|
143
|
-
* @param {*} stored
|
|
144
|
-
* @param {object[]} allFields
|
|
145
|
-
* @param {object} req
|
|
142
|
+
* @param {string} type
|
|
143
|
+
* @param {*} stored
|
|
144
|
+
* @param {object[]} allFields
|
|
145
|
+
* @param {object} req
|
|
146
146
|
* @returns {p[]}
|
|
147
147
|
*/
|
|
148
148
|
const expressionBlurb = (type, stored, allFields, req) => {
|
package/markup/forms.js
CHANGED
|
@@ -50,33 +50,32 @@ const editRoleForm = ({ url, current_role, roles, req }) =>
|
|
|
50
50
|
* @param folder
|
|
51
51
|
* @returns {Form}
|
|
52
52
|
*/
|
|
53
|
-
const fileUploadForm = (req, folder
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return frm;
|
|
53
|
+
const fileUploadForm = (req, folder) => {
|
|
54
|
+
const frm = form(
|
|
55
|
+
{
|
|
56
|
+
action: "/files/upload",
|
|
57
|
+
method: "post",
|
|
58
|
+
enctype: "multipart/form-data",
|
|
59
|
+
},
|
|
60
|
+
csrfField(req),
|
|
61
|
+
label(req.__("Upload file(s)")),
|
|
62
|
+
input({
|
|
63
|
+
name: "file",
|
|
64
|
+
class: "form-control ms-1 w-unset d-inline",
|
|
65
|
+
type: "file",
|
|
66
|
+
onchange: "form.submit()",
|
|
67
|
+
multiple: true,
|
|
68
|
+
}),
|
|
69
|
+
folder && input({ type: "hidden", name: "folder", value: folder })
|
|
70
|
+
);
|
|
71
|
+
return frm;
|
|
73
72
|
};
|
|
74
73
|
|
|
75
74
|
/**
|
|
76
75
|
* Get Wizard Card Title
|
|
77
76
|
* @param {string} wizardTitle
|
|
78
|
-
* @param {*} wf
|
|
79
|
-
* @param {object} wfres
|
|
77
|
+
* @param {*} wf
|
|
78
|
+
* @param {object} wfres
|
|
80
79
|
* @returns {string}
|
|
81
80
|
*/
|
|
82
81
|
const wizardCardTitle = (wizardTitle, wf, wfres) =>
|