@saltcorn/server 0.8.5 → 0.8.6-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/locales/en.json +4 -1
- package/locales/pl.json +32 -1
- package/package.json +8 -8
- package/routes/files.js +13 -2
- package/routes/tables.js +112 -4
- package/routes/viewedit.js +15 -0
- package/tests/table.test.js +13 -1
package/locales/en.json
CHANGED
|
@@ -1150,5 +1150,8 @@
|
|
|
1150
1150
|
"Tenant Base URL": "Tenant Base URL",
|
|
1151
1151
|
"Base hostname for newly created tenants. If unset, defaults to hostname": "Base hostname for newly created tenants. If unset, defaults to hostname",
|
|
1152
1152
|
"Redirect unathorized": "Redirect unathorized",
|
|
1153
|
-
"If tenant creation is not authorized, redirect to this URL": "If tenant creation is not authorized, redirect to this URL"
|
|
1153
|
+
"If tenant creation is not authorized, redirect to this URL": "If tenant creation is not authorized, redirect to this URL",
|
|
1154
|
+
"Import table %s": "Import table %s",
|
|
1155
|
+
"Import CSV": "Import CSV",
|
|
1156
|
+
"Show configuration object": "Show configuration object"
|
|
1154
1157
|
}
|
package/locales/pl.json
CHANGED
|
@@ -1122,5 +1122,36 @@
|
|
|
1122
1122
|
"Mem usage": "Zużycie pamięci",
|
|
1123
1123
|
"The field that will be shown to the user when choosing a value": "Pole jakie będzie pokazane użytkownikowi przy wyborze wartości",
|
|
1124
1124
|
"String value must match regular expression": "Wartość ciągu musi odpowiadać wyrażeniu regularnemu",
|
|
1125
|
-
"Modules up-to-date. Please restart server": "Moduły zaktualizowane. Proszę zresetować serwer"
|
|
1125
|
+
"Modules up-to-date. Please restart server": "Moduły zaktualizowane. Proszę zresetować serwer",
|
|
1126
|
+
"Install git plugins": "Zainstaluj wtyczki git",
|
|
1127
|
+
"Set available npm modules": "Ustaw dostępne moduły npm",
|
|
1128
|
+
"Only store modules can be installed on tenant instances": "Tylko moduły ze sklepu mogą być zainstalowane na instancjach tenantów",
|
|
1129
|
+
"Unsafe modules": "Moduly niezabezpieczone",
|
|
1130
|
+
"Notifications": "Powiadomienia",
|
|
1131
|
+
"No notifications": "Bez powiadomień",
|
|
1132
|
+
"In user menu": "W menu użytkownika",
|
|
1133
|
+
"Show notifications in the user menu": "Pokaż powiadomienia w menu użytkownika",
|
|
1134
|
+
"Notification settings": "Ustawienia powiadomień",
|
|
1135
|
+
"PWA": "PWA",
|
|
1136
|
+
"Progressive Web Application": "Progresywna Aplikacja Webowa",
|
|
1137
|
+
"Display": "Wyświetlanie",
|
|
1138
|
+
"Progressive Web Application enabled": "Progresywna Aplikacja Webowa włączona",
|
|
1139
|
+
"Saltcorn test email": "E-mail testowy Saltcorn",
|
|
1140
|
+
"Hello from Saltcorn": "Cześć od Saltcorn",
|
|
1141
|
+
"Set colors": "Ustaw kolory",
|
|
1142
|
+
"Theme color": "Kolor motywu",
|
|
1143
|
+
"Background color": "Kolor tła",
|
|
1144
|
+
"Table provider": "Dostawca tabeli",
|
|
1145
|
+
"Database table": "Tabela bazy danych",
|
|
1146
|
+
"Configure provider": "Skonfiguruj dostawcę",
|
|
1147
|
+
"In scope:": "W ramach:",
|
|
1148
|
+
"SSL expiry": "Wygaśnięcie SSL",
|
|
1149
|
+
"A page with this name already exists": "Strona z tą nazwą już istnieje",
|
|
1150
|
+
"Tenant Base URL": "Bazowy URL tenanta",
|
|
1151
|
+
"Base hostname for newly created tenants. If unset, defaults to hostname": "Bazowa nazwa hosta dla nowo utworzonych tenantów. Jeżeli nie ustawione, domyślnie do nazwy hosta",
|
|
1152
|
+
"Redirect unathorized": "Przekierowanie nieautoryzowane",
|
|
1153
|
+
"If tenant creation is not authorized, redirect to this URL": "Jeżeli utworzenie tenanta nie jest autoryzowane, przekieruj do tego URL",
|
|
1154
|
+
"Import table %s": "Importuj tabelę %s",
|
|
1155
|
+
"Import CSV": "Importuj CSV",
|
|
1156
|
+
"Show configuration object": "Pokaż obiekt konfiguracji"
|
|
1126
1157
|
}
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6-beta.1",
|
|
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.8.
|
|
10
|
-
"@saltcorn/builder": "0.8.
|
|
11
|
-
"@saltcorn/data": "0.8.
|
|
12
|
-
"@saltcorn/admin-models": "0.8.
|
|
13
|
-
"@saltcorn/filemanager": "0.8.
|
|
14
|
-
"@saltcorn/markup": "0.8.
|
|
15
|
-
"@saltcorn/sbadmin2": "0.8.
|
|
9
|
+
"@saltcorn/base-plugin": "0.8.6-beta.1",
|
|
10
|
+
"@saltcorn/builder": "0.8.6-beta.1",
|
|
11
|
+
"@saltcorn/data": "0.8.6-beta.1",
|
|
12
|
+
"@saltcorn/admin-models": "0.8.6-beta.1",
|
|
13
|
+
"@saltcorn/filemanager": "0.8.6-beta.1",
|
|
14
|
+
"@saltcorn/markup": "0.8.6-beta.1",
|
|
15
|
+
"@saltcorn/sbadmin2": "0.8.6-beta.1",
|
|
16
16
|
"@socket.io/cluster-adapter": "^0.2.1",
|
|
17
17
|
"@socket.io/sticky": "^1.0.1",
|
|
18
18
|
"adm-zip": "0.5.10",
|
package/routes/files.js
CHANGED
|
@@ -14,7 +14,12 @@ const resizer = require("resize-with-sharp-or-jimp");
|
|
|
14
14
|
const db = require("@saltcorn/data/db");
|
|
15
15
|
|
|
16
16
|
const { renderForm } = require("@saltcorn/markup");
|
|
17
|
-
const {
|
|
17
|
+
const {
|
|
18
|
+
isAdmin,
|
|
19
|
+
error_catcher,
|
|
20
|
+
setTenant,
|
|
21
|
+
is_relative_url,
|
|
22
|
+
} = require("./utils.js");
|
|
18
23
|
const { h1, div, text } = require("@saltcorn/markup/tags");
|
|
19
24
|
const { editRoleForm, fileUploadForm } = require("../markup/forms.js");
|
|
20
25
|
const { strictParseInt } = require("@saltcorn/data/plugin-helper");
|
|
@@ -441,6 +446,7 @@ router.post(
|
|
|
441
446
|
isAdmin,
|
|
442
447
|
error_catcher(async (req, res) => {
|
|
443
448
|
const serve_path = req.params[0];
|
|
449
|
+
const { redirect } = req.query;
|
|
444
450
|
const f = await File.findOne(serve_path);
|
|
445
451
|
if (!f) {
|
|
446
452
|
req.flash("error", "File not found");
|
|
@@ -460,7 +466,12 @@ router.post(
|
|
|
460
466
|
}
|
|
461
467
|
req.flash("error", result.error);
|
|
462
468
|
}
|
|
463
|
-
|
|
469
|
+
if (!req.xhr)
|
|
470
|
+
res.redirect(
|
|
471
|
+
(is_relative_url(redirect) && redirect) ||
|
|
472
|
+
`/files?dir=${encodeURIComponent(f.current_folder)}`
|
|
473
|
+
);
|
|
474
|
+
else res.json({ success: true });
|
|
464
475
|
})
|
|
465
476
|
);
|
|
466
477
|
|
package/routes/tables.js
CHANGED
|
@@ -17,6 +17,7 @@ const {
|
|
|
17
17
|
link,
|
|
18
18
|
settingsDropdown,
|
|
19
19
|
post_delete_btn,
|
|
20
|
+
post_btn,
|
|
20
21
|
post_dropdown_item,
|
|
21
22
|
} = require("@saltcorn/markup");
|
|
22
23
|
const {
|
|
@@ -52,7 +53,7 @@ const { getState } = require("@saltcorn/data/db/state");
|
|
|
52
53
|
const { cardHeaderTabs } = require("@saltcorn/markup/layout_utils");
|
|
53
54
|
const { tablesList } = require("./common_lists");
|
|
54
55
|
const { InvalidConfiguration } = require("@saltcorn/data/utils");
|
|
55
|
-
|
|
56
|
+
const path = require("path");
|
|
56
57
|
/**
|
|
57
58
|
* @type {object}
|
|
58
59
|
* @const
|
|
@@ -1463,6 +1464,89 @@ router.post(
|
|
|
1463
1464
|
})
|
|
1464
1465
|
);
|
|
1465
1466
|
|
|
1467
|
+
const previewCSV = async ({ newPath, table, req, res, full }) => {
|
|
1468
|
+
let parse_res;
|
|
1469
|
+
try {
|
|
1470
|
+
parse_res = await table.import_csv_file(newPath, {
|
|
1471
|
+
recalc_stored: true,
|
|
1472
|
+
no_table_write: true,
|
|
1473
|
+
});
|
|
1474
|
+
} catch (e) {
|
|
1475
|
+
parse_res = { error: e.message };
|
|
1476
|
+
}
|
|
1477
|
+
if (parse_res.error) {
|
|
1478
|
+
if (parse_res.error) req.flash("error", parse_res.error);
|
|
1479
|
+
await fs.unlink(newPath);
|
|
1480
|
+
res.redirect(`/table/${table.id}`);
|
|
1481
|
+
} else {
|
|
1482
|
+
const rows = parse_res.rows || [];
|
|
1483
|
+
res.sendWrap(req.__(`Import table %s`, table.name), {
|
|
1484
|
+
above: [
|
|
1485
|
+
{
|
|
1486
|
+
type: "breadcrumbs",
|
|
1487
|
+
crumbs: [
|
|
1488
|
+
{ text: req.__("Tables"), href: "/table" },
|
|
1489
|
+
{ href: `/table/${table.id}`, text: table.name },
|
|
1490
|
+
{
|
|
1491
|
+
text: req.__("Import CSV"),
|
|
1492
|
+
},
|
|
1493
|
+
],
|
|
1494
|
+
},
|
|
1495
|
+
{
|
|
1496
|
+
type: "card",
|
|
1497
|
+
title: req.__(`Import CSV`),
|
|
1498
|
+
contents: div(
|
|
1499
|
+
{
|
|
1500
|
+
"data-csv-filename": path.basename(newPath),
|
|
1501
|
+
},
|
|
1502
|
+
p(parse_res.success),
|
|
1503
|
+
post_btn(
|
|
1504
|
+
`/files/delete/${path.basename(newPath)}?redirect=/table/${
|
|
1505
|
+
table.id
|
|
1506
|
+
}}`,
|
|
1507
|
+
"Cancel",
|
|
1508
|
+
req.csrfToken(),
|
|
1509
|
+
{
|
|
1510
|
+
btnClass: "btn-danger",
|
|
1511
|
+
formClass: "d-inline me-2",
|
|
1512
|
+
icon: "fa fa-times",
|
|
1513
|
+
}
|
|
1514
|
+
),
|
|
1515
|
+
post_btn(
|
|
1516
|
+
`/table/finish_upload_to_table/${table.name}/${path.basename(
|
|
1517
|
+
newPath
|
|
1518
|
+
)}`,
|
|
1519
|
+
"Proceed",
|
|
1520
|
+
req.csrfToken(),
|
|
1521
|
+
{ icon: "fa fa-check", formClass: "d-inline" }
|
|
1522
|
+
)
|
|
1523
|
+
),
|
|
1524
|
+
},
|
|
1525
|
+
{
|
|
1526
|
+
type: "card",
|
|
1527
|
+
title: req.__(`Preview`),
|
|
1528
|
+
contents: div(
|
|
1529
|
+
mkTable(
|
|
1530
|
+
table.fields.map((f) => ({ label: f.name, key: f.name })),
|
|
1531
|
+
full ? rows : rows.slice(0, 10)
|
|
1532
|
+
),
|
|
1533
|
+
!full &&
|
|
1534
|
+
rows.length > 10 &&
|
|
1535
|
+
a(
|
|
1536
|
+
{
|
|
1537
|
+
href: `/table/preview_full_csv_file/${
|
|
1538
|
+
table.name
|
|
1539
|
+
}/${path.basename(newPath)}`,
|
|
1540
|
+
},
|
|
1541
|
+
`See all ${rows.length} rows`
|
|
1542
|
+
)
|
|
1543
|
+
),
|
|
1544
|
+
},
|
|
1545
|
+
],
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
};
|
|
1549
|
+
|
|
1466
1550
|
/**
|
|
1467
1551
|
* Import Table Data from CSV POST handler
|
|
1468
1552
|
* @name post/upload_to_table/:name,
|
|
@@ -1486,15 +1570,39 @@ router.post(
|
|
|
1486
1570
|
const newPath = File.get_new_path();
|
|
1487
1571
|
await req.files.file.mv(newPath);
|
|
1488
1572
|
//console.log(req.files.file.data)
|
|
1573
|
+
await previewCSV({ newPath, table, res, req });
|
|
1574
|
+
})
|
|
1575
|
+
);
|
|
1576
|
+
|
|
1577
|
+
router.get(
|
|
1578
|
+
"/preview_full_csv_file/:name/:filename",
|
|
1579
|
+
isAdmin,
|
|
1580
|
+
error_catcher(async (req, res) => {
|
|
1581
|
+
const { name, filename } = req.params;
|
|
1582
|
+
const table = await Table.findOne({ name });
|
|
1583
|
+
const f = await File.findOne(filename);
|
|
1584
|
+
await previewCSV({ newPath: f.location, table, res, req, full: true });
|
|
1585
|
+
})
|
|
1586
|
+
);
|
|
1587
|
+
|
|
1588
|
+
router.post(
|
|
1589
|
+
"/finish_upload_to_table/:name/:filename",
|
|
1590
|
+
isAdmin,
|
|
1591
|
+
error_catcher(async (req, res) => {
|
|
1592
|
+
const { name, filename } = req.params;
|
|
1593
|
+
const table = await Table.findOne({ name });
|
|
1594
|
+
const f = await File.findOne(filename);
|
|
1595
|
+
|
|
1489
1596
|
try {
|
|
1490
|
-
const parse_res = await table.import_csv_file(
|
|
1597
|
+
const parse_res = await table.import_csv_file(f.location, {
|
|
1598
|
+
recalc_stored: true,
|
|
1599
|
+
});
|
|
1491
1600
|
if (parse_res.error) req.flash("error", parse_res.error);
|
|
1492
1601
|
else req.flash("success", parse_res.success);
|
|
1493
1602
|
} catch (e) {
|
|
1494
1603
|
req.flash("error", e.message);
|
|
1495
1604
|
}
|
|
1496
|
-
|
|
1497
|
-
await fs.unlink(newPath);
|
|
1605
|
+
await fs.unlink(f.location);
|
|
1498
1606
|
res.redirect(`/table/${table.id}`);
|
|
1499
1607
|
})
|
|
1500
1608
|
);
|
package/routes/viewedit.js
CHANGED
|
@@ -15,6 +15,7 @@ const {
|
|
|
15
15
|
script,
|
|
16
16
|
text,
|
|
17
17
|
domReady,
|
|
18
|
+
code,
|
|
18
19
|
pre,
|
|
19
20
|
} = require("@saltcorn/markup/tags");
|
|
20
21
|
|
|
@@ -325,6 +326,20 @@ router.get(
|
|
|
325
326
|
),
|
|
326
327
|
contents: renderForm(form, req.csrfToken()),
|
|
327
328
|
},
|
|
329
|
+
{
|
|
330
|
+
type: "card",
|
|
331
|
+
|
|
332
|
+
title: req.__("View configuration"),
|
|
333
|
+
contents: {
|
|
334
|
+
type: "tabs",
|
|
335
|
+
contents: [
|
|
336
|
+
pre(code(JSON.stringify(viewrow.configuration, null, 2))),
|
|
337
|
+
],
|
|
338
|
+
tabsStyle: "Accordion",
|
|
339
|
+
startClosed: true,
|
|
340
|
+
titles: [req.__("Show configuration object")],
|
|
341
|
+
},
|
|
342
|
+
},
|
|
328
343
|
],
|
|
329
344
|
});
|
|
330
345
|
})
|
package/tests/table.test.js
CHANGED
|
@@ -156,13 +156,25 @@ Pencil, 0.5,2, t`;
|
|
|
156
156
|
it("should upload csv to existing table", async () => {
|
|
157
157
|
const csv = `author,Pages
|
|
158
158
|
Joe Celko, 856
|
|
159
|
-
Gordon Kane,
|
|
159
|
+
Gordon Kane, 218`;
|
|
160
160
|
const loginCookie = await getAdminLoginCookie();
|
|
161
161
|
const app = await getApp({ disableCsrf: true });
|
|
162
|
+
let filename;
|
|
162
163
|
await request(app)
|
|
163
164
|
.post("/table/upload_to_table/books")
|
|
164
165
|
.set("Cookie", loginCookie)
|
|
165
166
|
.attach("file", Buffer.from(csv, "utf-8"))
|
|
167
|
+
.expect(toInclude(">Preview<"))
|
|
168
|
+
.expect(toInclude("Proceed"))
|
|
169
|
+
.expect((res) => {
|
|
170
|
+
filename = res.text.match(
|
|
171
|
+
/data-csv-filename\=\"([A-Za-z0-9 _\-]*)\"/
|
|
172
|
+
)[1];
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
await request(app)
|
|
176
|
+
.post(`/table/finish_upload_to_table/books/${filename}`)
|
|
177
|
+
.set("Cookie", loginCookie)
|
|
166
178
|
.expect(toRedirect("/table/2"));
|
|
167
179
|
await request(app)
|
|
168
180
|
.get(`/table/2`)
|