@webiny/app-headless-cms 6.5.0-beta.9 → 6.5.1-beta.0

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 (88) hide show
  1. package/admin/components/ContentEntries/Filters/RefFieldRenderer.js +1 -0
  2. package/admin/components/ContentEntries/Filters/RefFieldRenderer.js.map +1 -1
  3. package/admin/plugins/editor/defaultBar/Name/Name.d.ts +0 -5
  4. package/admin/plugins/editor/defaultBar/Name/Name.js +0 -2
  5. package/admin/plugins/editor/defaultBar/Name/Name.js.map +1 -1
  6. package/features/contentEntry/feature.js +2 -0
  7. package/features/contentEntry/feature.js.map +1 -1
  8. package/features/contentEntry/referenceTitles/ReferenceTitles.d.ts +18 -0
  9. package/features/contentEntry/referenceTitles/ReferenceTitles.js +58 -0
  10. package/features/contentEntry/referenceTitles/ReferenceTitles.js.map +1 -0
  11. package/features/contentEntry/referenceTitles/ReferenceTitles.test.d.ts +1 -0
  12. package/features/contentEntry/referenceTitles/ReferenceTitles.test.js +173 -0
  13. package/features/contentEntry/referenceTitles/ReferenceTitles.test.js.map +1 -0
  14. package/features/contentEntry/referenceTitles/RememberTitlesDecorators.d.ts +22 -0
  15. package/features/contentEntry/referenceTitles/RememberTitlesDecorators.js +40 -0
  16. package/features/contentEntry/referenceTitles/RememberTitlesDecorators.js.map +1 -0
  17. package/features/contentEntry/referenceTitles/abstractions.d.ts +16 -0
  18. package/features/contentEntry/referenceTitles/abstractions.js +5 -0
  19. package/features/contentEntry/referenceTitles/abstractions.js.map +1 -0
  20. package/features/contentEntry/referenceTitles/feature.d.ts +3 -0
  21. package/features/contentEntry/referenceTitles/feature.js +20 -0
  22. package/features/contentEntry/referenceTitles/feature.js.map +1 -0
  23. package/features/formModel/CmsFormModelBuilder.test.js +213 -0
  24. package/features/formModel/CmsFormModelBuilder.test.js.map +1 -1
  25. package/features/formModel/CmsRefFieldValueFormatter.d.ts +12 -0
  26. package/features/formModel/CmsRefFieldValueFormatter.js +29 -0
  27. package/features/formModel/CmsRefFieldValueFormatter.js.map +1 -0
  28. package/features/formModel/CmsValidationMapper.d.ts +9 -0
  29. package/features/formModel/CmsValidationMapper.js +25 -19
  30. package/features/formModel/CmsValidationMapper.js.map +1 -1
  31. package/features/formModel/feature.js +2 -0
  32. package/features/formModel/feature.js.map +1 -1
  33. package/features/formModel/mappers/DateTimeFieldMapper.js +3 -0
  34. package/features/formModel/mappers/DateTimeFieldMapper.js.map +1 -1
  35. package/package.json +22 -22
  36. package/presentation/contentEntries/form/ContentEntryFormPresenter.js +30 -30
  37. package/presentation/contentEntries/form/ContentEntryFormPresenter.js.map +1 -1
  38. package/presentation/contentEntries/form/ContentEntryFormPresenter.test.js +144 -10
  39. package/presentation/contentEntries/form/ContentEntryFormPresenter.test.js.map +1 -1
  40. package/presentation/contentEntries/preview/ModelEditorComponentDiscovery.js +1 -1
  41. package/presentation/contentEntries/preview/ModelEditorComponentDiscovery.js.map +1 -1
  42. package/presentation/contentEntries/preview/PreviewDecorator.js +9 -3
  43. package/presentation/contentEntries/preview/PreviewDecorator.js.map +1 -1
  44. package/presentation/contentEntries/preview/PreviewDomainStatus.d.ts +10 -0
  45. package/presentation/contentEntries/preview/PreviewDomainStatus.js +19 -0
  46. package/presentation/contentEntries/preview/PreviewDomainStatus.js.map +1 -0
  47. package/presentation/contentEntries/preview/PreviewPane.d.ts +6 -1
  48. package/presentation/contentEntries/preview/PreviewPane.js +80 -44
  49. package/presentation/contentEntries/preview/PreviewPane.js.map +1 -1
  50. package/presentation/contentEntries/views/ContentEntryFormView.js +1 -0
  51. package/presentation/contentEntries/views/ContentEntryFormView.js.map +1 -1
  52. package/presentation/fieldEditor/groups/AppearanceGroup.js +12 -0
  53. package/presentation/fieldEditor/groups/AppearanceGroup.js.map +1 -1
  54. package/presentation/fieldEditor/groups/ValidationsGroup.d.ts +2 -0
  55. package/presentation/fieldEditor/groups/ValidationsGroup.js +20 -6
  56. package/presentation/fieldEditor/groups/ValidationsGroup.js.map +1 -1
  57. package/presentation/fieldEditor/renderers/CmsValidatorsRenderer.js +2 -2
  58. package/presentation/fieldEditor/renderers/CmsValidatorsRenderer.js.map +1 -1
  59. package/presentation/fieldRenderers/feature.js +2 -1
  60. package/presentation/fieldRenderers/feature.js.map +1 -1
  61. package/presentation/fieldRenderers/ref/CmsRefInputRenderer.js +1 -0
  62. package/presentation/fieldRenderers/ref/CmsRefInputRenderer.js.map +1 -1
  63. package/presentation/fieldRenderers/ref/CmsRefInputsRenderer.js +1 -0
  64. package/presentation/fieldRenderers/ref/CmsRefInputsRenderer.js.map +1 -1
  65. package/presentation/fieldRenderers/ref/autocomplete/BaseAutocompletePresenter.d.ts +1 -0
  66. package/presentation/fieldRenderers/ref/autocomplete/BaseAutocompletePresenter.js +8 -2
  67. package/presentation/fieldRenderers/ref/autocomplete/BaseAutocompletePresenter.js.map +1 -1
  68. package/presentation/fieldRenderers/ref/autocomplete/RefAutocompletePresenters.test.js +52 -0
  69. package/presentation/fieldRenderers/ref/autocomplete/RefAutocompletePresenters.test.js.map +1 -1
  70. package/presentation/fieldTypes/renderers/dateTime/BirthdayInputRenderer.d.ts +15 -0
  71. package/presentation/fieldTypes/renderers/dateTime/BirthdayInputRenderer.js +19 -0
  72. package/presentation/fieldTypes/renderers/dateTime/BirthdayInputRenderer.js.map +1 -0
  73. package/presentation/fieldTypes/renderers/index.d.ts +1 -0
  74. package/presentation/fieldTypes/renderers/index.js +1 -0
  75. package/presentation/fieldValidators/abstractions.d.ts +7 -0
  76. package/presentation/fieldValidators/abstractions.js.map +1 -1
  77. package/presentation/fieldValidators/validators/DateGteValidator.d.ts +6 -0
  78. package/presentation/fieldValidators/validators/DateGteValidator.js +17 -25
  79. package/presentation/fieldValidators/validators/DateGteValidator.js.map +1 -1
  80. package/presentation/fieldValidators/validators/DateLteValidator.d.ts +6 -0
  81. package/presentation/fieldValidators/validators/DateLteValidator.js +17 -25
  82. package/presentation/fieldValidators/validators/DateLteValidator.js.map +1 -1
  83. package/presentation/fieldValidators/validators/dateLimitSettings.d.ts +20 -0
  84. package/presentation/fieldValidators/validators/dateLimitSettings.js +124 -0
  85. package/presentation/fieldValidators/validators/dateLimitSettings.js.map +1 -0
  86. package/presentation/fieldValidators/validators/dateLimitSettings.test.d.ts +1 -0
  87. package/presentation/fieldValidators/validators/dateLimitSettings.test.js +111 -0
  88. package/presentation/fieldValidators/validators/dateLimitSettings.test.js.map +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/contentEntries/preview/PreviewDomainStatus.js","sources":["../../../../src/presentation/contentEntries/preview/PreviewDomainStatus.tsx"],"sourcesContent":["import React from \"react\";\nimport { Alert, OverlayLoader } from \"@webiny/admin-ui\";\n\ninterface PreviewDomainStatusProps {\n error: string | null;\n onRetry: () => void;\n}\n\n/**\n * Shown in place of the preview while the Frontend Domain setting loads, or when it fails to load.\n */\nexport const PreviewDomainStatus = ({ error, onRetry }: PreviewDomainStatusProps) => {\n return (\n <div className=\"relative border border-neutral-dimmed rounded-t-lg flex flex-col flex-1 h-full overflow-hidden fill-grid\">\n {error ? (\n <div className=\"p-md\">\n <Alert\n type={\"danger\"}\n variant={\"subtle\"}\n actions={<Alert.Action text={\"Retry\"} onClick={onRetry} />}\n >\n Could not load the Frontend Domain setting, so the live preview cannot\n start. {error}\n </Alert>\n </div>\n ) : (\n <OverlayLoader text=\"Loading preview settings...\" />\n )}\n </div>\n );\n};\n"],"names":["PreviewDomainStatus","error","onRetry","Alert","OverlayLoader"],"mappings":";;AAWO,MAAMA,sBAAsB,CAAC,EAAEC,KAAK,EAAEC,OAAO,EAA4B,GACrE,WAAP,GACI,oBAAC;QAAI,WAAU;OACVD,QAAQ,WAARA,GACG,oBAAC;QAAI,WAAU;qBACX,oBAACE,OAAKA;QACF,MAAM;QACN,SAAS;QACT,uBAAS,oBAACA,MAAM,MAAM;YAAC,MAAM;YAAS,SAASD;;OAClD,kFAEWD,UAAAA,WAAAA,GAIhB,oBAACG,eAAaA;QAAC,MAAK"}
@@ -1,6 +1,11 @@
1
1
  import React from "react";
