@saltcorn/server 0.7.3-beta.7 → 0.7.4-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 +9 -5
- package/auth/routes.js +16 -6
- package/errors.js +51 -48
- package/locales/en.json +29 -1
- package/locales/it.json +2 -1
- package/locales/ru.json +42 -6
- package/locales/zh.json +1 -1
- package/markup/admin.js +4 -3
- package/markup/plugin-store.js +5 -5
- package/package.json +7 -7
- package/public/jquery-menu-editor.min.js +1 -1
- package/public/saltcorn-builder.css +75 -0
- package/public/saltcorn-common.js +26 -10
- package/public/saltcorn.css +4 -0
- package/public/saltcorn.js +5 -1
- package/routes/admin.js +387 -96
- package/routes/api.js +9 -1
- package/routes/eventlog.js +24 -22
- package/routes/fields.js +11 -13
- package/routes/files.js +5 -5
- package/routes/homepage.js +60 -60
- package/routes/infoarch.js +6 -3
- package/routes/menu.js +65 -4
- package/routes/packs.js +4 -4
- package/routes/page.js +5 -1
- package/routes/pageedit.js +9 -1
- package/routes/plugins.js +187 -123
- package/routes/search.js +4 -2
- package/routes/settings.js +3 -3
- package/routes/tables.js +191 -190
- package/routes/tenant.js +31 -29
- package/routes/utils.js +4 -0
- package/routes/view.js +18 -1
- package/routes/viewedit.js +78 -70
- package/serve.js +54 -38
- package/tests/admin.test.js +1 -1
- package/tests/api.test.js +17 -0
- package/tests/clientjs.test.js +11 -1
- package/tests/plugins.test.js +1 -1
- package/tests/viewedit.test.js +1 -1
- package/wrapper.js +57 -55
package/auth/admin.js
CHANGED
|
@@ -381,7 +381,8 @@ router.post(
|
|
|
381
381
|
} else {
|
|
382
382
|
await save_config_from_form(form);
|
|
383
383
|
req.flash("success", req.__("User settings updated"));
|
|
384
|
-
res.redirect("/useradmin/settings");
|
|
384
|
+
if (!req.xhr) res.redirect("/useradmin/settings");
|
|
385
|
+
else res.json({ success: "ok" });
|
|
385
386
|
}
|
|
386
387
|
})
|
|
387
388
|
);
|
|
@@ -530,7 +531,7 @@ router.get(
|
|
|
530
531
|
send_users_page({
|
|
531
532
|
res,
|
|
532
533
|
req,
|
|
533
|
-
active_sub: "
|
|
534
|
+
active_sub: "SSL",
|
|
534
535
|
contents: {
|
|
535
536
|
type: "card",
|
|
536
537
|
title: req.__("Authentication settings"),
|
|
@@ -556,7 +557,7 @@ router.post(
|
|
|
556
557
|
send_users_page({
|
|
557
558
|
res,
|
|
558
559
|
req,
|
|
559
|
-
active_sub: "
|
|
560
|
+
active_sub: "SSL",
|
|
560
561
|
contents: {
|
|
561
562
|
type: "card",
|
|
562
563
|
title: req.__("Authentication settings"),
|
|
@@ -572,7 +573,9 @@ router.post(
|
|
|
572
573
|
" " +
|
|
573
574
|
a({ href: "/admin/system" }, req.__("Restart here"))
|
|
574
575
|
);
|
|
575
|
-
|
|
576
|
+
if (!req.xhr) {
|
|
577
|
+
res.redirect("/useradmin/ssl");
|
|
578
|
+
} else res.json({ success: "ok" });
|
|
576
579
|
}
|
|
577
580
|
})
|
|
578
581
|
);
|
|
@@ -690,7 +693,8 @@ router.post(
|
|
|
690
693
|
} = form.values;
|
|
691
694
|
if (id) {
|
|
692
695
|
try {
|
|
693
|
-
await
|
|
696
|
+
const u = await User.findOne({ id });
|
|
697
|
+
await u.update({ email, role_id, ...rest });
|
|
694
698
|
req.flash("success", req.__(`User %s saved`, email));
|
|
695
699
|
} catch (e) {
|
|
696
700
|
req.flash("error", req.__(`Error editing user: %s`, e.message));
|
package/auth/routes.js
CHANGED
|
@@ -199,8 +199,7 @@ const getAuthLinks = (current, noMethods) => {
|
|
|
199
199
|
return links;
|
|
200
200
|
};
|
|
201
201
|
|
|
202
|
-
const loginWithJwt = async (
|
|
203
|
-
const { email, password } = req.query;
|
|
202
|
+
const loginWithJwt = async (email, password, res) => {
|
|
204
203
|
const user = await User.findOne({ email });
|
|
205
204
|
if (user && user.checkPassword(password)) {
|
|
206
205
|
const now = new Date();
|
|
@@ -208,7 +207,13 @@ const loginWithJwt = async (req, res) => {
|
|
|
208
207
|
const token = jwt.sign(
|
|
209
208
|
{
|
|
210
209
|
sub: email,
|
|
211
|
-
|
|
210
|
+
user: {
|
|
211
|
+
id: user.id,
|
|
212
|
+
email: user.email,
|
|
213
|
+
role_id: user.role_id,
|
|
214
|
+
language: user.language ? user.language : "en",
|
|
215
|
+
disabled: user.disabled,
|
|
216
|
+
},
|
|
212
217
|
iss: "saltcorn@saltcorn",
|
|
213
218
|
aud: "saltcorn-mobile-app",
|
|
214
219
|
iat: now.valueOf(),
|
|
@@ -217,6 +222,10 @@ const loginWithJwt = async (req, res) => {
|
|
|
217
222
|
);
|
|
218
223
|
if (!user.last_mobile_login) await user.updateLastMobileLogin(now);
|
|
219
224
|
res.json(token);
|
|
225
|
+
} else {
|
|
226
|
+
res.json({
|
|
227
|
+
alerts: [{ type: "danger", msg: "Incorrect user or password" }],
|
|
228
|
+
});
|
|
220
229
|
}
|
|
221
230
|
};
|
|
222
231
|
|
|
@@ -900,8 +909,8 @@ router.post(
|
|
|
900
909
|
} else {
|
|
901
910
|
const u = await User.create({ email, password });
|
|
902
911
|
await send_verification_email(u, req);
|
|
903
|
-
|
|
904
|
-
signup_login_with_user(u, req, res);
|
|
912
|
+
if (req.smr) await loginWithJwt(email, password, res);
|
|
913
|
+
else signup_login_with_user(u, req, res);
|
|
905
914
|
}
|
|
906
915
|
}
|
|
907
916
|
})
|
|
@@ -1008,7 +1017,8 @@ router.get(
|
|
|
1008
1017
|
error_catcher(async (req, res, next) => {
|
|
1009
1018
|
const { method } = req.params;
|
|
1010
1019
|
if (method === "jwt") {
|
|
1011
|
-
|
|
1020
|
+
const { email, password } = req.query;
|
|
1021
|
+
await loginWithJwt(email, password, res);
|
|
1012
1022
|
} else {
|
|
1013
1023
|
const auth = getState().auth_methods[method];
|
|
1014
1024
|
if (auth) {
|
package/errors.js
CHANGED
|
@@ -7,55 +7,58 @@ const { pre, p, text, h3 } = require("@saltcorn/markup/tags");
|
|
|
7
7
|
const Crash = require("@saltcorn/data/models/crash");
|
|
8
8
|
const { getState } = require("@saltcorn/data/db/state");
|
|
9
9
|
|
|
10
|
-
module.exports =
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
async function (err, req, res, next) {
|
|
20
|
-
|
|
10
|
+
module.exports =
|
|
11
|
+
/**
|
|
12
|
+
*
|
|
13
|
+
* @param {object} err
|
|
14
|
+
* @param {object} req
|
|
15
|
+
* @param {object} res
|
|
16
|
+
* @param {*} next
|
|
17
|
+
* @returns {Promise<void>}
|
|
18
|
+
*/
|
|
19
|
+
async function (err, req, res, next) {
|
|
20
|
+
if (!req.__) req.__ = (s) => s;
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
const devmode = getState().getConfig("development_mode", false);
|
|
23
|
+
const log_sql = getState().getConfig("log_sql", false);
|
|
24
|
+
const role = (req.user || {}).role_id || 10;
|
|
25
|
+
if (err.message && err.message.includes("invalid csrf token")) {
|
|
26
|
+
console.error(err.message);
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
28
|
+
req.flash("error", req.__("Invalid form data, try again"));
|
|
29
|
+
if (req.url && req.url.includes("/auth/login"))
|
|
30
|
+
res.redirect("/auth/login");
|
|
31
|
+
else res.redirect("/");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const code = err.httpCode || 500;
|
|
35
|
+
const headline = err.headline || "An error occurred";
|
|
36
|
+
const severity = err.severity || 2;
|
|
37
|
+
const createCrash = severity <= 3;
|
|
38
|
+
//console.error(err.stack);
|
|
39
|
+
if (!(devmode && log_sql) && createCrash) await Crash.create(err, req);
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
?
|
|
55
|
-
|
|
56
|
-
|
|
41
|
+
if (req.xhr) {
|
|
42
|
+
res
|
|
43
|
+
.status(code)
|
|
44
|
+
.send(
|
|
45
|
+
devmode || role === 1
|
|
46
|
+
? text(err.message)
|
|
47
|
+
: req.__("An error occurred")
|
|
48
|
+
);
|
|
49
|
+
} else
|
|
50
|
+
res
|
|
51
|
+
.status(code)
|
|
52
|
+
.sendWrap(
|
|
53
|
+
req.__(headline),
|
|
54
|
+
devmode ? pre(text(err.stack)) : h3(req.__(headline)),
|
|
55
|
+
role === 1 && !devmode ? pre(text(err.message)) : "",
|
|
56
|
+
createCrash
|
|
57
|
+
? p(
|
|
58
|
+
req.__(
|
|
59
|
+
`A report has been logged and a team of bug-squashing squirrels has been dispatched to deal with the situation.`
|
|
60
|
+
)
|
|
57
61
|
)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
};
|
|
62
|
+
: ""
|
|
63
|
+
);
|
|
64
|
+
};
|
package/locales/en.json
CHANGED
|
@@ -920,5 +920,33 @@
|
|
|
920
920
|
"Download automated backup": "Download automated backup",
|
|
921
921
|
"Restoring automated backup": "Restoring automated backup",
|
|
922
922
|
"No errors detected during configuration check": "No errors detected during configuration check",
|
|
923
|
-
"%s view - %s on %s": "%s view - %s on %s"
|
|
923
|
+
"%s view - %s on %s": "%s view - %s on %s",
|
|
924
|
+
"Please select at least one platform (android or iOS).": "Please select at least one platform (android or iOS).",
|
|
925
|
+
"Back": "Back",
|
|
926
|
+
"Periodic snapshots enabled": "Periodic snapshots enabled",
|
|
927
|
+
"Snapshot will be made every hour if there are changes": "Snapshot will be made every hour if there are changes",
|
|
928
|
+
"Snapshots": "Snapshots",
|
|
929
|
+
"Snapshot settings updated": "Snapshot settings updated",
|
|
930
|
+
"Download snapshots": "Download snapshots",
|
|
931
|
+
"Snapshot successful": "Snapshot successful",
|
|
932
|
+
"System logging verbosity": "System logging verbosity",
|
|
933
|
+
"Destination URL Formula": "Destination URL Formula",
|
|
934
|
+
"Pattern": "Pattern",
|
|
935
|
+
"View pattern": "View pattern",
|
|
936
|
+
"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",
|
|
937
|
+
"Views display data from tables. A view is a view pattern applied to a table, with configuration.": "Views display data from tables. A view is a view pattern applied to a table, with configuration.",
|
|
938
|
+
"Modules": "Modules",
|
|
939
|
+
"Module installation and control": "Module installation and control",
|
|
940
|
+
"Module store": "Module store",
|
|
941
|
+
"Module": "Module",
|
|
942
|
+
"View patterns": "View patterns",
|
|
943
|
+
"%s module information": "%s module information",
|
|
944
|
+
"Upgrade installed modules": "Upgrade installed modules",
|
|
945
|
+
"Add another module": "Add another module",
|
|
946
|
+
"Add module": "Add module",
|
|
947
|
+
"Module name": "Module name",
|
|
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
|
+
"Version of module, latest is default value": "Version of module, latest is default value",
|
|
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"
|
|
924
952
|
}
|
package/locales/it.json
CHANGED
|
@@ -478,5 +478,6 @@
|
|
|
478
478
|
"Generate": "Generate",
|
|
479
479
|
"Two-factor authentication": "Two-factor authentication",
|
|
480
480
|
"Two-factor authentication is disabled": "Two-factor authentication is disabled",
|
|
481
|
-
"Enable TWA": "Enable TWA"
|
|
481
|
+
"Enable TWA": "Enable TWA",
|
|
482
|
+
"Modules": "Modules"
|
|
482
483
|
}
|
package/locales/ru.json
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"ID": "ID",
|
|
27
27
|
"Email": "Email",
|
|
28
28
|
"Role": "Роль",
|
|
29
|
-
"View": "
|
|
29
|
+
"View": "Представление",
|
|
30
30
|
"Delete": "Удалить",
|
|
31
31
|
"Add user": "Создать пользователя",
|
|
32
32
|
"New user": "Новый пользователь",
|
|
@@ -783,15 +783,51 @@
|
|
|
783
783
|
"Disable TWA": "Отключить TWA",
|
|
784
784
|
"Enable TWA": "Включить TWA",
|
|
785
785
|
"Deleted all rows": "Удалены все строки",
|
|
786
|
-
"Use this link: <a href=\"%s\">%s</a> to revisit your application at any time.": "В
|
|
786
|
+
"Use this link: <a href=\"%s\">%s</a> to revisit your application at any time.": "В дальнейшем используйте ссылку: <a href=\"%s\">%s</a> для входа в созданное приложение.",
|
|
787
787
|
"To login to a previously created application, go to: ": "Чтобы авторизоваться в ранее созданном приложении, перейдите по ссылке: ",
|
|
788
788
|
"Has channels?": "Связано с каналом?",
|
|
789
789
|
"Menu, search, languages and tenants": "Меню, поиск, языки и подсайты(тенанты)",
|
|
790
790
|
"Images and other files for download": "Изображения и другие файлы для загрузки",
|
|
791
791
|
"Channels to create events for. Separate by comma; leave blank for all": "Каналы, для которых создаются собятия. Разделяются ; Не заполняйте, чтобы использовать события для всех каналов",
|
|
792
792
|
"Event Name": "Имя события",
|
|
793
|
-
"Plugins (Extensions) Store endpoint": "
|
|
794
|
-
"Packs Store endpoint": "
|
|
795
|
-
"The endpoint of plugins store.": "
|
|
796
|
-
"The endpoint of packs store.": "
|
|
793
|
+
"Plugins (Extensions) Store endpoint": "Адрес (endpoint) магазина плагинов",
|
|
794
|
+
"Packs Store endpoint": "Адрес (endpoint) магазина паков",
|
|
795
|
+
"The endpoint of plugins store.": "Адрес (endpoint) магазина плагинов.",
|
|
796
|
+
"The endpoint of packs store.": "Адрес (endpoint) магазина паков.",
|
|
797
|
+
"Modules": "Модули",
|
|
798
|
+
"Frequency": "Регулярность",
|
|
799
|
+
"Destination": "Местоположение",
|
|
800
|
+
"Directory": "Папка",
|
|
801
|
+
"Expiration in days": "Срок хранения (в днях)",
|
|
802
|
+
"Delete old backup files in this directory after the set number of days": "Старые резервные копии в этой папке будут удалять после истечения срока хранения ",
|
|
803
|
+
"Backup settings updated": "Настройки резервного копирования обновлены",
|
|
804
|
+
"Periodic snapshots enabled": "Регулярные снимки (снэпшоты) активированы",
|
|
805
|
+
"Snapshot will be made every hour if there are changes": "Снимки (снэпшоты) будут выполняться каждый час",
|
|
806
|
+
"Manual backup": "Ручное резервное копирование",
|
|
807
|
+
"Automated backup": "Автоматическое резервное копирование",
|
|
808
|
+
"Snapshots": "Снимки (снэпшоты)",
|
|
809
|
+
"Mobile app": "Мобильное приложение",
|
|
810
|
+
"Module store": "Магазин модулей",
|
|
811
|
+
"Upgrade installed modules": "Обновить установленные модули",
|
|
812
|
+
"Add another module": "Добавить модуль",
|
|
813
|
+
"Module": "Модуль",
|
|
814
|
+
"Module installation and control": "Установка и управление модулями",
|
|
815
|
+
"System logging verbosity": "Уровень логирования системы",
|
|
816
|
+
"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": "Источник для установки модуля:npm - загрузка из репозитория npm,local - установка из локальной файловой системы,github - загрузка из github,git - загрузка из git",
|
|
817
|
+
"Version of module, latest is default value": "Версия модуля, значение по-умолчанию latest",
|
|
818
|
+
"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.": "для npm - имя npm пактеа, например, @saltcorn/html или saltcorn-gantt, см. npmjs.com, для local - абсолютный путь к папке модуля в локальной файловой системе, например, C:\\gitsrc\\any-bootstrap-theme\\, для github - имя проекта github.",
|
|
819
|
+
"Modules up-to-date": "Модули обновлены до актуальной версии",
|
|
820
|
+
"Add module": "Добавить модуль",
|
|
821
|
+
"Module name": "Имя модуля",
|
|
822
|
+
"Build mobile app": "Создать мобильное приложение",
|
|
823
|
+
"Please select at least one platform (android or iOS).": "Пожалуйста выберите как минимум одну платформу (android или iOS).",
|
|
824
|
+
"Please enter a valid server URL.": "Пожалуйста введите корректный URL сервера.",
|
|
825
|
+
"Only the android build supports docker.": "Только сборка для android поддерживает docker.",
|
|
826
|
+
"Entry point": "Точка входа в приложение",
|
|
827
|
+
"Platform": "Платформа",
|
|
828
|
+
"docker": "docker",
|
|
829
|
+
"App file": "Файл приложения",
|
|
830
|
+
"Server URL": "URL сервера",
|
|
831
|
+
"android": "android",
|
|
832
|
+
"iOS": "iOS"
|
|
797
833
|
}
|
package/locales/zh.json
CHANGED
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
"Pack %s installed": "已安装包 %s",
|
|
180
180
|
"Pack %s uninstalled": "包 %s 已卸载",
|
|
181
181
|
"Uninstall": "卸载",
|
|
182
|
-
"Result preview for ": "结果预览",
|
|
182
|
+
"Result preview for ": "结果预览",
|
|
183
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": "搜索配置",
|
package/markup/admin.js
CHANGED
|
@@ -345,7 +345,7 @@ const flash_restart = (req) => {
|
|
|
345
345
|
* @param {*} opts.formArgs
|
|
346
346
|
* @returns {Promise<Form>}
|
|
347
347
|
*/
|
|
348
|
-
const config_fields_form = async ({ field_names, req, ...formArgs }) => {
|
|
348
|
+
const config_fields_form = async ({ field_names, req, action, ...formArgs }) => {
|
|
349
349
|
const values = {};
|
|
350
350
|
const state = getState();
|
|
351
351
|
const fields = [];
|
|
@@ -396,8 +396,9 @@ const config_fields_form = async ({ field_names, req, ...formArgs }) => {
|
|
|
396
396
|
const form = new Form({
|
|
397
397
|
fields,
|
|
398
398
|
values,
|
|
399
|
-
|
|
400
|
-
|
|
399
|
+
action,
|
|
400
|
+
noSubmitButton: true,
|
|
401
|
+
onChange: `saveAndContinue(this)`,
|
|
401
402
|
...formArgs,
|
|
402
403
|
});
|
|
403
404
|
await form.fill_fkey_options();
|
package/markup/plugin-store.js
CHANGED
|
@@ -87,7 +87,7 @@ const plugin_functions_info_card = (plugin, req) => ({
|
|
|
87
87
|
*/
|
|
88
88
|
const plugin_viewtemplates_info_card = (plugin, req) => ({
|
|
89
89
|
type: "card",
|
|
90
|
-
title: req.__("View
|
|
90
|
+
title: req.__("View patterns"),
|
|
91
91
|
contents: withCfg(plugin, "viewtemplates", [])
|
|
92
92
|
.map(({ name, description }) => div(h4(name), p(description)))
|
|
93
93
|
.join("<hr>"),
|
|
@@ -101,10 +101,10 @@ const showRepository = (repo) =>
|
|
|
101
101
|
!repo
|
|
102
102
|
? repo
|
|
103
103
|
: repo.url
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
? link(repo.url, repo.url)
|
|
105
|
+
: repo.startsWith && repo.startsWith("github:")
|
|
106
|
+
? link(repo.replace("github:", "https://github.com/"), repo)
|
|
107
|
+
: repo;
|
|
108
108
|
|
|
109
109
|
module.exports = {
|
|
110
110
|
plugin_types_info_card,
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.4-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.7.
|
|
10
|
-
"@saltcorn/builder": "0.7.
|
|
11
|
-
"@saltcorn/data": "0.7.
|
|
12
|
-
"@saltcorn/admin-models": "0.7.
|
|
13
|
-
"@saltcorn/markup": "0.7.
|
|
14
|
-
"@saltcorn/sbadmin2": "0.7.
|
|
9
|
+
"@saltcorn/base-plugin": "0.7.4-beta.1",
|
|
10
|
+
"@saltcorn/builder": "0.7.4-beta.1",
|
|
11
|
+
"@saltcorn/data": "0.7.4-beta.1",
|
|
12
|
+
"@saltcorn/admin-models": "0.7.4-beta.1",
|
|
13
|
+
"@saltcorn/markup": "0.7.4-beta.1",
|
|
14
|
+
"@saltcorn/sbadmin2": "0.7.4-beta.1",
|
|
15
15
|
"@socket.io/cluster-adapter": "^0.1.0",
|
|
16
16
|
"@socket.io/sticky": "^1.0.1",
|
|
17
17
|
"aws-sdk": "^2.1037.0",
|
|
@@ -364,3 +364,78 @@ Copyright (c) 2017 Taha Paksu
|
|
|
364
364
|
.dropdown-menu.searchbar-dropdown.show {
|
|
365
365
|
transform: translate(0px, 40px);
|
|
366
366
|
}
|
|
367
|
+
|
|
368
|
+
.tippy-box[data-animation="fade"][data-state="hidden"] {
|
|
369
|
+
opacity: 0;
|
|
370
|
+
}
|
|
371
|
+
[data-tippy-root] {
|
|
372
|
+
max-width: calc(100vw - 10px);
|
|
373
|
+
}
|
|
374
|
+
.tippy-box {
|
|
375
|
+
position: relative;
|
|
376
|
+
background-color: #333;
|
|
377
|
+
color: #fff;
|
|
378
|
+
border-radius: 4px;
|
|
379
|
+
font-size: 14px;
|
|
380
|
+
line-height: 1.4;
|
|
381
|
+
white-space: normal;
|
|
382
|
+
outline: 0;
|
|
383
|
+
transition-property: transform, visibility, opacity;
|
|
384
|
+
}
|
|
385
|
+
.tippy-box[data-placement^="top"] > .tippy-arrow {
|
|
386
|
+
bottom: 0;
|
|
387
|
+
}
|
|
388
|
+
.tippy-box[data-placement^="top"] > .tippy-arrow:before {
|
|
389
|
+
bottom: -7px;
|
|
390
|
+
left: 0;
|
|
391
|
+
border-width: 8px 8px 0;
|
|
392
|
+
border-top-color: initial;
|
|
393
|
+
transform-origin: center top;
|
|
394
|
+
}
|
|
395
|
+
.tippy-box[data-placement^="bottom"] > .tippy-arrow {
|
|
396
|
+
top: 0;
|
|
397
|
+
}
|
|
398
|
+
.tippy-box[data-placement^="bottom"] > .tippy-arrow:before {
|
|
399
|
+
top: -7px;
|
|
400
|
+
left: 0;
|
|
401
|
+
border-width: 0 8px 8px;
|
|
402
|
+
border-bottom-color: initial;
|
|
403
|
+
transform-origin: center bottom;
|
|
404
|
+
}
|
|
405
|
+
.tippy-box[data-placement^="left"] > .tippy-arrow {
|
|
406
|
+
right: 0;
|
|
407
|
+
}
|
|
408
|
+
.tippy-box[data-placement^="left"] > .tippy-arrow:before {
|
|
409
|
+
border-width: 8px 0 8px 8px;
|
|
410
|
+
border-left-color: initial;
|
|
411
|
+
right: -7px;
|
|
412
|
+
transform-origin: center left;
|
|
413
|
+
}
|
|
414
|
+
.tippy-box[data-placement^="right"] > .tippy-arrow {
|
|
415
|
+
left: 0;
|
|
416
|
+
}
|
|
417
|
+
.tippy-box[data-placement^="right"] > .tippy-arrow:before {
|
|
418
|
+
left: -7px;
|
|
419
|
+
border-width: 8px 8px 8px 0;
|
|
420
|
+
border-right-color: initial;
|
|
421
|
+
transform-origin: center right;
|
|
422
|
+
}
|
|
423
|
+
.tippy-box[data-inertia][data-state="visible"] {
|
|
424
|
+
transition-timing-function: cubic-bezier(0.54, 1.5, 0.38, 1.11);
|
|
425
|
+
}
|
|
426
|
+
.tippy-arrow {
|
|
427
|
+
width: 16px;
|
|
428
|
+
height: 16px;
|
|
429
|
+
color: #333;
|
|
430
|
+
}
|
|
431
|
+
.tippy-arrow:before {
|
|
432
|
+
content: "";
|
|
433
|
+
position: absolute;
|
|
434
|
+
border-color: transparent;
|
|
435
|
+
border-style: solid;
|
|
436
|
+
}
|
|
437
|
+
.tippy-content {
|
|
438
|
+
position: relative;
|
|
439
|
+
padding: 5px 9px;
|
|
440
|
+
z-index: 1;
|
|
441
|
+
}
|
|
@@ -39,16 +39,26 @@ function apply_showif() {
|
|
|
39
39
|
$("[data-show-if]").each(function (ix, element) {
|
|
40
40
|
var e = $(element);
|
|
41
41
|
try {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
let to_show = e.data("data-show-if-fun");
|
|
43
|
+
if (!to_show) {
|
|
44
|
+
to_show = new Function(
|
|
45
|
+
"e",
|
|
46
|
+
"return " + decodeURIComponent(e.attr("data-show-if"))
|
|
47
|
+
);
|
|
48
|
+
e.data("data-show-if-fun", to_show);
|
|
49
|
+
}
|
|
50
|
+
if (!e.data("data-closest-form-ns"))
|
|
51
|
+
e.data("data-closest-form-ns", e.closest(".form-namespace"));
|
|
46
52
|
if (to_show(e))
|
|
47
53
|
e.show()
|
|
48
54
|
.find("input, textarea, button, select")
|
|
49
55
|
.prop("disabled", e.attr("data-disabled") || false);
|
|
50
56
|
else
|
|
51
|
-
e.hide()
|
|
57
|
+
e.hide()
|
|
58
|
+
.find(
|
|
59
|
+
"input:enabled, textarea:enabled, button:enabled, select:enabled"
|
|
60
|
+
)
|
|
61
|
+
.prop("disabled", true);
|
|
52
62
|
} catch (e) {
|
|
53
63
|
console.error(e);
|
|
54
64
|
}
|
|
@@ -111,7 +121,12 @@ function apply_showif() {
|
|
|
111
121
|
`<option ${
|
|
112
122
|
`${current}` === `${r[dynwhere.refname]}` ? "selected" : ""
|
|
113
123
|
} value="${r[dynwhere.refname]}">${
|
|
114
|
-
|
|
124
|
+
dynwhere.label_formula
|
|
125
|
+
? new Function(
|
|
126
|
+
`{${Object.keys(r).join(",")}}`,
|
|
127
|
+
"return " + dynwhere.label_formula
|
|
128
|
+
)(r)
|
|
129
|
+
: r[dynwhere.summary_field]
|
|
115
130
|
}</option>`
|
|
116
131
|
)
|
|
117
132
|
);
|
|
@@ -502,7 +517,7 @@ function common_done(res, isWeb = true) {
|
|
|
502
517
|
}
|
|
503
518
|
}
|
|
504
519
|
|
|
505
|
-
const repeaterCopyValuesToForm = (form, editor) => {
|
|
520
|
+
const repeaterCopyValuesToForm = (form, editor, noTriggerChange) => {
|
|
506
521
|
const vs = JSON.parse(editor.getString());
|
|
507
522
|
|
|
508
523
|
const setVal = (k, ix, v) => {
|
|
@@ -510,7 +525,7 @@ const repeaterCopyValuesToForm = (form, editor) => {
|
|
|
510
525
|
if ($e.length) $e.val(v);
|
|
511
526
|
else
|
|
512
527
|
form.append(
|
|
513
|
-
`<input type="hidden" name="${k}_${ix}" value="${v}"></input>`
|
|
528
|
+
`<input type="hidden" data-repeater-ix="${ix}" name="${k}_${ix}" value="${v}"></input>`
|
|
514
529
|
);
|
|
515
530
|
};
|
|
516
531
|
vs.forEach((v, ix) => {
|
|
@@ -521,8 +536,8 @@ const repeaterCopyValuesToForm = (form, editor) => {
|
|
|
521
536
|
});
|
|
522
537
|
});
|
|
523
538
|
//delete
|
|
524
|
-
//for (let ix = vs.length; ix < vs.length +
|
|
525
|
-
//
|
|
539
|
+
//for (let ix = vs.length; ix < vs.length + 5; ix++) {
|
|
540
|
+
// $(`input[data-repeater-ix="${ix}"]`).remove();
|
|
526
541
|
//}
|
|
527
542
|
$(`input[type=hidden]`).each(function () {
|
|
528
543
|
const name = $(this).attr("name");
|
|
@@ -533,6 +548,7 @@ const repeaterCopyValuesToForm = (form, editor) => {
|
|
|
533
548
|
if (typeof ix !== "number" || isNaN(ix)) return;
|
|
534
549
|
if (ix >= vs.length) $(this).remove();
|
|
535
550
|
});
|
|
551
|
+
!noTriggerChange && form.trigger("change");
|
|
536
552
|
};
|
|
537
553
|
function align_dropdown(id) {
|
|
538
554
|
setTimeout(() => {
|
package/public/saltcorn.css
CHANGED
package/public/saltcorn.js
CHANGED
|
@@ -213,6 +213,7 @@ function ajax_modal(url, opts = {}) {
|
|
|
213
213
|
(opts.onOpen || function () {})(res);
|
|
214
214
|
$("#scmodal").on("hidden.bs.modal", function (e) {
|
|
215
215
|
(opts.onClose || function () {})(res);
|
|
216
|
+
$("body").css("overflow", "");
|
|
216
217
|
});
|
|
217
218
|
},
|
|
218
219
|
});
|
|
@@ -248,7 +249,7 @@ function saveAndContinue(e, k) {
|
|
|
248
249
|
return false;
|
|
249
250
|
}
|
|
250
251
|
|
|
251
|
-
function applyViewConfig(e, url) {
|
|
252
|
+
function applyViewConfig(e, url, k) {
|
|
252
253
|
var form = $(e).closest("form");
|
|
253
254
|
var form_data = form.serializeArray();
|
|
254
255
|
const cfg = {};
|
|
@@ -264,6 +265,9 @@ function applyViewConfig(e, url) {
|
|
|
264
265
|
},
|
|
265
266
|
data: JSON.stringify(cfg),
|
|
266
267
|
error: function (request) {},
|
|
268
|
+
success: function (res) {
|
|
269
|
+
k && k(res);
|
|
270
|
+
},
|
|
267
271
|
});
|
|
268
272
|
|
|
269
273
|
return false;
|