@saltcorn/server 1.0.0-beta.9 → 1.0.0-rc.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/app.js +4 -7
- package/auth/admin.js +1 -0
- package/help/Aggregation where formula.tmd +11 -0
- package/help/Calculated fields.tmd +28 -0
- package/help/Date format.tmd +55 -0
- package/help/Protected fields.tmd +4 -0
- package/help/Snapshots.tmd +19 -0
- package/help/Table history.tmd +42 -0
- package/help/index.js +2 -0
- package/load_plugins.js +89 -8
- package/locales/en.json +13 -1
- package/locales/pl.json +407 -85
- package/package.json +11 -11
- package/public/saltcorn-common.js +195 -100
- package/public/saltcorn.css +17 -0
- package/public/saltcorn.js +69 -12
- package/routes/actions.js +18 -24
- package/routes/admin.js +256 -54
- package/routes/eventlog.js +2 -1
- package/routes/fields.js +21 -5
- package/routes/infoarch.js +40 -2
- package/routes/menu.js +3 -0
- package/routes/pageedit.js +7 -1
- package/routes/plugins.js +118 -23
- package/routes/scapi.js +19 -0
- package/routes/search.js +6 -1
- package/routes/sync.js +2 -1
- package/routes/tables.js +14 -4
- package/serve.js +17 -3
- package/tests/fields.test.js +32 -0
- package/tests/plugin_install.test.js +235 -0
- package/tests/plugins.test.js +140 -0
package/public/saltcorn.js
CHANGED
|
@@ -190,7 +190,8 @@ function pjax_to(href, e) {
|
|
|
190
190
|
initialize_page();
|
|
191
191
|
},
|
|
192
192
|
error: function (res) {
|
|
193
|
-
|
|
193
|
+
if (!checkNetworkError(res))
|
|
194
|
+
notifyAlert({ type: "danger", text: res.responseText });
|
|
194
195
|
},
|
|
195
196
|
});
|
|
196
197
|
}
|
|
@@ -224,8 +225,10 @@ function ajax_done(res, viewname) {
|
|
|
224
225
|
function spin_action_link(e) {
|
|
225
226
|
const $e = $(e);
|
|
226
227
|
const width = $e.width();
|
|
228
|
+
const height = $e.height();
|
|
229
|
+
|
|
227
230
|
$e.attr("data-innerhtml-prespin", $e.html());
|
|
228
|
-
$e.html('<i class="fas fa-spinner fa-spin"></i>').width(width);
|
|
231
|
+
$e.html('<i class="fas fa-spinner fa-spin"></i>').width(width).height(height);
|
|
229
232
|
}
|
|
230
233
|
|
|
231
234
|
function reset_spinners() {
|
|
@@ -264,7 +267,8 @@ function view_post(viewnameOrElem, route, data, onDone, sendState) {
|
|
|
264
267
|
reset_spinners();
|
|
265
268
|
})
|
|
266
269
|
.fail(function (res) {
|
|
267
|
-
|
|
270
|
+
if (!checkNetworkError(res))
|
|
271
|
+
notifyAlert({ type: "danger", text: res.responseText });
|
|
268
272
|
reset_spinners();
|
|
269
273
|
});
|
|
270
274
|
}
|
|
@@ -388,7 +392,7 @@ function ajax_modal(url, opts = {}) {
|
|
|
388
392
|
? {
|
|
389
393
|
error: opts.onError,
|
|
390
394
|
}
|
|
391
|
-
: {}),
|
|
395
|
+
: { error: checkNetworkError }),
|
|
392
396
|
});
|
|
393
397
|
}
|
|
394
398
|
function closeModal() {
|
|
@@ -451,7 +455,8 @@ function saveAndContinue(e, k, event) {
|
|
|
451
455
|
},
|
|
452
456
|
error: function (request) {
|
|
453
457
|
var ct = request.getResponseHeader("content-type") || "";
|
|
454
|
-
if (
|
|
458
|
+
if (checkNetworkError(request)) {
|
|
459
|
+
} else if (ct.startsWith && ct.startsWith("application/json")) {
|
|
455
460
|
notifyAlert({ type: "danger", text: request.responseJSON.error });
|
|
456
461
|
} else {
|
|
457
462
|
$("#page-inner-content").html(request.responseText);
|
|
@@ -500,6 +505,7 @@ function applyViewConfig(e, url, k, event) {
|
|
|
500
505
|
},
|
|
501
506
|
data: JSON.stringify(cfg),
|
|
502
507
|
error: function (request) {
|
|
508
|
+
checkNetworkError(request);
|
|
503
509
|
window.savingViewConfig = false;
|
|
504
510
|
ajax_indicate_error(e, request);
|
|
505
511
|
},
|
|
@@ -578,6 +584,7 @@ function ajaxSubmitForm(e, force_no_reload) {
|
|
|
578
584
|
else common_done(res, form.attr("data-viewname"));
|
|
579
585
|
},
|
|
580
586
|
error: function (request) {
|
|
587
|
+
checkNetworkError(request);
|
|
581
588
|
var title = request.getResponseHeader("Page-Title");
|
|
582
589
|
if (title) $("#scmodal .modal-title").html(decodeURIComponent(title));
|
|
583
590
|
var body = request.responseText;
|
|
@@ -594,6 +601,9 @@ function ajax_post_json(url, data, args = {}) {
|
|
|
594
601
|
...args,
|
|
595
602
|
});
|
|
596
603
|
}
|
|
604
|
+
|
|
605
|
+
let scNetworkErrorSignaled = false;
|
|
606
|
+
|
|
597
607
|
function ajax_post(url, args) {
|
|
598
608
|
$.ajax(url, {
|
|
599
609
|
type: "POST",
|
|
@@ -603,10 +613,31 @@ function ajax_post(url, args) {
|
|
|
603
613
|
...(args || {}),
|
|
604
614
|
})
|
|
605
615
|
.done(ajax_done)
|
|
606
|
-
.fail((e) =>
|
|
607
|
-
|
|
608
|
-
|
|
616
|
+
.fail((e, ...more) => {
|
|
617
|
+
if (!checkNetworkError(e))
|
|
618
|
+
return ajax_done(
|
|
619
|
+
e.responseJSON || { error: "Unknown error: " + e.responseText }
|
|
620
|
+
);
|
|
621
|
+
});
|
|
609
622
|
}
|
|
623
|
+
|
|
624
|
+
function checkNetworkError(e) {
|
|
625
|
+
if (e.readyState == 0 && !e.responseText && !e.responseJSON) {
|
|
626
|
+
//network error
|
|
627
|
+
if (scNetworkErrorSignaled) return true;
|
|
628
|
+
scNetworkErrorSignaled = true;
|
|
629
|
+
setTimeout(() => {
|
|
630
|
+
scNetworkErrorSignaled = false;
|
|
631
|
+
}, 1000);
|
|
632
|
+
console.error("Network error", e);
|
|
633
|
+
notifyAlert({
|
|
634
|
+
type: "danger",
|
|
635
|
+
text: "Network connection error",
|
|
636
|
+
});
|
|
637
|
+
return true;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
610
641
|
function ajax_post_btn(e, reload_on_done, reload_delay) {
|
|
611
642
|
var form = $(e).closest("form");
|
|
612
643
|
var url = form.attr("action");
|
|
@@ -620,6 +651,7 @@ function ajax_post_btn(e, reload_on_done, reload_delay) {
|
|
|
620
651
|
success: function () {
|
|
621
652
|
if (reload_on_done) location.reload();
|
|
622
653
|
},
|
|
654
|
+
error: checkNetworkError,
|
|
623
655
|
complete: function () {
|
|
624
656
|
if (reload_delay)
|
|
625
657
|
setTimeout(function () {
|
|
@@ -641,6 +673,7 @@ function api_action_call(name, body) {
|
|
|
641
673
|
success: function (res) {
|
|
642
674
|
common_done(res.data);
|
|
643
675
|
},
|
|
676
|
+
error: checkNetworkError,
|
|
644
677
|
});
|
|
645
678
|
}
|
|
646
679
|
|
|
@@ -840,7 +873,7 @@ function build_mobile_app(button) {
|
|
|
840
873
|
|
|
841
874
|
if (
|
|
842
875
|
params.useDocker &&
|
|
843
|
-
!cordovaBuilderAvailable &&
|
|
876
|
+
!window.cordovaBuilderAvailable &&
|
|
844
877
|
!confirm(
|
|
845
878
|
"Docker is selected but the Cordova builder seems not to be installed. " +
|
|
846
879
|
"Do you really want to continue?"
|
|
@@ -848,6 +881,30 @@ function build_mobile_app(button) {
|
|
|
848
881
|
) {
|
|
849
882
|
return;
|
|
850
883
|
}
|
|
884
|
+
if (
|
|
885
|
+
isSbadmin2 &&
|
|
886
|
+
!confirm(
|
|
887
|
+
"It seems you are using the standard sbadmin2 layout. " +
|
|
888
|
+
"This layout is not optimized for mobile, consider using any-bootstrap-theme. " +
|
|
889
|
+
"Do you really want to continue?"
|
|
890
|
+
)
|
|
891
|
+
) {
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
const notSupportedPlugins = params.includedPlugins.filter(
|
|
895
|
+
(plugin) => !window.pluginsReadyForMobile.includes(plugin)
|
|
896
|
+
);
|
|
897
|
+
if (
|
|
898
|
+
notSupportedPlugins.length > 0 &&
|
|
899
|
+
!confirm(
|
|
900
|
+
`It seems that the plugins '${notSupportedPlugins.join(
|
|
901
|
+
", "
|
|
902
|
+
)}' are not ready for mobile. Do you really want to continue?`
|
|
903
|
+
)
|
|
904
|
+
) {
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
|
|
851
908
|
ajax_post("/admin/build-mobile-app", {
|
|
852
909
|
data: params,
|
|
853
910
|
success: (data) => {
|
|
@@ -919,8 +976,8 @@ function check_cordova_builder() {
|
|
|
919
976
|
$.ajax("/admin/mobile-app/check-cordova-builder", {
|
|
920
977
|
type: "GET",
|
|
921
978
|
success: function (res) {
|
|
922
|
-
cordovaBuilderAvailable = !!res.installed;
|
|
923
|
-
if (cordovaBuilderAvailable) {
|
|
979
|
+
window.cordovaBuilderAvailable = !!res.installed;
|
|
980
|
+
if (window.cordovaBuilderAvailable) {
|
|
924
981
|
$("#dockerBuilderStatusId").html(
|
|
925
982
|
`<span>
|
|
926
983
|
installed<i class="ps-2 fas fa-check text-success"></i>
|
|
@@ -1014,7 +1071,7 @@ function toggle_tbl_sync() {
|
|
|
1014
1071
|
function toggle_android_platform() {
|
|
1015
1072
|
if ($("#androidCheckboxId")[0].checked === true) {
|
|
1016
1073
|
$("#dockerCheckboxId").attr("hidden", false);
|
|
1017
|
-
$("#dockerCheckboxId").attr("checked", cordovaBuilderAvailable);
|
|
1074
|
+
$("#dockerCheckboxId").attr("checked", window.cordovaBuilderAvailable);
|
|
1018
1075
|
$("#dockerLabelId").removeClass("d-none");
|
|
1019
1076
|
} else {
|
|
1020
1077
|
$("#dockerCheckboxId").attr("hidden", true);
|
package/routes/actions.js
CHANGED
|
@@ -57,21 +57,6 @@ const {
|
|
|
57
57
|
blocklyToolbox,
|
|
58
58
|
} = require("../markup/blockly.js");
|
|
59
59
|
|
|
60
|
-
/**
|
|
61
|
-
* @returns {Promise<object>}
|
|
62
|
-
*/
|
|
63
|
-
const getActions = async () => {
|
|
64
|
-
return Object.entries(getState().actions).map(([k, v]) => {
|
|
65
|
-
const hasConfig = !!v.configFields;
|
|
66
|
-
const requireRow = !!v.requireRow;
|
|
67
|
-
return {
|
|
68
|
-
name: k,
|
|
69
|
-
hasConfig,
|
|
70
|
-
requireRow,
|
|
71
|
-
};
|
|
72
|
-
});
|
|
73
|
-
};
|
|
74
|
-
|
|
75
60
|
/**
|
|
76
61
|
* Show list of Actions (Triggers) (HTTP GET)
|
|
77
62
|
* @name get
|
|
@@ -96,7 +81,7 @@ router.get(
|
|
|
96
81
|
triggers = triggers.filter((t) => tagged_trigger_ids.has(t.id));
|
|
97
82
|
filterOnTag = await Tag.findOne({ id: +req.query._tag });
|
|
98
83
|
}
|
|
99
|
-
const actions =
|
|
84
|
+
const actions = Trigger.abbreviated_actions;
|
|
100
85
|
send_events_page({
|
|
101
86
|
res,
|
|
102
87
|
req,
|
|
@@ -156,7 +141,7 @@ const triggerForm = async (req, trigger) => {
|
|
|
156
141
|
value: r.id,
|
|
157
142
|
label: r.role,
|
|
158
143
|
}));
|
|
159
|
-
const actions =
|
|
144
|
+
const actions = Trigger.abbreviated_actions;
|
|
160
145
|
const tables = await Table.find({});
|
|
161
146
|
let id;
|
|
162
147
|
let form_action;
|
|
@@ -168,14 +153,13 @@ const triggerForm = async (req, trigger) => {
|
|
|
168
153
|
const hasChannel = Object.entries(getState().eventTypes)
|
|
169
154
|
.filter(([k, v]) => v.hasChannel)
|
|
170
155
|
.map(([k, v]) => k);
|
|
171
|
-
|
|
172
|
-
allActions.
|
|
156
|
+
|
|
157
|
+
const allActions = Trigger.action_options({ notRequireRow: false });
|
|
173
158
|
const table_triggers = ["Insert", "Update", "Delete", "Validate"];
|
|
174
159
|
const action_options = {};
|
|
175
|
-
const actionsNotRequiringRow =
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
actionsNotRequiringRow.push("Multi-step action");
|
|
160
|
+
const actionsNotRequiringRow = Trigger.action_options({
|
|
161
|
+
notRequireRow: true,
|
|
162
|
+
});
|
|
179
163
|
|
|
180
164
|
Trigger.when_options.forEach((t) => {
|
|
181
165
|
if (table_triggers.includes(t)) action_options[t] = allActions;
|
|
@@ -237,6 +221,13 @@ const triggerForm = async (req, trigger) => {
|
|
|
237
221
|
showIf: { when_trigger: "Daily" },
|
|
238
222
|
sublabel: req.__("UTC timezone"),
|
|
239
223
|
},
|
|
224
|
+
{
|
|
225
|
+
name: "channel",
|
|
226
|
+
label: req.__("Time to run"),
|
|
227
|
+
input_type: "time_of_week",
|
|
228
|
+
showIf: { when_trigger: "Weekly" },
|
|
229
|
+
sublabel: req.__("UTC timezone"),
|
|
230
|
+
},
|
|
240
231
|
{
|
|
241
232
|
name: "channel",
|
|
242
233
|
label: req.__("Channel"),
|
|
@@ -555,7 +546,10 @@ router.get(
|
|
|
555
546
|
let trigger;
|
|
556
547
|
let id = parseInt(idorname);
|
|
557
548
|
if (id) trigger = await Trigger.findOne({ id });
|
|
558
|
-
else
|
|
549
|
+
else {
|
|
550
|
+
trigger = await Trigger.findOne({ name: idorname });
|
|
551
|
+
id = trigger.id;
|
|
552
|
+
}
|
|
559
553
|
|
|
560
554
|
if (!trigger) {
|
|
561
555
|
req.flash("warning", req.__("Action not found"));
|