@saltcorn/server 0.7.4-beta.1 → 0.7.4-beta.3
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/routes.js +64 -86
- package/locales/en.json +36 -1
- package/locales/ru.json +60 -7
- package/markup/admin.js +17 -4
- package/markup/expression_blurb.js +1 -1
- package/package.json +7 -7
- package/public/blockly.js +11 -5
- package/public/gridedit.js +7 -2
- package/public/saltcorn-common.js +27 -29
- package/public/saltcorn.css +24 -1
- package/public/saltcorn.js +56 -19
- package/routes/actions.js +2 -39
- package/routes/admin.js +16 -17
- package/routes/api.js +7 -6
- package/routes/common_lists.js +419 -0
- package/routes/diagram.js +59 -0
- package/routes/fields.js +42 -12
- package/routes/index.js +6 -0
- package/routes/pageedit.js +14 -108
- package/routes/plugins.js +15 -15
- package/routes/tables.js +10 -41
- package/routes/tag_entries.js +173 -0
- package/routes/tags.js +266 -0
- package/routes/viewedit.js +19 -136
- package/tests/page.test.js +9 -0
- package/tests/viewedit.test.js +16 -0
package/auth/routes.js
CHANGED
|
@@ -335,7 +335,7 @@ router.get(
|
|
|
335
335
|
if (result.error) req.flash("danger", result.error);
|
|
336
336
|
else if (result) {
|
|
337
337
|
req.flash("success", req.__("Email verified"));
|
|
338
|
-
const u = await User.
|
|
338
|
+
const u = await User.findForSession({ email });
|
|
339
339
|
if (u) u.relogin(req);
|
|
340
340
|
}
|
|
341
341
|
res.redirect("/");
|
|
@@ -470,11 +470,11 @@ router.get(
|
|
|
470
470
|
form,
|
|
471
471
|
{},
|
|
472
472
|
restore +
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
)
|
|
473
|
+
script(
|
|
474
|
+
domReady(
|
|
475
|
+
`$('form.create-first-user button[type=submit]').click(function(){press_store_button(this)})`
|
|
477
476
|
)
|
|
477
|
+
)
|
|
478
478
|
);
|
|
479
479
|
} else {
|
|
480
480
|
req.flash("danger", req.__("Users already present"));
|
|
@@ -503,7 +503,7 @@ router.post(
|
|
|
503
503
|
);
|
|
504
504
|
if (err) req.flash("error", err);
|
|
505
505
|
else req.flash("success", req.__("Successfully restored backup"));
|
|
506
|
-
fs.unlink(newPath, function () {});
|
|
506
|
+
fs.unlink(newPath, function () { });
|
|
507
507
|
res.redirect(`/auth/login`);
|
|
508
508
|
} else {
|
|
509
509
|
req.flash("danger", req.__("Users already present"));
|
|
@@ -536,12 +536,7 @@ router.post(
|
|
|
536
536
|
const { email, password } = form.values;
|
|
537
537
|
const u = await User.create({ email, password, role_id: 1 });
|
|
538
538
|
req.login(
|
|
539
|
-
|
|
540
|
-
email: u.email,
|
|
541
|
-
id: u.id,
|
|
542
|
-
role_id: u.role_id,
|
|
543
|
-
tenant: db.getTenantSchema(),
|
|
544
|
-
},
|
|
539
|
+
u.session_object,
|
|
545
540
|
function (err) {
|
|
546
541
|
if (!err) {
|
|
547
542
|
Trigger.emitEvent("Login", null, u);
|
|
@@ -646,12 +641,7 @@ const getNewUserForm = async (new_user_view_name, req, askEmail) => {
|
|
|
646
641
|
*/
|
|
647
642
|
const signup_login_with_user = (u, req, res) =>
|
|
648
643
|
req.login(
|
|
649
|
-
|
|
650
|
-
email: u.email,
|
|
651
|
-
id: u.id,
|
|
652
|
-
role_id: u.role_id,
|
|
653
|
-
tenant: db.getTenantSchema(),
|
|
654
|
-
},
|
|
644
|
+
u.session_object,
|
|
655
645
|
function (err) {
|
|
656
646
|
if (!err) {
|
|
657
647
|
Trigger.emitEvent("Login", null, u);
|
|
@@ -930,7 +920,7 @@ function handler(req, res) {
|
|
|
930
920
|
req.flash(
|
|
931
921
|
"error",
|
|
932
922
|
"You've made too many failed attempts in a short period of time, please try again " +
|
|
933
|
-
|
|
923
|
+
moment(req.rateLimit.resetTime).fromNow()
|
|
934
924
|
);
|
|
935
925
|
res.redirect("/auth/login"); // brute force protection triggered, send them back to the login page
|
|
936
926
|
}
|
|
@@ -1194,7 +1184,7 @@ const userSettings = async ({ req, res, pwform, user }) => {
|
|
|
1194
1184
|
div(
|
|
1195
1185
|
user.api_token
|
|
1196
1186
|
? span({ class: "me-1" }, req.__("API token for this user: ")) +
|
|
1197
|
-
|
|
1187
|
+
code(user.api_token)
|
|
1198
1188
|
: req.__("No API token issued")
|
|
1199
1189
|
),
|
|
1200
1190
|
// button for reset or generate api token
|
|
@@ -1208,16 +1198,16 @@ const userSettings = async ({ req, res, pwform, user }) => {
|
|
|
1208
1198
|
),
|
|
1209
1199
|
// button for remove api token
|
|
1210
1200
|
user.api_token &&
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1201
|
+
div(
|
|
1202
|
+
{ class: "mt-4 ms-2 d-inline-block" },
|
|
1203
|
+
post_btn(
|
|
1204
|
+
`/auth/remove-api-token`,
|
|
1205
|
+
// TBD localization
|
|
1206
|
+
user.api_token ? req.__("Remove") : req.__("Generate"),
|
|
1207
|
+
req.csrfToken(),
|
|
1208
|
+
{ req: req, confirm: true }
|
|
1209
|
+
)
|
|
1210
|
+
),
|
|
1221
1211
|
],
|
|
1222
1212
|
};
|
|
1223
1213
|
return {
|
|
@@ -1228,13 +1218,13 @@ const userSettings = async ({ req, res, pwform, user }) => {
|
|
|
1228
1218
|
},
|
|
1229
1219
|
...(usersets
|
|
1230
1220
|
? [
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1221
|
+
{
|
|
1222
|
+
type: "card",
|
|
1223
|
+
class: "mt-0",
|
|
1224
|
+
title: userSetsName,
|
|
1225
|
+
contents: usersets,
|
|
1226
|
+
},
|
|
1227
|
+
]
|
|
1238
1228
|
: []),
|
|
1239
1229
|
{
|
|
1240
1230
|
type: "card",
|
|
@@ -1257,35 +1247,35 @@ const userSettings = async ({ req, res, pwform, user }) => {
|
|
|
1257
1247
|
},
|
|
1258
1248
|
...(show2FAPolicy
|
|
1259
1249
|
? [
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1250
|
+
{
|
|
1251
|
+
type: "card",
|
|
1252
|
+
title: req.__("Two-factor authentication"),
|
|
1253
|
+
contents: [
|
|
1254
|
+
div(
|
|
1255
|
+
user._attributes.totp_enabled
|
|
1256
|
+
? req.__("Two-factor authentication is enabled")
|
|
1257
|
+
: req.__("Two-factor authentication is disabled")
|
|
1258
|
+
),
|
|
1259
|
+
div(
|
|
1260
|
+
user._attributes.totp_enabled
|
|
1261
|
+
? a(
|
|
1262
|
+
{
|
|
1263
|
+
href: "/auth/twofa/disable/totp",
|
|
1264
|
+
class: "btn btn-danger mt-2",
|
|
1265
|
+
},
|
|
1266
|
+
req.__("Disable TWA")
|
|
1267
|
+
)
|
|
1268
|
+
: a(
|
|
1269
|
+
{
|
|
1270
|
+
href: "/auth/twofa/setup/totp",
|
|
1271
|
+
class: "btn btn-primary mt-2",
|
|
1272
|
+
},
|
|
1273
|
+
req.__("Enable TWA")
|
|
1274
|
+
)
|
|
1275
|
+
),
|
|
1276
|
+
],
|
|
1277
|
+
},
|
|
1278
|
+
]
|
|
1289
1279
|
: []),
|
|
1290
1280
|
...(apikeycard ? [apikeycard] : []),
|
|
1291
1281
|
],
|
|
@@ -1338,18 +1328,12 @@ router.post(
|
|
|
1338
1328
|
"/setlanguage",
|
|
1339
1329
|
loggedIn,
|
|
1340
1330
|
error_catcher(async (req, res) => {
|
|
1341
|
-
const u = await User.
|
|
1331
|
+
const u = await User.findForSession({ id: req.user.id });
|
|
1342
1332
|
const newlang = available_languages[req.body.locale];
|
|
1343
1333
|
if (newlang && u) {
|
|
1344
1334
|
await u.set_language(req.body.locale);
|
|
1345
1335
|
req.login(
|
|
1346
|
-
|
|
1347
|
-
email: u.email,
|
|
1348
|
-
id: u.id,
|
|
1349
|
-
role_id: u.role_id,
|
|
1350
|
-
language: req.body.locale,
|
|
1351
|
-
tenant: db.getTenantSchema(),
|
|
1352
|
-
},
|
|
1336
|
+
u.session_object,
|
|
1353
1337
|
function (err) {
|
|
1354
1338
|
if (!err) {
|
|
1355
1339
|
req.flash("success", req.__("Language changed to %s", newlang));
|
|
@@ -1453,16 +1437,11 @@ router.post(
|
|
|
1453
1437
|
return;
|
|
1454
1438
|
}
|
|
1455
1439
|
|
|
1456
|
-
const u = await User.
|
|
1440
|
+
const u = await User.findForSession({ id: req.user.id });
|
|
1457
1441
|
await u.update({ email: form.values.email });
|
|
1458
1442
|
u.email = form.values.email;
|
|
1459
1443
|
req.login(
|
|
1460
|
-
|
|
1461
|
-
email: u.email,
|
|
1462
|
-
id: u.id,
|
|
1463
|
-
role_id: u.role_id,
|
|
1464
|
-
tenant: db.getTenantSchema(),
|
|
1465
|
-
},
|
|
1444
|
+
u.session_object,
|
|
1466
1445
|
function (err) {
|
|
1467
1446
|
if (!err) {
|
|
1468
1447
|
Trigger.emitEvent("Login", null, u);
|
|
@@ -1553,7 +1532,7 @@ router.all(
|
|
|
1553
1532
|
return;
|
|
1554
1533
|
}
|
|
1555
1534
|
if (wfres.verified === true) {
|
|
1556
|
-
const user = await User.
|
|
1535
|
+
const user = await User.findForSession({ id: req.user.id });
|
|
1557
1536
|
await user.set_to_verified();
|
|
1558
1537
|
req.flash("success", req.__("User verified"));
|
|
1559
1538
|
user.relogin(req);
|
|
@@ -1590,9 +1569,8 @@ router.get(
|
|
|
1590
1569
|
// generate QR code for scanning into Google Authenticator
|
|
1591
1570
|
// reference: https://code.google.com/p/google-authenticator/wiki/KeyUriFormat
|
|
1592
1571
|
const site_name = getState().getConfig("site_name");
|
|
1593
|
-
const otpUrl = `otpauth://totp/${
|
|
1594
|
-
|
|
1595
|
-
}?secret=${encodedKey}&period=30&issuer=${encodeURIComponent(site_name)}`;
|
|
1572
|
+
const otpUrl = `otpauth://totp/${user.email
|
|
1573
|
+
}?secret=${encodedKey}&period=30&issuer=${encodeURIComponent(site_name)}`;
|
|
1596
1574
|
const image = await qrcode.toDataURL(otpUrl);
|
|
1597
1575
|
res.sendWrap(req.__("Setup two-factor authentication"), {
|
|
1598
1576
|
type: "card",
|
|
@@ -1763,7 +1741,7 @@ router.post(
|
|
|
1763
1741
|
failureFlash: true,
|
|
1764
1742
|
}),
|
|
1765
1743
|
error_catcher(async (req, res) => {
|
|
1766
|
-
const user = await User.
|
|
1744
|
+
const user = await User.findForSession({ id: req.user.pending_user.id });
|
|
1767
1745
|
user.relogin(req);
|
|
1768
1746
|
Trigger.emitEvent("Login", null, user);
|
|
1769
1747
|
res.redirect("/");
|
package/locales/en.json
CHANGED
|
@@ -948,5 +948,40 @@
|
|
|
948
948
|
"Source of module for install. Few options:npm - download from npm repository,local - get from local file system,github - download from github,git - get from git": "Source of module for install. Few options:npm - download from npm repository,local - get from local file system,github - download from github,git - get from git",
|
|
949
949
|
"Version of module, latest is default value": "Version of module, latest is default value",
|
|
950
950
|
"For npm - name of npm package, e.g. @saltcorn/html or saltcorn-gantt, check at npmjs.com, for local - absolute path to module folder in file system, e.g. C:\\gitsrc\\any-bootstrap-theme\\, for github - name of github project.": "For npm - name of npm package, e.g. @saltcorn/html or saltcorn-gantt, check at npmjs.com, for local - absolute path to module folder in file system, e.g. C:\\gitsrc\\any-bootstrap-theme\\, for github - name of github project.",
|
|
951
|
-
"Modules up-to-date": "Modules up-to-date"
|
|
951
|
+
"Modules up-to-date": "Modules up-to-date",
|
|
952
|
+
"User must have this role or higher to read rows from the table, unless they are the owner": "User must have this role or higher to read rows from the table, unless they are the owner",
|
|
953
|
+
"User must have this role or higher to edit or create new rows in the table, unless they are the owner": "User must have this role or higher to edit or create new rows in the table, unless they are the owner",
|
|
954
|
+
"Tagname": "Tagname",
|
|
955
|
+
"Create tag": "Create tag",
|
|
956
|
+
"Tags": "Tags",
|
|
957
|
+
"New tag": "New tag",
|
|
958
|
+
"Tag name": "Tag name",
|
|
959
|
+
"%s Tag": "%s Tag",
|
|
960
|
+
"Remove From Tag": "Remove From Tag",
|
|
961
|
+
"Add tables": "Add tables",
|
|
962
|
+
"Add views": "Add views",
|
|
963
|
+
"Add tages": "Add tages",
|
|
964
|
+
"Trigger": "Trigger",
|
|
965
|
+
"Add %s to tag": "Add %s to tag",
|
|
966
|
+
"Tag %s deleted": "Tag %s deleted",
|
|
967
|
+
"Tag %s created": "Tag %s created",
|
|
968
|
+
"Application diagram": "Application diagram",
|
|
969
|
+
"Diagram": "Diagram",
|
|
970
|
+
"Entry point": "Entry point",
|
|
971
|
+
"Platform": "Platform",
|
|
972
|
+
"docker": "docker",
|
|
973
|
+
"android": "android",
|
|
974
|
+
"iOS": "iOS",
|
|
975
|
+
"App file": "App file",
|
|
976
|
+
"Server URL": "Server URL",
|
|
977
|
+
"Module %s installed, please complete configuration.": "Module %s installed, please complete configuration.",
|
|
978
|
+
"Module %s removed.": "Module %s removed.",
|
|
979
|
+
"Module %s installed": "Module %s installed",
|
|
980
|
+
"Upgrading modules...": "Upgrading modules...",
|
|
981
|
+
"Backup now": "Backup now",
|
|
982
|
+
"Snapshot now": "Snapshot now",
|
|
983
|
+
"Restore/download automated backups »": "Restore/download automated backups »",
|
|
984
|
+
"Snapshots store your application structure and definition, without the table data. Individual views and pages can be restored from snapshots from the <a href='/viewedit'>view</a> or <a href='/pageedit'>pages</a> overviews (\"Restore\" from individual page or view dropdowns).": "Snapshots store your application structure and definition, without the table data. Individual views and pages can be restored from snapshots from the <a href='/viewedit'>view</a> or <a href='/pageedit'>pages</a> overviews (\"Restore\" from individual page or view dropdowns).",
|
|
985
|
+
"List/download snapshots »": "List/download snapshots »",
|
|
986
|
+
"Discover tables that are already in the Database, but not known to Saltcorn": "Discover tables that are already in the Database, but not known to Saltcorn"
|
|
952
987
|
}
|
package/locales/ru.json
CHANGED
|
@@ -180,7 +180,7 @@
|
|
|
180
180
|
"Pack %s uninstalled": "Пакет %s удален",
|
|
181
181
|
"Uninstall": "Удалить",
|
|
182
182
|
"Result preview for ": "Предварительный просмотр результатов для ",
|
|
183
|
-
"Choose views for <a href=\"/search\">search results</a> for each table.<br/>Set to blank to omit table from global search.": "Выберите для каждой таблицы
|
|
183
|
+
"Choose views for <a href=\"/search\">search results</a> for each table.<br/>Set to blank to omit table from global search.": "Выберите для каждой таблицы представление для вывода <a href=\"/search\">результатов поиска</a>.<br/>Оставьте незаполненным, если не хотите, чтобы таблица отображалась в глобальном поиске.",
|
|
184
184
|
"These tables lack suitable views: ": "Указанные таблицы не имеют представлений с поддержкой поиска: ",
|
|
185
185
|
"Search configuration": "Настройки поиска",
|
|
186
186
|
"Table saved with version history enabled": "Таблица сохранена с включенной историей версий",
|
|
@@ -303,7 +303,7 @@
|
|
|
303
303
|
"Clone": "Клонировать",
|
|
304
304
|
"View %s cloned as %s": "Представление %s клонировано в %s",
|
|
305
305
|
"Duplicate": "Дублировать",
|
|
306
|
-
"View %s duplicated as %s": "Представление %s
|
|
306
|
+
"View %s duplicated as %s": "Представление %s дублировано в %s",
|
|
307
307
|
"The view name will appear as the title of pop-ups showing this view, and in the URL when it is shown alone.": "Имя представления отображается как заголовок всплывающего окна или в URL, в зависимости от режима отображения.",
|
|
308
308
|
"Saltcorn version": "версия платформы",
|
|
309
309
|
"Node.js version": "версия Node.js",
|
|
@@ -337,7 +337,7 @@
|
|
|
337
337
|
"Subtables": "Подчиненные таблицы",
|
|
338
338
|
"List View": "Представление Список (List)",
|
|
339
339
|
"Show View": "Представление Show",
|
|
340
|
-
"Which related tables would you like to show in sub-lists below the selected item?": "
|
|
340
|
+
"Which related tables would you like to show in sub-lists below the selected item?": "Какие связанные таблицы вы хотите отобразить в подчиненных списках (sub-lists) под выбранной записью?",
|
|
341
341
|
"Order and layout": "Сортировка и Макет",
|
|
342
342
|
"Order by": "Сортировка по",
|
|
343
343
|
"Descending": "В обратном порядке",
|
|
@@ -801,11 +801,11 @@
|
|
|
801
801
|
"Expiration in days": "Срок хранения (в днях)",
|
|
802
802
|
"Delete old backup files in this directory after the set number of days": "Старые резервные копии в этой папке будут удалять после истечения срока хранения ",
|
|
803
803
|
"Backup settings updated": "Настройки резервного копирования обновлены",
|
|
804
|
-
"Periodic snapshots enabled": "Регулярные снимки (
|
|
805
|
-
"Snapshot will be made every hour if there are changes": "Снимки (
|
|
804
|
+
"Periodic snapshots enabled": "Регулярные снимки (снепшоты)",
|
|
805
|
+
"Snapshot will be made every hour if there are changes": "Снимки (снепшоты) будут выполняться каждый час",
|
|
806
806
|
"Manual backup": "Ручное резервное копирование",
|
|
807
807
|
"Automated backup": "Автоматическое резервное копирование",
|
|
808
|
-
"Snapshots": "Снимки (
|
|
808
|
+
"Snapshots": "Снимки (снепшоты)",
|
|
809
809
|
"Mobile app": "Мобильное приложение",
|
|
810
810
|
"Module store": "Магазин модулей",
|
|
811
811
|
"Upgrade installed modules": "Обновить установленные модули",
|
|
@@ -829,5 +829,58 @@
|
|
|
829
829
|
"App file": "Файл приложения",
|
|
830
830
|
"Server URL": "URL сервера",
|
|
831
831
|
"android": "android",
|
|
832
|
-
"iOS": "iOS"
|
|
832
|
+
"iOS": "iOS",
|
|
833
|
+
"Tag %s created": "Тег %s создан",
|
|
834
|
+
"%s Tag": "%s Тег",
|
|
835
|
+
"Add tables": "Добавить таблицы",
|
|
836
|
+
"Add views": "Добавить представления",
|
|
837
|
+
"Remove From Tag": "Удалить из тега",
|
|
838
|
+
"Add tages": "Добавить теги",
|
|
839
|
+
"Trigger": "Триггер",
|
|
840
|
+
"Tag": "Тег",
|
|
841
|
+
"Download snapshots": "Скачать снепшоты",
|
|
842
|
+
"Snapshots store your application structure and definition, without the table data. Individual views and pages can be restored from snapshots from the <a href='/viewedit'>view</a> or <a href='/pageedit'>pages</a> overviews (\"Restore\" from individual page or view dropdowns).": "Снепшоты сохраняют структуру приложения, но не сохраняют данные в таблицах. Конкретные представления и страницы могут быть восстановлены по ссылке <a href='/viewedit'>view</a> или <a href='/pageedit'>pages</a> (Кнопка \"Восстановить\" в выпадающем меню представления или страницы).",
|
|
843
|
+
"List/download snapshots »": "Список снепшотов »",
|
|
844
|
+
"Add %s to tag": "Добавить %s к тегу",
|
|
845
|
+
"Tagname": "Имя тега",
|
|
846
|
+
"Create tag": "Создать тег",
|
|
847
|
+
"Tags": "Теги",
|
|
848
|
+
"New tag": "Новый тег",
|
|
849
|
+
"Tag name": "Имя тега",
|
|
850
|
+
"Tag %s deleted": "Тег %s удален",
|
|
851
|
+
"Add entries to tag": "Добавить объекты в тег",
|
|
852
|
+
"Please select at least one item": "Пожалуйста добавьте хотя бы один объект",
|
|
853
|
+
"Backup now": "Сделать бекап сейчас",
|
|
854
|
+
"Snapshot now": "Сделать снепшот сейчас",
|
|
855
|
+
"Restore/download automated backups »": "Восстановить/скачать резервные копии »",
|
|
856
|
+
"No changes detected, snapshot skipped": "Нет изменений, снепшот пропущен",
|
|
857
|
+
"Pattern": "Паттерн",
|
|
858
|
+
"Add pages": "Добавить страницы",
|
|
859
|
+
"Add triggers": "Добавить триггеры",
|
|
860
|
+
"Edit Module": "Настроить Модуль",
|
|
861
|
+
"Page %s duplicated as %s": "Страница %s дублирована в %s",
|
|
862
|
+
"Auto save": "Автосохранение",
|
|
863
|
+
"Save any changes immediately": "Сохранять все изменения данных в форме немедленно",
|
|
864
|
+
"This is the view to which the user will be sent when the form is submitted. The view you specify here can be ignored depending on the context of the form, for instance if it appears in a pop-up the redirect will not take place.": "Указывается представление, куда будет перенаправлен пользователь после отправки формы. В некоторых случаях перенаправление не будет выполнено, например, если форма использована в режиме всплывающего окна.",
|
|
865
|
+
"Destination view": "Destination view",
|
|
866
|
+
"Destination URL Formula": "Destination URL Formula",
|
|
867
|
+
"Back": "Назад",
|
|
868
|
+
"Backup successful": "Резервная копия успешно создана",
|
|
869
|
+
"Save before going back": "Save before going back",
|
|
870
|
+
"Reload after going back": "Reload after going back",
|
|
871
|
+
"Steps to go back": "Steps to go back",
|
|
872
|
+
"View pattern": "Паттерн представления",
|
|
873
|
+
"The view pattern sets the foundation of how the view relates to the table and the behaviour of the view": "The view pattern sets the foundation of how the view relates to the table and the behaviour of the view",
|
|
874
|
+
"This will delete <strong>EVERYTHING</strong> in the selected categories": "Внимание! Будут удалены <strong>ВСЕ</strong> данные в выбранных категориях",
|
|
875
|
+
"Tag not found": "Тэг не найден",
|
|
876
|
+
"Build Result": "Результат сборки",
|
|
877
|
+
"Download automated backup": "Автоматически созданные резервные копии",
|
|
878
|
+
"Restoring automated backup": "Восстановление из автоматически созданной резервной копии",
|
|
879
|
+
"Download one of the backups above": "Скачать один из бекапов (файлов с резервной копией) выше",
|
|
880
|
+
"Clear this application": "Удалить ВСЕ данные в текущем приложении",
|
|
881
|
+
"(tick all boxes)": "(указав все галочки)",
|
|
882
|
+
"When prompted to create the first user, click the link to restore a backup": "Вместо создания первого пользователя, выберите Восстановление из резервной копии (restore a backup)",
|
|
883
|
+
"Select the downloaded backup file": "Выбрать скаченный бекап (файл с резервной копией)",
|
|
884
|
+
"Snapshot successful": "Снимок (Снепшот) выполнен успешно",
|
|
885
|
+
"Unable to build the app:": "Ошибка создания приложения:"
|
|
833
886
|
}
|
package/markup/admin.js
CHANGED
|
@@ -203,6 +203,8 @@ const send_infoarch_page = (args) => {
|
|
|
203
203
|
{ text: "Multitenancy", href: "/tenant/settings" },
|
|
204
204
|
]
|
|
205
205
|
: []),
|
|
206
|
+
{ text: "Tags", href: "/tag" },
|
|
207
|
+
{ text: "Diagram", href: "/diagram" },
|
|
206
208
|
],
|
|
207
209
|
...args,
|
|
208
210
|
});
|
|
@@ -245,6 +247,13 @@ const send_files_page = (args) => {
|
|
|
245
247
|
});
|
|
246
248
|
};
|
|
247
249
|
|
|
250
|
+
const send_tags_page = (args) => {
|
|
251
|
+
return send_settings_page({
|
|
252
|
+
main_section: "Tags",
|
|
253
|
+
...args,
|
|
254
|
+
});
|
|
255
|
+
};
|
|
256
|
+
|
|
248
257
|
/**
|
|
249
258
|
* Send Events Page
|
|
250
259
|
* @param {object} args
|
|
@@ -281,9 +290,7 @@ const send_admin_page = (args) => {
|
|
|
281
290
|
{ text: "Backup", href: "/admin/backup" },
|
|
282
291
|
{ text: "Email", href: "/admin/email" },
|
|
283
292
|
{ text: "System", href: "/admin/system" },
|
|
284
|
-
|
|
285
|
-
? [{ text: "Mobile app", href: "/admin/build-mobile-app" }]
|
|
286
|
-
: []),
|
|
293
|
+
{ text: "Mobile app", href: "/admin/build-mobile-app" },
|
|
287
294
|
],
|
|
288
295
|
...args,
|
|
289
296
|
});
|
|
@@ -345,7 +352,12 @@ const flash_restart = (req) => {
|
|
|
345
352
|
* @param {*} opts.formArgs
|
|
346
353
|
* @returns {Promise<Form>}
|
|
347
354
|
*/
|
|
348
|
-
const config_fields_form = async ({
|
|
355
|
+
const config_fields_form = async ({
|
|
356
|
+
field_names,
|
|
357
|
+
req,
|
|
358
|
+
action,
|
|
359
|
+
...formArgs
|
|
360
|
+
}) => {
|
|
349
361
|
const values = {};
|
|
350
362
|
const state = getState();
|
|
351
363
|
const fields = [];
|
|
@@ -512,4 +524,5 @@ module.exports = {
|
|
|
512
524
|
save_config_from_form,
|
|
513
525
|
flash_restart_if_required,
|
|
514
526
|
flash_restart,
|
|
527
|
+
send_tags_page,
|
|
515
528
|
};
|
|
@@ -146,7 +146,7 @@ const boolExamples = (type, fields) => {
|
|
|
146
146
|
* @returns {p[]}
|
|
147
147
|
*/
|
|
148
148
|
const expressionBlurb = (type, stored, allFields, req) => {
|
|
149
|
-
const fields = allFields.filter((f) => !f.
|
|
149
|
+
const fields = allFields.filter((f) => !f.calculated);
|
|
150
150
|
const funs = getState().functions;
|
|
151
151
|
const funNames = Object.entries(funs)
|
|
152
152
|
.filter(([k, v]) => !(!stored && v.isAsync))
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "0.7.4-beta.
|
|
3
|
+
"version": "0.7.4-beta.3",
|
|
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.7.4-beta.
|
|
10
|
-
"@saltcorn/builder": "0.7.4-beta.
|
|
11
|
-
"@saltcorn/data": "0.7.4-beta.
|
|
12
|
-
"@saltcorn/admin-models": "0.7.4-beta.
|
|
13
|
-
"@saltcorn/markup": "0.7.4-beta.
|
|
14
|
-
"@saltcorn/sbadmin2": "0.7.4-beta.
|
|
9
|
+
"@saltcorn/base-plugin": "0.7.4-beta.3",
|
|
10
|
+
"@saltcorn/builder": "0.7.4-beta.3",
|
|
11
|
+
"@saltcorn/data": "0.7.4-beta.3",
|
|
12
|
+
"@saltcorn/admin-models": "0.7.4-beta.3",
|
|
13
|
+
"@saltcorn/markup": "0.7.4-beta.3",
|
|
14
|
+
"@saltcorn/sbadmin2": "0.7.4-beta.3",
|
|
15
15
|
"@socket.io/cluster-adapter": "^0.1.0",
|
|
16
16
|
"@socket.io/sticky": "^1.0.1",
|
|
17
17
|
"aws-sdk": "^2.1037.0",
|
package/public/blockly.js
CHANGED
|
@@ -403,11 +403,10 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
403
403
|
Blockly.JavaScript.ORDER_ATOMIC
|
|
404
404
|
);
|
|
405
405
|
// TODO: Assemble JavaScript into code variable.
|
|
406
|
-
var code = `await fetchJSON(${value_url}, { method: '${dropdown_method}'${
|
|
407
|
-
value_body
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
} })`;
|
|
406
|
+
var code = `await fetchJSON(${value_url}, { method: '${dropdown_method}'${value_body
|
|
407
|
+
? `, body: ${value_body}, headers: { "Content-Type": "application/json" }`
|
|
408
|
+
: ""
|
|
409
|
+
} })`;
|
|
411
410
|
// TODO: Change ORDER_NONE to the correct strength.
|
|
412
411
|
return [code, Blockly.JavaScript.ORDER_NONE];
|
|
413
412
|
};
|
|
@@ -416,6 +415,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
416
415
|
init: function () {
|
|
417
416
|
this.appendDummyInput().appendField("Return");
|
|
418
417
|
this.appendValueInput("GOTO").setCheck("String").appendField("Go to URL");
|
|
418
|
+
this.appendValueInput("POPUP").setCheck("String").appendField("Popup URL");
|
|
419
419
|
this.appendDummyInput()
|
|
420
420
|
.appendField("Reload page")
|
|
421
421
|
.appendField(new Blockly.FieldCheckbox("FALSE"), "RELOAD");
|
|
@@ -434,6 +434,11 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
434
434
|
"GOTO",
|
|
435
435
|
Blockly.JavaScript.ORDER_ATOMIC
|
|
436
436
|
);
|
|
437
|
+
var value_popup = Blockly.JavaScript.valueToCode(
|
|
438
|
+
block,
|
|
439
|
+
"POPUP",
|
|
440
|
+
Blockly.JavaScript.ORDER_ATOMIC
|
|
441
|
+
);
|
|
437
442
|
var checkbox_reload = block.getFieldValue("RELOAD") == "TRUE";
|
|
438
443
|
var value_notify = Blockly.JavaScript.valueToCode(
|
|
439
444
|
block,
|
|
@@ -443,6 +448,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
443
448
|
// TODO: Assemble JavaScript into code variable.
|
|
444
449
|
let s = "";
|
|
445
450
|
if (value_goto) s += `goto: ${value_goto},`;
|
|
451
|
+
if (value_popup) s += `popup: ${value_popup},`;
|
|
446
452
|
if (value_notify) s += `notify: ${value_notify},`;
|
|
447
453
|
if (checkbox_reload) s += `reload_page: true,`;
|
|
448
454
|
var code = `return {${s}};\n`;
|
package/public/gridedit.js
CHANGED
|
@@ -4,7 +4,10 @@ function showHideCol(nm, e) {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
function lookupIntToString(cell, formatterParams, onRendered) {
|
|
7
|
-
const
|
|
7
|
+
const cellVal = cell.getValue()
|
|
8
|
+
const val = typeof cellVal === "object" && cellVal !== null
|
|
9
|
+
? `${cellVal.id}`
|
|
10
|
+
: `${cellVal}`;
|
|
8
11
|
const res = formatterParams.values[val];
|
|
9
12
|
return res;
|
|
10
13
|
}
|
|
@@ -150,6 +153,8 @@ function delete_tabulator_row(e, cell) {
|
|
|
150
153
|
if (def && def.formatterParams && def.formatterParams.confirm) {
|
|
151
154
|
if (!confirm("Are you sure you want to delete this row?")) return;
|
|
152
155
|
}
|
|
156
|
+
const tableName = def?.formatterParams?.tableName || window.tabulator_table_name
|
|
157
|
+
|
|
153
158
|
const row = cell.getRow().getData();
|
|
154
159
|
if (!row.id) {
|
|
155
160
|
cell.getRow().delete();
|
|
@@ -157,7 +162,7 @@ function delete_tabulator_row(e, cell) {
|
|
|
157
162
|
}
|
|
158
163
|
$.ajax({
|
|
159
164
|
type: "DELETE",
|
|
160
|
-
url: `/api/${
|
|
165
|
+
url: `/api/${tableName}/${row.id}`,
|
|
161
166
|
data: row, // to process primary keys different from id
|
|
162
167
|
headers: {
|
|
163
168
|
"CSRF-Token": _sc_globalCsrf,
|