@saltcorn/server 1.1.1-beta.0 → 1.1.1-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/locales/pl.json +16 -1
- package/package.json +9 -9
- package/routes/actions.js +67 -181
- package/routes/utils.js +1 -0
- package/tests/view.test.js +37 -0
package/locales/pl.json
CHANGED
|
@@ -1508,5 +1508,20 @@
|
|
|
1508
1508
|
"Workflow runs": "Przepływ pracy jest uruchomiony",
|
|
1509
1509
|
"Workflow run": "Uruchomienie przepływu pracy",
|
|
1510
1510
|
"Share to enabled": "Udostępnij włączone",
|
|
1511
|
-
"Enable the share to feature": "Włącz udostępnianie funkcji"
|
|
1511
|
+
"Enable the share to feature": "Włącz udostępnianie funkcji",
|
|
1512
|
+
"Allocate new row": "Przydziel nowy wiersz",
|
|
1513
|
+
"If the view is run without existing row, allocate a new row on load. Defaults must be set on all required fields.": "Jeśli widok jest uruchamiany bez istniejącego wiersza, przydziel nowy wiersz podczas ładowania. Domyślne wartości muszą być ustawione na wszystkich wymaganych polach.",
|
|
1514
|
+
"Step traces": "Ślady kroków",
|
|
1515
|
+
"Please enter a version in the format 'x.y.z' (e.g. 0.0.1 with numbers from 0 to 999) or leave it empty.": "Wprowadź wersję w formacie 'x.y.z' (np. 0.0.1 z liczbami od 0 do 999) lub pozostaw puste.",
|
|
1516
|
+
"Delete unchanged": "Usuń bez zmian",
|
|
1517
|
+
"Delete allocated row if there are no changes.": "Usuń przydzielony wiersz, jeśli nie wprowadzono żadnych zmian.",
|
|
1518
|
+
"Triggers on table": "Wyzwalacze na tabeli",
|
|
1519
|
+
"Please provide the keystore alias and password for the android build.": "Podaj alias i hasło do keystore dla kompilacji Android.",
|
|
1520
|
+
"Submit": "Prześlij",
|
|
1521
|
+
"OK": "OK",
|
|
1522
|
+
"Step settings": "Ustawienia kroku",
|
|
1523
|
+
"Action settings": "Ustawienia akcji",
|
|
1524
|
+
"Workflow": "Przepływ pracy",
|
|
1525
|
+
"Previous runs": "Poprzednie uruchomienia",
|
|
1526
|
+
"The workflow the user will be interacting with.": "Przepływ pracy, z którym użytkownik będzie wchodził w interakcję."
|
|
1512
1527
|
}
|
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.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
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.1",
|
|
11
|
+
"@saltcorn/builder": "1.1.1-beta.1",
|
|
12
|
+
"@saltcorn/data": "1.1.1-beta.1",
|
|
13
|
+
"@saltcorn/admin-models": "1.1.1-beta.1",
|
|
14
|
+
"@saltcorn/filemanager": "1.1.1-beta.1",
|
|
15
|
+
"@saltcorn/markup": "1.1.1-beta.1",
|
|
16
|
+
"@saltcorn/plugins-loader": "1.1.1-beta.1",
|
|
17
|
+
"@saltcorn/sbadmin2": "1.1.1-beta.1",
|
|
18
18
|
"@socket.io/cluster-adapter": "^0.2.1",
|
|
19
19
|
"@socket.io/sticky": "^1.0.1",
|
|
20
20
|
"adm-zip": "0.5.10",
|
package/routes/actions.js
CHANGED
|
@@ -11,7 +11,7 @@ const {
|
|
|
11
11
|
addOnDoneRedirect,
|
|
12
12
|
is_relative_url,
|
|
13
13
|
} = require("./utils.js");
|
|
14
|
-
const { ppVal } = require("@saltcorn/data/utils");
|
|
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
17
|
const FieldRepeat = require("@saltcorn/data/models/fieldrepeat");
|
|
@@ -495,7 +495,7 @@ router.post(
|
|
|
495
495
|
function genWorkflowDiagram(steps) {
|
|
496
496
|
const stepNames = steps.map((s) => s.name);
|
|
497
497
|
const nodeLines = steps.map(
|
|
498
|
-
(s) => ` ${s.
|
|
498
|
+
(s) => ` ${s.mmname}["\`**${s.name}**
|
|
499
499
|
${s.action_name}\`"]:::wfstep${s.id}`
|
|
500
500
|
);
|
|
501
501
|
|
|
@@ -503,36 +503,39 @@ function genWorkflowDiagram(steps) {
|
|
|
503
503
|
const linkLines = [];
|
|
504
504
|
let step_ix = 0;
|
|
505
505
|
for (const step of steps) {
|
|
506
|
-
if (step.initial_step) linkLines.push(` _Start --> ${step.
|
|
507
|
-
if (step.
|
|
508
|
-
linkLines.push(
|
|
509
|
-
` ${step.name} --> ${step.configuration.for_loop_step_name}`
|
|
510
|
-
);
|
|
511
|
-
} else if (stepNames.includes(step.next_step)) {
|
|
506
|
+
if (step.initial_step) linkLines.push(` _Start --> ${step.mmname}`);
|
|
507
|
+
if (stepNames.includes(step.next_step)) {
|
|
512
508
|
linkLines.push(
|
|
513
|
-
` ${step.
|
|
509
|
+
` ${step.mmname}-- <i class="fas fa-plus add-btw-nodes btw-nodes-${step.id}-${step.next_step}"></i> ---${step.mmnext}`
|
|
514
510
|
);
|
|
515
511
|
} else if (step.next_step) {
|
|
516
512
|
let found = false;
|
|
517
513
|
for (const otherStep of stepNames)
|
|
518
514
|
if (step.next_step.includes(otherStep)) {
|
|
519
|
-
linkLines.push(
|
|
515
|
+
linkLines.push(
|
|
516
|
+
` ${step.mmname} --> ${WorkflowStep.mmescape(otherStep)}`
|
|
517
|
+
);
|
|
520
518
|
found = true;
|
|
521
519
|
}
|
|
522
520
|
if (!found) {
|
|
523
521
|
linkLines.push(
|
|
524
|
-
` ${step.
|
|
522
|
+
` ${step.mmname}-- <a href="/actions/stepedit/${step.trigger_id}/${step.id}">Error: missing next step in ${step.mmname}</a> ---_End_${step.mmname}`
|
|
525
523
|
);
|
|
526
524
|
nodeLines.push(
|
|
527
|
-
` _End_${step.
|
|
525
|
+
` _End_${step.mmname}:::wfadd${step.id}@{ shape: circle, label: "<i class='fas fa-plus with-link'></i>" }`
|
|
528
526
|
);
|
|
529
527
|
}
|
|
530
528
|
} else if (!step.next_step) {
|
|
531
|
-
linkLines.push(` ${step.
|
|
529
|
+
linkLines.push(` ${step.mmname} --> _End_${step.mmname}`);
|
|
532
530
|
nodeLines.push(
|
|
533
|
-
` _End_${step.
|
|
531
|
+
` _End_${step.mmname}:::wfadd${step.id}@{ shape: circle, label: "<i class='fas fa-plus with-link'></i>" }`
|
|
534
532
|
);
|
|
535
533
|
}
|
|
534
|
+
if (step.action_name === "ForLoop") {
|
|
535
|
+
linkLines.push(
|
|
536
|
+
` ${step.mmname}-.->${WorkflowStep.mmescape(step.configuration.loop_body_initial_step)}`
|
|
537
|
+
);
|
|
538
|
+
}
|
|
536
539
|
if (step.action_name === "EndForLoop") {
|
|
537
540
|
// TODO this is not correct. improve.
|
|
538
541
|
let forStep;
|
|
@@ -542,7 +545,7 @@ function genWorkflowDiagram(steps) {
|
|
|
542
545
|
break;
|
|
543
546
|
}
|
|
544
547
|
}
|
|
545
|
-
if (forStep) linkLines.push(` ${step.
|
|
548
|
+
if (forStep) linkLines.push(` ${step.mmname} --> ${forStep.mmname}`);
|
|
546
549
|
}
|
|
547
550
|
step_ix += 1;
|
|
548
551
|
}
|
|
@@ -581,7 +584,29 @@ const getWorkflowConfig = async (req, id, table, trigger) => {
|
|
|
581
584
|
],
|
|
582
585
|
});
|
|
583
586
|
trigCfgForm.values = trigger.configuration;
|
|
587
|
+
let copilot_form = "";
|
|
588
|
+
|
|
589
|
+
if (getState().functions.copilot_generate_workflow) {
|
|
590
|
+
copilot_form = renderForm(
|
|
591
|
+
new Form({
|
|
592
|
+
action: `/actions/gen-copilot/${id}`,
|
|
593
|
+
values: { description: trigger.description || "" },
|
|
594
|
+
submitLabel: "Generate workflow with copilot",
|
|
595
|
+
formStyle: "vert",
|
|
596
|
+
fields: [
|
|
597
|
+
{
|
|
598
|
+
name: "description",
|
|
599
|
+
label: "Description",
|
|
600
|
+
type: "String",
|
|
601
|
+
fieldview: "textarea",
|
|
602
|
+
},
|
|
603
|
+
],
|
|
604
|
+
}),
|
|
605
|
+
req.csrfToken()
|
|
606
|
+
);
|
|
607
|
+
}
|
|
584
608
|
return (
|
|
609
|
+
copilot_form +
|
|
585
610
|
pre({ class: "mermaid" }, genWorkflowDiagram(steps)) +
|
|
586
611
|
script(
|
|
587
612
|
{ defer: "defer" },
|
|
@@ -641,16 +666,6 @@ window.addEventListener('DOMContentLoaded',tryAddWFNodes)`
|
|
|
641
666
|
);
|
|
642
667
|
};
|
|
643
668
|
|
|
644
|
-
const jsIdentifierValidator = (s) => {
|
|
645
|
-
if (!s) return "An identifier is required";
|
|
646
|
-
if (s.includes(" ")) return "Spaces not allowd";
|
|
647
|
-
let badc = "'#:/\\@()[]{}\"!%^&*-+*~<>,.?|"
|
|
648
|
-
.split("")
|
|
649
|
-
.find((c) => s.includes(c));
|
|
650
|
-
|
|
651
|
-
if (badc) return `Character ${badc} not allowed`;
|
|
652
|
-
};
|
|
653
|
-
|
|
654
669
|
const getWorkflowStepForm = async (
|
|
655
670
|
trigger,
|
|
656
671
|
req,
|
|
@@ -700,19 +715,12 @@ const getWorkflowStepForm = async (
|
|
|
700
715
|
}
|
|
701
716
|
} catch {}
|
|
702
717
|
}
|
|
718
|
+
const builtInActionExplainers = WorkflowStep.builtInActionExplainers();
|
|
703
719
|
const actionsNotRequiringRow = Trigger.action_options({
|
|
704
720
|
notRequireRow: true,
|
|
705
721
|
noMultiStep: true,
|
|
706
722
|
builtInLabel: "Workflow Actions",
|
|
707
|
-
builtIns:
|
|
708
|
-
"SetContext",
|
|
709
|
-
"TableQuery",
|
|
710
|
-
"Output",
|
|
711
|
-
"DataOutput",
|
|
712
|
-
"WaitUntil",
|
|
713
|
-
"WaitNextTick",
|
|
714
|
-
"UserForm",
|
|
715
|
-
],
|
|
723
|
+
builtIns: Object.keys(builtInActionExplainers),
|
|
716
724
|
forWorkflow: true,
|
|
717
725
|
});
|
|
718
726
|
const triggers = Trigger.find({
|
|
@@ -721,152 +729,8 @@ const getWorkflowStepForm = async (
|
|
|
721
729
|
triggers.forEach((tr) => {
|
|
722
730
|
if (tr.description) actionExplainers[tr.name] = tr.description;
|
|
723
731
|
});
|
|
724
|
-
actionExplainers
|
|
725
|
-
|
|
726
|
-
actionExplainers.Output =
|
|
727
|
-
"Display a message to the user. Pause workflow until the message is read.";
|
|
728
|
-
actionExplainers.DataOutput =
|
|
729
|
-
"Display a value to the user. Arrays of objects will be displayed as tables. Pause workflow until the message is read.";
|
|
730
|
-
actionExplainers.WaitUntil = "Pause until a time in the future";
|
|
731
|
-
actionExplainers.WaitNextTick =
|
|
732
|
-
"Pause until the next scheduler invocation (at most 5 minutes)";
|
|
733
|
-
actionExplainers.UserForm =
|
|
734
|
-
"Ask a user one or more questions, pause until they are answered";
|
|
735
|
-
|
|
736
|
-
actionConfigFields.push({
|
|
737
|
-
label: "Form header",
|
|
738
|
-
sublabel: "Text shown to the user at the top of the form",
|
|
739
|
-
name: "form_header",
|
|
740
|
-
type: "String",
|
|
741
|
-
showIf: { wf_action_name: "UserForm" },
|
|
742
|
-
});
|
|
743
|
-
actionConfigFields.push({
|
|
744
|
-
label: "User ID",
|
|
745
|
-
name: "user_id_expression",
|
|
746
|
-
type: "String",
|
|
747
|
-
sublabel: "Optional. If blank assigned to user starting the workflow",
|
|
748
|
-
showIf: { wf_action_name: "UserForm" },
|
|
749
|
-
});
|
|
750
|
-
actionConfigFields.push({
|
|
751
|
-
label: "Resume at",
|
|
752
|
-
name: "resume_at",
|
|
753
|
-
sublabel:
|
|
754
|
-
"JavaScript expression for the time to resume. <code>moment</code> is in scope.",
|
|
755
|
-
type: "String",
|
|
756
|
-
showIf: { wf_action_name: "WaitUntil" },
|
|
757
|
-
});
|
|
758
|
-
actionConfigFields.push({
|
|
759
|
-
label: "Context values",
|
|
760
|
-
name: "ctx_values",
|
|
761
|
-
sublabel:
|
|
762
|
-
"JavaScript object expression for the variables to set. Example <code>{x: 5, y:y+1}</code> will set x to 5 and increment existing context variable y",
|
|
763
|
-
type: "String",
|
|
764
|
-
fieldview: "textarea",
|
|
765
|
-
class: "validate-expression",
|
|
766
|
-
default: "{}",
|
|
767
|
-
showIf: { wf_action_name: "SetContext" },
|
|
768
|
-
});
|
|
769
|
-
actionConfigFields.push({
|
|
770
|
-
label: "Output text",
|
|
771
|
-
name: "output_text",
|
|
772
|
-
sublabel:
|
|
773
|
-
"Message shown to the user. Can contain HTML tags and use interpolations {{ }} to access the context",
|
|
774
|
-
type: "String",
|
|
775
|
-
fieldview: "textarea",
|
|
776
|
-
showIf: { wf_action_name: "Output" },
|
|
777
|
-
});
|
|
778
|
-
actionConfigFields.push({
|
|
779
|
-
label: "Output expression",
|
|
780
|
-
name: "output_expr",
|
|
781
|
-
sublabel:
|
|
782
|
-
"JavaScript expression for the value to output. Typically the name of a variable",
|
|
783
|
-
type: "String",
|
|
784
|
-
class: "validate-expression",
|
|
785
|
-
showIf: { wf_action_name: "DataOutput" },
|
|
786
|
-
});
|
|
787
|
-
actionConfigFields.push({
|
|
788
|
-
label: "Markdown",
|
|
789
|
-
name: "markdown",
|
|
790
|
-
sublabel:
|
|
791
|
-
"The centents are markdown formatted and should be rendered to HTML",
|
|
792
|
-
type: "Bool",
|
|
793
|
-
showIf: { wf_action_name: "Output" },
|
|
794
|
-
});
|
|
795
|
-
actionConfigFields.push({
|
|
796
|
-
label: "Table",
|
|
797
|
-
name: "query_table",
|
|
798
|
-
type: "String",
|
|
799
|
-
required: true,
|
|
800
|
-
attributes: { options: (await Table.find()).map((t) => t.name) },
|
|
801
|
-
showIf: { wf_action_name: "TableQuery" },
|
|
802
|
-
});
|
|
803
|
-
actionConfigFields.push({
|
|
804
|
-
label: "Query",
|
|
805
|
-
name: "query_object",
|
|
806
|
-
sublabel: "Where object, example <code>{manager: 1}</code>",
|
|
807
|
-
type: "String",
|
|
808
|
-
required: true,
|
|
809
|
-
class: "validate-expression",
|
|
810
|
-
default: "{}",
|
|
811
|
-
showIf: { wf_action_name: "TableQuery" },
|
|
812
|
-
});
|
|
813
|
-
actionConfigFields.push({
|
|
814
|
-
label: "Variable",
|
|
815
|
-
name: "query_variable",
|
|
816
|
-
sublabel: "Context variable to write to query results to",
|
|
817
|
-
type: "String",
|
|
818
|
-
required: true,
|
|
819
|
-
validator: jsIdentifierValidator,
|
|
820
|
-
showIf: { wf_action_name: "TableQuery" },
|
|
821
|
-
});
|
|
822
|
-
actionConfigFields.push(
|
|
823
|
-
new FieldRepeat({
|
|
824
|
-
name: "user_form_questions",
|
|
825
|
-
showIf: { wf_action_name: "UserForm" },
|
|
826
|
-
fields: [
|
|
827
|
-
{
|
|
828
|
-
label: "Label",
|
|
829
|
-
name: "label",
|
|
830
|
-
type: "String",
|
|
831
|
-
sublabel:
|
|
832
|
-
"The text that will shown to the user above the input elements",
|
|
833
|
-
},
|
|
834
|
-
{
|
|
835
|
-
label: "Variable name",
|
|
836
|
-
name: "var_name",
|
|
837
|
-
type: "String",
|
|
838
|
-
sublabel:
|
|
839
|
-
"The answer will be set in the context with this variable name",
|
|
840
|
-
validator: jsIdentifierValidator,
|
|
841
|
-
},
|
|
842
|
-
{
|
|
843
|
-
label: "Input Type",
|
|
844
|
-
name: "qtype",
|
|
845
|
-
type: "String",
|
|
846
|
-
required: true,
|
|
847
|
-
attributes: {
|
|
848
|
-
options: [
|
|
849
|
-
"Yes/No",
|
|
850
|
-
"Checkbox",
|
|
851
|
-
"Free text",
|
|
852
|
-
"Multiple choice",
|
|
853
|
-
//"Multiple checks",
|
|
854
|
-
"Integer",
|
|
855
|
-
"Float",
|
|
856
|
-
//"File upload",
|
|
857
|
-
],
|
|
858
|
-
},
|
|
859
|
-
},
|
|
860
|
-
{
|
|
861
|
-
label: "Options",
|
|
862
|
-
name: "options",
|
|
863
|
-
type: "String",
|
|
864
|
-
sublabel: "Comma separated list of multiple choice options",
|
|
865
|
-
showIf: { qtype: ["Multiple choice", "Multiple checks"] },
|
|
866
|
-
},
|
|
867
|
-
],
|
|
868
|
-
})
|
|
869
|
-
);
|
|
732
|
+
Object.assign(actionExplainers, builtInActionExplainers);
|
|
733
|
+
actionConfigFields.push(...(await WorkflowStep.builtInActionConfigFields()));
|
|
870
734
|
|
|
871
735
|
const form = new Form({
|
|
872
736
|
action: addOnDoneRedirect(`/actions/stepedit/${trigger.id}`, req),
|
|
@@ -1561,7 +1425,7 @@ router.post(
|
|
|
1561
1425
|
res.redirect(`/actions/configure/${step.trigger_id}`);
|
|
1562
1426
|
}
|
|
1563
1427
|
}
|
|
1564
|
-
if (_after_step) {
|
|
1428
|
+
if (_after_step && _after_step !== "undefined") {
|
|
1565
1429
|
const astep = await WorkflowStep.findOne({
|
|
1566
1430
|
id: _after_step,
|
|
1567
1431
|
trigger_id,
|
|
@@ -1583,6 +1447,28 @@ router.post(
|
|
|
1583
1447
|
})
|
|
1584
1448
|
);
|
|
1585
1449
|
|
|
1450
|
+
router.post(
|
|
1451
|
+
"/gen-copilot/:trigger_id",
|
|
1452
|
+
isAdmin,
|
|
1453
|
+
error_catcher(async (req, res) => {
|
|
1454
|
+
const { trigger_id } = req.params;
|
|
1455
|
+
const trigger = await Trigger.findOne({ id: trigger_id });
|
|
1456
|
+
await WorkflowStep.deleteForTrigger(trigger.id);
|
|
1457
|
+
const description = req.body.description;
|
|
1458
|
+
await Trigger.update(trigger.id, { description });
|
|
1459
|
+
const steps = await getState().functions.copilot_generate_workflow.run(
|
|
1460
|
+
description,
|
|
1461
|
+
trigger.id
|
|
1462
|
+
);
|
|
1463
|
+
if (steps.length) steps[0].initial_step = true;
|
|
1464
|
+
for (const step of steps) {
|
|
1465
|
+
step.trigger_id = trigger.id;
|
|
1466
|
+
await WorkflowStep.create(step);
|
|
1467
|
+
}
|
|
1468
|
+
res.redirect(`/actions/configure/${trigger.id}`);
|
|
1469
|
+
})
|
|
1470
|
+
);
|
|
1471
|
+
|
|
1586
1472
|
router.post(
|
|
1587
1473
|
"/delete-step/:step_id",
|
|
1588
1474
|
isAdmin,
|
package/routes/utils.js
CHANGED
package/tests/view.test.js
CHANGED
|
@@ -194,6 +194,43 @@ describe("render view with slug", () => {
|
|
|
194
194
|
});
|
|
195
195
|
});
|
|
196
196
|
|
|
197
|
+
describe("frozen user object", () => {
|
|
198
|
+
it("should create view writing to user object", async () => {
|
|
199
|
+
const table = Table.findOne({ name: "books" });
|
|
200
|
+
const configuration = {
|
|
201
|
+
layout: {
|
|
202
|
+
type: "container",
|
|
203
|
+
style: {},
|
|
204
|
+
contents: {
|
|
205
|
+
type: "blank",
|
|
206
|
+
contents: "'userid='+user.id",
|
|
207
|
+
isFormula: {
|
|
208
|
+
text: true,
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
showIfFormula: "user.id=1",
|
|
212
|
+
},
|
|
213
|
+
columns: [],
|
|
214
|
+
};
|
|
215
|
+
await View.create({
|
|
216
|
+
table_id: table.id,
|
|
217
|
+
name: "ShowBookWriteUser",
|
|
218
|
+
viewtemplate: "Show",
|
|
219
|
+
configuration,
|
|
220
|
+
min_role: 100,
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
it("should run view setting user", async () => {
|
|
224
|
+
const loginCookie = await getStaffLoginCookie();
|
|
225
|
+
|
|
226
|
+
const app = await getApp({ disableCsrf: true });
|
|
227
|
+
await request(app)
|
|
228
|
+
.get("/view/ShowBookWriteUser?id=1")
|
|
229
|
+
.set("Cookie", loginCookie)
|
|
230
|
+
.expect(toInclude(">userid=2</div>"));
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
197
234
|
describe("action row_variable", () => {
|
|
198
235
|
const createFilterView = async ({
|
|
199
236
|
configuration,
|