@webiny/app-admin 6.5.0-beta.1 → 6.5.0-beta.10

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.
Files changed (146) hide show
  1. package/base/Admin.js +2 -0
  2. package/base/Admin.js.map +1 -1
  3. package/base/Base/FieldRenderers/AutoCompleteRenderer.js +1 -0
  4. package/base/Base/FieldRenderers/AutoCompleteRenderer.js.map +1 -1
  5. package/base/Base/FieldRenderers/HorizontalTabsRenderer.d.ts +2 -2
  6. package/base/Base/FieldRenderers/ObjectRenderer/MultiValueDynamicZone/MultiValueDynamicZone.d.ts +2 -2
  7. package/base/Base/FieldRenderers/ObjectRenderer/MultiValueDynamicZone/MultiValueDynamicZone.js +1 -1
  8. package/base/Base/FieldRenderers/ObjectRenderer/MultiValueDynamicZone/MultiValueDynamicZone.js.map +1 -1
  9. package/base/Base/FieldRenderers/ObjectRenderer/ObjectFieldComponents.d.ts +8 -4
  10. package/base/Base/FieldRenderers/ObjectRenderer/SingleValueDynamicZone.d.ts +2 -2
  11. package/base/Base/FieldRenderers/ObjectRenderer/SingleValueDynamicZone.js +1 -1
  12. package/base/Base/FieldRenderers/ObjectRenderer/SingleValueDynamicZone.js.map +1 -1
  13. package/base/Base/FieldRenderers/ObjectRenderer/{TemplatePicker.d.ts → TemplatePicker/AddTemplateButton.d.ts} +1 -1
  14. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/AddTemplateButton.js +24 -0
  15. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/AddTemplateButton.js.map +1 -0
  16. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/SelectableTemplate.d.ts +13 -0
  17. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/SelectableTemplate.js +21 -0
  18. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/SelectableTemplate.js.map +1 -0
  19. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateCard.d.ts +3 -0
  20. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateCard.js +35 -0
  21. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateCard.js.map +1 -0
  22. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateGallery.d.ts +8 -0
  23. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateGallery.js +22 -0
  24. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateGallery.js.map +1 -0
  25. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateGalleryToolbar.d.ts +10 -0
  26. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateGalleryToolbar.js +46 -0
  27. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateGalleryToolbar.js.map +1 -0
  28. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateIcon.d.ts +8 -0
  29. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateIcon.js +16 -0
  30. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateIcon.js.map +1 -0
  31. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateList.d.ts +10 -0
  32. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateList.js +22 -0
  33. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateList.js.map +1 -0
  34. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateListItem.d.ts +3 -0
  35. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateListItem.js +35 -0
  36. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/TemplateListItem.js.map +1 -0
  37. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/index.d.ts +1 -0
  38. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/index.js +1 -0
  39. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/types.d.ts +6 -0
  40. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker/types.js +0 -0
  41. package/base/Base/FieldRenderers/SelectRenderer.js +1 -0
  42. package/base/Base/FieldRenderers/SelectRenderer.js.map +1 -1
  43. package/base/Base/FieldRenderers/VerticalTabsRenderer.d.ts +2 -2
  44. package/components/Filters/Filters.js +7 -1
  45. package/components/Filters/Filters.js.map +1 -1
  46. package/components/IconPicker/IconPickerComponent.d.ts +2 -2
  47. package/components/IconPicker/IconPickerComponent.js +1 -1
  48. package/components/IconPicker/IconPickerComponent.js.map +1 -1
  49. package/components/ListView/ListViewBulkActions.d.ts +2 -2
  50. package/components/ListView/ListViewContent.d.ts +2 -2
  51. package/components/ListView/ListViewFilters.d.ts +2 -2
  52. package/components/ListView/index.d.ts +6 -6
  53. package/components/RolesMultiAutocomplete/index.js +1 -1
  54. package/components/RolesMultiAutocomplete/index.js.map +1 -1
  55. package/components/Table/components/Table/TableInner.d.ts +2 -2
  56. package/components/TeamsMultiAutocomplete/index.js +1 -1
  57. package/components/TeamsMultiAutocomplete/index.js.map +1 -1
  58. package/domain/Identity.js +1 -1
  59. package/domain/Identity.js.map +1 -1
  60. package/features/debugger/Debugger.d.ts +8 -0
  61. package/features/debugger/Debugger.js +25 -0
  62. package/features/debugger/Debugger.js.map +1 -0
  63. package/features/debugger/DebuggerIndicator.d.ts +16 -0
  64. package/features/debugger/DebuggerIndicator.js +31 -0
  65. package/features/debugger/DebuggerIndicator.js.map +1 -0
  66. package/features/debugger/DebuggerStore.d.ts +55 -0
  67. package/features/debugger/DebuggerStore.js +65 -0
  68. package/features/debugger/DebuggerStore.js.map +1 -0
  69. package/features/debugger/DebuggerView.d.ts +4 -0
  70. package/features/debugger/DebuggerView.js +49 -0
  71. package/features/debugger/DebuggerView.js.map +1 -0
  72. package/features/debugger/GraphQLExtensionsDebugHandler.d.ts +15 -0
  73. package/features/debugger/GraphQLExtensionsDebugHandler.js +15 -0
  74. package/features/debugger/GraphQLExtensionsDebugHandler.js.map +1 -0
  75. package/features/debugger/debuggerLink.d.ts +12 -0
  76. package/features/debugger/debuggerLink.js +10 -0
  77. package/features/debugger/debuggerLink.js.map +1 -0
  78. package/features/debugger/feature.d.ts +1 -0
  79. package/features/debugger/feature.js +18 -0
  80. package/features/debugger/feature.js.map +1 -0
  81. package/features/debugger/index.d.ts +7 -0
  82. package/features/debugger/index.js +7 -0
  83. package/features/debugger/permissions.d.ts +68 -0
  84. package/features/debugger/permissions.js +27 -0
  85. package/features/debugger/permissions.js.map +1 -0
  86. package/features/debugger/report.d.ts +7 -0
  87. package/features/debugger/report.js +22 -0
  88. package/features/debugger/report.js.map +1 -0
  89. package/features/debugger/routes.d.ts +4 -0
  90. package/features/debugger/routes.js +10 -0
  91. package/features/debugger/routes.js.map +1 -0
  92. package/features/formModel/Field.d.ts +7 -1
  93. package/features/formModel/Field.js +13 -5
  94. package/features/formModel/Field.js.map +1 -1
  95. package/features/formModel/FieldBuilder.test.js +25 -0
  96. package/features/formModel/FieldBuilder.test.js.map +1 -1
  97. package/features/formModel/FormErrors.d.ts +2 -2
  98. package/features/formModel/FormErrors.js +1 -1
  99. package/features/formModel/FormErrors.js.map +1 -1
  100. package/features/formModel/FormModel.d.ts +2 -0
  101. package/features/formModel/FormModel.js +25 -0
  102. package/features/formModel/FormModel.js.map +1 -1
  103. package/features/formModel/FormModel.test.js +587 -2
  104. package/features/formModel/FormModel.test.js.map +1 -1
  105. package/features/formModel/FormView.d.ts +8 -4
  106. package/features/formModel/ObjectField.d.ts +11 -1
  107. package/features/formModel/ObjectField.js +45 -20
  108. package/features/formModel/ObjectField.js.map +1 -1
  109. package/features/formModel/PresenterErrors.d.ts +2 -2
  110. package/features/formModel/abstractions.d.ts +30 -1
  111. package/features/formModel/abstractions.js.map +1 -1
  112. package/features/formModel/createFieldRenderer.js +3 -4
  113. package/features/formModel/createFieldRenderer.js.map +1 -1
  114. package/features/formModel/demo/FormModelDemo.d.ts +2 -2
  115. package/features/formModel/fieldTypes/DateTimeFieldType.d.ts +2 -0
  116. package/features/formModel/fieldTypes/DateTimeFieldType.js +19 -15
  117. package/features/formModel/fieldTypes/DateTimeFieldType.js.map +1 -1
  118. package/features/formModel/fieldTypes/ObjectFieldType.d.ts +3 -1
  119. package/features/formModel/fieldTypes/ObjectFieldType.js +23 -1
  120. package/features/formModel/fieldTypes/ObjectFieldType.js.map +1 -1
  121. package/features/notifications/NotificationsRenderer.d.ts +2 -2
  122. package/features/wcp/WcpGateway.js +7 -0
  123. package/features/wcp/WcpGateway.js.map +1 -1
  124. package/hooks/useHotkeys.js +3 -1
  125. package/hooks/useHotkeys.js.map +1 -1
  126. package/hooks/useSnackbar.js.map +1 -1
  127. package/index.d.ts +1 -0
  128. package/index.js +3 -2
  129. package/package.json +34 -34
  130. package/presentation/accessManagement/apiKeys/ApiKeysPresenter.js +1 -2
  131. package/presentation/accessManagement/apiKeys/ApiKeysPresenter.js.map +1 -1
  132. package/presentation/accessManagement/apiKeys/components/ApiKeysView.d.ts +2 -2
  133. package/presentation/accessManagement/roles/RolesPresenter.js +1 -2
  134. package/presentation/accessManagement/roles/RolesPresenter.js.map +1 -1
  135. package/presentation/accessManagement/roles/components/RolesView.d.ts +2 -2
  136. package/presentation/accessManagement/teams/TeamsPresenter.js +1 -2
  137. package/presentation/accessManagement/teams/TeamsPresenter.js.map +1 -1
  138. package/presentation/accessManagement/teams/components/TeamsView.d.ts +2 -2
  139. package/presentation/installation/components/SystemInstaller/SystemInstaller.d.ts +2 -2
  140. package/presentation/listPresenter/QueryMatcher.js +3 -3
  141. package/presentation/listPresenter/QueryMatcher.js.map +1 -1
  142. package/presentation/trashBin/components/BulkActions/DeleteItems.d.ts +2 -2
  143. package/presentation/trashBin/components/BulkActions/RestoreItems.d.ts +2 -2
  144. package/presentation/trashBin/components/TrashBinOverlay.d.ts +2 -2
  145. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker.js +0 -68
  146. package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker.js.map +0 -1
