@saltcorn/server 0.9.6-beta.7 → 0.9.6-beta.8
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/locales/en.json +2 -1
- package/markup/admin.js +1 -0
- package/package.json +9 -9
- package/public/saltcorn-common.js +5 -1
- package/public/saltcorn.css +8 -0
- package/routes/index.js +2 -0
- package/routes/registry.js +289 -0
package/locales/en.json
CHANGED
|
@@ -1425,5 +1425,6 @@
|
|
|
1425
1425
|
"Keystore Alias": "Keystore Alias",
|
|
1426
1426
|
"Keystore Password": "Keystore Password",
|
|
1427
1427
|
"xcodebuild": "xcodebuild",
|
|
1428
|
-
"Provisioning Profile": "Provisioning Profile"
|
|
1428
|
+
"Provisioning Profile": "Provisioning Profile",
|
|
1429
|
+
"Registry editor": "Registry editor"
|
|
1429
1430
|
}
|
package/markup/admin.js
CHANGED
|
@@ -241,6 +241,7 @@ const send_infoarch_page = (args) => {
|
|
|
241
241
|
{ text: "Pagegroups", href: "/page_group/settings" },
|
|
242
242
|
{ text: "Tags", href: "/tag" },
|
|
243
243
|
{ text: "Diagram", href: "/diagram" },
|
|
244
|
+
{ text: "Registry editor", href: "/registry-editor" },
|
|
244
245
|
],
|
|
245
246
|
...args,
|
|
246
247
|
});
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "0.9.6-beta.
|
|
3
|
+
"version": "0.9.6-beta.8",
|
|
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
9
|
"@aws-sdk/client-s3": "^3.451.0",
|
|
10
|
-
"@saltcorn/base-plugin": "0.9.6-beta.
|
|
11
|
-
"@saltcorn/builder": "0.9.6-beta.
|
|
12
|
-
"@saltcorn/data": "0.9.6-beta.
|
|
13
|
-
"@saltcorn/admin-models": "0.9.6-beta.
|
|
14
|
-
"@saltcorn/filemanager": "0.9.6-beta.
|
|
15
|
-
"@saltcorn/markup": "0.9.6-beta.
|
|
16
|
-
"@saltcorn/plugins-loader": "0.9.6-beta.
|
|
17
|
-
"@saltcorn/sbadmin2": "0.9.6-beta.
|
|
10
|
+
"@saltcorn/base-plugin": "0.9.6-beta.8",
|
|
11
|
+
"@saltcorn/builder": "0.9.6-beta.8",
|
|
12
|
+
"@saltcorn/data": "0.9.6-beta.8",
|
|
13
|
+
"@saltcorn/admin-models": "0.9.6-beta.8",
|
|
14
|
+
"@saltcorn/filemanager": "0.9.6-beta.8",
|
|
15
|
+
"@saltcorn/markup": "0.9.6-beta.8",
|
|
16
|
+
"@saltcorn/plugins-loader": "0.9.6-beta.8",
|
|
17
|
+
"@saltcorn/sbadmin2": "0.9.6-beta.8",
|
|
18
18
|
"@socket.io/cluster-adapter": "^0.2.1",
|
|
19
19
|
"@socket.io/sticky": "^1.0.1",
|
|
20
20
|
"adm-zip": "0.5.10",
|
|
@@ -179,7 +179,11 @@ function apply_showif() {
|
|
|
179
179
|
is_or ? "&_or_field=" + k : ""
|
|
180
180
|
}`;
|
|
181
181
|
};
|
|
182
|
-
const qss = Object.entries(dynwhere.whereParsed).map(kvToQs);
|
|
182
|
+
const qss = Object.entries(dynwhere.whereParsed).map((kv) => kvToQs(kv));
|
|
183
|
+
if (dynwhere.existingValue) {
|
|
184
|
+
qss.push(`id=${dynwhere.existingValue}`);
|
|
185
|
+
qss.push(`_or_field=id`);
|
|
186
|
+
}
|
|
183
187
|
if (dynwhere.dereference) {
|
|
184
188
|
if (Array.isArray(dynwhere.dereference))
|
|
185
189
|
qss.push(...dynwhere.dereference.map((d) => `dereference=${d}`));
|
package/public/saltcorn.css
CHANGED
package/routes/index.js
CHANGED
|
@@ -36,6 +36,7 @@ const roleadmin = require("../auth/roleadmin");
|
|
|
36
36
|
const tags = require("./tags");
|
|
37
37
|
const tagentries = require("./tag_entries");
|
|
38
38
|
const diagram = require("./diagram");
|
|
39
|
+
const registry = require("./registry");
|
|
39
40
|
const sync = require("./sync");
|
|
40
41
|
|
|
41
42
|
module.exports =
|
|
@@ -78,5 +79,6 @@ module.exports =
|
|
|
78
79
|
app.use("/tag", tags);
|
|
79
80
|
app.use("/tag-entries", tagentries);
|
|
80
81
|
app.use("/diagram", diagram);
|
|
82
|
+
app.use("/registry-editor", registry);
|
|
81
83
|
app.use("/sync", sync);
|
|
82
84
|
};
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
const Router = require("express-promise-router");
|
|
2
|
+
|
|
3
|
+
const db = require("@saltcorn/data/db");
|
|
4
|
+
const { mkTable, link, post_btn, renderForm } = require("@saltcorn/markup");
|
|
5
|
+
const {
|
|
6
|
+
script,
|
|
7
|
+
domReady,
|
|
8
|
+
a,
|
|
9
|
+
div,
|
|
10
|
+
i,
|
|
11
|
+
text,
|
|
12
|
+
button,
|
|
13
|
+
input,
|
|
14
|
+
label,
|
|
15
|
+
form,
|
|
16
|
+
ul,
|
|
17
|
+
li,
|
|
18
|
+
details,
|
|
19
|
+
summary,
|
|
20
|
+
} = require("@saltcorn/markup/tags");
|
|
21
|
+
const Table = require("@saltcorn/data/models/table");
|
|
22
|
+
const { isAdmin, error_catcher } = require("./utils");
|
|
23
|
+
const { send_infoarch_page } = require("../markup/admin.js");
|
|
24
|
+
const View = require("@saltcorn/data/models/view");
|
|
25
|
+
const Page = require("@saltcorn/data/models/page");
|
|
26
|
+
const Form = require("@saltcorn/data/models/form");
|
|
27
|
+
const {
|
|
28
|
+
table_pack,
|
|
29
|
+
view_pack,
|
|
30
|
+
plugin_pack,
|
|
31
|
+
page_pack,
|
|
32
|
+
page_group_pack,
|
|
33
|
+
role_pack,
|
|
34
|
+
library_pack,
|
|
35
|
+
trigger_pack,
|
|
36
|
+
tag_pack,
|
|
37
|
+
model_pack,
|
|
38
|
+
model_instance_pack,
|
|
39
|
+
event_log_pack,
|
|
40
|
+
install_pack,
|
|
41
|
+
} = require("@saltcorn/admin-models/models/pack");
|
|
42
|
+
const Trigger = require("@saltcorn/data/models/trigger");
|
|
43
|
+
/**
|
|
44
|
+
* @type {object}
|
|
45
|
+
* @const
|
|
46
|
+
* @namespace listRouter
|
|
47
|
+
* @category server
|
|
48
|
+
* @subcategory routes
|
|
49
|
+
*/
|
|
50
|
+
const router = new Router();
|
|
51
|
+
|
|
52
|
+
// export our router to be mounted by the parent application
|
|
53
|
+
module.exports = router;
|
|
54
|
+
|
|
55
|
+
async function asyncFilter(arr, cb) {
|
|
56
|
+
const filtered = [];
|
|
57
|
+
|
|
58
|
+
for (const element of arr) {
|
|
59
|
+
const needAdd = await cb(element);
|
|
60
|
+
|
|
61
|
+
if (needAdd) {
|
|
62
|
+
filtered.push(element);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return filtered;
|
|
67
|
+
}
|
|
68
|
+
router.get(
|
|
69
|
+
"/",
|
|
70
|
+
isAdmin,
|
|
71
|
+
error_catcher(async (req, res) => {
|
|
72
|
+
const { etype, ename, q } = req.query;
|
|
73
|
+
const qlink = q ? `&q=${encodeURIComponent(q)}` : "";
|
|
74
|
+
let edContents = "Choose an entity to edit";
|
|
75
|
+
const all_tables = await Table.find({}, { orderBy: "name", nocase: true });
|
|
76
|
+
const all_views = await View.find({}, { orderBy: "name", nocase: true });
|
|
77
|
+
const all_pages = await Page.find({}, { orderBy: "name", nocase: true });
|
|
78
|
+
const all_triggers = await Trigger.find(
|
|
79
|
+
{},
|
|
80
|
+
{ orderBy: "name", nocase: true }
|
|
81
|
+
);
|
|
82
|
+
let tables, views, pages, triggers;
|
|
83
|
+
if (q) {
|
|
84
|
+
const qlower = q.toLowerCase();
|
|
85
|
+
const includesQ = (s) => s.toLowerCase().includes(qlower);
|
|
86
|
+
|
|
87
|
+
tables = await asyncFilter(all_tables, async (t) => {
|
|
88
|
+
const pack = await table_pack(t);
|
|
89
|
+
return includesQ(JSON.stringify(pack));
|
|
90
|
+
});
|
|
91
|
+
views = await asyncFilter(all_views, async (t) => {
|
|
92
|
+
const pack = await view_pack(t);
|
|
93
|
+
return includesQ(JSON.stringify(pack));
|
|
94
|
+
});
|
|
95
|
+
pages = await asyncFilter(all_pages, async (t) => {
|
|
96
|
+
const pack = await page_pack(t);
|
|
97
|
+
return includesQ(JSON.stringify(pack));
|
|
98
|
+
});
|
|
99
|
+
triggers = await asyncFilter(all_triggers, async (t) => {
|
|
100
|
+
const pack = await trigger_pack(t);
|
|
101
|
+
return includesQ(JSON.stringify(pack));
|
|
102
|
+
});
|
|
103
|
+
} else {
|
|
104
|
+
tables = all_tables;
|
|
105
|
+
views = all_views;
|
|
106
|
+
pages = all_pages;
|
|
107
|
+
triggers = all_triggers;
|
|
108
|
+
}
|
|
109
|
+
const li_link = (etype1, ename1) =>
|
|
110
|
+
li(
|
|
111
|
+
a(
|
|
112
|
+
{
|
|
113
|
+
href: `/registry-editor?etype=${etype1}&ename=${encodeURIComponent(
|
|
114
|
+
ename1
|
|
115
|
+
)}${qlink}`,
|
|
116
|
+
class: etype1 === etype && ename1 === ename ? "fw-bold" : undefined,
|
|
117
|
+
},
|
|
118
|
+
ename1
|
|
119
|
+
)
|
|
120
|
+
);
|
|
121
|
+
const mkForm = (jsonVal) =>
|
|
122
|
+
new Form({
|
|
123
|
+
labelCols: 0,
|
|
124
|
+
action: `/registry-editor?etype=${etype}&ename=${encodeURIComponent(
|
|
125
|
+
ename
|
|
126
|
+
)}${qlink}`,
|
|
127
|
+
|
|
128
|
+
values: { regval: JSON.stringify(jsonVal, null, 2) },
|
|
129
|
+
fields: [
|
|
130
|
+
{
|
|
131
|
+
name: "regval",
|
|
132
|
+
label: "",
|
|
133
|
+
input_type: "code",
|
|
134
|
+
attributes: { mode: "application/json" },
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
});
|
|
138
|
+
switch (etype) {
|
|
139
|
+
case "table":
|
|
140
|
+
const tpack = await table_pack(
|
|
141
|
+
all_tables.find((t) => t.name === ename)
|
|
142
|
+
);
|
|
143
|
+
edContents = renderForm(mkForm(tpack), req.csrfToken());
|
|
144
|
+
break;
|
|
145
|
+
case "view":
|
|
146
|
+
const vpack = await view_pack(all_views.find((v) => v.name === ename));
|
|
147
|
+
edContents = renderForm(mkForm(vpack), req.csrfToken());
|
|
148
|
+
break;
|
|
149
|
+
case "page":
|
|
150
|
+
const ppack = await page_pack(all_pages.find((v) => v.name === ename));
|
|
151
|
+
edContents = renderForm(mkForm(ppack), req.csrfToken());
|
|
152
|
+
break;
|
|
153
|
+
case "trigger":
|
|
154
|
+
const trpack = await trigger_pack(
|
|
155
|
+
all_triggers.find((t) => t.name === ename)
|
|
156
|
+
);
|
|
157
|
+
edContents = renderForm(mkForm(trpack), req.csrfToken());
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
send_infoarch_page({
|
|
161
|
+
res,
|
|
162
|
+
req,
|
|
163
|
+
active_sub: "Registry editor",
|
|
164
|
+
contents: {
|
|
165
|
+
widths: [3, 9],
|
|
166
|
+
besides: [
|
|
167
|
+
{
|
|
168
|
+
type: "card",
|
|
169
|
+
bodyClass: "p-1",
|
|
170
|
+
title: "Entities",
|
|
171
|
+
contents: div(
|
|
172
|
+
form(
|
|
173
|
+
{ method: "GET", action: `/registry-editor` },
|
|
174
|
+
div(
|
|
175
|
+
{ class: "input-group search-bar mb-2" },
|
|
176
|
+
etype &&
|
|
177
|
+
input({ type: "hidden", name: "etype", value: etype }),
|
|
178
|
+
ename &&
|
|
179
|
+
input({ type: "hidden", name: "ename", value: ename }),
|
|
180
|
+
input({
|
|
181
|
+
type: "search",
|
|
182
|
+
class: "form-control search-bar ps-2 hasbl",
|
|
183
|
+
placeholder: "Search",
|
|
184
|
+
name: "q",
|
|
185
|
+
value: q,
|
|
186
|
+
"aria-label": "Search",
|
|
187
|
+
"aria-describedby": "button-search-submit",
|
|
188
|
+
}),
|
|
189
|
+
button(
|
|
190
|
+
{
|
|
191
|
+
class: "btn btn-outline-secondary search-bar",
|
|
192
|
+
type: "submit",
|
|
193
|
+
},
|
|
194
|
+
i({ class: "fas fa-search" })
|
|
195
|
+
)
|
|
196
|
+
)
|
|
197
|
+
),
|
|
198
|
+
// following https://iamkate.com/code/tree-views/
|
|
199
|
+
ul(
|
|
200
|
+
{ class: "katetree ps-2" },
|
|
201
|
+
li(
|
|
202
|
+
details(
|
|
203
|
+
{ open: q || etype === "table" },
|
|
204
|
+
summary("Tables"),
|
|
205
|
+
ul(
|
|
206
|
+
{ class: "ps-3" },
|
|
207
|
+
tables.map((t) => li_link("table", t.name))
|
|
208
|
+
)
|
|
209
|
+
)
|
|
210
|
+
),
|
|
211
|
+
li(
|
|
212
|
+
details(
|
|
213
|
+
{ open: q || etype === "view" },
|
|
214
|
+
summary("Views"),
|
|
215
|
+
ul(
|
|
216
|
+
{ class: "ps-3" },
|
|
217
|
+
views.map((v) => li_link("view", v.name))
|
|
218
|
+
)
|
|
219
|
+
)
|
|
220
|
+
),
|
|
221
|
+
li(
|
|
222
|
+
details(
|
|
223
|
+
{ open: q || etype === "page" }, //
|
|
224
|
+
summary("Pages"),
|
|
225
|
+
ul(
|
|
226
|
+
{ class: "ps-3" },
|
|
227
|
+
pages.map((p) => li_link("page", p.name))
|
|
228
|
+
)
|
|
229
|
+
)
|
|
230
|
+
),
|
|
231
|
+
li(
|
|
232
|
+
details(
|
|
233
|
+
{ open: q || etype === "trigger" }, //
|
|
234
|
+
summary("Triggers"),
|
|
235
|
+
ul(
|
|
236
|
+
{ class: "ps-3" },
|
|
237
|
+
triggers.map((t) => li_link("trigger", t.name))
|
|
238
|
+
)
|
|
239
|
+
)
|
|
240
|
+
)
|
|
241
|
+
)
|
|
242
|
+
),
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
type: "card",
|
|
246
|
+
title:
|
|
247
|
+
ename && etype
|
|
248
|
+
? `Registry editor: ${ename} ${etype}`
|
|
249
|
+
: "Registry editor",
|
|
250
|
+
contents: edContents,
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
})
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
router.post(
|
|
259
|
+
"/",
|
|
260
|
+
isAdmin,
|
|
261
|
+
error_catcher(async (req, res) => {
|
|
262
|
+
const { etype, ename, q } = req.query;
|
|
263
|
+
const qlink = q ? `&q=${encodeURIComponent(q)}` : "";
|
|
264
|
+
|
|
265
|
+
const entVal = JSON.parse(req.body.regval);
|
|
266
|
+
let pack = { plugins: [], tables: [], views: [], pages: [], triggers: [] };
|
|
267
|
+
|
|
268
|
+
switch (etype) {
|
|
269
|
+
case "table":
|
|
270
|
+
pack.tables = [entVal];
|
|
271
|
+
break;
|
|
272
|
+
case "view":
|
|
273
|
+
pack.views = [entVal];
|
|
274
|
+
break;
|
|
275
|
+
case "page":
|
|
276
|
+
pack.pages = [entVal];
|
|
277
|
+
break;
|
|
278
|
+
case "trigger":
|
|
279
|
+
pack.triggers = [entVal];
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
await install_pack(pack);
|
|
283
|
+
res.redirect(
|
|
284
|
+
`/registry-editor?etype=${etype}&ename=${encodeURIComponent(
|
|
285
|
+
ename
|
|
286
|
+
)}${qlink}`
|
|
287
|
+
);
|
|
288
|
+
})
|
|
289
|
+
);
|