@saltcorn/server 1.1.1-beta.2 → 1.1.1-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/CHANGELOG.md +83 -5
- package/auth/testhelp.js +6 -0
- package/package.json +9 -9
- package/public/saltcorn-common.js +30 -0
- package/public/saltcorn.css +141 -0
- package/routes/actions.js +21 -5
- package/routes/admin.js +24 -2
- package/routes/api.js +19 -8
- package/routes/pageedit.js +1 -0
- package/routes/tables.js +1 -0
- package/tests/clientjs.test.js +9 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,86 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Notable changes
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
3
|
+
## 1.1.1 - In beta
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
* Stored calculated fields that contain joinfields in the expression are now automatically
|
|
6
|
+
updated when the values they reference are changed, i.e. changes occur in the tables they
|
|
7
|
+
reference. This is limited to single (expression contains x.y) and double joinfields
|
|
8
|
+
(expression contains x.y.z). In most cases, you can now remove all recalculate_stored_fields
|
|
9
|
+
actions.
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
* Builder:
|
|
12
|
+
- Add ability to set custom `id` on containers. This is useful for scroll targets
|
|
13
|
+
- Add animations tab to containers. All animations are activated on scroll
|
|
14
|
+
- Tabs and multi-step actions implement a new interface that lets you move, delete and
|
|
15
|
+
add steps/tabs.
|
|
16
|
+
|
|
17
|
+
* Workflows:
|
|
18
|
+
- APIResponse step type. Provide the API response
|
|
19
|
+
- Stop step type. Stop workflow immediately
|
|
20
|
+
- EditViewForm step type: run a form from an Edit view, add respnse to context
|
|
21
|
+
- Call other workflows in a workflow step. Control subcontext for called workflow
|
|
22
|
+
- Error handling. SetErrorHandler step type, which set the step invoked on errors
|
|
23
|
+
- ForLoop step type for loops over arrays.
|
|
24
|
+
- Varius UX improvements for editing workflows
|
|
25
|
+
- Integrate copilot, if installed, in workflow editing
|
|
26
|
+
|
|
27
|
+
* sbadmin2 theme - Color update: dark side bar, darker primary blue
|
|
28
|
+
|
|
29
|
+
* AppChange event, runs every time a view, table, trigger, page or configuration value
|
|
30
|
+
is changed.
|
|
31
|
+
|
|
32
|
+
* Mobile builder:
|
|
33
|
+
- PJAX view loading.
|
|
34
|
+
|
|
35
|
+
### Fixes
|
|
36
|
+
|
|
37
|
+
* fix query string build on check_state_field (#2948). Author: St0rml
|
|
38
|
+
|
|
39
|
+
### Translations
|
|
40
|
+
|
|
41
|
+
* Update Polish translation. Author: skaskiewicz
|
|
42
|
+
|
|
43
|
+
## 1.1.0 - Released 19 December 2024
|
|
44
|
+
|
|
45
|
+
* Workflows: a new type of trigger composed of steps, with durable execution and
|
|
46
|
+
a context for sharing information between steps. Workflows can include user interaction
|
|
47
|
+
including asking for user input in specified form fields.
|
|
48
|
+
|
|
49
|
+
* Workflow rooms: a new view for chatbot-style interactions with workflows
|
|
50
|
+
|
|
51
|
+
* HTTPS proxy: set an HTTPS proxy with the HTTPS_PROXY environment variable.
|
|
52
|
+
|
|
53
|
+
* Edit view: option to allocate new table row when running with a specified row. This is
|
|
54
|
+
useful when the Edit row includes embedded views based on relations. The allocated row can be
|
|
55
|
+
deleted if there are no changes.
|
|
56
|
+
|
|
57
|
+
* Acquire Let's Encrypt certificates for tenants. If Let's Encrypt is enabled in the root tenant,
|
|
58
|
+
newly created tenants will acquire a certificate. Certificate for existing tenants can be acquired
|
|
59
|
+
in that the settings for that tenant in the root tenant's list of tenants.
|
|
60
|
+
|
|
61
|
+
* Icon plugins. Plugins can now supply additional icons which can be chosen in the builder and
|
|
62
|
+
menu editor
|
|
63
|
+
|
|
64
|
+
* Registry editor: Edit configuration values
|
|
65
|
+
|
|
66
|
+
* Webhook action has more options: method, set reponse value, headers.
|
|
67
|
+
|
|
68
|
+
### Security
|
|
69
|
+
|
|
70
|
+
- SameSite cookie settings
|
|
71
|
+
- Options to enable Content Security Policy and CORS
|
|
72
|
+
- Warn when loading embedded with without role. Strict enforcement in 1.1.2.
|
|
73
|
+
- Check table permissions when filling select dropdown options
|
|
74
|
+
|
|
75
|
+
### Fixes
|
|
76
|
+
|
|
77
|
+
* Edit destination formulae are evaluated against the whole row, not only saved form fields
|
|
78
|
+
* Set user groups when admin becomes user
|
|
79
|
+
|
|
80
|
+
### Translations
|
|
81
|
+
|
|
82
|
+
* Update Polish translation. Author: skaskiewicz
|
|
83
|
+
|
|
84
|
+
## 1.0.0 - Released 15 November 2024
|
|
85
|
+
|
|
86
|
+
Change tracking from this point.
|
package/auth/testhelp.js
CHANGED
|
@@ -383,7 +383,13 @@ const load_url_dom = async (url) => {
|
|
|
383
383
|
.join("\n");
|
|
384
384
|
}
|
|
385
385
|
}
|
|
386
|
+
class FakeIntersectionObserver {
|
|
387
|
+
constructor() {}
|
|
388
|
+
observe() {}
|
|
389
|
+
}
|
|
390
|
+
|
|
386
391
|
dom.window.XMLHttpRequest = FakeXHR;
|
|
392
|
+
dom.window.IntersectionObserver = FakeIntersectionObserver;
|
|
387
393
|
await new Promise(function (resolve, reject) {
|
|
388
394
|
dom.window.addEventListener("DOMContentLoaded", (event) => {
|
|
389
395
|
resolve();
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "1.1.1-beta.
|
|
3
|
+
"version": "1.1.1-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
9
|
"@aws-sdk/client-s3": "^3.451.0",
|
|
10
|
-
"@saltcorn/base-plugin": "1.1.1-beta.
|
|
11
|
-
"@saltcorn/builder": "1.1.1-beta.
|
|
12
|
-
"@saltcorn/data": "1.1.1-beta.
|
|
13
|
-
"@saltcorn/admin-models": "1.1.1-beta.
|
|
14
|
-
"@saltcorn/filemanager": "1.1.1-beta.
|
|
15
|
-
"@saltcorn/markup": "1.1.1-beta.
|
|
16
|
-
"@saltcorn/plugins-loader": "1.1.1-beta.
|
|
17
|
-
"@saltcorn/sbadmin2": "1.1.1-beta.
|
|
10
|
+
"@saltcorn/base-plugin": "1.1.1-beta.3",
|
|
11
|
+
"@saltcorn/builder": "1.1.1-beta.3",
|
|
12
|
+
"@saltcorn/data": "1.1.1-beta.3",
|
|
13
|
+
"@saltcorn/admin-models": "1.1.1-beta.3",
|
|
14
|
+
"@saltcorn/filemanager": "1.1.1-beta.3",
|
|
15
|
+
"@saltcorn/markup": "1.1.1-beta.3",
|
|
16
|
+
"@saltcorn/plugins-loader": "1.1.1-beta.3",
|
|
17
|
+
"@saltcorn/sbadmin2": "1.1.1-beta.3",
|
|
18
18
|
"@socket.io/cluster-adapter": "^0.2.1",
|
|
19
19
|
"@socket.io/sticky": "^1.0.1",
|
|
20
20
|
"adm-zip": "0.5.10",
|
|
@@ -2024,3 +2024,33 @@ function update_time_of_week(nm) {
|
|
|
2024
2024
|
$(`#inputh${nm}`).val(s).trigger("change");
|
|
2025
2025
|
};
|
|
2026
2026
|
}
|
|
2027
|
+
|
|
2028
|
+
const observer = new IntersectionObserver(
|
|
2029
|
+
(entries, observer) => {
|
|
2030
|
+
entries.forEach((entry) => {
|
|
2031
|
+
if (entry.isIntersecting) {
|
|
2032
|
+
const delay = entry.target.getAttribute("data-animate-delay"); // delay is optional
|
|
2033
|
+
const duration = entry.target.getAttribute("data-animate-duration"); // delay is optional
|
|
2034
|
+
const animationClass = entry.target.getAttribute("data-animate");
|
|
2035
|
+
if (animationClass) {
|
|
2036
|
+
if (delay) entry.target.style.animationDelay = delay + "s";
|
|
2037
|
+
if (duration) entry.target.style.animationDuration = duration + "s";
|
|
2038
|
+
entry.target.style.animationName = animationClass;
|
|
2039
|
+
entry.target.style.animationFillMode = "both";
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
if (entry.target.getAttribute("data-animate-initial-hide") === "")
|
|
2043
|
+
entry.target.removeAttribute("data-animate-initial-hide");
|
|
2044
|
+
|
|
2045
|
+
observer.unobserve(entry.target);
|
|
2046
|
+
}
|
|
2047
|
+
});
|
|
2048
|
+
},
|
|
2049
|
+
{
|
|
2050
|
+
threshold: 0.2,
|
|
2051
|
+
}
|
|
2052
|
+
);
|
|
2053
|
+
|
|
2054
|
+
document.querySelectorAll("[data-animate]").forEach((element) => {
|
|
2055
|
+
observer.observe(element);
|
|
2056
|
+
});
|
package/public/saltcorn.css
CHANGED
|
@@ -632,3 +632,144 @@ i[class*=" unicode-"] {
|
|
|
632
632
|
.mobile-toast-margin {
|
|
633
633
|
margin-bottom: 1rem;
|
|
634
634
|
}
|
|
635
|
+
|
|
636
|
+
@keyframes fadeIn {
|
|
637
|
+
from {
|
|
638
|
+
opacity: 0;
|
|
639
|
+
}
|
|
640
|
+
to {
|
|
641
|
+
opacity: 1;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
@keyframes fadeInLeft {
|
|
646
|
+
from {
|
|
647
|
+
opacity: 0;
|
|
648
|
+
transform: translate3d(-100%, 0, 0);
|
|
649
|
+
}
|
|
650
|
+
to {
|
|
651
|
+
opacity: 1;
|
|
652
|
+
transform: translate3d(0, 0, 0);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
@keyframes fadeInDown {
|
|
657
|
+
from {
|
|
658
|
+
opacity: 0;
|
|
659
|
+
transform: translate3d(0, -100%, 0);
|
|
660
|
+
}
|
|
661
|
+
to {
|
|
662
|
+
opacity: 1;
|
|
663
|
+
transform: translate3d(0, 0, 0);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
@keyframes fadeInRight {
|
|
668
|
+
from {
|
|
669
|
+
opacity: 0;
|
|
670
|
+
transform: translate3d(100%, 0, 0);
|
|
671
|
+
}
|
|
672
|
+
to {
|
|
673
|
+
opacity: 1;
|
|
674
|
+
transform: translate3d(0, 0, 0);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
@keyframes fadeInUp {
|
|
679
|
+
from {
|
|
680
|
+
opacity: 0;
|
|
681
|
+
transform: translate3d(0, 100%, 0);
|
|
682
|
+
}
|
|
683
|
+
to {
|
|
684
|
+
opacity: 1;
|
|
685
|
+
transform: translate3d(0, 0, 0);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
@keyframes rollIn {
|
|
690
|
+
from {
|
|
691
|
+
opacity: 0;
|
|
692
|
+
transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
|
|
693
|
+
}
|
|
694
|
+
to {
|
|
695
|
+
opacity: 1;
|
|
696
|
+
transform: translate3d(0, 0, 0);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
@keyframes zoomIn {
|
|
701
|
+
from {
|
|
702
|
+
opacity: 0;
|
|
703
|
+
transform: scale3d(0.3, 0.3, 0.3);
|
|
704
|
+
}
|
|
705
|
+
50% {
|
|
706
|
+
opacity: 1;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
@keyframes zoomInUp {
|
|
711
|
+
from {
|
|
712
|
+
opacity: 0;
|
|
713
|
+
transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
|
|
714
|
+
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
715
|
+
}
|
|
716
|
+
60% {
|
|
717
|
+
opacity: 1;
|
|
718
|
+
transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
|
|
719
|
+
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
@keyframes bounce {
|
|
724
|
+
from,
|
|
725
|
+
20%,
|
|
726
|
+
53%,
|
|
727
|
+
to {
|
|
728
|
+
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
729
|
+
transform: translate3d(0, 0, 0);
|
|
730
|
+
}
|
|
731
|
+
40%,
|
|
732
|
+
43% {
|
|
733
|
+
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
|
734
|
+
transform: translate3d(0, -30px, 0) scaleY(1.1);
|
|
735
|
+
}
|
|
736
|
+
70% {
|
|
737
|
+
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
|
738
|
+
transform: translate3d(0, -15px, 0) scaleY(1.05);
|
|
739
|
+
}
|
|
740
|
+
80% {
|
|
741
|
+
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
742
|
+
transform: translate3d(0, 0, 0) scaleY(0.95);
|
|
743
|
+
}
|
|
744
|
+
90% {
|
|
745
|
+
transform: translate3d(0, -4px, 0) scaleY(1.02);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
@keyframes tada {
|
|
750
|
+
from {
|
|
751
|
+
transform: scale3d(1, 1, 1);
|
|
752
|
+
}
|
|
753
|
+
10%,
|
|
754
|
+
20% {
|
|
755
|
+
transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
|
|
756
|
+
}
|
|
757
|
+
30%,
|
|
758
|
+
50%,
|
|
759
|
+
70%,
|
|
760
|
+
90% {
|
|
761
|
+
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
|
|
762
|
+
}
|
|
763
|
+
40%,
|
|
764
|
+
60%,
|
|
765
|
+
80% {
|
|
766
|
+
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
|
|
767
|
+
}
|
|
768
|
+
to {
|
|
769
|
+
transform: scale3d(1, 1, 1);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
[data-animate-initial-hide] {
|
|
774
|
+
opacity: 0;
|
|
775
|
+
}
|
package/routes/actions.js
CHANGED
|
@@ -508,14 +508,19 @@ function genWorkflowDiagram(steps) {
|
|
|
508
508
|
const stepNames = steps.map((s) => s.name);
|
|
509
509
|
const nodeLines = steps.map(
|
|
510
510
|
(s) => ` ${s.mmname}["\`**${s.name}**
|
|
511
|
-
${s.action_name}\`"]:::wfstep${s.id}`
|
|
511
|
+
${s.action_name}\`"]:::wfstep${s.id}${s.only_if ? "@{ shape: hex }" : ""}`
|
|
512
512
|
);
|
|
513
513
|
|
|
514
514
|
nodeLines.unshift(` _Start@{ shape: circle, label: "Start" }`);
|
|
515
515
|
const linkLines = [];
|
|
516
516
|
let step_ix = 0;
|
|
517
517
|
for (const step of steps) {
|
|
518
|
-
if (step.initial_step)
|
|
518
|
+
if (step.initial_step)
|
|
519
|
+
linkLines.push(
|
|
520
|
+
` _Start-- <i class="fas fa-plus add-btw-nodes btw-nodes-${0}-${
|
|
521
|
+
step.name
|
|
522
|
+
}"></i> ---${step.mmname}`
|
|
523
|
+
);
|
|
519
524
|
if (stepNames.includes(step.next_step)) {
|
|
520
525
|
linkLines.push(
|
|
521
526
|
` ${step.mmname}-- <i class="fas fa-plus add-btw-nodes btw-nodes-${step.id}-${step.next_step}"></i> ---${step.mmnext}`
|
|
@@ -739,7 +744,9 @@ const getWorkflowStepForm = async (
|
|
|
739
744
|
},
|
|
740
745
|
});
|
|
741
746
|
|
|
742
|
-
const builtInActionExplainers = WorkflowStep.builtInActionExplainers(
|
|
747
|
+
const builtInActionExplainers = WorkflowStep.builtInActionExplainers({
|
|
748
|
+
api_call: trigger.when_trigger == "API call",
|
|
749
|
+
});
|
|
743
750
|
const actionsNotRequiringRow = Trigger.action_options({
|
|
744
751
|
notRequireRow: true,
|
|
745
752
|
noMultiStep: true,
|
|
@@ -830,7 +837,8 @@ const getWorkflowStepForm = async (
|
|
|
830
837
|
form.hidden("wf_step_id");
|
|
831
838
|
form.hidden("_after_step");
|
|
832
839
|
if (before_step) form.values.wf_next_step = before_step;
|
|
833
|
-
if (after_step) form.values.
|
|
840
|
+
if (after_step == "0") form.values.wf_initial_step = true;
|
|
841
|
+
else if (after_step) form.values._after_step = after_step;
|
|
834
842
|
if (step_id) {
|
|
835
843
|
const step = await WorkflowStep.findOne({ id: step_id });
|
|
836
844
|
if (!step) throw new Error("Step not found");
|
|
@@ -1744,7 +1752,14 @@ const getWorkflowStepUserForm = async (run, trigger, step, req) => {
|
|
|
1744
1752
|
null,
|
|
1745
1753
|
req
|
|
1746
1754
|
);
|
|
1755
|
+
await form.fill_fkey_options(false, undefined, req?.user);
|
|
1747
1756
|
form.action = `/actions/fill-workflow-form/${run.id}`;
|
|
1757
|
+
if (run.context[step.configuration.response_variable])
|
|
1758
|
+
Object.assign(
|
|
1759
|
+
form.values,
|
|
1760
|
+
run.context[step.configuration.response_variable]
|
|
1761
|
+
);
|
|
1762
|
+
|
|
1748
1763
|
return form;
|
|
1749
1764
|
}
|
|
1750
1765
|
|
|
@@ -1880,8 +1895,9 @@ WORKFLOWS TODO
|
|
|
1880
1895
|
|
|
1881
1896
|
help file to explain steps, and context
|
|
1882
1897
|
|
|
1883
|
-
workflow actions:
|
|
1898
|
+
workflow actions: ReadFile, WriteFile,
|
|
1884
1899
|
|
|
1900
|
+
EditViewForm: presets. response var can be blank
|
|
1885
1901
|
other triggers can be steps
|
|
1886
1902
|
interactive workflows for not logged in
|
|
1887
1903
|
actions can declare which variables they inject into scope
|
package/routes/admin.js
CHANGED
|
@@ -115,6 +115,8 @@ const { get_help_markup } = require("../help/index.js");
|
|
|
115
115
|
const Docker = require("dockerode");
|
|
116
116
|
const npmFetch = require("npm-registry-fetch");
|
|
117
117
|
const Tag = require("@saltcorn/data/models/tag");
|
|
118
|
+
const MarkdownIt = require("markdown-it"),
|
|
119
|
+
md = new MarkdownIt();
|
|
118
120
|
|
|
119
121
|
const router = new Router();
|
|
120
122
|
module.exports = router;
|
|
@@ -287,6 +289,18 @@ router.get(
|
|
|
287
289
|
})
|
|
288
290
|
);
|
|
289
291
|
|
|
292
|
+
router.get(
|
|
293
|
+
"/whatsnew",
|
|
294
|
+
isAdmin,
|
|
295
|
+
error_catcher(async (req, res) => {
|
|
296
|
+
const fp = path.join(__dirname, "..", "CHANGELOG.md");
|
|
297
|
+
const fileBuf = await fs.promises.readFile(fp);
|
|
298
|
+
const mdContents = fileBuf.toString().replace("# Notable changes\n","");
|
|
299
|
+
const markup = md.render(mdContents);
|
|
300
|
+
res.sendWrap(`What's new in Saltcorn`, { above: [markup] });
|
|
301
|
+
})
|
|
302
|
+
);
|
|
303
|
+
|
|
290
304
|
/**
|
|
291
305
|
* @name get/backup
|
|
292
306
|
* @function
|
|
@@ -1137,7 +1151,7 @@ router.get(
|
|
|
1137
1151
|
table(
|
|
1138
1152
|
tbody(
|
|
1139
1153
|
tr(
|
|
1140
|
-
th(req.__("Saltcorn version")),
|
|
1154
|
+
th({ valign: "top" }, req.__("Saltcorn version")),
|
|
1141
1155
|
td(
|
|
1142
1156
|
packagejson.version,
|
|
1143
1157
|
isRoot && can_update
|
|
@@ -1177,7 +1191,15 @@ router.get(
|
|
|
1177
1191
|
` onError: (res) => { selectVersionError(res, '${rndid}') } });`,
|
|
1178
1192
|
},
|
|
1179
1193
|
req.__("Choose version")
|
|
1180
|
-
)
|
|
1194
|
+
),
|
|
1195
|
+
"<br>",
|
|
1196
|
+
a(
|
|
1197
|
+
{
|
|
1198
|
+
onclick: "ajax_modal('/admin/whatsnew')",
|
|
1199
|
+
href: `javascript:void(0)`,
|
|
1200
|
+
},
|
|
1201
|
+
"What's new?"
|
|
1202
|
+
)
|
|
1181
1203
|
)
|
|
1182
1204
|
),
|
|
1183
1205
|
git_commit &&
|
package/routes/api.js
CHANGED
|
@@ -398,15 +398,26 @@ router.all(
|
|
|
398
398
|
async function (err, user, info) {
|
|
399
399
|
if (accessAllowed(req, user, trigger)) {
|
|
400
400
|
try {
|
|
401
|
-
|
|
401
|
+
let resp;
|
|
402
402
|
const row = req.method === "GET" ? req.query : req.body;
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
403
|
+
if (trigger.action === "Workflow") {
|
|
404
|
+
resp = await trigger.runWithoutRow({
|
|
405
|
+
req,
|
|
406
|
+
interactive: true,
|
|
407
|
+
row,
|
|
408
|
+
user: user || req.user,
|
|
409
|
+
});
|
|
410
|
+
delete resp.__wf_run_id;
|
|
411
|
+
} else {
|
|
412
|
+
const action = getState().actions[trigger.action];
|
|
413
|
+
resp = await action.run({
|
|
414
|
+
configuration: trigger.configuration,
|
|
415
|
+
body: req.body,
|
|
416
|
+
row,
|
|
417
|
+
req,
|
|
418
|
+
user: user || req.user,
|
|
419
|
+
});
|
|
420
|
+
}
|
|
410
421
|
if (
|
|
411
422
|
(row._process_result || req.headers?.scprocessresults) &&
|
|
412
423
|
resp?.goto
|
package/routes/pageedit.js
CHANGED
package/routes/tables.js
CHANGED
package/tests/clientjs.test.js
CHANGED
|
@@ -13,6 +13,13 @@ const load_script = (fnm) => {
|
|
|
13
13
|
document.body.appendChild(scriptEl);
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
class IntersectionObserver {
|
|
17
|
+
constructor() {}
|
|
18
|
+
observe() {}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
window.IntersectionObserver = IntersectionObserver;
|
|
22
|
+
|
|
16
23
|
load_script("jquery-3.6.0.min.js");
|
|
17
24
|
load_script("saltcorn-common.js");
|
|
18
25
|
load_script("saltcorn.js");
|
|
@@ -91,15 +98,11 @@ test("updateQueryStringParameter hash", () => {
|
|
|
91
98
|
);
|
|
92
99
|
});
|
|
93
100
|
test("addQueryStringParameter", () => {
|
|
94
|
-
expect(addQueryStringParameter("/foo", "age", 43)).toBe(
|
|
95
|
-
"/foo?age=43"
|
|
96
|
-
);
|
|
101
|
+
expect(addQueryStringParameter("/foo", "age", 43)).toBe("/foo?age=43");
|
|
97
102
|
expect(addQueryStringParameter("/foo?age=43", "age", 44)).toBe(
|
|
98
103
|
"/foo?age=43&age=44"
|
|
99
104
|
);
|
|
100
|
-
expect(addQueryStringParameter("/foo?age=43", "age", 43)).toBe(
|
|
101
|
-
"/foo?age=43"
|
|
102
|
-
);
|
|
105
|
+
expect(addQueryStringParameter("/foo?age=43", "age", 43)).toBe("/foo?age=43");
|
|
103
106
|
});
|
|
104
107
|
test("addQueryStringParameter hash", () => {
|
|
105
108
|
expect(addQueryStringParameter("/foo#baz", "age", 43)).toBe(
|