@@ -1834,7 +1834,7 @@ describe("FormModel", ()=>{
1834
1834
  return createForm({
1835
1835
  fields: (fields)=>({
1836
1836
  content: fields.object().label("Content").template("hero", (t)=>{
1837
- t.label("Hero Banner").fields((f)=>({
1837
+ t.label("Hero Banner").description("Large heading with an image").fields((f)=>({
1838
1838
  heading: f.text().label("Heading").required("Required"),
1839
1839
  image: f.text().label("Image")
1840
1840
  }));
@@ -1861,7 +1861,8 @@ describe("FormModel", ()=>{
1861
1861
  expect(vm.availableTemplates).toEqual([
1862
1862
  {
1863
1863
  id: "hero",
1864
- label: "Hero Banner"
1864
+ label: "Hero Banner",
1865
+ description: "Large heading with an image"
1865
1866
  },
1866
1867
  {
1867
1868
  id: "text",
@@ -2732,6 +2733,190 @@ describe("FormModel", ()=>{
2732
2733
  });
2733
2734
  });
2734
2735
  });
2736
+ describe("inner layouts declared on the field builder", ()=>{
2737
+ it("lays out a single object's children with .layout()", ()=>{
2738
+ const form = createForm({
2739
+ fields: (fields)=>({
2740
+ address: fields.object().fields((f)=>({
2741
+ street: f.text().label("Street"),
2742
+ city: f.text().label("City"),
2743
+ zip: f.text().label("Zip")
2744
+ })).layout((l)=>[
2745
+ l.row("street"),
2746
+ l.row("city", "zip")
2747
+ ])
2748
+ })
2749
+ });
2750
+ const vm = form.field("address").vm;
2751
+ expect(vm.layout.map((node)=>asRow(node).fields.map((f)=>f.name))).toEqual([
2752
+ [
2753
+ "street"
2754
+ ],
2755
+ [
2756
+ "city",
2757
+ "zip"
2758
+ ]
2759
+ ]);
2760
+ });
2761
+ it("applies .layout() to every list item", ()=>{
2762
+ const form = createForm({
2763
+ fields: (fields)=>({
2764
+ stats: fields.object().list().fields((f)=>({
2765
+ value: f.number().label("Value"),
2766
+ label: f.text().label("Label")
2767
+ })).layout((l)=>[
2768
+ l.row("value", "label")
2769
+ ])
2770
+ })
2771
+ });
2772
+ form.setData({
2773
+ stats: [
2774
+ {
2775
+ value: 1,
2776
+ label: "A"
2777
+ },
2778
+ {
2779
+ value: 2,
2780
+ label: "B"
2781
+ }
2782
+ ]
2783
+ });
2784
+ const vm = form.field("stats").vm;
2785
+ expect(vm.items).toHaveLength(2);
2786
+ for (const item of vm.items)expect(item.layout.map((node)=>asRow(node).fields.map((f)=>f.name))).toEqual([
2787
+ [
2788
+ "value",
2789
+ "label"
2790
+ ]
2791
+ ]);
2792
+ });
2793
+ it("lays out an object nested in another object with its own .layout()", ()=>{
2794
+ const form = createForm({
2795
+ fields: (fields)=>({
2796
+ subMenu: fields.object().fields((f)=>({
2797
+ climbing: f.object().list().fields((c)=>({
2798
+ label: c.text().label("Label"),
2799
+ url: c.text().label("URL")
2800
+ })).layout((l)=>[
2801
+ l.row("label", "url")
2802
+ ]),
2803
+ yoga: f.text().label("Yoga")
2804
+ })).layout((l)=>[
2805
+ l.row("climbing", "yoga")
2806
+ ])
2807
+ })
2808
+ });
2809
+ form.setData({
2810
+ subMenu: {
2811
+ climbing: [
2812
+ {
2813
+ label: "Classes",
2814
+ url: "/c"
2815
+ }
2816
+ ],
2817
+ yoga: ""
2818
+ }
2819
+ });
2820
+ const outer = form.field("subMenu").vm;
2821
+ expect(asRow(outer.layout[0]).fields.map((f)=>f.name)).toEqual([
2822
+ "climbing",
2823
+ "yoga"
2824
+ ]);
2825
+ const inner = form.field("subMenu.climbing").vm;
2826
+ expect(asRow(inner.items[0].layout[0]).fields.map((f)=>f.name)).toEqual([
2827
+ "label",
2828
+ "url"
2829
+ ]);
2830
+ });
2831
+ it("lets a layout.object() node override the field's .layout()", ()=>{
2832
+ const form = createForm({
2833
+ fields: (fields)=>({
2834
+ meta: fields.object().fields((f)=>({
2835
+ a: f.text().label("A"),
2836
+ b: f.text().label("B")
2837
+ })).layout((l)=>[
2838
+ l.row("a", "b")
2839
+ ])
2840
+ }),
2841
+ layout: (layout)=>[
2842
+ layout.object("meta", (l)=>[
2843
+ l.row("b"),
2844
+ l.row("a")
2845
+ ])
2846
+ ]
2847
+ });
2848
+ const vm = form.field("meta").vm;
2849
+ expect(vm.layout.map((node)=>asRow(node).fields.map((f)=>f.name))).toEqual([
2850
+ [
2851
+ "b"
2852
+ ],
2853
+ [
2854
+ "a"
2855
+ ]
2856
+ ]);
2857
+ });
2858
+ it("uses the layout declared on each template", ()=>{
2859
+ const form = createForm({
2860
+ fields: (fields)=>({
2861
+ content: fields.object().template("hero", (t)=>{
2862
+ t.label("Hero").fields((f)=>({
2863
+ heading: f.text().label("Heading"),
2864
+ subheading: f.text().label("Subheading")
2865
+ })).layout((l)=>[
2866
+ l.row("heading", "subheading")
2867
+ ]);
2868
+ }).template("cta", (t)=>{
2869
+ t.label("CTA").fields((f)=>({
2870
+ text: f.text().label("Text"),
2871
+ url: f.text().label("URL")
2872
+ })).layout((l)=>[
2873
+ l.row("url", "text")
2874
+ ]);
2875
+ })
2876
+ }),
2877
+ layout: (layout)=>[
2878
+ layout.object("content", {
2879
+ hero: (l)=>[
2880
+ l.row("subheading"),
2881
+ l.row("heading")
2882
+ ]
2883
+ })
2884
+ ]
2885
+ });
2886
+ const field = form.field("content");
2887
+ field.setTemplate("hero");
2888
+ let vm = form.field("content").vm;
2889
+ expect(vm.layout.map((node)=>asRow(node).fields.map((f)=>f.name))).toEqual([
2890
+ [
2891
+ "subheading"
2892
+ ],
2893
+ [
2894
+ "heading"
2895
+ ]
2896
+ ]);
2897
+ field.setTemplate("cta");
2898
+ vm = form.field("content").vm;
2899
+ expect(vm.layout.map((node)=>asRow(node).fields.map((f)=>f.name))).toEqual([
2900
+ [
2901
+ "url",
2902
+ "text"
2903
+ ]
2904
+ ]);
2905
+ });
2906
+ it("throws when an object has both .layout() and .template()", ()=>{
2907
+ expect(()=>createForm({
2908
+ fields: (fields)=>({
2909
+ content: fields.object().template("hero", (t)=>{
2910
+ t.fields((f)=>({
2911
+ heading: f.text()
2912
+ }));
2913
+ }).layout((l)=>[
2914
+ l.row("heading")
2915
+ ])
2916
+ })
2917
+ })).toThrow(/both .layout\(\) and .template\(\)/);
2918
+ });
2919
+ });
2735
2920
  describe("nested object layouts (Phase 8c.1)", ()=>{
2736
2921
  it("registers layout.object() nested inside another object's inner layout (non-templated)", ()=>{
2737
2922
  const form = createForm({
@@ -3049,6 +3234,24 @@ describe("FormModel", ()=>{
3049
3234
  "text"
3050
3235
  ]);
3051
3236
  });
3237
+ it("templates.add keeps the layout declared on the added template", ()=>{
3238
+ const form = createSingleTemplatedForm();
3239
+ const field = form.field("content").as("object");
3240
+ field.templates.add("cta", (t)=>{
3241
+ t.label("CTA").fields((f)=>({
3242
+ text: f.text(),
3243
+ url: f.text()
3244
+ })).layout((l)=>[
3245
+ l.row("text", "url")
3246
+ ]);
3247
+ });
3248
+ form.field("content").setTemplate("cta");
3249
+ const vm = form.field("content").vm;
3250
+ expect(asRow(vm.layout[0]).fields.map((f)=>f.name)).toEqual([
3251
+ "text",
3252
+ "url"
3253
+ ]);
3254
+ });
3052
3255
  it("templates.add throws on duplicate id", ()=>{
3053
3256
  const form = createSingleTemplatedForm();
3054
3257
  const field = form.field("content").as("object");
@@ -4349,6 +4552,388 @@ describe("FormModel", ()=>{
4349
4552
  expect(form.field("wrapper.editable").disabled).toBe(false);
4350
4553
  });
4351
4554
  });
4555
+ describe("$. static references in rules inside list items", ()=>{
4556
+ const hideWhen = (target, operator, value)=>[
4557
+ {
4558
+ type: "condition",
4559
+ target,
4560
+ operator,
4561
+ value,
4562
+ action: "hide"
4563
+ }
4564
+ ];
4565
+ const itemChild = (form, listPath, index, name)=>{
4566
+ const list = form.field(listPath);
4567
+ const child = list.items[index]?.children.get(name);
4568
+ if (!child) throw new Error(`No child "${name}" on item ${index} of "${listPath}".`);
4569
+ return child;
4570
+ };
4571
+ it("resolves $. against the owning item of an object list", ()=>{
4572
+ const form = createForm({
4573
+ fields: (fields)=>({
4574
+ links: fields.object().list().renderer("passthrough").fields((f)=>({
4575
+ style: f.text(),
4576
+ url: f.text().rules(hideWhen("$.style", "==", "initiative")),
4577
+ customUrls: f.text().rules(hideWhen("$.style", "!=", "initiative"))
4578
+ }))
4579
+ })
4580
+ });
4581
+ form.setData({
4582
+ links: [
4583
+ {
4584
+ style: "initiative"
4585
+ },
4586
+ {
4587
+ style: "standard"
4588
+ }
4589
+ ]
4590
+ });
4591
+ expect(itemChild(form, "links", 0, "url").visible).toBe(false);
4592
+ expect(itemChild(form, "links", 0, "customUrls").visible).toBe(true);
4593
+ expect(itemChild(form, "links", 1, "url").visible).toBe(true);
4594
+ expect(itemChild(form, "links", 1, "customUrls").visible).toBe(false);
4595
+ itemChild(form, "links", 1, "style").setValue("initiative");
4596
+ expect(itemChild(form, "links", 1, "url").visible).toBe(false);
4597
+ expect(itemChild(form, "links", 1, "customUrls").visible).toBe(true);
4598
+ });
4599
+ it("resolves $. for items added with addItem()", ()=>{
4600
+ const form = createForm({
4601
+ fields: (fields)=>({
4602
+ links: fields.object().list().renderer("passthrough").fields((f)=>({
4603
+ locked: f.boolean(),
4604
+ label: f.text().rules([
4605
+ {
4606
+ type: "condition",
4607
+ target: "$.locked",
4608
+ operator: "==",
4609
+ value: true,
4610
+ action: "disable"
4611
+ }
4612
+ ])
4613
+ }))
4614
+ })
4615
+ });
4616
+ form.field("links").addItem();
4617
+ expect(itemChild(form, "links", 0, "label").disabled).toBe(false);
4618
+ itemChild(form, "links", 0, "locked").setValue(true);
4619
+ expect(itemChild(form, "links", 0, "label").disabled).toBe(true);
4620
+ });
4621
+ it("keeps resolving against the owning item after reorder and removal", ()=>{
4622
+ const form = createForm({
4623
+ fields: (fields)=>({
4624
+ links: fields.object().list().renderer("passthrough").fields((f)=>({
4625
+ style: f.text(),
4626
+ url: f.text().rules(hideWhen("$.style", "==", "initiative"))
4627
+ }))
4628
+ })
4629
+ });
4630
+ form.setData({
4631
+ links: [
4632
+ {
4633
+ style: "initiative"
4634
+ },
4635
+ {
4636
+ style: "standard"
4637
+ }
4638
+ ]
4639
+ });
4640
+ const list = form.field("links");
4641
+ const firstUrl = itemChild(form, "links", 0, "url");
4642
+ const secondUrl = itemChild(form, "links", 1, "url");
4643
+ list.moveItem(0, 1);
4644
+ expect(firstUrl.visible).toBe(false);
4645
+ expect(secondUrl.visible).toBe(true);
4646
+ list.removeItem(0);
4647
+ expect(firstUrl.visible).toBe(false);
4648
+ });
4649
+ it("field.parent() resolves siblings of the owning item in callbacks", ()=>{
4650
+ const form = createForm({
4651
+ fields: (fields)=>({
4652
+ links: fields.object().list().renderer("passthrough").fields((f)=>({
4653
+ style: f.text(),
4654
+ url: f.text().hiddenWhen(({ field })=>"initiative" === field.parent().field("style").getValue())
4655
+ }))
4656
+ })
4657
+ });
4658
+ form.setData({
4659
+ links: [
4660
+ {
4661
+ style: "initiative"
4662
+ },
4663
+ {
4664
+ style: "standard"
4665
+ }
4666
+ ]
4667
+ });
4668
+ expect(itemChild(form, "links", 0, "url").visible).toBe(false);
4669
+ expect(itemChild(form, "links", 1, "url").visible).toBe(true);
4670
+ });
4671
+ describe("dynamic zone shaped templated list", ()=>{
4672
+ const createBlocksForm = ()=>createForm({
4673
+ fields: (fields)=>({
4674
+ blocks: fields.object().list().renderer("passthrough").template("heroBlock", (t)=>{
4675
+ t.label("Hero").fields((f)=>({
4676
+ _id: f.text().hidden(),
4677
+ ctaStyle: f.text(),
4678
+ ctaUrl: f.text().rules(hideWhen("$.ctaStyle", "==", "initiative")),
4679
+ customUrls: f.text().rules(hideWhen("$.ctaStyle", "!=", "initiative"))
4680
+ }));
4681
+ }).template("richTextBlock", (t)=>{
4682
+ t.label("Rich Text").fields((f)=>({
4683
+ _id: f.text().hidden(),
4684
+ headerStyle: f.text().defaultValue("manual"),
4685
+ header: f.text().rules(hideWhen("$.headerStyle", "!=", "manual")),
4686
+ headingGroupRef: f.text().rules(hideWhen("$.headerStyle", "!=", "reference"))
4687
+ }));
4688
+ }).template("classesBlock", (t)=>{
4689
+ t.label("Classes").fields((f)=>({
4690
+ _id: f.text().hidden(),
4691
+ classes: f.object().list().renderer("passthrough").fields((c)=>({
4692
+ customCTA: c.boolean(),
4693
+ customCTALabel: c.text().rules(hideWhen("$.customCTA", "!=", true))
4694
+ }))
4695
+ }));
4696
+ })
4697
+ })
4698
+ });
4699
+ it("resolves $. against the owning template item", ()=>{
4700
+ const form = createBlocksForm();
4701
+ form.setData({
4702
+ blocks: [
4703
+ {
4704
+ _templateId: "heroBlock",
4705
+ _id: "hero1",
4706
+ ctaStyle: "initiative"
4707
+ },
4708
+ {
4709
+ _templateId: "heroBlock",
4710
+ _id: "hero2",
4711
+ ctaStyle: "standard"
4712
+ }
4713
+ ]
4714
+ });
4715
+ expect(itemChild(form, "blocks", 0, "ctaUrl").visible).toBe(false);
4716
+ expect(itemChild(form, "blocks", 0, "customUrls").visible).toBe(true);
4717
+ expect(itemChild(form, "blocks", 1, "ctaUrl").visible).toBe(true);
4718
+ expect(itemChild(form, "blocks", 1, "customUrls").visible).toBe(false);
4719
+ });
4720
+ it("re-evaluates when the referenced sibling changes", ()=>{
4721
+ const form = createBlocksForm();
4722
+ form.setData({
4723
+ blocks: [
4724
+ {
4725
+ _templateId: "richTextBlock",
4726
+ _id: "rt1",
4727
+ headerStyle: "manual"
4728
+ }
4729
+ ]
4730
+ });
4731
+ expect(itemChild(form, "blocks", 0, "header").visible).toBe(true);
4732
+ expect(itemChild(form, "blocks", 0, "headingGroupRef").visible).toBe(false);
4733
+ itemChild(form, "blocks", 0, "headerStyle").setValue("reference");
4734
+ expect(itemChild(form, "blocks", 0, "header").visible).toBe(false);
4735
+ expect(itemChild(form, "blocks", 0, "headingGroupRef").visible).toBe(true);
4736
+ });
4737
+ it("resolves $. inside an object list nested in a template item", ()=>{
4738
+ const form = createBlocksForm();
4739
+ form.setData({
4740
+ blocks: [
4741
+ {
4742
+ _templateId: "classesBlock",
4743
+ _id: "classes1",
4744
+ classes: [
4745
+ {
4746
+ customCTA: true
4747
+ },
4748
+ {
4749
+ customCTA: false
4750
+ }
4751
+ ]
4752
+ }
4753
+ ]
4754
+ });
4755
+ const classes = itemChild(form, "blocks", 0, "classes");
4756
+ const classItem = (index, name)=>classes.items[index].children.get(name);
4757
+ expect(classItem(0, "customCTALabel").visible).toBe(true);
4758
+ expect(classItem(1, "customCTALabel").visible).toBe(false);
4759
+ classItem(1, "customCTA").setValue(true);
4760
+ expect(classItem(1, "customCTALabel").visible).toBe(true);
4761
+ });
4762
+ });
4763
+ });
4764
+ describe("setErrors", ()=>{
4765
+ const createProductForm = ()=>createForm({
4766
+ fields: (fields)=>({
4767
+ sku: fields.text().label("SKU"),
4768
+ variants: fields.object().list().label("Variants").fields((f)=>({
4769
+ code: f.text().label("Code")
4770
+ }))
4771
+ })
4772
+ });
4773
+ it("assigns an error to the field at its path and lists it in form errors", ()=>{
4774
+ const form = createProductForm();
4775
+ form.setErrors([
4776
+ {
4777
+ path: "sku",
4778
+ message: "Value must be unique."
4779
+ }
4780
+ ]);
4781
+ expect(form.field("sku").vm.validation).toMatchObject({
4782
+ isValid: false,
4783
+ message: "Value must be unique."
4784
+ });
4785
+ expect(form.vm.hasErrors).toBe(true);
4786
+ expect(form.errors).toEqual([
4787
+ {
4788
+ path: "sku",
4789
+ label: "SKU",
4790
+ breadcrumb: [
4791
+ "SKU"
4792
+ ],
4793
+ message: "Value must be unique."
4794
+ }
4795
+ ]);
4796
+ });
4797
+ it("resolves paths into list items", ()=>{
4798
+ const form = createProductForm();
4799
+ form.setData({
4800
+ variants: [
4801
+ {
4802
+ code: "a"
4803
+ },
4804
+ {
4805
+ code: "b"
4806
+ }
4807
+ ]
4808
+ });
4809
+ form.setErrors([
4810
+ {
4811
+ path: "variants.1.code",
4812
+ message: "Invalid code."
4813
+ }
4814
+ ]);
4815
+ const list = form.field("variants");
4816
+ expect(list.items[1].children.get("code").vm.validation.isValid).toBe(false);
4817
+ expect(list.items[0].children.get("code").vm.validation.isValid).not.toBe(false);
4818
+ expect(form.errors).toEqual([
4819
+ expect.objectContaining({
4820
+ path: "variants.1.code",
4821
+ breadcrumb: [
4822
+ "Variants",
4823
+ "Code"
4824
+ ]
4825
+ })
4826
+ ]);
4827
+ });
4828
+ it("keeps errors without a matching field as form-level errors", ()=>{
4829
+ const form = createProductForm();
4830
+ form.setErrors([
4831
+ {
4832
+ path: "",
4833
+ message: "Could not update entry."
4834
+ },
4835
+ {
4836
+ path: "unknown.field",
4837
+ message: "Something is wrong."
4838
+ }
4839
+ ]);
4840
+ expect(form.errors).toEqual([
4841
+ {
4842
+ path: "",
4843
+ message: "Could not update entry."
4844
+ },
4845
+ {
4846
+ path: "unknown.field",
4847
+ message: "Something is wrong."
4848
+ }
4849
+ ]);
4850
+ expect(form.isValid).toBe(false);
4851
+ });
4852
+ it("bumps submitCount so FormErrors scrolls into view", ()=>{
4853
+ const form = createProductForm();
4854
+ const before = form.submitCount;
4855
+ form.setErrors([
4856
+ {
4857
+ path: "sku",
4858
+ message: "Value must be unique."
4859
+ }
4860
+ ]);
4861
+ expect(form.submitCount).toBe(before + 1);
4862
+ });
4863
+ it("is cleared by the next validate()", async ()=>{
4864
+ const form = createProductForm();
4865
+ form.setErrors([
4866
+ {
4867
+ path: "sku",
4868
+ message: "Value must be unique."
4869
+ },
4870
+ {
4871
+ path: "",
4872
+ message: "Could not update entry."
4873
+ }
4874
+ ]);
4875
+ await form.validate();
4876
+ expect(form.errors).toEqual([]);
4877
+ expect(form.field("sku").vm.validation.isValid).not.toBe(false);
4878
+ });
4879
+ it("is cleared by setData()", ()=>{
4880
+ const form = createProductForm();
4881
+ form.setErrors([
4882
+ {
4883
+ path: "",
4884
+ message: "Could not update entry."
4885
+ }
4886
+ ]);
4887
+ form.setData({
4888
+ sku: "ABC"
4889
+ });
4890
+ expect(form.errors).toEqual([]);
4891
+ expect(form.vm.hasErrors).toBe(false);
4892
+ });
4893
+ it("clears the field errors of the previous call when given an empty set", ()=>{
4894
+ const form = createProductForm();
4895
+ form.setErrors([
4896
+ {
4897
+ path: "sku",
4898
+ message: "Value must be unique."
4899
+ }
4900
+ ]);
4901
+ form.setErrors([]);
4902
+ expect(form.field("sku").vm.validation.isValid).not.toBe(false);
4903
+ expect(form.errors).toEqual([]);
4904
+ expect(form.isValid).toBe(true);
4905
+ expect(form.vm.hasErrors).toBe(false);
4906
+ });
4907
+ it("keeps only the errors of the latest rejected save", ()=>{
4908
+ const form = createProductForm();
4909
+ form.setData({
4910
+ variants: [
4911
+ {
4912
+ code: "a"
4913
+ }
4914
+ ]
4915
+ });
4916
+ form.setErrors([
4917
+ {
4918
+ path: "sku",
4919
+ message: "Value must be unique."
4920
+ }
4921
+ ]);
4922
+ form.setErrors([
4923
+ {
4924
+ path: "variants.0.code",
4925
+ message: "Invalid code."
4926
+ }
4927
+ ]);
4928
+ expect(form.field("sku").vm.validation.isValid).not.toBe(false);
4929
+ expect(form.errors).toEqual([
4930
+ expect.objectContaining({
4931
+ path: "variants.0.code",
4932
+ message: "Invalid code."
4933
+ })
4934
+ ]);
4935
+ });
4936
+ });
4352
4937
  });
4353
4938
 
4354
4939
  //# sourceMappingURL=FormModel.test.js.map