2
2
  interface PreviewPaneProps {
3
3
  domain: string;
4
+ /**
5
+ * The Frontend Domain setting, passed only when the user overrides it with their own preview domain.
6
+ */
7
+ settingsDomain: string | null;
8
+ onResetDomain: () => void;
4
9
  previewPath: string;
5
10
  entryId: string;
6
11
  entryData: Record<string, unknown> | null;
@@ -9,5 +14,5 @@ interface PreviewPaneProps {
9
14
  */
10
15
  urlEntryData: Record<string, unknown> | null;
11
16
  }
12
- export declare const PreviewPane: ({ domain, previewPath, entryId, entryData, urlEntryData }: PreviewPaneProps) => React.JSX.Element;
17
+ export declare const PreviewPane: ({ domain, settingsDomain, onResetDomain, previewPath, entryId, entryData, urlEntryData }: PreviewPaneProps) => React.JSX.Element;
13
18
  export {};
@@ -1,32 +1,29 @@
1
1
  import react, { useCallback, useEffect, useRef, useState } from "react";
2
2
  import { MessageOrigin, Messenger } from "@webiny/cms-sdk/messenger";
3
3
  import { jsonPatch } from "@webiny/cms-sdk";
4
- import { IconButton, Input, OverlayLoader, SegmentedControl } from "@webiny/admin-ui";
4
+ import { Alert, CopyButton, IconButton, OverlayLoader, SegmentedControl, Text, Tooltip, useToast } from "@webiny/admin-ui";
5
5
  import { ReactComponent } from "@webiny/icons/refresh.svg";
6
- import { ReactComponent as content_copy_svg_ReactComponent } from "@webiny/icons/content_copy.svg";
7
6
  import { ReactComponent as laptop_svg_ReactComponent } from "@webiny/icons/laptop.svg";
8
7
  import { ReactComponent as smartphone_svg_ReactComponent } from "@webiny/icons/smartphone.svg";
9
8
  import { ReactComponent as open_in_new_svg_ReactComponent } from "@webiny/icons/open_in_new.svg";
9
+ import { PreviewDomainMenu } from "@webiny/frontend-settings/exports/admin.js";
10
10
  import { useLivePreviewPresenter } from "./useLivePreviewPresenter.js";
11
11
  import { buildDisplayUrl, buildEditorUrl } from "./resolvePreviewUrl.js";
12
- const PreviewPane = ({ domain, previewPath, entryId, entryData, urlEntryData })=>{
12
+ const READY_TIMEOUT_MS = 20000;
13
+ const PreviewPane = ({ domain, settingsDomain, onResetDomain, previewPath, entryId, entryData, urlEntryData })=>{
13
14
  const iframeRef = useRef(null);
14
15
  const messengerRef = useRef(null);
15
16
  const entryDataRef = useRef(entryData);
16
17
  const lastSentDataRef = useRef(null);
17
18
  const [ready, setReady] = useState(false);
18
19
  const [loading, setLoading] = useState(true);
20
+ const [timedOut, setTimedOut] = useState(false);
19
21
  const [iframeKey, setIframeKey] = useState(0);
20
22
  const [viewport, setViewport] = useState("desktop");
21
23
  const presenter = useLivePreviewPresenter();
24
+ const { showToast } = useToast();
22
25
  entryDataRef.current = entryData;
23
26
  const displayUrl = buildDisplayUrl(domain, previewPath, urlEntryData || {});
24
- const [address, setAddress] = useState(displayUrl);
25
- useEffect(()=>{
26
- setAddress(displayUrl);
27
- }, [
28
- displayUrl
29
- ]);
30
27
  const iframeSrc = (()=>{
31
28
  const editorPath = buildEditorUrl(domain, previewPath);
32
29
  const url = new URL(editorPath);
@@ -52,15 +49,21 @@ const PreviewPane = ({ domain, previewPath, entryId, entryData, urlEntryData })=
52
49
  const previewTarget = new MessageOrigin(()=>iframe.contentWindow, targetOrigin);
53
50
  const messenger = new Messenger(editorOrigin, previewTarget, "wb.editor.*");
54
51
  messengerRef.current = messenger;
52
+ setLoading(true);
53
+ setTimedOut(false);
54
+ const timeout = setTimeout(()=>setTimedOut(true), READY_TIMEOUT_MS);
55
55
  messenger.on("preview.ready", ()=>{
56
+ clearTimeout(timeout);
56
57
  setReady(true);
57
58
  setLoading(false);
59
+ setTimedOut(false);
58
60
  sendEntryData();
59
61
  });
60
62
  messenger.on("preview.component.register", (manifest)=>{
61
63
  presenter.addComponent(manifest);
62
64
  });
63
65
  return ()=>{
66
+ clearTimeout(timeout);
64
67
  messenger.dispose();
65
68
  messengerRef.current = null;
66
69
  lastSentDataRef.current = null;
@@ -102,11 +105,11 @@ const PreviewPane = ({ domain, previewPath, entryId, entryData, urlEntryData })=
102
105
  displayUrl,
103
106
  entryId
104
107
  ]);
105
- const copyUrl = useCallback(()=>{
106
- navigator.clipboard.writeText(getDraftUrl());
107
- }, [
108
- getDraftUrl
109
- ]);
108
+ const confirmCopy = useCallback(()=>{
109
+ showToast({
110
+ title: "Preview link copied to clipboard!"
111
+ });
112
+ }, []);
110
113
  const openInNewTab = useCallback(()=>{
111
114
  window.open(getDraftUrl(), "_blank");
112
115
  }, [
@@ -115,34 +118,51 @@ const PreviewPane = ({ domain, previewPath, entryId, entryData, urlEntryData })=
115
118
  return /*#__PURE__*/ react.createElement("div", {
116
119
  className: "relative border border-neutral-dimmed rounded-t-lg flex flex-col flex-1 h-full overflow-hidden"
117
120
  }, /*#__PURE__*/ react.createElement("div", {
118
- className: "flex p-md items-center bg-white border-b border-neutral-dimmed"
121
+ className: "flex flex-row items-center gap-sm p-sm bg-neutral-base border-b-sm border-neutral-dimmed"
119
122
  }, /*#__PURE__*/ react.createElement("div", {
120
- className: "w-full"
121
- }, /*#__PURE__*/ react.createElement(Input, {
122
- value: address,
123
- onChange: setAddress,
124
- readOnly: true,
125
- size: "md",
126
- variant: "secondary",
127
- className: "bg-gray-100"
128
- })), /*#__PURE__*/ react.createElement("div", {
129
- className: "flex items-center gap-xxs ml-sm"
130
- }, /*#__PURE__*/ react.createElement(IconButton, {
131
- onClick: openInNewTab,
132
- icon: /*#__PURE__*/ react.createElement(open_in_new_svg_ReactComponent, null),
133
- variant: "ghost",
134
- size: "md"
135
- }), /*#__PURE__*/ react.createElement(IconButton, {
136
- onClick: copyUrl,
137
- icon: /*#__PURE__*/ react.createElement(content_copy_svg_ReactComponent, null),
138
- variant: "ghost",
139
- size: "sm"
140
- }), /*#__PURE__*/ react.createElement(IconButton, {
141
- onClick: reload,
142
- icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
143
- variant: "ghost",
144
- size: "sm"
145
- }), /*#__PURE__*/ react.createElement(SegmentedControl, {
123
+ className: "relative flex-auto min-w-0 h-[32px]"
124
+ }, /*#__PURE__*/ react.createElement("div", {
125
+ className: "w-full absolute -top-px py-xs-plus pl-xl pr-[112px] border-sm text-md truncate cursor-not-allowed rounded-md border-neutral-subtle bg-neutral-disabled text-neutral-disabled"
126
+ }, /*#__PURE__*/ react.createElement(PreviewDomainMenu, {
127
+ className: "absolute left-0 top-0"
128
+ }), displayUrl), /*#__PURE__*/ react.createElement("div", {
129
+ className: "absolute right-0 top-0 flex"
130
+ }, /*#__PURE__*/ react.createElement(Tooltip, {
131
+ content: /*#__PURE__*/ react.createElement(Text, {
132
+ size: "md"
133
+ }, "Refresh preview"),
134
+ side: "bottom",
135
+ trigger: /*#__PURE__*/ react.createElement(IconButton, {
136
+ icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
137
+ size: "md",
138
+ onClick: reload,
139
+ variant: "ghost"
140
+ })
141
+ }), /*#__PURE__*/ react.createElement(Tooltip, {
142
+ content: /*#__PURE__*/ react.createElement(Text, {
143
+ size: "md"
144
+ }, "Copy preview link"),
145
+ side: "bottom",
146
+ trigger: /*#__PURE__*/ react.createElement(CopyButton, {
147
+ size: "md",
148
+ value: getDraftUrl(),
149
+ onCopy: confirmCopy,
150
+ variant: "ghost"
151
+ })
152
+ }), /*#__PURE__*/ react.createElement(Tooltip, {
153
+ content: /*#__PURE__*/ react.createElement(Text, {
154
+ size: "md"
155
+ }, "Preview entry in a new tab"),
156
+ side: "bottom",
157
+ trigger: /*#__PURE__*/ react.createElement(IconButton, {
158
+ icon: /*#__PURE__*/ react.createElement(open_in_new_svg_ReactComponent, null),
159
+ size: "md",
160
+ onClick: openInNewTab,
161
+ variant: "ghost"
162
+ })
163
+ }))), /*#__PURE__*/ react.createElement("div", {
164
+ className: "shrink-0"
165
+ }, /*#__PURE__*/ react.createElement(SegmentedControl, {
146
166
  value: viewport,
147
167
  onChange: (value)=>setViewport(value),
148
168
  items: [
@@ -157,9 +177,25 @@ const PreviewPane = ({ domain, previewPath, entryId, entryData, urlEntryData })=
157
177
  icon: /*#__PURE__*/ react.createElement(smartphone_svg_ReactComponent, null)
158
178
  }
159
179
  ]
160
- }))), /*#__PURE__*/ react.createElement("div", {
161
- className: "block box-border h-full w-full overflow-auto fill-grid"
162
- }, loading ? /*#__PURE__*/ react.createElement(OverlayLoader, {
180
+ }))), settingsDomain ? /*#__PURE__*/ react.createElement(Alert, {
181
+ type: "warning",
182
+ variant: "subtle",
183
+ className: "rounded-none",
184
+ actions: /*#__PURE__*/ react.createElement(Alert.Action, {
185
+ text: "Use Frontend Domain",
186
+ onClick: onResetDomain
187
+ })
188
+ }, "Previewing on your custom domain ", domain, " instead of the Frontend Domain", " ", settingsDomain, ".") : null, loading && timedOut ? /*#__PURE__*/ react.createElement(Alert, {
189
+ type: "warning",
190
+ variant: "subtle",
191
+ className: "rounded-none",
192
+ actions: /*#__PURE__*/ react.createElement(Alert.Action, {
193
+ text: "Reload",
194
+ onClick: reload
195
+ })
196
+ }, new URL(iframeSrc).origin, " is not responding to the live preview. Check that the frontend app is running at that address, that it initializes the Webiny SDK in editing mode, and that it allows this admin app as a referrer.") : null, /*#__PURE__*/ react.createElement("div", {
197
+ className: "relative block box-border h-full w-full overflow-auto fill-grid"
198
+ }, loading && !timedOut ? /*#__PURE__*/ react.createElement(OverlayLoader, {
163
199
  text: "Connecting to Live Preview..."
164
200
  }) : null, /*#__PURE__*/ react.createElement("div", {
165
201
  className: `mx-auto h-full transition-all duration-300 ${"mobile" === viewport ? "p-md" : ""}`,
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/contentEntries/preview/PreviewPane.js","sources":["../../../../src/presentation/contentEntries/preview/PreviewPane.tsx"],"sourcesContent":["import React, { useRef, useEffect, useCallback, useState } from \"react\";\nimport { Messenger, MessageOrigin } from \"@webiny/cms-sdk/messenger\";\nimport { jsonPatch } from \"@webiny/cms-sdk\";\nimport { IconButton, Input, OverlayLoader, SegmentedControl } from \"@webiny/admin-ui\";\nimport { ReactComponent as RefreshIcon } from \"@webiny/icons/refresh.svg\";\nimport { ReactComponent as ContentCopyIcon } from \"@webiny/icons/content_copy.svg\";\nimport { ReactComponent as LaptopIcon } from \"@webiny/icons/laptop.svg\";\nimport { ReactComponent as SmartphoneIcon } from \"@webiny/icons/smartphone.svg\";\nimport { ReactComponent as OpenInNewIcon } from \"@webiny/icons/open_in_new.svg\";\nimport { useLivePreviewPresenter } from \"./useLivePreviewPresenter.js\";\nimport { buildEditorUrl, buildDisplayUrl } from \"./resolvePreviewUrl.js\";\n\ninterface PreviewPaneProps {\n domain: string;\n previewPath: string;\n entryId: string;\n entryData: Record<string, unknown> | null;\n /**\n * Entry data used to resolve the preview path, with referenced entries' values filled in.\n */\n urlEntryData: Record<string, unknown> | null;\n}\n\ntype ViewportMode = \"desktop\" | \"mobile\";\n\nexport const PreviewPane = ({\n domain,\n previewPath,\n entryId,\n entryData,\n urlEntryData\n}: PreviewPaneProps) => {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const messengerRef = useRef<Messenger | null>(null);\n const entryDataRef = useRef(entryData);\n const lastSentDataRef = useRef<Record<string, unknown> | null>(null);\n const [ready, setReady] = useState(false);\n const [loading, setLoading] = useState(true);\n const [iframeKey, setIframeKey] = useState(0);\n const [viewport, setViewport] = useState<ViewportMode>(\"desktop\");\n const presenter = useLivePreviewPresenter();\n\n entryDataRef.current = entryData;\n\n const displayUrl = buildDisplayUrl(domain, previewPath, urlEntryData || {});\n\n const [address, setAddress] = useState(displayUrl);\n\n useEffect(() => {\n setAddress(displayUrl);\n }, [displayUrl]);\n\n const iframeSrc = (() => {\n const editorPath = buildEditorUrl(domain, previewPath);\n const url = new URL(editorPath);\n url.searchParams.set(\"wb.editing\", \"true\");\n url.searchParams.set(\"wb.type\", \"entry\");\n url.searchParams.set(\"wb.id\", entryId);\n url.searchParams.set(\"wb.path\", url.pathname);\n url.searchParams.set(\"wb.referrer\", window.location.origin);\n return url.toString();\n })();\n\n const sendEntryData = useCallback(() => {\n const data = entryDataRef.current;\n if (!data || !messengerRef.current) {\n return;\n }\n\n const serialized = JSON.parse(JSON.stringify(data));\n messengerRef.current.send(\"document.set\", serialized);\n lastSentDataRef.current = serialized;\n }, []);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe || !iframe.contentWindow) {\n return;\n }\n\n const targetOrigin = new URL(iframe.src).origin;\n const editorOrigin = new MessageOrigin(() => window, window.location.origin);\n const previewTarget = new MessageOrigin(() => iframe.contentWindow!, targetOrigin);\n\n const messenger = new Messenger(editorOrigin, previewTarget, \"wb.editor.*\");\n messengerRef.current = messenger;\n\n messenger.on(\"preview.ready\", () => {\n setReady(true);\n setLoading(false);\n sendEntryData();\n });\n\n messenger.on(\n \"preview.component.register\",\n (manifest: { name: string; label: string; description: string }) => {\n presenter.addComponent(manifest);\n }\n );\n\n return () => {\n messenger.dispose();\n messengerRef.current = null;\n lastSentDataRef.current = null;\n setReady(false);\n };\n }, [iframeSrc, presenter, iframeKey, sendEntryData]);\n\n useEffect(() => {\n if (!ready || !entryData || !messengerRef.current) {\n return;\n }\n\n const current = JSON.parse(JSON.stringify(entryData));\n const previous = lastSentDataRef.current;\n\n if (previous) {\n const patch = jsonPatch.compare(previous, current);\n if (patch.length > 0) {\n messengerRef.current.send(\"document.patch\", patch);\n }\n } else {\n messengerRef.current.send(\"document.set\", current);\n }\n\n lastSentDataRef.current = current;\n }, [ready, entryData]);\n\n const reload = useCallback(() => {\n setLoading(true);\n setReady(false);\n lastSentDataRef.current = null;\n setIframeKey(prev => prev + 1);\n }, []);\n\n const getDraftUrl = useCallback(() => {\n const url = new URL(displayUrl);\n url.searchParams.set(\"wb.type\", \"entry\");\n url.searchParams.set(\"wb.path\", url.pathname);\n url.searchParams.set(\"wb.preview\", \"true\");\n url.searchParams.set(\"wb.id\", entryId);\n return url.toString();\n }, [displayUrl, entryId]);\n\n const copyUrl = useCallback(() => {\n navigator.clipboard.writeText(getDraftUrl());\n }, [getDraftUrl]);\n\n const openInNewTab = useCallback(() => {\n window.open(getDraftUrl(), \"_blank\");\n }, [getDraftUrl]);\n\n return (\n <div className=\"relative border border-neutral-dimmed rounded-t-lg flex flex-col flex-1 h-full overflow-hidden\">\n <div className=\"flex p-md items-center bg-white border-b border-neutral-dimmed\">\n <div className=\"w-full\">\n <Input\n value={address}\n onChange={setAddress}\n readOnly\n size=\"md\"\n variant={\"secondary\"}\n className=\"bg-gray-100\"\n />\n </div>\n\n <div className=\"flex items-center gap-xxs ml-sm\">\n <IconButton\n onClick={openInNewTab}\n icon={<OpenInNewIcon />}\n variant=\"ghost\"\n size=\"md\"\n />\n <IconButton\n onClick={copyUrl}\n icon={<ContentCopyIcon />}\n variant=\"ghost\"\n size=\"sm\"\n />\n <IconButton onClick={reload} icon={<RefreshIcon />} variant=\"ghost\" size=\"sm\" />\n <SegmentedControl\n value={viewport}\n onChange={(value: string) => setViewport(value as ViewportMode)}\n items={[\n { value: \"desktop\", label: \"\", icon: <LaptopIcon /> },\n { value: \"mobile\", label: \"\", icon: <SmartphoneIcon /> }\n ]}\n />\n </div>\n </div>\n\n <div className=\"block box-border h-full w-full overflow-auto fill-grid\">\n {loading ? <OverlayLoader text=\"Connecting to Live Preview...\" /> : null}\n <div\n className={`mx-auto h-full transition-all duration-300 ${viewport === \"mobile\" ? \"p-md\" : \"\"}`}\n style={{ width: viewport === \"mobile\" ? \"375px\" : \"100%\" }}\n >\n <iframe\n key={iframeKey}\n ref={iframeRef}\n src={iframeSrc}\n width=\"100%\"\n height=\"100%\"\n className=\"h-full\"\n sandbox=\"allow-same-origin allow-scripts allow-forms\"\n />\n </div>\n </div>\n </div>\n );\n};\n"],"names":["PreviewPane","domain","previewPath","entryId","entryData","urlEntryData","iframeRef","useRef","messengerRef","entryDataRef","lastSentDataRef","ready","setReady","useState","loading","setLoading","iframeKey","setIframeKey","viewport","setViewport","presenter","useLivePreviewPresenter","displayUrl","buildDisplayUrl","address","setAddress","useEffect","iframeSrc","editorPath","buildEditorUrl","url","URL","window","sendEntryData","useCallback","data","serialized","JSON","iframe","targetOrigin","editorOrigin","MessageOrigin","previewTarget","messenger","Messenger","manifest","current","previous","patch","jsonPatch","reload","prev","getDraftUrl","copyUrl","navigator","openInNewTab","Input","IconButton","OpenInNewIcon","ContentCopyIcon","RefreshIcon","SegmentedControl","value","LaptopIcon","SmartphoneIcon","OverlayLoader"],"mappings":";;;;;;;;;;;AAyBO,MAAMA,cAAc,CAAC,EACxBC,MAAM,EACNC,WAAW,EACXC,OAAO,EACPC,SAAS,EACTC,YAAY,EACG;IACf,MAAMC,YAAYC,OAAiC;IACnD,MAAMC,eAAeD,OAAyB;IAC9C,MAAME,eAAeF,OAAOH;IAC5B,MAAMM,kBAAkBH,OAAuC;IAC/D,MAAM,CAACI,OAAOC,SAAS,GAAGC,SAAS;IACnC,MAAM,CAACC,SAASC,WAAW,GAAGF,SAAS;IACvC,MAAM,CAACG,WAAWC,aAAa,GAAGJ,SAAS;IAC3C,MAAM,CAACK,UAAUC,YAAY,GAAGN,SAAuB;IACvD,MAAMO,YAAYC;IAElBZ,aAAa,OAAO,GAAGL;IAEvB,MAAMkB,aAAaC,gBAAgBtB,QAAQC,aAAaG,gBAAgB,CAAC;IAEzE,MAAM,CAACmB,SAASC,WAAW,GAAGZ,SAASS;IAEvCI,UAAU;QACND,WAAWH;IACf,GAAG;QAACA;KAAW;IAEf,MAAMK,YAAa,AAAC;QAChB,MAAMC,aAAaC,eAAe5B,QAAQC;QAC1C,MAAM4B,MAAM,IAAIC,IAAIH;QACpBE,IAAI,YAAY,CAAC,GAAG,CAAC,cAAc;QACnCA,IAAI,YAAY,CAAC,GAAG,CAAC,WAAW;QAChCA,IAAI,YAAY,CAAC,GAAG,CAAC,SAAS3B;QAC9B2B,IAAI,YAAY,CAAC,GAAG,CAAC,WAAWA,IAAI,QAAQ;QAC5CA,IAAI,YAAY,CAAC,GAAG,CAAC,eAAeE,OAAO,QAAQ,CAAC,MAAM;QAC1D,OAAOF,IAAI,QAAQ;IACvB;IAEA,MAAMG,gBAAgBC,YAAY;QAC9B,MAAMC,OAAO1B,aAAa,OAAO;QACjC,IAAI,CAAC0B,QAAQ,CAAC3B,aAAa,OAAO,EAC9B;QAGJ,MAAM4B,aAAaC,KAAK,KAAK,CAACA,KAAK,SAAS,CAACF;QAC7C3B,aAAa,OAAO,CAAC,IAAI,CAAC,gBAAgB4B;QAC1C1B,gBAAgB,OAAO,GAAG0B;IAC9B,GAAG,EAAE;IAELV,UAAU;QACN,MAAMY,SAAShC,UAAU,OAAO;QAChC,IAAI,CAACgC,UAAU,CAACA,OAAO,aAAa,EAChC;QAGJ,MAAMC,eAAe,IAAIR,IAAIO,OAAO,GAAG,EAAE,MAAM;QAC/C,MAAME,eAAe,IAAIC,cAAc,IAAMT,QAAQA,OAAO,QAAQ,CAAC,MAAM;QAC3E,MAAMU,gBAAgB,IAAID,cAAc,IAAMH,OAAO,aAAa,EAAGC;QAErE,MAAMI,YAAY,IAAIC,UAAUJ,cAAcE,eAAe;QAC7DlC,aAAa,OAAO,GAAGmC;QAEvBA,UAAU,EAAE,CAAC,iBAAiB;YAC1B/B,SAAS;YACTG,WAAW;YACXkB;QACJ;QAEAU,UAAU,EAAE,CACR,8BACA,CAACE;YACGzB,UAAU,YAAY,CAACyB;QAC3B;QAGJ,OAAO;YACHF,UAAU,OAAO;YACjBnC,aAAa,OAAO,GAAG;YACvBE,gBAAgB,OAAO,GAAG;YAC1BE,SAAS;QACb;IACJ,GAAG;QAACe;QAAWP;QAAWJ;QAAWiB;KAAc;IAEnDP,UAAU;QACN,IAAI,CAACf,SAAS,CAACP,aAAa,CAACI,aAAa,OAAO,EAC7C;QAGJ,MAAMsC,UAAUT,KAAK,KAAK,CAACA,KAAK,SAAS,CAACjC;QAC1C,MAAM2C,WAAWrC,gBAAgB,OAAO;QAExC,IAAIqC,UAAU;YACV,MAAMC,QAAQC,UAAU,OAAO,CAACF,UAAUD;YAC1C,IAAIE,MAAM,MAAM,GAAG,GACfxC,aAAa,OAAO,CAAC,IAAI,CAAC,kBAAkBwC;QAEpD,OACIxC,aAAa,OAAO,CAAC,IAAI,CAAC,gBAAgBsC;QAG9CpC,gBAAgB,OAAO,GAAGoC;IAC9B,GAAG;QAACnC;QAAOP;KAAU;IAErB,MAAM8C,SAAShB,YAAY;QACvBnB,WAAW;QACXH,SAAS;QACTF,gBAAgB,OAAO,GAAG;QAC1BO,aAAakC,CAAAA,OAAQA,OAAO;IAChC,GAAG,EAAE;IAEL,MAAMC,cAAclB,YAAY;QAC5B,MAAMJ,MAAM,IAAIC,IAAIT;QACpBQ,IAAI,YAAY,CAAC,GAAG,CAAC,WAAW;QAChCA,IAAI,YAAY,CAAC,GAAG,CAAC,WAAWA,IAAI,QAAQ;QAC5CA,IAAI,YAAY,CAAC,GAAG,CAAC,cAAc;QACnCA,IAAI,YAAY,CAAC,GAAG,CAAC,SAAS3B;QAC9B,OAAO2B,IAAI,QAAQ;IACvB,GAAG;QAACR;QAAYnB;KAAQ;IAExB,MAAMkD,UAAUnB,YAAY;QACxBoB,UAAU,SAAS,CAAC,SAAS,CAACF;IAClC,GAAG;QAACA;KAAY;IAEhB,MAAMG,eAAerB,YAAY;QAC7BF,OAAO,IAAI,CAACoB,eAAe;IAC/B,GAAG;QAACA;KAAY;IAEhB,OAAO,WAAP,GACI,oBAAC;QAAI,WAAU;qBACX,oBAAC;QAAI,WAAU;qBACX,oBAAC;QAAI,WAAU;qBACX,oBAACI,OAAKA;QACF,OAAOhC;QACP,UAAUC;QACV;QACA,MAAK;QACL,SAAS;QACT,WAAU;uBAIlB,oBAAC;QAAI,WAAU;qBACX,oBAACgC,YAAUA;QACP,SAASF;QACT,oBAAM,oBAACG,gCAAaA;QACpB,SAAQ;QACR,MAAK;sBAET,oBAACD,YAAUA;QACP,SAASJ;QACT,oBAAM,oBAACM,iCAAeA;QACtB,SAAQ;QACR,MAAK;sBAET,oBAACF,YAAUA;QAAC,SAASP;QAAQ,oBAAM,oBAACU,gBAAWA;QAAK,SAAQ;QAAQ,MAAK;sBACzE,oBAACC,kBAAgBA;QACb,OAAO3C;QACP,UAAU,CAAC4C,QAAkB3C,YAAY2C;QACzC,OAAO;YACH;gBAAE,OAAO;gBAAW,OAAO;gBAAI,MAAM,WAAN,GAAM,oBAACC,2BAAUA;YAAI;YACpD;gBAAE,OAAO;gBAAU,OAAO;gBAAI,MAAM,WAAN,GAAM,oBAACC,+BAAcA;YAAI;SAC1D;wBAKb,oBAAC;QAAI,WAAU;OACVlD,UAAU,WAAVA,GAAU,oBAACmD,eAAaA;QAAC,MAAK;SAAqC,oBACpE,oBAAC;QACG,WAAW,CAAC,2CAA2C,EAAE/C,AAAa,aAAbA,WAAwB,SAAS,IAAI;QAC9F,OAAO;YAAE,OAAOA,AAAa,aAAbA,WAAwB,UAAU;QAAO;qBAEzD,oBAAC;QACG,KAAKF;QACL,KAAKV;QACL,KAAKqB;QACL,OAAM;QACN,QAAO;QACP,WAAU;QACV,SAAQ;;AAMhC"}
1
+ {"version":3,"file":"presentation/contentEntries/preview/PreviewPane.js","sources":["../../../../src/presentation/contentEntries/preview/PreviewPane.tsx"],"sourcesContent":["import React, { useRef, useEffect, useCallback, useState } from \"react\";\nimport { Messenger, MessageOrigin } from \"@webiny/cms-sdk/messenger\";\nimport { jsonPatch } from \"@webiny/cms-sdk\";\nimport {\n Alert,\n CopyButton,\n IconButton,\n OverlayLoader,\n SegmentedControl,\n Text,\n Tooltip,\n useToast\n} from \"@webiny/admin-ui\";\nimport { ReactComponent as RefreshIcon } from \"@webiny/icons/refresh.svg\";\nimport { ReactComponent as LaptopIcon } from \"@webiny/icons/laptop.svg\";\nimport { ReactComponent as SmartphoneIcon } from \"@webiny/icons/smartphone.svg\";\nimport { ReactComponent as OpenInNewIcon } from \"@webiny/icons/open_in_new.svg\";\nimport { PreviewDomainMenu } from \"@webiny/frontend-settings/exports/admin.js\";\nimport { useLivePreviewPresenter } from \"./useLivePreviewPresenter.js\";\nimport { buildEditorUrl, buildDisplayUrl } from \"./resolvePreviewUrl.js\";\n\n/**\n * How long to wait for the frontend to report it is ready before showing troubleshooting hints.\n */\nconst READY_TIMEOUT_MS = 20_000;\n\ninterface PreviewPaneProps {\n domain: string;\n /**\n * The Frontend Domain setting, passed only when the user overrides it with their own preview domain.\n */\n settingsDomain: string | null;\n onResetDomain: () => void;\n previewPath: string;\n entryId: string;\n entryData: Record<string, unknown> | null;\n /**\n * Entry data used to resolve the preview path, with referenced entries' values filled in.\n */\n urlEntryData: Record<string, unknown> | null;\n}\n\ntype ViewportMode = \"desktop\" | \"mobile\";\n\nexport const PreviewPane = ({\n domain,\n settingsDomain,\n onResetDomain,\n previewPath,\n entryId,\n entryData,\n urlEntryData\n}: PreviewPaneProps) => {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const messengerRef = useRef<Messenger | null>(null);\n const entryDataRef = useRef(entryData);\n const lastSentDataRef = useRef<Record<string, unknown> | null>(null);\n const [ready, setReady] = useState(false);\n const [loading, setLoading] = useState(true);\n const [timedOut, setTimedOut] = useState(false);\n const [iframeKey, setIframeKey] = useState(0);\n const [viewport, setViewport] = useState<ViewportMode>(\"desktop\");\n const presenter = useLivePreviewPresenter();\n const { showToast } = useToast();\n\n entryDataRef.current = entryData;\n\n const displayUrl = buildDisplayUrl(domain, previewPath, urlEntryData || {});\n\n const iframeSrc = (() => {\n const editorPath = buildEditorUrl(domain, previewPath);\n const url = new URL(editorPath);\n url.searchParams.set(\"wb.editing\", \"true\");\n url.searchParams.set(\"wb.type\", \"entry\");\n url.searchParams.set(\"wb.id\", entryId);\n url.searchParams.set(\"wb.path\", url.pathname);\n url.searchParams.set(\"wb.referrer\", window.location.origin);\n return url.toString();\n })();\n\n const sendEntryData = useCallback(() => {\n const data = entryDataRef.current;\n if (!data || !messengerRef.current) {\n return;\n }\n\n const serialized = JSON.parse(JSON.stringify(data));\n messengerRef.current.send(\"document.set\", serialized);\n lastSentDataRef.current = serialized;\n }, []);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe || !iframe.contentWindow) {\n return;\n }\n\n const targetOrigin = new URL(iframe.src).origin;\n const editorOrigin = new MessageOrigin(() => window, window.location.origin);\n const previewTarget = new MessageOrigin(() => iframe.contentWindow!, targetOrigin);\n\n const messenger = new Messenger(editorOrigin, previewTarget, \"wb.editor.*\");\n messengerRef.current = messenger;\n\n setLoading(true);\n setTimedOut(false);\n const timeout = setTimeout(() => setTimedOut(true), READY_TIMEOUT_MS);\n\n messenger.on(\"preview.ready\", () => {\n clearTimeout(timeout);\n setReady(true);\n setLoading(false);\n setTimedOut(false);\n sendEntryData();\n });\n\n messenger.on(\n \"preview.component.register\",\n (manifest: { name: string; label: string; description: string }) => {\n presenter.addComponent(manifest);\n }\n );\n\n return () => {\n clearTimeout(timeout);\n messenger.dispose();\n messengerRef.current = null;\n lastSentDataRef.current = null;\n setReady(false);\n };\n }, [iframeSrc, presenter, iframeKey, sendEntryData]);\n\n useEffect(() => {\n if (!ready || !entryData || !messengerRef.current) {\n return;\n }\n\n const current = JSON.parse(JSON.stringify(entryData));\n const previous = lastSentDataRef.current;\n\n if (previous) {\n const patch = jsonPatch.compare(previous, current);\n if (patch.length > 0) {\n messengerRef.current.send(\"document.patch\", patch);\n }\n } else {\n messengerRef.current.send(\"document.set\", current);\n }\n\n lastSentDataRef.current = current;\n }, [ready, entryData]);\n\n const reload = useCallback(() => {\n setLoading(true);\n setReady(false);\n lastSentDataRef.current = null;\n setIframeKey(prev => prev + 1);\n }, []);\n\n const getDraftUrl = useCallback(() => {\n const url = new URL(displayUrl);\n url.searchParams.set(\"wb.type\", \"entry\");\n url.searchParams.set(\"wb.path\", url.pathname);\n url.searchParams.set(\"wb.preview\", \"true\");\n url.searchParams.set(\"wb.id\", entryId);\n return url.toString();\n }, [displayUrl, entryId]);\n\n const confirmCopy = useCallback(() => {\n showToast({ title: \"Preview link copied to clipboard!\" });\n }, []);\n\n const openInNewTab = useCallback(() => {\n window.open(getDraftUrl(), \"_blank\");\n }, [getDraftUrl]);\n\n return (\n <div className=\"relative border border-neutral-dimmed rounded-t-lg flex flex-col flex-1 h-full overflow-hidden\">\n <div className=\"flex flex-row items-center gap-sm p-sm bg-neutral-base border-b-sm border-neutral-dimmed\">\n <div className=\"relative flex-auto min-w-0 h-[32px]\">\n <div className=\"w-full absolute -top-px py-xs-plus pl-xl pr-[112px] border-sm text-md truncate cursor-not-allowed rounded-md border-neutral-subtle bg-neutral-disabled text-neutral-disabled\">\n <PreviewDomainMenu className={\"absolute left-0 top-0\"} />\n {displayUrl}\n </div>\n <div className=\"absolute right-0 top-0 flex\">\n <Tooltip\n content={<Text size=\"md\">Refresh preview</Text>}\n side=\"bottom\"\n trigger={\n <IconButton\n icon={<RefreshIcon />}\n size=\"md\"\n onClick={reload}\n variant={\"ghost\"}\n />\n }\n />\n <Tooltip\n content={<Text size=\"md\">Copy preview link</Text>}\n side=\"bottom\"\n trigger={\n <CopyButton\n size=\"md\"\n value={getDraftUrl()}\n onCopy={confirmCopy}\n variant={\"ghost\"}\n />\n }\n />\n <Tooltip\n content={<Text size=\"md\">Preview entry in a new tab</Text>}\n side=\"bottom\"\n trigger={\n <IconButton\n icon={<OpenInNewIcon />}\n size=\"md\"\n onClick={openInNewTab}\n variant={\"ghost\"}\n />\n }\n />\n </div>\n </div>\n <div className=\"shrink-0\">\n <SegmentedControl\n value={viewport}\n onChange={(value: string) => setViewport(value as ViewportMode)}\n items={[\n { value: \"desktop\", label: \"\", icon: <LaptopIcon /> },\n { value: \"mobile\", label: \"\", icon: <SmartphoneIcon /> }\n ]}\n />\n </div>\n </div>\n\n {settingsDomain ? (\n <Alert\n type={\"warning\"}\n variant={\"subtle\"}\n className={\"rounded-none\"}\n actions={<Alert.Action text={\"Use Frontend Domain\"} onClick={onResetDomain} />}\n >\n Previewing on your custom domain {domain} instead of the Frontend Domain{\" \"}\n {settingsDomain}.\n </Alert>\n ) : null}\n\n {loading && timedOut ? (\n <Alert\n type={\"warning\"}\n variant={\"subtle\"}\n className={\"rounded-none\"}\n actions={<Alert.Action text={\"Reload\"} onClick={reload} />}\n >\n {new URL(iframeSrc).origin} is not responding to the live preview. Check that\n the frontend app is running at that address, that it initializes the Webiny SDK\n in editing mode, and that it allows this admin app as a referrer.\n </Alert>\n ) : null}\n\n <div className=\"relative block box-border h-full w-full overflow-auto fill-grid\">\n {loading && !timedOut ? (\n <OverlayLoader text=\"Connecting to Live Preview...\" />\n ) : null}\n <div\n className={`mx-auto h-full transition-all duration-300 ${viewport === \"mobile\" ? \"p-md\" : \"\"}`}\n style={{ width: viewport === \"mobile\" ? \"375px\" : \"100%\" }}\n >\n <iframe\n key={iframeKey}\n ref={iframeRef}\n src={iframeSrc}\n width=\"100%\"\n height=\"100%\"\n className=\"h-full\"\n sandbox=\"allow-same-origin allow-scripts allow-forms\"\n />\n </div>\n </div>\n </div>\n );\n};\n"],"names":["READY_TIMEOUT_MS","PreviewPane","domain","settingsDomain","onResetDomain","previewPath","entryId","entryData","urlEntryData","iframeRef","useRef","messengerRef","entryDataRef","lastSentDataRef","ready","setReady","useState","loading","setLoading","timedOut","setTimedOut","iframeKey","setIframeKey","viewport","setViewport","presenter","useLivePreviewPresenter","showToast","useToast","displayUrl","buildDisplayUrl","iframeSrc","editorPath","buildEditorUrl","url","URL","window","sendEntryData","useCallback","data","serialized","JSON","useEffect","iframe","targetOrigin","editorOrigin","MessageOrigin","previewTarget","messenger","Messenger","timeout","setTimeout","clearTimeout","manifest","current","previous","patch","jsonPatch","reload","prev","getDraftUrl","confirmCopy","openInNewTab","PreviewDomainMenu","Tooltip","Text","IconButton","RefreshIcon","CopyButton","OpenInNewIcon","SegmentedControl","value","LaptopIcon","SmartphoneIcon","Alert","OverlayLoader"],"mappings":"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"}
@@ -28,6 +28,7 @@ const ContentEntryFormView = observer(()=>{
28
28
  const showWizard = hasWizard && null === vm.form;
29
29
  useEffect(()=>{
30
30
  if ("new" === entryId) {
31
+ formPresenter.setFolderId(listPresenter.folders.vm.currentFolderId);
31
32
  if (!newEntryWizard) formPresenter.newEntry();
32
33
  } else if (entryId) {
33
34
  formPresenter.loadRevision(entryId);
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/contentEntries/views/ContentEntryFormView.js","sources":["../../../../src/presentation/contentEntries/views/ContentEntryFormView.tsx"],"sourcesContent":["import React, { useEffect } from \"react\";\nimport { Helmet } from \"react-helmet\";\nimport { observer } from \"mobx-react-lite\";\nimport { useFeature, useRouter } from \"@webiny/app\";\nimport { Buttons, useDialogs, useRoute } from \"@webiny/app-admin\";\nimport { HeaderBar, Heading, Icon, IconButton, OverlayLoader, Tooltip } from \"@webiny/admin-ui\";\nimport { ReactComponent as BackIcon } from \"@webiny/icons/arrow_back.svg\";\nimport { ReactComponent as InfoIcon } from \"@webiny/icons/info.svg\";\nimport { useContentEntryEditorConfig } from \"~/admin/config/contentEntries/index.js\";\nimport { Routes } from \"~/routes.js\";\nimport {\n Container,\n ScrollArea,\n ContentEntryFormContent,\n ContentEntryForm\n} from \"./layout/index.js\";\nimport { RevisionsListFeature } from \"../revisionsList/feature.js\";\nimport { useContentEntriesPresenter } from \"~/presentation/contentEntries/list/useContentEntriesPresenter.js\";\nimport { useContentEntryFormPresenter } from \"~/presentation/contentEntries/form/useContentEntryFormPresenter.js\";\nimport { RevisionDrawer } from \"./RevisionDrawer.js\";\nimport { OlderRevisionAlert } from \"./OlderRevisionAlert.js\";\n\nexport const ContentEntryFormView = observer(() => {\n const listPresenter = useContentEntriesPresenter();\n const formPresenter = useContentEntryFormPresenter();\n const { presenter: revisionsPresenter } = useFeature(RevisionsListFeature);\n const { newEntryWizard, width } = useContentEntryEditorConfig();\n const router = useRouter();\n const dialogs = useDialogs();\n const { route } = useRoute(Routes.ContentEntries.List);\n\n const entryId = listPresenter.vm.selectedEntryId;\n const { vm } = formPresenter;\n\n const hasWizard = entryId === \"new\" && newEntryWizard !== null;\n const showWizard = hasWizard && vm.form === null;\n\n useEffect(() => {\n if (entryId === \"new\") {\n if (!newEntryWizard) {\n formPresenter.newEntry();\n }\n } else if (entryId) {\n formPresenter.loadRevision(entryId);\n revisionsPresenter.init(entryId);\n }\n\n return () => {\n formPresenter.reset();\n revisionsPresenter.dispose();\n };\n }, [entryId]);\n\n useEffect(() => {\n return router.addTransitionGuard({\n guard: () => formPresenter.vm.isDirty,\n onBlocked: () => {\n dialogs.showDialog({\n title: \"Confirm Navigation\",\n content:\n \"There are some unsaved changes! Are you sure you want to navigate away and discard all changes?\",\n acceptLabel: \"Yes!\",\n cancelLabel: \"No, stay here.\",\n onAccept: () => {\n // We must reset the form to prevent the guard from kicking in again.\n formPresenter.reset();\n router.confirmTransition();\n },\n onClose: () => router.cancelTransition()\n });\n }\n });\n }, []);\n\n const handleBack = () => {\n const { modelId, folderId } = route.params;\n router.goToRoute(Routes.ContentEntries.List, { modelId, folderId });\n };\n\n return (\n <Container>\n <Helmet title={vm.entry?.meta?.title || listPresenter.vm.model.name} />\n <HeaderBar\n start={\n <EntryFormHeaderLeft\n onBack={handleBack}\n title={vm.entry?.meta?.title || `New ${listPresenter.vm.model.name}`}\n isNewEntry={vm.isNewEntry}\n modelName={listPresenter.vm.model.name}\n status={vm.entry?.meta?.status ?? null}\n />\n }\n end={<EntryFormHeaderRight />}\n />\n <ScrollArea>\n {vm.loading ? <OverlayLoader text={vm.loading} /> : null}\n <OlderRevisionAlert />\n {showWizard ? (\n newEntryWizard\n ) : (\n <ContentEntryFormContent width={width}>\n <div className={\"bg-neutral-base rounded-lg p-lg\"}>\n <ContentEntryForm />\n </div>\n </ContentEntryFormContent>\n )}\n </ScrollArea>\n <RevisionDrawer />\n </Container>\n );\n});\n\ninterface EntryFormHeaderLeftProps {\n onBack: () => void;\n title: string;\n isNewEntry: boolean;\n modelName: string;\n status: string | null;\n}\n\nconst EntryFormHeaderLeft = ({\n onBack,\n title,\n isNewEntry,\n modelName,\n status\n}: EntryFormHeaderLeftProps) => {\n return (\n <div className={\"flex items-center gap-sm\"}>\n <IconButton variant={\"ghost\"} onClick={onBack} icon={<BackIcon />} />\n <Heading level={5} className={`text-neutral-primary${isNewEntry ? \" opacity-50\" : \"\"}`}>\n {title}\n </Heading>\n <Tooltip\n content={`Model: ${modelName}${status ? ` - Status: ${status}` : \"\"}`}\n trigger={\n <Icon icon={<InfoIcon />} label={\"Info\"} size={\"sm\"} color={\"neutral-light\"} />\n }\n />\n </div>\n );\n};\n\nconst EntryFormHeaderRight = observer(() => {\n const presenter = useContentEntryFormPresenter();\n const { buttonActions } = useContentEntryEditorConfig();\n\n const { canSave, canPublish, canUnpublish, canDelete } = presenter.vm;\n\n if (!canSave && !canPublish && !canUnpublish && !canDelete) {\n return <div />;\n }\n\n return (\n <div className={\"flex items-center gap-sm\"}>\n <Buttons actions={buttonActions} />\n </div>\n );\n});\n"],"names":["ContentEntryFormView","observer","listPresenter","useContentEntriesPresenter","formPresenter","useContentEntryFormPresenter","revisionsPresenter","useFeature","RevisionsListFeature","newEntryWizard","width","useContentEntryEditorConfig","router","useRouter","dialogs","useDialogs","route","useRoute","Routes","entryId","vm","hasWizard","showWizard","useEffect","handleBack","modelId","folderId","Container","Helmet","HeaderBar","EntryFormHeaderLeft","EntryFormHeaderRight","ScrollArea","OverlayLoader","OlderRevisionAlert","ContentEntryFormContent","ContentEntryForm","RevisionDrawer","onBack","title","isNewEntry","modelName","status","IconButton","BackIcon","Heading","Tooltip","Icon","InfoIcon","presenter","buttonActions","canSave","canPublish","canUnpublish","canDelete","Buttons"],"mappings":"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"}
1
+ {"version":3,"file":"presentation/contentEntries/views/ContentEntryFormView.js","sources":["../../../../src/presentation/contentEntries/views/ContentEntryFormView.tsx"],"sourcesContent":["import React, { useEffect } from \"react\";\nimport { Helmet } from \"react-helmet\";\nimport { observer } from \"mobx-react-lite\";\nimport { useFeature, useRouter } from \"@webiny/app\";\nimport { Buttons, useDialogs, useRoute } from \"@webiny/app-admin\";\nimport { HeaderBar, Heading, Icon, IconButton, OverlayLoader, Tooltip } from \"@webiny/admin-ui\";\nimport { ReactComponent as BackIcon } from \"@webiny/icons/arrow_back.svg\";\nimport { ReactComponent as InfoIcon } from \"@webiny/icons/info.svg\";\nimport { useContentEntryEditorConfig } from \"~/admin/config/contentEntries/index.js\";\nimport { Routes } from \"~/routes.js\";\nimport {\n Container,\n ScrollArea,\n ContentEntryFormContent,\n ContentEntryForm\n} from \"./layout/index.js\";\nimport { RevisionsListFeature } from \"../revisionsList/feature.js\";\nimport { useContentEntriesPresenter } from \"~/presentation/contentEntries/list/useContentEntriesPresenter.js\";\nimport { useContentEntryFormPresenter } from \"~/presentation/contentEntries/form/useContentEntryFormPresenter.js\";\nimport { RevisionDrawer } from \"./RevisionDrawer.js\";\nimport { OlderRevisionAlert } from \"./OlderRevisionAlert.js\";\n\nexport const ContentEntryFormView = observer(() => {\n const listPresenter = useContentEntriesPresenter();\n const formPresenter = useContentEntryFormPresenter();\n const { presenter: revisionsPresenter } = useFeature(RevisionsListFeature);\n const { newEntryWizard, width } = useContentEntryEditorConfig();\n const router = useRouter();\n const dialogs = useDialogs();\n const { route } = useRoute(Routes.ContentEntries.List);\n\n const entryId = listPresenter.vm.selectedEntryId;\n const { vm } = formPresenter;\n\n const hasWizard = entryId === \"new\" && newEntryWizard !== null;\n const showWizard = hasWizard && vm.form === null;\n\n useEffect(() => {\n if (entryId === \"new\") {\n // Wizards start the entry later, so the folder is set for them too.\n formPresenter.setFolderId(listPresenter.folders.vm.currentFolderId);\n if (!newEntryWizard) {\n formPresenter.newEntry();\n }\n } else if (entryId) {\n formPresenter.loadRevision(entryId);\n revisionsPresenter.init(entryId);\n }\n\n return () => {\n formPresenter.reset();\n revisionsPresenter.dispose();\n };\n }, [entryId]);\n\n useEffect(() => {\n return router.addTransitionGuard({\n guard: () => formPresenter.vm.isDirty,\n onBlocked: () => {\n dialogs.showDialog({\n title: \"Confirm Navigation\",\n content:\n \"There are some unsaved changes! Are you sure you want to navigate away and discard all changes?\",\n acceptLabel: \"Yes!\",\n cancelLabel: \"No, stay here.\",\n onAccept: () => {\n // We must reset the form to prevent the guard from kicking in again.\n formPresenter.reset();\n router.confirmTransition();\n },\n onClose: () => router.cancelTransition()\n });\n }\n });\n }, []);\n\n const handleBack = () => {\n const { modelId, folderId } = route.params;\n router.goToRoute(Routes.ContentEntries.List, { modelId, folderId });\n };\n\n return (\n <Container>\n <Helmet title={vm.entry?.meta?.title || listPresenter.vm.model.name} />\n <HeaderBar\n start={\n <EntryFormHeaderLeft\n onBack={handleBack}\n title={vm.entry?.meta?.title || `New ${listPresenter.vm.model.name}`}\n isNewEntry={vm.isNewEntry}\n modelName={listPresenter.vm.model.name}\n status={vm.entry?.meta?.status ?? null}\n />\n }\n end={<EntryFormHeaderRight />}\n />\n <ScrollArea>\n {vm.loading ? <OverlayLoader text={vm.loading} /> : null}\n <OlderRevisionAlert />\n {showWizard ? (\n newEntryWizard\n ) : (\n <ContentEntryFormContent width={width}>\n <div className={\"bg-neutral-base rounded-lg p-lg\"}>\n <ContentEntryForm />\n </div>\n </ContentEntryFormContent>\n )}\n </ScrollArea>\n <RevisionDrawer />\n </Container>\n );\n});\n\ninterface EntryFormHeaderLeftProps {\n onBack: () => void;\n title: string;\n isNewEntry: boolean;\n modelName: string;\n status: string | null;\n}\n\nconst EntryFormHeaderLeft = ({\n onBack,\n title,\n isNewEntry,\n modelName,\n status\n}: EntryFormHeaderLeftProps) => {\n return (\n <div className={\"flex items-center gap-sm\"}>\n <IconButton variant={\"ghost\"} onClick={onBack} icon={<BackIcon />} />\n <Heading level={5} className={`text-neutral-primary${isNewEntry ? \" opacity-50\" : \"\"}`}>\n {title}\n </Heading>\n <Tooltip\n content={`Model: ${modelName}${status ? ` - Status: ${status}` : \"\"}`}\n trigger={\n <Icon icon={<InfoIcon />} label={\"Info\"} size={\"sm\"} color={\"neutral-light\"} />\n }\n />\n </div>\n );\n};\n\nconst EntryFormHeaderRight = observer(() => {\n const presenter = useContentEntryFormPresenter();\n const { buttonActions } = useContentEntryEditorConfig();\n\n const { canSave, canPublish, canUnpublish, canDelete } = presenter.vm;\n\n if (!canSave && !canPublish && !canUnpublish && !canDelete) {\n return <div />;\n }\n\n return (\n <div className={\"flex items-center gap-sm\"}>\n <Buttons actions={buttonActions} />\n </div>\n );\n});\n"],"names":["ContentEntryFormView","observer","listPresenter","useContentEntriesPresenter","formPresenter","useContentEntryFormPresenter","revisionsPresenter","useFeature","RevisionsListFeature","newEntryWizard","width","useContentEntryEditorConfig","router","useRouter","dialogs","useDialogs","route","useRoute","Routes","entryId","vm","hasWizard","showWizard","useEffect","handleBack","modelId","folderId","Container","Helmet","HeaderBar","EntryFormHeaderLeft","EntryFormHeaderRight","ScrollArea","OverlayLoader","OlderRevisionAlert","ContentEntryFormContent","ContentEntryForm","RevisionDrawer","onBack","title","isNewEntry","modelName","status","IconButton","BackIcon","Heading","Tooltip","Icon","InfoIcon","presenter","buttonActions","canSave","canPublish","canUnpublish","canDelete","Buttons"],"mappings":"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"}
@@ -1,5 +1,12 @@
1
1
  import { CmsFieldEditorGroup } from "../abstractions.js";
2
2
  import { CmsFieldRenderer } from "../../fieldRenderers/abstractions.js";
3
+ const getOptionalValue = (form, path)=>{
4
+ try {
5
+ return form.field(path).getValue();
6
+ } catch {
7
+ return;
8
+ }
9
+ };
3
10
  class AppearanceGroupImpl {
4
11
  constructor(allRenderers){
5
12
  this.allRenderers = allRenderers;
@@ -13,9 +20,14 @@ class AppearanceGroupImpl {
13
20
  name: fields.text().options(({ form })=>{
14
21
  const list = Boolean(form.field("general.list").getValue());
15
22
  const predefined = Boolean(form.field("general.predefinedValuesEnabled").getValue());
23
+ const settingsType = getOptionalValue(form, "general.settingsType");
16
24
  const liveField = {
17
25
  ...context.field,
18
26
  list,
27
+ settings: "string" == typeof settingsType ? {
28
+ ...context.field.settings,
29
+ type: settingsType
30
+ } : context.field.settings,
19
31
  predefinedValues: {
20
32
  values: context.field.predefinedValues?.values ?? [],
21
33
  enabled: predefined
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/fieldEditor/groups/AppearanceGroup.js","sources":["../../../../src/presentation/fieldEditor/groups/AppearanceGroup.ts"],"sourcesContent":["import { CmsFieldEditorGroup } from \"../abstractions.js\";\nimport type { ICmsFieldEditorFormBuilder, ICmsFieldEditorContext } from \"../abstractions.js\";\nimport type { CmsModelField } from \"~/types.js\";\nimport { CmsFieldRenderer } from \"~/presentation/fieldRenderers/abstractions.js\";\nimport type {\n ICmsFieldRenderer,\n ICmsFieldRendererFormBuilder\n} from \"~/presentation/fieldRenderers/abstractions.js\";\nimport type { FormModelFactory, FormModel } from \"@webiny/app-admin\";\n\ndeclare module \"@webiny/app-admin/features/formModel/abstractions.js\" {\n interface IFieldRendererRegistry {\n cmsAppearance: { fieldType: \"object\"; settings: undefined };\n }\n}\n\ninterface RendererSettingsBuild {\n rendererName: string;\n fieldsFns: Array<\n (f: FormModelFactory.FieldBuilderRegistry) => Record<string, FormModelFactory.FieldBuilder>\n >;\n layoutFns: Array<(l: FormModelFactory.LayoutBuilder) => FormModel.LayoutNodeBuilder[]>;\n}\n\nclass AppearanceGroupImpl implements CmsFieldEditorGroup.Interface {\n name = \"appearance\";\n label = \"Appearance\";\n\n constructor(private allRenderers: ICmsFieldRenderer[]) {}\n\n buildForm(form: ICmsFieldEditorFormBuilder, context: ICmsFieldEditorContext) {\n const settingsBuilds = this.collectRendererSettings(this.allRenderers);\n\n form.fields(fields => {\n const rendererChildren: Record<string, FormModelFactory.FieldBuilder> = {\n name: fields.text().options(({ form }) => {\n const list = Boolean(form.field(\"general.list\").getValue());\n const predefined = Boolean(\n form.field(\"general.predefinedValuesEnabled\").getValue()\n );\n const liveField = {\n ...context.field,\n list,\n predefinedValues: {\n values: context.field.predefinedValues?.values ?? [],\n enabled: predefined\n }\n };\n\n return this.allRenderers\n .filter(r => r.canUse({ field: liveField, model: context.model }))\n .map(r => ({ label: r.name, value: r.rendererName }));\n })\n };\n\n for (const build of settingsBuilds) {\n const notSelected = ({ field }: FormModel.CallbackParams) =>\n field.parent().field(\"name\").getValue() !== build.rendererName;\n\n rendererChildren[`settings__${build.rendererName}`] = fields\n .object()\n .renderer(\"passthrough\")\n .hiddenWhen(notSelected)\n .fields((f: FormModelFactory.FieldBuilderRegistry) => {\n const merged: Record<string, FormModelFactory.FieldBuilder> = {};\n for (const fn of build.fieldsFns) {\n Object.assign(merged, fn(f));\n }\n return merged;\n });\n }\n\n return {\n renderer: fields\n .object()\n .renderer(\"cmsAppearance\")\n .fields(() => rendererChildren)\n };\n });\n\n form.layout(layout => {\n const innerLayout = (inner: FormModelFactory.LayoutBuilder) => {\n const nodes: FormModel.LayoutNodeBuilder[] = [inner.row(\"name\")];\n for (const build of settingsBuilds) {\n nodes.push(\n inner.object(`settings__${build.rendererName}`, settingsInner =>\n build.layoutFns.flatMap(fn => fn(settingsInner))\n )\n );\n }\n return nodes;\n };\n\n return [layout.object(\"renderer\", innerLayout)];\n });\n }\n\n mapToForm(field: CmsModelField) {\n const renderer = typeof field.renderer === \"object\" ? field.renderer : null;\n const rendererName = renderer ? renderer.name : \"\";\n const settings = renderer ? (renderer.settings ?? {}) : {};\n\n const result: Record<string, unknown> = {\n name: rendererName\n };\n\n for (const r of this.allRenderers) {\n if (r.buildSettingsForm) {\n result[`settings__${r.rendererName}`] =\n r.rendererName === rendererName ? settings : {};\n }\n }\n\n return { renderer: result };\n }\n\n mapFromForm(formData: Record<string, any>, field: CmsModelField) {\n const rendererName = formData.renderer?.name || \"\";\n const settingsKey = `settings__${rendererName}`;\n const settings = formData.renderer?.[settingsKey] ?? {};\n\n field.renderer = {\n name: rendererName,\n settings\n };\n }\n\n private collectRendererSettings(renderers: ICmsFieldRenderer[]): RendererSettingsBuild[] {\n const builds: RendererSettingsBuild[] = [];\n\n for (const renderer of renderers) {\n if (!renderer.buildSettingsForm) {\n continue;\n }\n\n const fieldsFns: RendererSettingsBuild[\"fieldsFns\"] = [];\n const layoutFns: RendererSettingsBuild[\"layoutFns\"] = [];\n\n const builder: ICmsFieldRendererFormBuilder = {\n fields: fn => {\n fieldsFns.push(fn);\n },\n layout: fn => {\n layoutFns.push(fn);\n }\n };\n\n renderer.buildSettingsForm(builder);\n\n if (fieldsFns.length > 0) {\n builds.push({ rendererName: renderer.rendererName, fieldsFns, layoutFns });\n }\n }\n\n return builds;\n }\n}\n\nexport const AppearanceGroup = CmsFieldEditorGroup.createImplementation({\n implementation: AppearanceGroupImpl,\n dependencies: [[CmsFieldRenderer, { multiple: true }]]\n});\n"],"names":["AppearanceGroupImpl","allRenderers","form","context","settingsBuilds","fields","rendererChildren","list","Boolean","predefined","liveField","r","build","notSelected","field","f","merged","fn","Object","layout","innerLayout","inner","nodes","settingsInner","renderer","rendererName","settings","result","formData","settingsKey","renderers","builds","fieldsFns","layoutFns","builder","AppearanceGroup","CmsFieldEditorGroup","CmsFieldRenderer"],"mappings":"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"}
1
+ {"version":3,"file":"presentation/fieldEditor/groups/AppearanceGroup.js","sources":["../../../../src/presentation/fieldEditor/groups/AppearanceGroup.ts"],"sourcesContent":["import { CmsFieldEditorGroup } from \"../abstractions.js\";\nimport type { ICmsFieldEditorFormBuilder, ICmsFieldEditorContext } from \"../abstractions.js\";\nimport type { CmsModelField } from \"~/types.js\";\nimport { CmsFieldRenderer } from \"~/presentation/fieldRenderers/abstractions.js\";\nimport type {\n ICmsFieldRenderer,\n ICmsFieldRendererFormBuilder\n} from \"~/presentation/fieldRenderers/abstractions.js\";\nimport type { FormModelFactory, FormModel } from \"@webiny/app-admin\";\n\ndeclare module \"@webiny/app-admin/features/formModel/abstractions.js\" {\n interface IFieldRendererRegistry {\n cmsAppearance: { fieldType: \"object\"; settings: undefined };\n }\n}\n\n/**\n * Only some field types add the field (date/time adds `general.settingsType`, the Format\n * dropdown), and `form.field()` throws for a path the form doesn't have.\n */\nconst getOptionalValue = (form: FormModel.Interface, path: string): unknown => {\n try {\n return form.field(path).getValue();\n } catch {\n return undefined;\n }\n};\n\ninterface RendererSettingsBuild {\n rendererName: string;\n fieldsFns: Array<\n (f: FormModelFactory.FieldBuilderRegistry) => Record<string, FormModelFactory.FieldBuilder>\n >;\n layoutFns: Array<(l: FormModelFactory.LayoutBuilder) => FormModel.LayoutNodeBuilder[]>;\n}\n\nclass AppearanceGroupImpl implements CmsFieldEditorGroup.Interface {\n name = \"appearance\";\n label = \"Appearance\";\n\n constructor(private allRenderers: ICmsFieldRenderer[]) {}\n\n buildForm(form: ICmsFieldEditorFormBuilder, context: ICmsFieldEditorContext) {\n const settingsBuilds = this.collectRendererSettings(this.allRenderers);\n\n form.fields(fields => {\n const rendererChildren: Record<string, FormModelFactory.FieldBuilder> = {\n name: fields.text().options(({ form }) => {\n const list = Boolean(form.field(\"general.list\").getValue());\n const predefined = Boolean(\n form.field(\"general.predefinedValuesEnabled\").getValue()\n );\n const settingsType = getOptionalValue(form, \"general.settingsType\");\n const liveField = {\n ...context.field,\n list,\n settings:\n typeof settingsType === \"string\"\n ? { ...context.field.settings, type: settingsType }\n : context.field.settings,\n predefinedValues: {\n values: context.field.predefinedValues?.values ?? [],\n enabled: predefined\n }\n };\n\n return this.allRenderers\n .filter(r => r.canUse({ field: liveField, model: context.model }))\n .map(r => ({ label: r.name, value: r.rendererName }));\n })\n };\n\n for (const build of settingsBuilds) {\n const notSelected = ({ field }: FormModel.CallbackParams) =>\n field.parent().field(\"name\").getValue() !== build.rendererName;\n\n rendererChildren[`settings__${build.rendererName}`] = fields\n .object()\n .renderer(\"passthrough\")\n .hiddenWhen(notSelected)\n .fields((f: FormModelFactory.FieldBuilderRegistry) => {\n const merged: Record<string, FormModelFactory.FieldBuilder> = {};\n for (const fn of build.fieldsFns) {\n Object.assign(merged, fn(f));\n }\n return merged;\n });\n }\n\n return {\n renderer: fields\n .object()\n .renderer(\"cmsAppearance\")\n .fields(() => rendererChildren)\n };\n });\n\n form.layout(layout => {\n const innerLayout = (inner: FormModelFactory.LayoutBuilder) => {\n const nodes: FormModel.LayoutNodeBuilder[] = [inner.row(\"name\")];\n for (const build of settingsBuilds) {\n nodes.push(\n inner.object(`settings__${build.rendererName}`, settingsInner =>\n build.layoutFns.flatMap(fn => fn(settingsInner))\n )\n );\n }\n return nodes;\n };\n\n return [layout.object(\"renderer\", innerLayout)];\n });\n }\n\n mapToForm(field: CmsModelField) {\n const renderer = typeof field.renderer === \"object\" ? field.renderer : null;\n const rendererName = renderer ? renderer.name : \"\";\n const settings = renderer ? (renderer.settings ?? {}) : {};\n\n const result: Record<string, unknown> = {\n name: rendererName\n };\n\n for (const r of this.allRenderers) {\n if (r.buildSettingsForm) {\n result[`settings__${r.rendererName}`] =\n r.rendererName === rendererName ? settings : {};\n }\n }\n\n return { renderer: result };\n }\n\n mapFromForm(formData: Record<string, any>, field: CmsModelField) {\n const rendererName = formData.renderer?.name || \"\";\n const settingsKey = `settings__${rendererName}`;\n const settings = formData.renderer?.[settingsKey] ?? {};\n\n field.renderer = {\n name: rendererName,\n settings\n };\n }\n\n private collectRendererSettings(renderers: ICmsFieldRenderer[]): RendererSettingsBuild[] {\n const builds: RendererSettingsBuild[] = [];\n\n for (const renderer of renderers) {\n if (!renderer.buildSettingsForm) {\n continue;\n }\n\n const fieldsFns: RendererSettingsBuild[\"fieldsFns\"] = [];\n const layoutFns: RendererSettingsBuild[\"layoutFns\"] = [];\n\n const builder: ICmsFieldRendererFormBuilder = {\n fields: fn => {\n fieldsFns.push(fn);\n },\n layout: fn => {\n layoutFns.push(fn);\n }\n };\n\n renderer.buildSettingsForm(builder);\n\n if (fieldsFns.length > 0) {\n builds.push({ rendererName: renderer.rendererName, fieldsFns, layoutFns });\n }\n }\n\n return builds;\n }\n}\n\nexport const AppearanceGroup = CmsFieldEditorGroup.createImplementation({\n implementation: AppearanceGroupImpl,\n dependencies: [[CmsFieldRenderer, { multiple: true }]]\n});\n"],"names":["getOptionalValue","form","path","AppearanceGroupImpl","allRenderers","context","settingsBuilds","fields","rendererChildren","list","Boolean","predefined","settingsType","liveField","r","build","notSelected","field","f","merged","fn","Object","layout","innerLayout","inner","nodes","settingsInner","renderer","rendererName","settings","result","formData","settingsKey","renderers","builds","fieldsFns","layoutFns","builder","AppearanceGroup","CmsFieldEditorGroup","CmsFieldRenderer"],"mappings":"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"}
@@ -16,6 +16,8 @@ declare class ValidationsGroupImpl implements CmsFieldEditorGroup.Interface {
16
16
  };
17
17
  mapFromForm(formData: Record<string, unknown>, field: CmsModelField): void;
18
18
  private flattenValidators;
19
+ private settingsToForm;
20
+ private settingsFromForm;
19
21
  }
20
22
  export declare const ValidationsGroup: typeof ValidationsGroupImpl & {
21
23
  __abstraction: import("@webiny/di").Abstraction<import("../abstractions.js").ICmsFieldEditorGroup>;
@@ -128,14 +128,14 @@ class ValidationsGroupImpl {
128
128
  validationMap[validator.name] = {
129
129
  enabled: true,
130
130
  message: validator.message,
131
- settings: validator.settings || {}
131
+ settings: this.settingsToForm(validator.name, validator.settings || {}, field)
132
132
  };
133
133
  }
134
134
  const listValidationMap = {};
135
135
  for (const v of field.listValidation || [])listValidationMap[v.name] = {
136
136
  enabled: true,
137
137
  message: v.message,
138
- settings: v.settings || {}
138
+ settings: this.settingsToForm(v.name, v.settings || {}, field)
139
139
  };
140
140
  return {
141
141
  validation: validationMap,
@@ -143,16 +143,30 @@ class ValidationsGroupImpl {
143
143
  };
144
144
  }
145
145
  mapFromForm(formData, field) {
146
- field.validation = this.flattenValidators(formData.validation || {});
147
- field.listValidation = this.flattenValidators(formData.listValidation || {});
146
+ field.validation = this.flattenValidators(formData.validation || {}, field);
147
+ field.listValidation = this.flattenValidators(formData.listValidation || {}, field);
148
148
  }
149
- flattenValidators(data) {
149
+ flattenValidators(data, field) {
150
150
  return Object.entries(data).filter(([_, v])=>v && v.enabled).map(([name, v])=>({
151
151
  name,
152
152
  message: v.message,
153
- settings: v.settings
153
+ settings: this.settingsFromForm(name, v.settings, field)
154
154
  }));
155
155
  }
156
+ settingsToForm(name, settings, field) {
157
+ const validator = this.allValidators.find((v)=>v.name === name);
158
+ if (!validator?.mapSettingsToForm) return settings;
159
+ return validator.mapSettingsToForm(settings, {
160
+ field
161
+ });
162
+ }
163
+ settingsFromForm(name, settings, field) {
164
+ const validator = this.allValidators.find((v)=>v.name === name);
165
+ if (!settings || !validator?.mapSettingsFromForm) return settings;
166
+ return validator.mapSettingsFromForm(settings, {
167
+ field
168
+ });
169
+ }
156
170
  }
157
171
  const ValidationsGroup = CmsFieldEditorGroup.createImplementation({
158
172
  implementation: ValidationsGroupImpl,
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/fieldEditor/groups/ValidationsGroup.js","sources":["../../../../src/presentation/fieldEditor/groups/ValidationsGroup.ts"],"sourcesContent":["import { CmsFieldEditorGroup } from \"../abstractions.js\";\nimport type { ICmsFieldEditorFormBuilder, ICmsFieldEditorContext } from \"../abstractions.js\";\nimport type { CmsModelField } from \"~/types.js\";\nimport type { CmsModelFieldValidatorsGroup } from \"~/presentation/fieldTypes/abstractions.js\";\nimport { CmsFieldValidator } from \"~/presentation/fieldValidators/abstractions.js\";\nimport type {\n ICmsFieldValidator,\n ICmsFieldValidatorFormBuilder\n} from \"~/presentation/fieldValidators/abstractions.js\";\nimport type { FormModelFactory, FormModel } from \"@webiny/app-admin\";\n\nfunction resolveValidatorNames(\n config:\n | string[]\n | CmsModelFieldValidatorsGroup\n | ((field: CmsModelField) => string[] | CmsModelFieldValidatorsGroup)\n | undefined,\n field: CmsModelField\n): string[] {\n if (!config) {\n return [];\n }\n if (typeof config === \"function\") {\n return resolveValidatorNames(config(field), field);\n }\n if (Array.isArray(config)) {\n return config;\n }\n return config.validators.map(v => (typeof v === \"string\" ? v : v.name));\n}\n\ninterface ValidatorBuildResult {\n fields: Record<string, FormModelFactory.FieldBuilder>;\n layouts: Map<\n string,\n {\n settingsLayoutFns: Array<\n (l: FormModelFactory.LayoutBuilder) => FormModel.LayoutNodeBuilder[]\n >;\n hasSettings: boolean;\n }\n >;\n}\n\nclass ValidationsGroupImpl implements CmsFieldEditorGroup.Interface {\n name = \"validations\";\n label = \"Validations\";\n\n constructor(private allValidators: ICmsFieldValidator[]) {}\n\n buildForm(form: ICmsFieldEditorFormBuilder, context: ICmsFieldEditorContext) {\n const fieldValidatorNames = resolveValidatorNames(\n context.fieldType.validators,\n context.field\n );\n const DEFAULT_LIST_VALIDATORS = [\"minLength\", \"maxLength\"];\n const listValidatorNames =\n resolveValidatorNames(context.fieldType.listValidators, context.field).length > 0\n ? resolveValidatorNames(context.fieldType.listValidators, context.field)\n : DEFAULT_LIST_VALIDATORS;\n\n const fieldValidators = this.allValidators.filter(v =>\n fieldValidatorNames.includes(v.name)\n );\n const listValidators = this.allValidators.filter(v => listValidatorNames.includes(v.name));\n\n let fieldResult: ValidatorBuildResult | null = null;\n let listResult: ValidatorBuildResult | null = null;\n\n form.fields(fields => {\n const result: Record<string, FormModelFactory.FieldBuilder> = {};\n\n if (listValidators.length > 0) {\n listResult = this.buildValidatorFields(\n fields as FormModelFactory.FieldBuilderRegistry,\n listValidators,\n context\n );\n result.listValidation = fields\n .object()\n .renderer(\"passthrough\")\n .hiddenWhen(\n ({ form }: FormModel.CallbackParams) =>\n !form.field(\"general.list\").getValue()\n )\n .fields(() => listResult!.fields);\n }\n\n if (fieldValidators.length > 0) {\n fieldResult = this.buildValidatorFields(\n fields as FormModelFactory.FieldBuilderRegistry,\n fieldValidators,\n context\n );\n result.validation = fields\n .object()\n .renderer(\"passthrough\")\n .fields(() => fieldResult!.fields);\n }\n\n return result;\n });\n\n const listRule = {\n type: \"condition\",\n target: \"general.list\",\n operator: \"isFalsy\",\n value: null,\n action: \"hide\" as const\n };\n\n form.layout(layout => {\n const rows: FormModel.LayoutNodeBuilder[] = [];\n\n if (listValidators.length > 0 && listResult) {\n rows.push(\n layout\n .separator()\n .title(\"List validators\")\n .description(\"These validators are applied to the entire list of values.\")\n .rules([listRule])\n );\n rows.push(\n layout.object(\"listValidation\", inner =>\n this.buildValidatorLayouts(inner, listValidators, listResult!)\n )\n );\n }\n\n if (fieldValidators.length > 0 && fieldResult) {\n if (listValidators.length > 0) {\n rows.push(\n layout\n .separator()\n .title(\"Individual value validators\")\n .description(\"These validators are applied to each value in the list.\")\n .rules([listRule])\n );\n }\n rows.push(\n layout.object(\"validation\", inner =>\n this.buildValidatorLayouts(inner, fieldValidators, fieldResult!)\n )\n );\n }\n\n return rows;\n });\n }\n\n private buildValidatorLayouts(\n layout: FormModelFactory.LayoutBuilder,\n validators: ICmsFieldValidator[],\n result: ValidatorBuildResult\n ): FormModel.LayoutNodeBuilder[] {\n return validators.map(validator => {\n const meta = result.layouts.get(validator.name);\n return layout.object(validator.name, inner => {\n const rows: FormModel.LayoutNodeBuilder[] = [inner.row(\"message\")];\n if (meta && meta.hasSettings) {\n rows.push(\n inner.object(\"settings\", settingsLayout =>\n meta.settingsLayoutFns.flatMap(fn => fn(settingsLayout))\n )\n );\n }\n return rows;\n });\n });\n }\n\n private buildValidatorFields(\n fields: FormModelFactory.FieldBuilderRegistry,\n validators: ICmsFieldValidator[],\n context: ICmsFieldEditorContext\n ): ValidatorBuildResult {\n const resultFields: Record<string, FormModelFactory.FieldBuilder> = {};\n const layouts = new Map<\n string,\n {\n settingsLayoutFns: Array<\n (l: FormModelFactory.LayoutBuilder) => FormModel.LayoutNodeBuilder[]\n >;\n hasSettings: boolean;\n }\n >();\n\n for (const validator of validators) {\n let messageDescription = \"This message will be displayed to the user.\";\n if (validator.variables && validator.variables.length > 0) {\n const vars = validator.variables.map(v => `{${v.name}}`).join(\", \");\n messageDescription += ` Available variables: ${vars}.`;\n }\n\n const notEnabled = ({ field }: FormModel.CallbackParams) =>\n !field.parent().field(\"enabled\").getValue();\n\n const childFields: Record<string, FormModelFactory.FieldBuilder> = {\n enabled: fields.boolean().label(\"Enabled\").defaultValue(false).hidden(),\n message: fields\n .text()\n .label(\"Message\")\n .description(messageDescription)\n .defaultValue(validator.defaultMessage)\n .hiddenWhen(notEnabled)\n };\n\n const settingsLayoutFns: Array<\n (l: FormModelFactory.LayoutBuilder) => FormModel.LayoutNodeBuilder[]\n > = [];\n let hasSettings = false;\n\n if (validator.buildSettingsForm) {\n const settingsFieldsFns: Array<\n (\n f: FormModelFactory.FieldBuilderRegistry\n ) => Record<string, FormModelFactory.FieldBuilder>\n > = [];\n\n const builder: ICmsFieldValidatorFormBuilder = {\n message: childFields.message,\n fields: fn => {\n settingsFieldsFns.push(fn);\n },\n layout: fn => {\n settingsLayoutFns.push(fn);\n }\n };\n validator.buildSettingsForm(builder, { field: context.field });\n\n if (settingsFieldsFns.length > 0) {\n hasSettings = true;\n childFields.settings = fields\n .object()\n .renderer(\"passthrough\")\n .hiddenWhen(notEnabled)\n .fields((f: FormModelFactory.FieldBuilderRegistry) => {\n const merged: Record<string, FormModelFactory.FieldBuilder> = {};\n for (const fn of settingsFieldsFns) {\n Object.assign(merged, fn(f));\n }\n return merged;\n });\n }\n }\n\n layouts.set(validator.name, { settingsLayoutFns, hasSettings });\n\n resultFields[validator.name] = fields\n .object()\n .label(validator.label)\n .description(validator.description)\n .renderer(\"cmsValidatorItem\")\n .fields(() => childFields);\n }\n\n return { fields: resultFields, layouts };\n }\n\n mapToForm(field: CmsModelField) {\n const validationMap: Record<string, Record<string, unknown>> = {};\n for (const v of field.validation || []) {\n const validator = v as {\n name: string;\n message?: string;\n settings?: Record<string, unknown>;\n };\n validationMap[validator.name] = {\n enabled: true,\n message: validator.message,\n settings: validator.settings || {}\n };\n }\n\n const listValidationMap: Record<string, Record<string, unknown>> = {};\n for (const v of field.listValidation || []) {\n listValidationMap[v.name] = {\n enabled: true,\n message: v.message,\n settings: v.settings || {}\n };\n }\n\n return {\n validation: validationMap,\n listValidation: listValidationMap\n };\n }\n\n mapFromForm(formData: Record<string, unknown>, field: CmsModelField) {\n field.validation = this.flattenValidators(\n (formData.validation || {}) as Record<string, any>\n );\n field.listValidation = this.flattenValidators(\n (formData.listValidation || {}) as Record<string, any>\n );\n }\n\n private flattenValidators(\n data: Record<\n string,\n {\n enabled?: boolean;\n message?: string;\n settings?: Record<string, unknown>;\n }\n >\n ) {\n return Object.entries(data)\n .filter(([_, v]) => v && v.enabled)\n .map(([name, v]) => ({\n name,\n message: v.message,\n settings: v.settings\n }));\n }\n}\n\nexport const ValidationsGroup = CmsFieldEditorGroup.createImplementation({\n implementation: ValidationsGroupImpl,\n dependencies: [[CmsFieldValidator, { multiple: true }]]\n});\n"],"names":["resolveValidatorNames","config","field","Array","v","ValidationsGroupImpl","allValidators","form","context","fieldValidatorNames","DEFAULT_LIST_VALIDATORS","listValidatorNames","fieldValidators","listValidators","fieldResult","listResult","fields","result","listRule","layout","rows","inner","validators","validator","meta","settingsLayout","fn","resultFields","layouts","Map","messageDescription","vars","notEnabled","childFields","settingsLayoutFns","hasSettings","settingsFieldsFns","builder","f","merged","Object","validationMap","listValidationMap","formData","data","_","name","ValidationsGroup","CmsFieldEditorGroup","CmsFieldValidator"],"mappings":"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"}
1
+ {"version":3,"file":"presentation/fieldEditor/groups/ValidationsGroup.js","sources":["../../../../src/presentation/fieldEditor/groups/ValidationsGroup.ts"],"sourcesContent":["import { CmsFieldEditorGroup } from \"../abstractions.js\";\nimport type { ICmsFieldEditorFormBuilder, ICmsFieldEditorContext } from \"../abstractions.js\";\nimport type { CmsModelField } from \"~/types.js\";\nimport type { CmsModelFieldValidatorsGroup } from \"~/presentation/fieldTypes/abstractions.js\";\nimport { CmsFieldValidator } from \"~/presentation/fieldValidators/abstractions.js\";\nimport type {\n ICmsFieldValidator,\n ICmsFieldValidatorFormBuilder\n} from \"~/presentation/fieldValidators/abstractions.js\";\nimport type { FormModelFactory, FormModel } from \"@webiny/app-admin\";\n\nfunction resolveValidatorNames(\n config:\n | string[]\n | CmsModelFieldValidatorsGroup\n | ((field: CmsModelField) => string[] | CmsModelFieldValidatorsGroup)\n | undefined,\n field: CmsModelField\n): string[] {\n if (!config) {\n return [];\n }\n if (typeof config === \"function\") {\n return resolveValidatorNames(config(field), field);\n }\n if (Array.isArray(config)) {\n return config;\n }\n return config.validators.map(v => (typeof v === \"string\" ? v : v.name));\n}\n\ninterface ValidatorBuildResult {\n fields: Record<string, FormModelFactory.FieldBuilder>;\n layouts: Map<\n string,\n {\n settingsLayoutFns: Array<\n (l: FormModelFactory.LayoutBuilder) => FormModel.LayoutNodeBuilder[]\n >;\n hasSettings: boolean;\n }\n >;\n}\n\nclass ValidationsGroupImpl implements CmsFieldEditorGroup.Interface {\n name = \"validations\";\n label = \"Validations\";\n\n constructor(private allValidators: ICmsFieldValidator[]) {}\n\n buildForm(form: ICmsFieldEditorFormBuilder, context: ICmsFieldEditorContext) {\n const fieldValidatorNames = resolveValidatorNames(\n context.fieldType.validators,\n context.field\n );\n const DEFAULT_LIST_VALIDATORS = [\"minLength\", \"maxLength\"];\n const listValidatorNames =\n resolveValidatorNames(context.fieldType.listValidators, context.field).length > 0\n ? resolveValidatorNames(context.fieldType.listValidators, context.field)\n : DEFAULT_LIST_VALIDATORS;\n\n const fieldValidators = this.allValidators.filter(v =>\n fieldValidatorNames.includes(v.name)\n );\n const listValidators = this.allValidators.filter(v => listValidatorNames.includes(v.name));\n\n let fieldResult: ValidatorBuildResult | null = null;\n let listResult: ValidatorBuildResult | null = null;\n\n form.fields(fields => {\n const result: Record<string, FormModelFactory.FieldBuilder> = {};\n\n if (listValidators.length > 0) {\n listResult = this.buildValidatorFields(\n fields as FormModelFactory.FieldBuilderRegistry,\n listValidators,\n context\n );\n result.listValidation = fields\n .object()\n .renderer(\"passthrough\")\n .hiddenWhen(\n ({ form }: FormModel.CallbackParams) =>\n !form.field(\"general.list\").getValue()\n )\n .fields(() => listResult!.fields);\n }\n\n if (fieldValidators.length > 0) {\n fieldResult = this.buildValidatorFields(\n fields as FormModelFactory.FieldBuilderRegistry,\n fieldValidators,\n context\n );\n result.validation = fields\n .object()\n .renderer(\"passthrough\")\n .fields(() => fieldResult!.fields);\n }\n\n return result;\n });\n\n const listRule = {\n type: \"condition\",\n target: \"general.list\",\n operator: \"isFalsy\",\n value: null,\n action: \"hide\" as const\n };\n\n form.layout(layout => {\n const rows: FormModel.LayoutNodeBuilder[] = [];\n\n if (listValidators.length > 0 && listResult) {\n rows.push(\n layout\n .separator()\n .title(\"List validators\")\n .description(\"These validators are applied to the entire list of values.\")\n .rules([listRule])\n );\n rows.push(\n layout.object(\"listValidation\", inner =>\n this.buildValidatorLayouts(inner, listValidators, listResult!)\n )\n );\n }\n\n if (fieldValidators.length > 0 && fieldResult) {\n if (listValidators.length > 0) {\n rows.push(\n layout\n .separator()\n .title(\"Individual value validators\")\n .description(\"These validators are applied to each value in the list.\")\n .rules([listRule])\n );\n }\n rows.push(\n layout.object(\"validation\", inner =>\n this.buildValidatorLayouts(inner, fieldValidators, fieldResult!)\n )\n );\n }\n\n return rows;\n });\n }\n\n private buildValidatorLayouts(\n layout: FormModelFactory.LayoutBuilder,\n validators: ICmsFieldValidator[],\n result: ValidatorBuildResult\n ): FormModel.LayoutNodeBuilder[] {\n return validators.map(validator => {\n const meta = result.layouts.get(validator.name);\n return layout.object(validator.name, inner => {\n const rows: FormModel.LayoutNodeBuilder[] = [inner.row(\"message\")];\n if (meta && meta.hasSettings) {\n rows.push(\n inner.object(\"settings\", settingsLayout =>\n meta.settingsLayoutFns.flatMap(fn => fn(settingsLayout))\n )\n );\n }\n return rows;\n });\n });\n }\n\n private buildValidatorFields(\n fields: FormModelFactory.FieldBuilderRegistry,\n validators: ICmsFieldValidator[],\n context: ICmsFieldEditorContext\n ): ValidatorBuildResult {\n const resultFields: Record<string, FormModelFactory.FieldBuilder> = {};\n const layouts = new Map<\n string,\n {\n settingsLayoutFns: Array<\n (l: FormModelFactory.LayoutBuilder) => FormModel.LayoutNodeBuilder[]\n >;\n hasSettings: boolean;\n }\n >();\n\n for (const validator of validators) {\n let messageDescription = \"This message will be displayed to the user.\";\n if (validator.variables && validator.variables.length > 0) {\n const vars = validator.variables.map(v => `{${v.name}}`).join(\", \");\n messageDescription += ` Available variables: ${vars}.`;\n }\n\n const notEnabled = ({ field }: FormModel.CallbackParams) =>\n !field.parent().field(\"enabled\").getValue();\n\n const childFields: Record<string, FormModelFactory.FieldBuilder> = {\n enabled: fields.boolean().label(\"Enabled\").defaultValue(false).hidden(),\n message: fields\n .text()\n .label(\"Message\")\n .description(messageDescription)\n .defaultValue(validator.defaultMessage)\n .hiddenWhen(notEnabled)\n };\n\n const settingsLayoutFns: Array<\n (l: FormModelFactory.LayoutBuilder) => FormModel.LayoutNodeBuilder[]\n > = [];\n let hasSettings = false;\n\n if (validator.buildSettingsForm) {\n const settingsFieldsFns: Array<\n (\n f: FormModelFactory.FieldBuilderRegistry\n ) => Record<string, FormModelFactory.FieldBuilder>\n > = [];\n\n const builder: ICmsFieldValidatorFormBuilder = {\n message: childFields.message,\n fields: fn => {\n settingsFieldsFns.push(fn);\n },\n layout: fn => {\n settingsLayoutFns.push(fn);\n }\n };\n validator.buildSettingsForm(builder, { field: context.field });\n\n if (settingsFieldsFns.length > 0) {\n hasSettings = true;\n childFields.settings = fields\n .object()\n .renderer(\"passthrough\")\n .hiddenWhen(notEnabled)\n .fields((f: FormModelFactory.FieldBuilderRegistry) => {\n const merged: Record<string, FormModelFactory.FieldBuilder> = {};\n for (const fn of settingsFieldsFns) {\n Object.assign(merged, fn(f));\n }\n return merged;\n });\n }\n }\n\n layouts.set(validator.name, { settingsLayoutFns, hasSettings });\n\n resultFields[validator.name] = fields\n .object()\n .label(validator.label)\n .description(validator.description)\n .renderer(\"cmsValidatorItem\")\n .fields(() => childFields);\n }\n\n return { fields: resultFields, layouts };\n }\n\n mapToForm(field: CmsModelField) {\n const validationMap: Record<string, Record<string, unknown>> = {};\n for (const v of field.validation || []) {\n const validator = v as {\n name: string;\n message?: string;\n settings?: Record<string, unknown>;\n };\n validationMap[validator.name] = {\n enabled: true,\n message: validator.message,\n settings: this.settingsToForm(validator.name, validator.settings || {}, field)\n };\n }\n\n const listValidationMap: Record<string, Record<string, unknown>> = {};\n for (const v of field.listValidation || []) {\n listValidationMap[v.name] = {\n enabled: true,\n message: v.message,\n settings: this.settingsToForm(v.name, v.settings || {}, field)\n };\n }\n\n return {\n validation: validationMap,\n listValidation: listValidationMap\n };\n }\n\n mapFromForm(formData: Record<string, unknown>, field: CmsModelField) {\n field.validation = this.flattenValidators(\n (formData.validation || {}) as Record<string, any>,\n field\n );\n field.listValidation = this.flattenValidators(\n (formData.listValidation || {}) as Record<string, any>,\n field\n );\n }\n\n private flattenValidators(\n data: Record<\n string,\n {\n enabled?: boolean;\n message?: string;\n settings?: Record<string, unknown>;\n }\n >,\n field: CmsModelField\n ) {\n return Object.entries(data)\n .filter(([_, v]) => v && v.enabled)\n .map(([name, v]) => ({\n name,\n message: v.message,\n settings: this.settingsFromForm(name, v.settings, field)\n }));\n }\n\n private settingsToForm(\n name: string,\n settings: Record<string, unknown>,\n field: CmsModelField\n ): Record<string, unknown> {\n const validator = this.allValidators.find(v => v.name === name);\n if (!validator?.mapSettingsToForm) {\n return settings;\n }\n return validator.mapSettingsToForm(settings, { field });\n }\n\n private settingsFromForm(\n name: string,\n settings: Record<string, unknown> | undefined,\n field: CmsModelField\n ): Record<string, unknown> | undefined {\n const validator = this.allValidators.find(v => v.name === name);\n if (!settings || !validator?.mapSettingsFromForm) {\n return settings;\n }\n return validator.mapSettingsFromForm(settings, { field });\n }\n}\n\nexport const ValidationsGroup = CmsFieldEditorGroup.createImplementation({\n implementation: ValidationsGroupImpl,\n dependencies: [[CmsFieldValidator, { multiple: true }]]\n});\n"],"names":["resolveValidatorNames","config","field","Array","v","ValidationsGroupImpl","allValidators","form","context","fieldValidatorNames","DEFAULT_LIST_VALIDATORS","listValidatorNames","fieldValidators","listValidators","fieldResult","listResult","fields","result","listRule","layout","rows","inner","validators","validator","meta","settingsLayout","fn","resultFields","layouts","Map","messageDescription","vars","notEnabled","childFields","settingsLayoutFns","hasSettings","settingsFieldsFns","builder","f","merged","Object","validationMap","listValidationMap","formData","data","_","name","settings","ValidationsGroup","CmsFieldEditorGroup","CmsFieldValidator"],"mappings":"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"}
@@ -2,7 +2,7 @@ import react from "react";
2
2
  import { observer } from "mobx-react-lite";
3
3
  import { createObjectFieldRenderer } from "@webiny/app-admin/features/formModel/createFieldRenderer.js";
4
4
  import { LayoutNodeRenderer } from "@webiny/app-admin/features/formModel/FormView.js";
5
- import { Accordion, Switch } from "@webiny/admin-ui";
5
+ import { Accordion, SwitchPrimitive } from "@webiny/admin-ui";
6
6
  const CmsValidatorItemRenderer = createObjectFieldRenderer(({ field })=>/*#__PURE__*/ react.createElement(ValidatorItem, {
7
7
  field: field
8
8
  }));
@@ -20,7 +20,7 @@ const ValidatorItem = observer(({ field })=>{
20
20
  open: isEnabled,
21
21
  title: field.label,
22
22
  description: field.description,
23
- actions: /*#__PURE__*/ react.createElement(Switch, {
23
+ actions: /*#__PURE__*/ react.createElement(SwitchPrimitive, {
24
24
  label: "Enabled",
25
25
  checked: isEnabled,
26
26
  onChange: toggleEnabled