@saltcorn/server 1.1.1-beta.1 → 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/help/Event types.tmd +2 -0
- package/locales/en.json +7 -1
- package/package.json +9 -9
- package/public/saltcorn-common.js +30 -0
- package/public/saltcorn.css +141 -0
- package/public/saltcorn.js +87 -17
- package/routes/actions.js +86 -11
- package/routes/admin.js +281 -48
- package/routes/api.js +19 -8
- package/routes/fields.js +9 -0
- package/routes/menu.js +1 -0
- package/routes/notifications.js +20 -12
- package/routes/page.js +2 -2
- package/routes/pageedit.js +35 -1
- package/routes/tables.js +1 -0
- package/routes/utils.js +4 -0
- package/routes/view.js +14 -12
- package/routes/viewedit.js +26 -0
- package/tests/clientjs.test.js +22 -0
package/routes/actions.js
CHANGED
|
@@ -14,6 +14,10 @@ const {
|
|
|
14
14
|
const { ppVal, jsIdentifierValidator } = require("@saltcorn/data/utils");
|
|
15
15
|
const { getState } = require("@saltcorn/data/db/state");
|
|
16
16
|
const Trigger = require("@saltcorn/data/models/trigger");
|
|
17
|
+
const View = require("@saltcorn/data/models/view");
|
|
18
|
+
const {
|
|
19
|
+
getForm,
|
|
20
|
+
} = require("@saltcorn/data/base-plugin/viewtemplates/viewable_fields");
|
|
17
21
|
const FieldRepeat = require("@saltcorn/data/models/fieldrepeat");
|
|
18
22
|
const { getTriggerList } = require("./common_lists");
|
|
19
23
|
const TagEntry = require("@saltcorn/data/models/tag_entry");
|
|
@@ -441,6 +445,10 @@ router.post(
|
|
|
441
445
|
const tr = await Trigger.create(form.values);
|
|
442
446
|
id = tr.id;
|
|
443
447
|
}
|
|
448
|
+
Trigger.emitEvent("AppChange", `Trigger ${form.values.name}`, req.user, {
|
|
449
|
+
entity_type: "Trigger",
|
|
450
|
+
entity_name: form.values.name,
|
|
451
|
+
});
|
|
444
452
|
res.redirect(addOnDoneRedirect(`/actions/configure/${id}`, req));
|
|
445
453
|
}
|
|
446
454
|
})
|
|
@@ -482,6 +490,10 @@ router.post(
|
|
|
482
490
|
...form.values.configuration,
|
|
483
491
|
};
|
|
484
492
|
await Trigger.update(trigger.id, form.values); //{configuration: form.values});
|
|
493
|
+
Trigger.emitEvent("AppChange", `Trigger ${trigger.name}`, req.user, {
|
|
494
|
+
entity_type: "Trigger",
|
|
495
|
+
entity_name: trigger.name,
|
|
496
|
+
});
|
|
485
497
|
if (req.xhr) {
|
|
486
498
|
res.json({ success: "ok" });
|
|
487
499
|
return;
|
|
@@ -496,14 +508,19 @@ function genWorkflowDiagram(steps) {
|
|
|
496
508
|
const stepNames = steps.map((s) => s.name);
|
|
497
509
|
const nodeLines = steps.map(
|
|
498
510
|
(s) => ` ${s.mmname}["\`**${s.name}**
|
|
499
|
-
${s.action_name}\`"]:::wfstep${s.id}`
|
|
511
|
+
${s.action_name}\`"]:::wfstep${s.id}${s.only_if ? "@{ shape: hex }" : ""}`
|
|
500
512
|
);
|
|
501
513
|
|
|
502
514
|
nodeLines.unshift(` _Start@{ shape: circle, label: "Start" }`);
|
|
503
515
|
const linkLines = [];
|
|
504
516
|
let step_ix = 0;
|
|
505
517
|
for (const step of steps) {
|
|
506
|
-
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
|
+
);
|
|
507
524
|
if (stepNames.includes(step.next_step)) {
|
|
508
525
|
linkLines.push(
|
|
509
526
|
` ${step.mmname}-- <i class="fas fa-plus add-btw-nodes btw-nodes-${step.id}-${step.next_step}"></i> ---${step.mmnext}`
|
|
@@ -533,9 +550,11 @@ function genWorkflowDiagram(steps) {
|
|
|
533
550
|
}
|
|
534
551
|
if (step.action_name === "ForLoop") {
|
|
535
552
|
linkLines.push(
|
|
536
|
-
` ${step.mmname}-.->${WorkflowStep.mmescape(
|
|
553
|
+
` ${step.mmname}-.->${WorkflowStep.mmescape(
|
|
554
|
+
step.configuration.loop_body_initial_step
|
|
555
|
+
)}`
|
|
537
556
|
);
|
|
538
|
-
}
|
|
557
|
+
}
|
|
539
558
|
if (step.action_name === "EndForLoop") {
|
|
540
559
|
// TODO this is not correct. improve.
|
|
541
560
|
let forStep;
|
|
@@ -711,11 +730,23 @@ const getWorkflowStepForm = async (
|
|
|
711
730
|
},
|
|
712
731
|
};
|
|
713
732
|
if (cfgFld.input_type === "code") cfgFld.input_type = "textarea";
|
|
714
|
-
actionConfigFields.push(cfgFld);
|
|
715
733
|
}
|
|
716
734
|
} catch {}
|
|
717
735
|
}
|
|
718
|
-
|
|
736
|
+
actionConfigFields.push({
|
|
737
|
+
label: "Subcontext",
|
|
738
|
+
name: "subcontext",
|
|
739
|
+
type: "String",
|
|
740
|
+
sublabel:
|
|
741
|
+
"Optional. A key on the current workflow's context, the values of which will be the called workflow's context.",
|
|
742
|
+
showIf: {
|
|
743
|
+
wf_action_name: Trigger.find({ action: "Workflow" }).map((wf) => wf.name),
|
|
744
|
+
},
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
const builtInActionExplainers = WorkflowStep.builtInActionExplainers({
|
|
748
|
+
api_call: trigger.when_trigger == "API call",
|
|
749
|
+
});
|
|
719
750
|
const actionsNotRequiringRow = Trigger.action_options({
|
|
720
751
|
notRequireRow: true,
|
|
721
752
|
noMultiStep: true,
|
|
@@ -730,7 +761,9 @@ const getWorkflowStepForm = async (
|
|
|
730
761
|
if (tr.description) actionExplainers[tr.name] = tr.description;
|
|
731
762
|
});
|
|
732
763
|
Object.assign(actionExplainers, builtInActionExplainers);
|
|
733
|
-
actionConfigFields.push(
|
|
764
|
+
actionConfigFields.push(
|
|
765
|
+
...(await WorkflowStep.builtInActionConfigFields({ trigger }))
|
|
766
|
+
);
|
|
734
767
|
|
|
735
768
|
const form = new Form({
|
|
736
769
|
action: addOnDoneRedirect(`/actions/stepedit/${trigger.id}`, req),
|
|
@@ -804,7 +837,8 @@ const getWorkflowStepForm = async (
|
|
|
804
837
|
form.hidden("wf_step_id");
|
|
805
838
|
form.hidden("_after_step");
|
|
806
839
|
if (before_step) form.values.wf_next_step = before_step;
|
|
807
|
-
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;
|
|
808
842
|
if (step_id) {
|
|
809
843
|
const step = await WorkflowStep.findOne({ id: step_id });
|
|
810
844
|
if (!step) throw new Error("Step not found");
|
|
@@ -1142,6 +1176,10 @@ router.post(
|
|
|
1142
1176
|
await Trigger.update(trigger.id, {
|
|
1143
1177
|
configuration: { ...trigger.configuration, ...form.values },
|
|
1144
1178
|
});
|
|
1179
|
+
Trigger.emitEvent("AppChange", `Trigger ${trigger.name}`, req.user, {
|
|
1180
|
+
entity_type: "Trigger",
|
|
1181
|
+
entity_name: trigger.name,
|
|
1182
|
+
});
|
|
1145
1183
|
if (req.xhr) {
|
|
1146
1184
|
res.json({ success: "ok" });
|
|
1147
1185
|
return;
|
|
@@ -1168,6 +1206,10 @@ router.post(
|
|
|
1168
1206
|
error_catcher(async (req, res) => {
|
|
1169
1207
|
const { id } = req.params;
|
|
1170
1208
|
const trigger = await Trigger.findOne({ id });
|
|
1209
|
+
Trigger.emitEvent("AppChange", `Trigger ${trigger.name}`, req.user, {
|
|
1210
|
+
entity_type: "Trigger",
|
|
1211
|
+
entity_name: trigger.name,
|
|
1212
|
+
});
|
|
1171
1213
|
await trigger.delete();
|
|
1172
1214
|
res.redirect(`/actions/`);
|
|
1173
1215
|
})
|
|
@@ -1296,6 +1338,10 @@ router.post(
|
|
|
1296
1338
|
const { id } = req.params;
|
|
1297
1339
|
const trig = await Trigger.findOne({ id });
|
|
1298
1340
|
const newtrig = await trig.clone();
|
|
1341
|
+
Trigger.emitEvent("AppChange", `Trigger ${newtrig.name}`, req.user, {
|
|
1342
|
+
entity_type: "Trigger",
|
|
1343
|
+
entity_name: newtrig.name,
|
|
1344
|
+
});
|
|
1299
1345
|
req.flash(
|
|
1300
1346
|
"success",
|
|
1301
1347
|
req.__("Trigger %s duplicated as %s", trig.name, newtrig.name)
|
|
@@ -1425,6 +1471,10 @@ router.post(
|
|
|
1425
1471
|
res.redirect(`/actions/configure/${step.trigger_id}`);
|
|
1426
1472
|
}
|
|
1427
1473
|
}
|
|
1474
|
+
Trigger.emitEvent("AppChange", `Trigger ${trigger.name}`, req.user, {
|
|
1475
|
+
entity_type: "Trigger",
|
|
1476
|
+
entity_name: trigger.name,
|
|
1477
|
+
});
|
|
1428
1478
|
if (_after_step && _after_step !== "undefined") {
|
|
1429
1479
|
const astep = await WorkflowStep.findOne({
|
|
1430
1480
|
id: _after_step,
|
|
@@ -1465,6 +1515,10 @@ router.post(
|
|
|
1465
1515
|
step.trigger_id = trigger.id;
|
|
1466
1516
|
await WorkflowStep.create(step);
|
|
1467
1517
|
}
|
|
1518
|
+
Trigger.emitEvent("AppChange", `Trigger ${trigger.name}`, req.user, {
|
|
1519
|
+
entity_type: "Trigger",
|
|
1520
|
+
entity_name: trigger.name,
|
|
1521
|
+
});
|
|
1468
1522
|
res.redirect(`/actions/configure/${trigger.id}`);
|
|
1469
1523
|
})
|
|
1470
1524
|
);
|
|
@@ -1687,6 +1741,28 @@ router.post(
|
|
|
1687
1741
|
);
|
|
1688
1742
|
|
|
1689
1743
|
const getWorkflowStepUserForm = async (run, trigger, step, req) => {
|
|
1744
|
+
if (step.action_name === "EditViewForm") {
|
|
1745
|
+
const view = View.findOne({ name: step.configuration.edit_view });
|
|
1746
|
+
const table = Table.findOne({ id: view.table_id });
|
|
1747
|
+
const form = await getForm(
|
|
1748
|
+
table,
|
|
1749
|
+
view.name,
|
|
1750
|
+
view.configuration.columns,
|
|
1751
|
+
view.configuration.layout,
|
|
1752
|
+
null,
|
|
1753
|
+
req
|
|
1754
|
+
);
|
|
1755
|
+
await form.fill_fkey_options(false, undefined, req?.user);
|
|
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
|
+
|
|
1763
|
+
return form;
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1690
1766
|
let blurb = run.wait_info.output || step.configuration?.form_header || "";
|
|
1691
1767
|
if (run.wait_info.markdown && run.wait_info.output) blurb = md.render(blurb);
|
|
1692
1768
|
const form = new Form({
|
|
@@ -1819,12 +1895,11 @@ WORKFLOWS TODO
|
|
|
1819
1895
|
|
|
1820
1896
|
help file to explain steps, and context
|
|
1821
1897
|
|
|
1822
|
-
workflow actions:
|
|
1898
|
+
workflow actions: ReadFile, WriteFile,
|
|
1823
1899
|
|
|
1824
|
-
|
|
1900
|
+
EditViewForm: presets. response var can be blank
|
|
1825
1901
|
other triggers can be steps
|
|
1826
1902
|
interactive workflows for not logged in
|
|
1827
|
-
show end node in diagram
|
|
1828
1903
|
actions can declare which variables they inject into scope
|
|
1829
1904
|
|
|
1830
1905
|
show unconnected steps
|