@webiny/app-headless-cms 6.5.0 → 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 (36) hide show
  1. package/features/formModel/CmsFormModelBuilder.test.js +213 -0
  2. package/features/formModel/CmsFormModelBuilder.test.js.map +1 -1
  3. package/features/formModel/CmsValidationMapper.d.ts +9 -0
  4. package/features/formModel/CmsValidationMapper.js +25 -19
  5. package/features/formModel/CmsValidationMapper.js.map +1 -1
  6. package/features/formModel/mappers/DateTimeFieldMapper.js +3 -0
  7. package/features/formModel/mappers/DateTimeFieldMapper.js.map +1 -1
  8. package/package.json +20 -20
  9. package/presentation/fieldEditor/groups/AppearanceGroup.js +12 -0
  10. package/presentation/fieldEditor/groups/AppearanceGroup.js.map +1 -1
  11. package/presentation/fieldEditor/groups/ValidationsGroup.d.ts +2 -0
  12. package/presentation/fieldEditor/groups/ValidationsGroup.js +20 -6
  13. package/presentation/fieldEditor/groups/ValidationsGroup.js.map +1 -1
  14. package/presentation/fieldEditor/renderers/CmsValidatorsRenderer.js +2 -2
  15. package/presentation/fieldEditor/renderers/CmsValidatorsRenderer.js.map +1 -1
  16. package/presentation/fieldRenderers/feature.js +2 -1
  17. package/presentation/fieldRenderers/feature.js.map +1 -1
  18. package/presentation/fieldTypes/renderers/dateTime/BirthdayInputRenderer.d.ts +15 -0
  19. package/presentation/fieldTypes/renderers/dateTime/BirthdayInputRenderer.js +19 -0
  20. package/presentation/fieldTypes/renderers/dateTime/BirthdayInputRenderer.js.map +1 -0
  21. package/presentation/fieldTypes/renderers/index.d.ts +1 -0
  22. package/presentation/fieldTypes/renderers/index.js +1 -0
  23. package/presentation/fieldValidators/abstractions.d.ts +7 -0
  24. package/presentation/fieldValidators/abstractions.js.map +1 -1
  25. package/presentation/fieldValidators/validators/DateGteValidator.d.ts +6 -0
  26. package/presentation/fieldValidators/validators/DateGteValidator.js +17 -25
  27. package/presentation/fieldValidators/validators/DateGteValidator.js.map +1 -1
  28. package/presentation/fieldValidators/validators/DateLteValidator.d.ts +6 -0
  29. package/presentation/fieldValidators/validators/DateLteValidator.js +17 -25
  30. package/presentation/fieldValidators/validators/DateLteValidator.js.map +1 -1
  31. package/presentation/fieldValidators/validators/dateLimitSettings.d.ts +20 -0
  32. package/presentation/fieldValidators/validators/dateLimitSettings.js +124 -0
  33. package/presentation/fieldValidators/validators/dateLimitSettings.js.map +1 -0
  34. package/presentation/fieldValidators/validators/dateLimitSettings.test.d.ts +1 -0
  35. package/presentation/fieldValidators/validators/dateLimitSettings.test.js +111 -0
  36. package/presentation/fieldValidators/validators/dateLimitSettings.test.js.map +1 -0
@@ -7,6 +7,7 @@ import { CmsFormModelBuilder } from "./abstractions.js";
7
7
  import { CmsFormModelFeature } from "./feature.js";
8
8
  import { DateTimeInputRenderer } from "../../presentation/fieldTypes/renderers/dateTime/DateTimeInputRenderer.js";
9
9
  import { DateTimeInputsRenderer } from "../../presentation/fieldTypes/renderers/dateTime/DateTimeInputsRenderer.js";
10
+ import { BirthdayInputRenderer } from "../../presentation/fieldTypes/renderers/dateTime/BirthdayInputRenderer.js";
10
11
  import { TextInputRenderer } from "../../presentation/fieldTypes/renderers/text/TextInputRenderer.js";
11
12
  import { TextInputsRenderer } from "../../presentation/fieldTypes/renderers/text/TextInputsRenderer.js";
12
13
  const field = (fieldId, type, list, renderer, extra = {})=>({
@@ -36,6 +37,7 @@ function createCmsForm(fields) {
36
37
  CmsFormModelFeature.register(container);
37
38
  container.register(DateTimeInputRenderer);
38
39
  container.register(DateTimeInputsRenderer);
40
+ container.register(BirthdayInputRenderer);
39
41
  container.register(TextInputRenderer);
40
42
  container.register(TextInputsRenderer);
41
43
  const model = {
@@ -107,6 +109,217 @@ describe("CmsFormModelBuilder renderer cardinality", ()=>{
107
109
  expect(item.children.get("openTime").vm.renderer).toBe("dateTimeInput");
108
110
  });
109
111
  });
112
+ describe("CmsFormModelBuilder birthday picker", ()=>{
113
+ it("renders a date-only field with the birthday picker and keeps its value", ()=>{
114
+ const form = createCmsForm([
115
+ field("dob", "datetime", false, "birthday-input", {
116
+ settings: {
117
+ type: "date"
118
+ },
119
+ renderer: {
120
+ name: "birthday-input",
121
+ settings: null
122
+ }
123
+ })
124
+ ]);
125
+ form.setData({
126
+ dob: "1990-02-09"
127
+ });
128
+ const vm = form.field("dob").vm;
129
+ expect(vm.renderer).toBe("birthdayInput");
130
+ expect(vm.rendererSettings).toEqual({
131
+ type: "date"
132
+ });
133
+ expect(vm.value).toBe("1990-02-09");
134
+ });
135
+ it("hands the field's date limits to the birthday picker", ()=>{
136
+ const form = createCmsForm([
137
+ field("dob", "datetime", false, "birthday-input", {
138
+ settings: {
139
+ type: "date"
140
+ },
141
+ validation: [
142
+ {
143
+ name: "dateGte",
144
+ message: "Too old.",
145
+ settings: {
146
+ value: "1950-01-01"
147
+ }
148
+ },
149
+ {
150
+ name: "dateLte",
151
+ message: "You must be 18 or older.",
152
+ settings: {
153
+ expression: "today-18y",
154
+ type: "date"
155
+ }
156
+ }
157
+ ]
158
+ })
159
+ ]);
160
+ expect(form.field("dob").vm.rendererSettings).toEqual({
161
+ type: "date",
162
+ dateLimits: {
163
+ gte: [
164
+ "1950-01-01"
165
+ ],
166
+ lte: [
167
+ {
168
+ expression: "today-18y"
169
+ }
170
+ ]
171
+ }
172
+ });
173
+ });
174
+ it("falls back to the date/time input when the field is no longer date-only", ()=>{
175
+ const form = createCmsForm([
176
+ field("openTime", "datetime", false, "birthday-input", {
177
+ settings: {
178
+ type: "time"
179
+ }
180
+ })
181
+ ]);
182
+ expect(form.field("openTime").vm.renderer).toBe("dateTimeInput");
183
+ });
184
+ });
185
+ describe("CmsFormModelBuilder validators", ()=>{
186
+ const validate = async (form, name)=>{
187
+ const valid = await form.field(name).validate({
188
+ force: true
189
+ });
190
+ return {
191
+ valid,
192
+ message: form.field(name).vm.validation.message
193
+ };
194
+ };
195
+ it("checks both date limits on a field that has two", async ()=>{
196
+ const form = createCmsForm([
197
+ field("bornOn", "datetime", false, "date-time-input", {
198
+ settings: {
199
+ type: "date"
200
+ },
201
+ validation: [
202
+ {
203
+ name: "dateGte",
204
+ message: "Too early.",
205
+ settings: {
206
+ value: "1950-01-01"
207
+ }
208
+ },
209
+ {
210
+ name: "dateLte",
211
+ message: "Too late.",
212
+ settings: {
213
+ value: "2000-12-31"
214
+ }
215
+ }
216
+ ]
217
+ })
218
+ ]);
219
+ form.setData({
220
+ bornOn: "2005-01-01"
221
+ });
222
+ expect(await validate(form, "bornOn")).toEqual({
223
+ valid: false,
224
+ message: "Too late."
225
+ });
226
+ form.setData({
227
+ bornOn: "1949-01-01"
228
+ });
229
+ expect(await validate(form, "bornOn")).toEqual({
230
+ valid: false,
231
+ message: "Too early."
232
+ });
233
+ form.setData({
234
+ bornOn: "1975-06-15"
235
+ });
236
+ expect((await validate(form, "bornOn")).valid).toBe(true);
237
+ });
238
+ it("works out a relative limit from today", async ()=>{
239
+ const form = createCmsForm([
240
+ field("bornOn", "datetime", false, "birthday-input", {
241
+ settings: {
242
+ type: "date"
243
+ },
244
+ validation: [
245
+ {
246
+ name: "dateLte",
247
+ message: "You must be 18 or older.",
248
+ settings: {
249
+ expression: "today-18y",
250
+ type: "date"
251
+ }
252
+ }
253
+ ]
254
+ })
255
+ ]);
256
+ form.setData({
257
+ bornOn: `${new Date().getFullYear() - 10}-01-01`
258
+ });
259
+ expect(await validate(form, "bornOn")).toEqual({
260
+ valid: false,
261
+ message: "You must be 18 or older."
262
+ });
263
+ form.setData({
264
+ bornOn: `${new Date().getFullYear() - 30}-01-01`
265
+ });
266
+ expect((await validate(form, "bornOn")).valid).toBe(true);
267
+ });
268
+ it("checks every validator on a text field that has several", async ()=>{
269
+ const form = createCmsForm([
270
+ field("code", "text", false, "text-input", {
271
+ validation: [
272
+ {
273
+ name: "minLength",
274
+ message: "Too short.",
275
+ settings: {
276
+ value: 3
277
+ }
278
+ },
279
+ {
280
+ name: "maxLength",
281
+ message: "Too long.",
282
+ settings: {
283
+ value: 5
284
+ }
285
+ },
286
+ {
287
+ name: "pattern",
288
+ message: "Letters only.",
289
+ settings: {
290
+ regex: "^[a-z]+$"
291
+ }
292
+ }
293
+ ]
294
+ })
295
+ ]);
296
+ form.setData({
297
+ code: "ab"
298
+ });
299
+ expect(await validate(form, "code")).toEqual({
300
+ valid: false,
301
+ message: "Too short."
302
+ });
303
+ form.setData({
304
+ code: "abcdef"
305
+ });
306
+ expect(await validate(form, "code")).toEqual({
307
+ valid: false,
308
+ message: "Too long."
309
+ });
310
+ form.setData({
311
+ code: "ab1"
312
+ });
313
+ expect(await validate(form, "code")).toEqual({
314
+ valid: false,
315
+ message: "Letters only."
316
+ });
317
+ form.setData({
318
+ code: "abcd"
319
+ });
320
+ expect((await validate(form, "code")).valid).toBe(true);
321
+ });
322
+ });
110
323
  const rowNames = (layout)=>layout.map((row)=>row.fields.map((f)=>f.name));
111
324
  describe("CmsFormModelBuilder nested layouts", ()=>{
112
325
  it("lays out a single object with the layout stored on the field", ()=>{
@@ -1 +1 @@
1
- {"version":3,"file":"features/formModel/CmsFormModelBuilder.test.js","sources":["../../../src/features/formModel/CmsFormModelBuilder.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { FormModelFeature } from \"@webiny/app-admin/features/formModel/feature.js\";\nimport { IdentityContextFeature } from \"@webiny/app-admin/features/security/IdentityContext/feature.js\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { CmsFormModelBuilder } from \"~/features/formModel/abstractions.js\";\nimport { CmsFormModelFeature } from \"~/features/formModel/feature.js\";\nimport { DateTimeInputRenderer } from \"~/presentation/fieldTypes/renderers/dateTime/DateTimeInputRenderer.js\";\nimport { DateTimeInputsRenderer } from \"~/presentation/fieldTypes/renderers/dateTime/DateTimeInputsRenderer.js\";\nimport { TextInputRenderer } from \"~/presentation/fieldTypes/renderers/text/TextInputRenderer.js\";\nimport { TextInputsRenderer } from \"~/presentation/fieldTypes/renderers/text/TextInputsRenderer.js\";\n\nconst field = (fieldId: string, type: string, list: boolean, renderer: string, extra = {}) => ({\n id: fieldId,\n fieldId,\n type,\n label: fieldId,\n tags: [],\n list,\n renderer: { name: renderer, settings: {} },\n validation: [],\n listValidation: [],\n settings: {},\n predefinedValues: { enabled: false, values: [] },\n ...extra\n});\n\nfunction createCmsForm(fields: any[]) {\n const container = new Container();\n IdentityContextFeature.register(container);\n FormModelFeature.register(container);\n CmsFormModelFeature.register(container);\n container.register(DateTimeInputRenderer);\n container.register(DateTimeInputsRenderer);\n container.register(TextInputRenderer);\n container.register(TextInputsRenderer);\n\n const model = {\n modelId: \"test\",\n fields,\n layout: fields.map(f => [f.fieldId])\n } as any;\n const config = container.resolve(CmsFormModelBuilder).build(model);\n return container.resolve(FormModelFactory).create(config);\n}\n\ndescribe(\"CmsFormModelBuilder renderer cardinality\", () => {\n it(\"keeps renderers that match the field's cardinality\", () => {\n const form = createCmsForm([\n field(\"single\", \"datetime\", false, \"date-time-input\"),\n field(\"many\", \"datetime\", true, \"date-time-inputs\")\n ]);\n\n expect(form.field(\"single\").vm.renderer).toBe(\"dateTimeInput\");\n expect(form.field(\"many\").vm.renderer).toBe(\"dateTimeInputs\");\n });\n\n it(\"falls back to the single-value renderer when a list renderer is set on a non-list field\", () => {\n const form = createCmsForm([\n field(\"openTime\", \"datetime\", false, \"date-time-inputs\"),\n field(\"name\", \"text\", false, \"text-inputs\")\n ]);\n\n expect(form.field(\"openTime\").vm.renderer).toBe(\"dateTimeInput\");\n expect(form.field(\"name\").vm.renderer).toBe(\"textInput\");\n });\n\n it(\"keeps the list renderer for list datetime fields with a subtype\", () => {\n const form = createCmsForm(\n [\"date\", \"time\", \"dateTimeWithTimezone\", \"dateTimeWithoutTimezone\"].map(type =>\n field(type, \"datetime\", true, \"date-time-inputs\", { settings: { type } })\n )\n );\n\n expect(form.field(\"date\").vm.renderer).toBe(\"dateTimeInputs\");\n expect(form.field(\"time\").vm.renderer).toBe(\"dateTimeInputs\");\n expect(form.field(\"dateTimeWithTimezone\").vm.renderer).toBe(\"dateTimeInputs\");\n expect(form.field(\"dateTimeWithoutTimezone\").vm.renderer).toBe(\"dateTimeInputs\");\n });\n\n it(\"applies the fallback to fields nested in object lists\", () => {\n const form = createCmsForm([\n field(\"holidayHours\", \"object\", true, \"objects-accordion\", {\n settings: {\n fields: [field(\"openTime\", \"datetime\", false, \"date-time-inputs\")],\n layout: [[\"openTime\"]]\n }\n })\n ]);\n\n form.setData({ holidayHours: [{ openTime: \"2026-12-24T09:00:00.000Z\" }] });\n const item = (form.field(\"holidayHours\") as any).items[0];\n\n expect(item.children.get(\"openTime\").vm.renderer).toBe(\"dateTimeInput\");\n });\n});\n\nconst rowNames = (layout: any[]) => layout.map(row => row.fields.map((f: any) => f.name));\n\ndescribe(\"CmsFormModelBuilder nested layouts\", () => {\n it(\"lays out a single object with the layout stored on the field\", () => {\n const form = createCmsForm([\n field(\"address\", \"object\", false, \"object-accordion\", {\n settings: {\n fields: [\n field(\"street\", \"text\", false, \"text-input\"),\n // Fields created in the model editor have an `id` that differs from `fieldId`.\n field(\"city\", \"text\", false, \"text-input\", { id: \"c1ty\" }),\n field(\"zipCode\", \"text\", false, \"text-input\")\n ],\n layout: [[\"street\"], [\"c1ty\", \"zipCode\"]]\n }\n })\n ]);\n\n expect(rowNames((form.field(\"address\").vm as any).layout)).toEqual([\n [\"street\"],\n [\"city\", \"zipCode\"]\n ]);\n });\n\n it(\"lays out every item of an object list\", () => {\n const form = createCmsForm([\n field(\"facilityStats\", \"object\", true, \"objects-accordion\", {\n settings: {\n fields: [\n field(\"statValue\", \"text\", false, \"text-input\"),\n field(\"statLabel\", \"text\", false, \"text-input\")\n ],\n layout: [[\"statValue\", \"statLabel\"]]\n }\n })\n ]);\n\n form.setData({ facilityStats: [{ statValue: \"1\", statLabel: \"a\" }] });\n const vm = form.field(\"facilityStats\").vm as any;\n\n expect(rowNames(vm.items[0].layout)).toEqual([[\"statValue\", \"statLabel\"]]);\n });\n\n it(\"gives children missing from the stored layout a row of their own\", () => {\n const form = createCmsForm([\n field(\"address\", \"object\", false, \"object-accordion\", {\n settings: {\n fields: [\n field(\"street\", \"text\", false, \"text-input\"),\n field(\"city\", \"text\", false, \"text-input\"),\n field(\"state\", \"text\", false, \"text-input\")\n ],\n layout: [[\"street\", \"city\"]]\n }\n })\n ]);\n\n expect(rowNames((form.field(\"address\").vm as any).layout)).toEqual([\n [\"street\", \"city\"],\n [\"state\"]\n ]);\n });\n\n it(\"lays out a dynamic zone template with the template's layout\", () => {\n const form = createCmsForm([\n field(\"blocks\", \"dynamicZone\", true, \"dynamicZone\", {\n settings: {\n templates: [\n {\n id: \"hero\",\n name: \"Hero\",\n gqlTypeName: \"Hero\",\n description: \"\",\n icon: null,\n fields: [\n field(\"title\", \"text\", false, \"text-input\"),\n field(\"subtitle\", \"text\", false, \"text-input\")\n ],\n layout: [[\"title\", \"subtitle\"]],\n validation: []\n }\n ]\n }\n })\n ]);\n\n form.setData({ blocks: [{ _templateId: \"hero\", title: \"T\", subtitle: \"S\" }] });\n const vm = form.field(\"blocks\").vm as any;\n\n expect(rowNames(vm.items[0].layout)).toEqual([[\"title\", \"subtitle\"]]);\n });\n});\n"],"names":["field","fieldId","type","list","renderer","extra","createCmsForm","fields","container","Container","IdentityContextFeature","FormModelFeature","CmsFormModelFeature","DateTimeInputRenderer","DateTimeInputsRenderer","TextInputRenderer","TextInputsRenderer","model","f","config","CmsFormModelBuilder","FormModelFactory","describe","it","form","expect","item","rowNames","layout","row","vm"],"mappings":"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"}
1
+ {"version":3,"file":"features/formModel/CmsFormModelBuilder.test.js","sources":["../../../src/features/formModel/CmsFormModelBuilder.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { FormModelFeature } from \"@webiny/app-admin/features/formModel/feature.js\";\nimport { IdentityContextFeature } from \"@webiny/app-admin/features/security/IdentityContext/feature.js\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { CmsFormModelBuilder } from \"~/features/formModel/abstractions.js\";\nimport { CmsFormModelFeature } from \"~/features/formModel/feature.js\";\nimport { DateTimeInputRenderer } from \"~/presentation/fieldTypes/renderers/dateTime/DateTimeInputRenderer.js\";\nimport { DateTimeInputsRenderer } from \"~/presentation/fieldTypes/renderers/dateTime/DateTimeInputsRenderer.js\";\nimport { BirthdayInputRenderer } from \"~/presentation/fieldTypes/renderers/dateTime/BirthdayInputRenderer.js\";\nimport { TextInputRenderer } from \"~/presentation/fieldTypes/renderers/text/TextInputRenderer.js\";\nimport { TextInputsRenderer } from \"~/presentation/fieldTypes/renderers/text/TextInputsRenderer.js\";\n\nconst field = (fieldId: string, type: string, list: boolean, renderer: string, extra = {}) => ({\n id: fieldId,\n fieldId,\n type,\n label: fieldId,\n tags: [],\n list,\n renderer: { name: renderer, settings: {} },\n validation: [],\n listValidation: [],\n settings: {},\n predefinedValues: { enabled: false, values: [] },\n ...extra\n});\n\nfunction createCmsForm(fields: any[]) {\n const container = new Container();\n IdentityContextFeature.register(container);\n FormModelFeature.register(container);\n CmsFormModelFeature.register(container);\n container.register(DateTimeInputRenderer);\n container.register(DateTimeInputsRenderer);\n container.register(BirthdayInputRenderer);\n container.register(TextInputRenderer);\n container.register(TextInputsRenderer);\n\n const model = {\n modelId: \"test\",\n fields,\n layout: fields.map(f => [f.fieldId])\n } as any;\n const config = container.resolve(CmsFormModelBuilder).build(model);\n return container.resolve(FormModelFactory).create(config);\n}\n\ndescribe(\"CmsFormModelBuilder renderer cardinality\", () => {\n it(\"keeps renderers that match the field's cardinality\", () => {\n const form = createCmsForm([\n field(\"single\", \"datetime\", false, \"date-time-input\"),\n field(\"many\", \"datetime\", true, \"date-time-inputs\")\n ]);\n\n expect(form.field(\"single\").vm.renderer).toBe(\"dateTimeInput\");\n expect(form.field(\"many\").vm.renderer).toBe(\"dateTimeInputs\");\n });\n\n it(\"falls back to the single-value renderer when a list renderer is set on a non-list field\", () => {\n const form = createCmsForm([\n field(\"openTime\", \"datetime\", false, \"date-time-inputs\"),\n field(\"name\", \"text\", false, \"text-inputs\")\n ]);\n\n expect(form.field(\"openTime\").vm.renderer).toBe(\"dateTimeInput\");\n expect(form.field(\"name\").vm.renderer).toBe(\"textInput\");\n });\n\n it(\"keeps the list renderer for list datetime fields with a subtype\", () => {\n const form = createCmsForm(\n [\"date\", \"time\", \"dateTimeWithTimezone\", \"dateTimeWithoutTimezone\"].map(type =>\n field(type, \"datetime\", true, \"date-time-inputs\", { settings: { type } })\n )\n );\n\n expect(form.field(\"date\").vm.renderer).toBe(\"dateTimeInputs\");\n expect(form.field(\"time\").vm.renderer).toBe(\"dateTimeInputs\");\n expect(form.field(\"dateTimeWithTimezone\").vm.renderer).toBe(\"dateTimeInputs\");\n expect(form.field(\"dateTimeWithoutTimezone\").vm.renderer).toBe(\"dateTimeInputs\");\n });\n\n it(\"applies the fallback to fields nested in object lists\", () => {\n const form = createCmsForm([\n field(\"holidayHours\", \"object\", true, \"objects-accordion\", {\n settings: {\n fields: [field(\"openTime\", \"datetime\", false, \"date-time-inputs\")],\n layout: [[\"openTime\"]]\n }\n })\n ]);\n\n form.setData({ holidayHours: [{ openTime: \"2026-12-24T09:00:00.000Z\" }] });\n const item = (form.field(\"holidayHours\") as any).items[0];\n\n expect(item.children.get(\"openTime\").vm.renderer).toBe(\"dateTimeInput\");\n });\n});\n\ndescribe(\"CmsFormModelBuilder birthday picker\", () => {\n it(\"renders a date-only field with the birthday picker and keeps its value\", () => {\n const form = createCmsForm([\n field(\"dob\", \"datetime\", false, \"birthday-input\", {\n settings: { type: \"date\" },\n renderer: { name: \"birthday-input\", settings: null }\n })\n ]);\n form.setData({ dob: \"1990-02-09\" });\n\n const vm = form.field(\"dob\").vm as any;\n expect(vm.renderer).toBe(\"birthdayInput\");\n expect(vm.rendererSettings).toEqual({ type: \"date\" });\n expect(vm.value).toBe(\"1990-02-09\");\n });\n\n it(\"hands the field's date limits to the birthday picker\", () => {\n const form = createCmsForm([\n field(\"dob\", \"datetime\", false, \"birthday-input\", {\n settings: { type: \"date\" },\n validation: [\n { name: \"dateGte\", message: \"Too old.\", settings: { value: \"1950-01-01\" } },\n {\n name: \"dateLte\",\n message: \"You must be 18 or older.\",\n settings: { expression: \"today-18y\", type: \"date\" }\n }\n ]\n })\n ]);\n\n expect((form.field(\"dob\").vm as any).rendererSettings).toEqual({\n type: \"date\",\n dateLimits: { gte: [\"1950-01-01\"], lte: [{ expression: \"today-18y\" }] }\n });\n });\n\n it(\"falls back to the date/time input when the field is no longer date-only\", () => {\n const form = createCmsForm([\n field(\"openTime\", \"datetime\", false, \"birthday-input\", { settings: { type: \"time\" } })\n ]);\n\n expect(form.field(\"openTime\").vm.renderer).toBe(\"dateTimeInput\");\n });\n});\n\ndescribe(\"CmsFormModelBuilder validators\", () => {\n const validate = async (form: ReturnType<typeof createCmsForm>, name: string) => {\n const valid = await form.field(name).validate({ force: true });\n return { valid, message: form.field(name).vm.validation.message };\n };\n\n it(\"checks both date limits on a field that has two\", async () => {\n const form = createCmsForm([\n field(\"bornOn\", \"datetime\", false, \"date-time-input\", {\n settings: { type: \"date\" },\n validation: [\n { name: \"dateGte\", message: \"Too early.\", settings: { value: \"1950-01-01\" } },\n { name: \"dateLte\", message: \"Too late.\", settings: { value: \"2000-12-31\" } }\n ]\n })\n ]);\n\n form.setData({ bornOn: \"2005-01-01\" });\n expect(await validate(form, \"bornOn\")).toEqual({ valid: false, message: \"Too late.\" });\n\n form.setData({ bornOn: \"1949-01-01\" });\n expect(await validate(form, \"bornOn\")).toEqual({ valid: false, message: \"Too early.\" });\n\n form.setData({ bornOn: \"1975-06-15\" });\n expect((await validate(form, \"bornOn\")).valid).toBe(true);\n });\n\n it(\"works out a relative limit from today\", async () => {\n const form = createCmsForm([\n field(\"bornOn\", \"datetime\", false, \"birthday-input\", {\n settings: { type: \"date\" },\n validation: [\n {\n name: \"dateLte\",\n message: \"You must be 18 or older.\",\n settings: { expression: \"today-18y\", type: \"date\" }\n }\n ]\n })\n ]);\n\n form.setData({ bornOn: `${new Date().getFullYear() - 10}-01-01` });\n expect(await validate(form, \"bornOn\")).toEqual({\n valid: false,\n message: \"You must be 18 or older.\"\n });\n\n form.setData({ bornOn: `${new Date().getFullYear() - 30}-01-01` });\n expect((await validate(form, \"bornOn\")).valid).toBe(true);\n });\n\n it(\"checks every validator on a text field that has several\", async () => {\n const form = createCmsForm([\n field(\"code\", \"text\", false, \"text-input\", {\n validation: [\n { name: \"minLength\", message: \"Too short.\", settings: { value: 3 } },\n { name: \"maxLength\", message: \"Too long.\", settings: { value: 5 } },\n { name: \"pattern\", message: \"Letters only.\", settings: { regex: \"^[a-z]+$\" } }\n ]\n })\n ]);\n\n form.setData({ code: \"ab\" });\n expect(await validate(form, \"code\")).toEqual({ valid: false, message: \"Too short.\" });\n\n form.setData({ code: \"abcdef\" });\n expect(await validate(form, \"code\")).toEqual({ valid: false, message: \"Too long.\" });\n\n form.setData({ code: \"ab1\" });\n expect(await validate(form, \"code\")).toEqual({ valid: false, message: \"Letters only.\" });\n\n form.setData({ code: \"abcd\" });\n expect((await validate(form, \"code\")).valid).toBe(true);\n });\n});\n\nconst rowNames = (layout: any[]) => layout.map(row => row.fields.map((f: any) => f.name));\n\ndescribe(\"CmsFormModelBuilder nested layouts\", () => {\n it(\"lays out a single object with the layout stored on the field\", () => {\n const form = createCmsForm([\n field(\"address\", \"object\", false, \"object-accordion\", {\n settings: {\n fields: [\n field(\"street\", \"text\", false, \"text-input\"),\n // Fields created in the model editor have an `id` that differs from `fieldId`.\n field(\"city\", \"text\", false, \"text-input\", { id: \"c1ty\" }),\n field(\"zipCode\", \"text\", false, \"text-input\")\n ],\n layout: [[\"street\"], [\"c1ty\", \"zipCode\"]]\n }\n })\n ]);\n\n expect(rowNames((form.field(\"address\").vm as any).layout)).toEqual([\n [\"street\"],\n [\"city\", \"zipCode\"]\n ]);\n });\n\n it(\"lays out every item of an object list\", () => {\n const form = createCmsForm([\n field(\"facilityStats\", \"object\", true, \"objects-accordion\", {\n settings: {\n fields: [\n field(\"statValue\", \"text\", false, \"text-input\"),\n field(\"statLabel\", \"text\", false, \"text-input\")\n ],\n layout: [[\"statValue\", \"statLabel\"]]\n }\n })\n ]);\n\n form.setData({ facilityStats: [{ statValue: \"1\", statLabel: \"a\" }] });\n const vm = form.field(\"facilityStats\").vm as any;\n\n expect(rowNames(vm.items[0].layout)).toEqual([[\"statValue\", \"statLabel\"]]);\n });\n\n it(\"gives children missing from the stored layout a row of their own\", () => {\n const form = createCmsForm([\n field(\"address\", \"object\", false, \"object-accordion\", {\n settings: {\n fields: [\n field(\"street\", \"text\", false, \"text-input\"),\n field(\"city\", \"text\", false, \"text-input\"),\n field(\"state\", \"text\", false, \"text-input\")\n ],\n layout: [[\"street\", \"city\"]]\n }\n })\n ]);\n\n expect(rowNames((form.field(\"address\").vm as any).layout)).toEqual([\n [\"street\", \"city\"],\n [\"state\"]\n ]);\n });\n\n it(\"lays out a dynamic zone template with the template's layout\", () => {\n const form = createCmsForm([\n field(\"blocks\", \"dynamicZone\", true, \"dynamicZone\", {\n settings: {\n templates: [\n {\n id: \"hero\",\n name: \"Hero\",\n gqlTypeName: \"Hero\",\n description: \"\",\n icon: null,\n fields: [\n field(\"title\", \"text\", false, \"text-input\"),\n field(\"subtitle\", \"text\", false, \"text-input\")\n ],\n layout: [[\"title\", \"subtitle\"]],\n validation: []\n }\n ]\n }\n })\n ]);\n\n form.setData({ blocks: [{ _templateId: \"hero\", title: \"T\", subtitle: \"S\" }] });\n const vm = form.field(\"blocks\").vm as any;\n\n expect(rowNames(vm.items[0].layout)).toEqual([[\"title\", \"subtitle\"]]);\n });\n});\n"],"names":["field","fieldId","type","list","renderer","extra","createCmsForm","fields","container","Container","IdentityContextFeature","FormModelFeature","CmsFormModelFeature","DateTimeInputRenderer","DateTimeInputsRenderer","BirthdayInputRenderer","TextInputRenderer","TextInputsRenderer","model","f","config","CmsFormModelBuilder","FormModelFactory","describe","it","form","expect","item","vm","validate","name","valid","Date","rowNames","layout","row"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import type { DateBound } from "@webiny/utils";
2
3
  import type { CmsModelFieldValidator } from "../../types.js";
3
4
  export declare function mapCmsValidators(validators: (CmsModelFieldValidator | {
4
5
  name: string;
@@ -7,6 +8,14 @@ export declare function mapCmsValidators(validators: (CmsModelFieldValidator | {
7
8
  requiredMessage?: string;
8
9
  schema: z.ZodTypeAny | undefined;
9
10
  };
11
+ /** The `dateGte`/`dateLte` validators, as limits for the `datetime()` builder. */
12
+ export declare function mapCmsDateLimits(validators: (CmsModelFieldValidator | {
13
+ name: string;
14
+ })[] | undefined): {
15
+ name: "dateGte" | "dateLte";
16
+ bound: DateBound;
17
+ message?: string;
18
+ }[];
10
19
  export declare function mapCmsListValidators(validators: (CmsModelFieldValidator | {
11
20
  name: string;
12
21
  })[] | undefined): {
@@ -44,31 +44,37 @@ function mapCmsValidators(validators) {
44
44
  case "in":
45
45
  if (Array.isArray(settings.values) && settings.values.length > 0) schemas.push(z["enum"](settings.values));
46
46
  break;
47
- case "dateGte":
48
- if (null != settings.value) {
49
- const minDate = settings.value;
50
- schemas.push(z.string().refine((val)=>val >= minDate, {
51
- message: msg || `Must be on or after ${minDate}`
52
- }));
53
- }
54
- break;
55
- case "dateLte":
56
- if (null != settings.value) {
57
- const maxDate = settings.value;
58
- schemas.push(z.string().refine((val)=>val <= maxDate, {
59
- message: msg || `Must be on or before ${maxDate}`
60
- }));
61
- }
62
- break;
63
47
  }
64
48
  }
65
- const schema = 0 === schemas.length ? void 0 : 1 === schemas.length ? schemas[0] : z.intersection(schemas[0], schemas.slice(1).reduce((acc, s)=>z.intersection(acc, s), schemas[0]));
49
+ const schema = 0 === schemas.length ? void 0 : schemas.slice(1).reduce((acc, s)=>z.intersection(acc, s), schemas[0]);
66
50
  return {
67
51
  required,
68
52
  requiredMessage,
69
- schema: schemas.length <= 1 ? schema : void 0
53
+ schema
70
54
  };
71
55
  }
56
+ function mapCmsDateLimits(validators) {
57
+ const limits = [];
58
+ for (const v of validators || []){
59
+ const validator = v;
60
+ if ("dateGte" !== validator.name && "dateLte" !== validator.name) continue;
61
+ const settings = validator.settings || {};
62
+ const message = interpolateMessage(validator.message, settings);
63
+ if ("string" == typeof settings.expression) limits.push({
64
+ name: validator.name,
65
+ bound: {
66
+ expression: settings.expression
67
+ },
68
+ message
69
+ });
70
+ else if (null != settings.value) limits.push({
71
+ name: validator.name,
72
+ bound: String(settings.value),
73
+ message
74
+ });
75
+ }
76
+ return limits;
77
+ }
72
78
  function mapCmsListValidators(validators) {
73
79
  if (!validators || 0 === validators.length) return {
74
80
  required: false,
@@ -101,6 +107,6 @@ function mapCmsListValidators(validators) {
101
107
  schema: hasConstraints ? arraySchema : void 0
102
108
  };
103
109
  }
104
- export { mapCmsListValidators, mapCmsValidators };
110
+ export { mapCmsDateLimits, mapCmsListValidators, mapCmsValidators };
105
111
 
106
112
  //# sourceMappingURL=CmsValidationMapper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"features/formModel/CmsValidationMapper.js","sources":["../../../src/features/formModel/CmsValidationMapper.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type { CmsModelFieldValidator } from \"~/types.js\";\n\nfunction interpolateMessage(\n message: string | undefined,\n settings: Record<string, unknown>\n): string | undefined {\n if (!message) {\n return undefined;\n }\n return message.replace(/\\{(\\w+)}/g, (match, key) => {\n const val = settings[key];\n return val != null ? String(val) : match;\n });\n}\n\nexport function mapCmsValidators(\n validators: (CmsModelFieldValidator | { name: string })[] | undefined\n): { required: boolean; requiredMessage?: string; schema: z.ZodTypeAny | undefined } {\n if (!validators || validators.length === 0) {\n return { required: false, schema: undefined };\n }\n\n let required = false;\n let requiredMessage: string | undefined;\n const schemas: z.ZodTypeAny[] = [];\n\n for (const v of validators) {\n const validator = v as CmsModelFieldValidator;\n const settings = validator.settings || {};\n\n const msg = interpolateMessage(validator.message, settings);\n\n switch (validator.name) {\n case \"required\":\n required = true;\n requiredMessage = msg;\n break;\n\n case \"minLength\":\n if (settings.value != null) {\n schemas.push(z.string().min(Number(settings.value), msg || undefined));\n }\n break;\n\n case \"maxLength\":\n if (settings.value != null) {\n schemas.push(z.string().max(Number(settings.value), msg || undefined));\n }\n break;\n\n case \"pattern\":\n if (settings.regex) {\n const flags = settings.flags || \"\";\n schemas.push(\n z.string().regex(new RegExp(settings.regex, flags), msg || undefined)\n );\n }\n break;\n\n case \"gte\":\n if (settings.value != null) {\n schemas.push(z.number().gte(Number(settings.value), msg || undefined));\n }\n break;\n\n case \"lte\":\n if (settings.value != null) {\n schemas.push(z.number().lte(Number(settings.value), msg || undefined));\n }\n break;\n\n case \"in\":\n if (Array.isArray(settings.values) && settings.values.length > 0) {\n schemas.push(z.enum(settings.values as [string, ...string[]]));\n }\n break;\n\n case \"dateGte\":\n if (settings.value != null) {\n const minDate = settings.value;\n schemas.push(\n z.string().refine(val => val >= minDate, {\n message: msg || `Must be on or after ${minDate}`\n })\n );\n }\n break;\n\n case \"dateLte\":\n if (settings.value != null) {\n const maxDate = settings.value;\n schemas.push(\n z.string().refine(val => val <= maxDate, {\n message: msg || `Must be on or before ${maxDate}`\n })\n );\n }\n break;\n }\n }\n\n const schema =\n schemas.length === 0\n ? undefined\n : schemas.length === 1\n ? schemas[0]\n : z.intersection(\n schemas[0],\n schemas.slice(1).reduce((acc, s) => z.intersection(acc, s), schemas[0])\n );\n\n return { required, requiredMessage, schema: schemas.length <= 1 ? schema : undefined };\n}\n\nexport function mapCmsListValidators(\n validators: (CmsModelFieldValidator | { name: string })[] | undefined\n): { required: boolean; requiredMessage?: string; schema: z.ZodTypeAny | undefined } {\n if (!validators || validators.length === 0) {\n return { required: false, schema: undefined };\n }\n\n let required = false;\n let requiredMessage: string | undefined;\n let arraySchema = z.array(z.unknown());\n\n for (const v of validators) {\n const validator = v as CmsModelFieldValidator;\n const settings = validator.settings || {};\n const msg = interpolateMessage(validator.message, settings);\n\n switch (validator.name) {\n case \"required\":\n required = true;\n requiredMessage = msg;\n break;\n\n case \"minLength\":\n if (settings.value != null) {\n arraySchema = arraySchema.min(\n Number(settings.value),\n msg || undefined\n ) as typeof arraySchema;\n }\n break;\n\n case \"maxLength\":\n if (settings.value != null) {\n arraySchema = arraySchema.max(\n Number(settings.value),\n msg || undefined\n ) as typeof arraySchema;\n }\n break;\n }\n }\n\n const hasConstraints = validators.some(\n v =>\n (v as CmsModelFieldValidator).name === \"minLength\" ||\n (v as CmsModelFieldValidator).name === \"maxLength\"\n );\n\n return {\n required,\n requiredMessage,\n schema: hasConstraints ? arraySchema : undefined\n };\n}\n"],"names":["interpolateMessage","message","settings","match","key","val","String","mapCmsValidators","validators","undefined","required","requiredMessage","schemas","v","validator","msg","z","Number","flags","RegExp","Array","minDate","maxDate","schema","acc","s","mapCmsListValidators","arraySchema","hasConstraints"],"mappings":"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"}
1
+ {"version":3,"file":"features/formModel/CmsValidationMapper.js","sources":["../../../src/features/formModel/CmsValidationMapper.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type { DateBound } from \"@webiny/utils\";\nimport type { CmsModelFieldValidator } from \"~/types.js\";\n\nfunction interpolateMessage(\n message: string | undefined,\n settings: Record<string, unknown>\n): string | undefined {\n if (!message) {\n return undefined;\n }\n return message.replace(/\\{(\\w+)}/g, (match, key) => {\n const val = settings[key];\n return val != null ? String(val) : match;\n });\n}\n\nexport function mapCmsValidators(\n validators: (CmsModelFieldValidator | { name: string })[] | undefined\n): { required: boolean; requiredMessage?: string; schema: z.ZodTypeAny | undefined } {\n if (!validators || validators.length === 0) {\n return { required: false, schema: undefined };\n }\n\n let required = false;\n let requiredMessage: string | undefined;\n const schemas: z.ZodTypeAny[] = [];\n\n for (const v of validators) {\n const validator = v as CmsModelFieldValidator;\n const settings = validator.settings || {};\n\n const msg = interpolateMessage(validator.message, settings);\n\n switch (validator.name) {\n case \"required\":\n required = true;\n requiredMessage = msg;\n break;\n\n case \"minLength\":\n if (settings.value != null) {\n schemas.push(z.string().min(Number(settings.value), msg || undefined));\n }\n break;\n\n case \"maxLength\":\n if (settings.value != null) {\n schemas.push(z.string().max(Number(settings.value), msg || undefined));\n }\n break;\n\n case \"pattern\":\n if (settings.regex) {\n const flags = settings.flags || \"\";\n schemas.push(\n z.string().regex(new RegExp(settings.regex, flags), msg || undefined)\n );\n }\n break;\n\n case \"gte\":\n if (settings.value != null) {\n schemas.push(z.number().gte(Number(settings.value), msg || undefined));\n }\n break;\n\n case \"lte\":\n if (settings.value != null) {\n schemas.push(z.number().lte(Number(settings.value), msg || undefined));\n }\n break;\n\n case \"in\":\n if (Array.isArray(settings.values) && settings.values.length > 0) {\n schemas.push(z.enum(settings.values as [string, ...string[]]));\n }\n break;\n\n // \"dateGte\" and \"dateLte\" are applied by `DateTimeFieldMapper`, through the\n // `datetime()` builder, which also hands the limits to the field's picker.\n }\n }\n\n const schema =\n schemas.length === 0\n ? undefined\n : schemas.slice(1).reduce<z.ZodTypeAny>((acc, s) => z.intersection(acc, s), schemas[0]);\n\n return { required, requiredMessage, schema };\n}\n\n/** The `dateGte`/`dateLte` validators, as limits for the `datetime()` builder. */\nexport function mapCmsDateLimits(\n validators: (CmsModelFieldValidator | { name: string })[] | undefined\n): { name: \"dateGte\" | \"dateLte\"; bound: DateBound; message?: string }[] {\n const limits: { name: \"dateGte\" | \"dateLte\"; bound: DateBound; message?: string }[] = [];\n for (const v of validators || []) {\n const validator = v as CmsModelFieldValidator;\n if (validator.name !== \"dateGte\" && validator.name !== \"dateLte\") {\n continue;\n }\n const settings = validator.settings || {};\n const message = interpolateMessage(validator.message, settings);\n if (typeof settings.expression === \"string\") {\n limits.push({\n name: validator.name,\n bound: { expression: settings.expression },\n message\n });\n } else if (settings.value != null) {\n limits.push({ name: validator.name, bound: String(settings.value), message });\n }\n }\n return limits;\n}\n\nexport function mapCmsListValidators(\n validators: (CmsModelFieldValidator | { name: string })[] | undefined\n): { required: boolean; requiredMessage?: string; schema: z.ZodTypeAny | undefined } {\n if (!validators || validators.length === 0) {\n return { required: false, schema: undefined };\n }\n\n let required = false;\n let requiredMessage: string | undefined;\n let arraySchema = z.array(z.unknown());\n\n for (const v of validators) {\n const validator = v as CmsModelFieldValidator;\n const settings = validator.settings || {};\n const msg = interpolateMessage(validator.message, settings);\n\n switch (validator.name) {\n case \"required\":\n required = true;\n requiredMessage = msg;\n break;\n\n case \"minLength\":\n if (settings.value != null) {\n arraySchema = arraySchema.min(\n Number(settings.value),\n msg || undefined\n ) as typeof arraySchema;\n }\n break;\n\n case \"maxLength\":\n if (settings.value != null) {\n arraySchema = arraySchema.max(\n Number(settings.value),\n msg || undefined\n ) as typeof arraySchema;\n }\n break;\n }\n }\n\n const hasConstraints = validators.some(\n v =>\n (v as CmsModelFieldValidator).name === \"minLength\" ||\n (v as CmsModelFieldValidator).name === \"maxLength\"\n );\n\n return {\n required,\n requiredMessage,\n schema: hasConstraints ? arraySchema : undefined\n };\n}\n"],"names":["interpolateMessage","message","settings","match","key","val","String","mapCmsValidators","validators","undefined","required","requiredMessage","schemas","v","validator","msg","z","Number","flags","RegExp","Array","schema","acc","s","mapCmsDateLimits","limits","mapCmsListValidators","arraySchema","hasConstraints"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { applyFieldProps } from "./applyFieldProps.js";
2
+ import { mapCmsDateLimits } from "../CmsValidationMapper.js";
2
3
  class DateTimeFieldMapper {
3
4
  map(field, registry, context) {
4
5
  const builder = registry.datetime();
@@ -18,6 +19,8 @@ class DateTimeFieldMapper {
18
19
  builder.withoutTimezone();
19
20
  break;
20
21
  }
22
+ for (const limit of mapCmsDateLimits(field.validation))if ("dateGte" === limit.name) builder.dateGte(limit.bound, limit.message);
23
+ else builder.dateLte(limit.bound, limit.message);
21
24
  return builder;
22
25
  }
23
26
  constructor(){
@@ -1 +1 @@
1
- {"version":3,"file":"features/formModel/mappers/DateTimeFieldMapper.js","sources":["../../../../src/features/formModel/mappers/DateTimeFieldMapper.ts"],"sourcesContent":["import type { ICmsFieldTypeMapper, ICmsFieldMapperContext } from \"../abstractions.js\";\nimport type { IFieldBuilderRegistry } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { CmsModelField } from \"~/types.js\";\nimport { applyFieldProps } from \"./applyFieldProps.js\";\n\nexport class DateTimeFieldMapper implements ICmsFieldTypeMapper {\n readonly type = \"datetime\";\n\n map(field: CmsModelField, registry: IFieldBuilderRegistry, context: ICmsFieldMapperContext) {\n const builder = registry.datetime();\n applyFieldProps(builder, field, context.rendererMap);\n\n const subtype = field.settings?.type as string | undefined;\n switch (subtype) {\n case \"date\":\n builder.dateOnly();\n break;\n case \"time\":\n builder.timeOnly();\n break;\n case \"dateTimeWithTimezone\":\n builder.withTimezone();\n break;\n case \"dateTimeWithoutTimezone\":\n builder.withoutTimezone();\n break;\n }\n\n return builder;\n }\n}\n"],"names":["DateTimeFieldMapper","field","registry","context","builder","applyFieldProps","subtype"],"mappings":";AAKO,MAAMA;IAGT,IAAIC,KAAoB,EAAEC,QAA+B,EAAEC,OAA+B,EAAE;QACxF,MAAMC,UAAUF,SAAS,QAAQ;QACjCG,gBAAgBD,SAASH,OAAOE,QAAQ,WAAW;QAEnD,MAAMG,UAAUL,MAAM,QAAQ,EAAE;QAChC,OAAQK;YACJ,KAAK;gBACDF,QAAQ,QAAQ;gBAChB;YACJ,KAAK;gBACDA,QAAQ,QAAQ;gBAChB;YACJ,KAAK;gBACDA,QAAQ,YAAY;gBACpB;YACJ,KAAK;gBACDA,QAAQ,eAAe;gBACvB;QACR;QAEA,OAAOA;IACX;;aAvBS,IAAI,GAAG;;AAwBpB"}
1
+ {"version":3,"file":"features/formModel/mappers/DateTimeFieldMapper.js","sources":["../../../../src/features/formModel/mappers/DateTimeFieldMapper.ts"],"sourcesContent":["import type { ICmsFieldTypeMapper, ICmsFieldMapperContext } from \"../abstractions.js\";\nimport type { IFieldBuilderRegistry } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { CmsModelField } from \"~/types.js\";\nimport { applyFieldProps } from \"./applyFieldProps.js\";\nimport { mapCmsDateLimits } from \"../CmsValidationMapper.js\";\n\nexport class DateTimeFieldMapper implements ICmsFieldTypeMapper {\n readonly type = \"datetime\";\n\n map(field: CmsModelField, registry: IFieldBuilderRegistry, context: ICmsFieldMapperContext) {\n const builder = registry.datetime();\n applyFieldProps(builder, field, context.rendererMap);\n\n const subtype = field.settings?.type as string | undefined;\n switch (subtype) {\n case \"date\":\n builder.dateOnly();\n break;\n case \"time\":\n builder.timeOnly();\n break;\n case \"dateTimeWithTimezone\":\n builder.withTimezone();\n break;\n case \"dateTimeWithoutTimezone\":\n builder.withoutTimezone();\n break;\n }\n\n for (const limit of mapCmsDateLimits(field.validation)) {\n if (limit.name === \"dateGte\") {\n builder.dateGte(limit.bound, limit.message);\n } else {\n builder.dateLte(limit.bound, limit.message);\n }\n }\n\n return builder;\n }\n}\n"],"names":["DateTimeFieldMapper","field","registry","context","builder","applyFieldProps","subtype","limit","mapCmsDateLimits"],"mappings":";;AAMO,MAAMA;IAGT,IAAIC,KAAoB,EAAEC,QAA+B,EAAEC,OAA+B,EAAE;QACxF,MAAMC,UAAUF,SAAS,QAAQ;QACjCG,gBAAgBD,SAASH,OAAOE,QAAQ,WAAW;QAEnD,MAAMG,UAAUL,MAAM,QAAQ,EAAE;QAChC,OAAQK;YACJ,KAAK;gBACDF,QAAQ,QAAQ;gBAChB;YACJ,KAAK;gBACDA,QAAQ,QAAQ;gBAChB;YACJ,KAAK;gBACDA,QAAQ,YAAY;gBACpB;YACJ,KAAK;gBACDA,QAAQ,eAAe;gBACvB;QACR;QAEA,KAAK,MAAMG,SAASC,iBAAiBP,MAAM,UAAU,EACjD,IAAIM,AAAe,cAAfA,MAAM,IAAI,EACVH,QAAQ,OAAO,CAACG,MAAM,KAAK,EAAEA,MAAM,OAAO;aAE1CH,QAAQ,OAAO,CAACG,MAAM,KAAK,EAAEA,MAAM,OAAO;QAIlD,OAAOH;IACX;;aA/BS,IAAI,GAAG;;AAgCpB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webiny/app-headless-cms",
3
- "version": "6.5.0",
3
+ "version": "6.5.1-beta.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./index.js",
@@ -28,25 +28,25 @@
28
28
  "@fortawesome/react-fontawesome": "3.5.0",
29
29
  "@lexical/utils": "0.52.0",
30
30
  "@types/react": "18.3.31",
31
- "@webiny/admin-ui": "6.5.0",
32
- "@webiny/app": "6.5.0",
33
- "@webiny/app-aco": "6.5.0",
34
- "@webiny/app-admin": "6.5.0",
35
- "@webiny/app-graphql-playground": "6.5.0",
36
- "@webiny/app-headless-cms-common": "6.5.0",
37
- "@webiny/cms-sdk": "6.5.0",
31
+ "@webiny/admin-ui": "6.5.1-beta.0",
32
+ "@webiny/app": "6.5.1-beta.0",
33
+ "@webiny/app-aco": "6.5.1-beta.0",
34
+ "@webiny/app-admin": "6.5.1-beta.0",
35
+ "@webiny/app-graphql-playground": "6.5.1-beta.0",
36
+ "@webiny/app-headless-cms-common": "6.5.1-beta.0",
37
+ "@webiny/cms-sdk": "6.5.1-beta.0",
38
38
  "@webiny/di": "1.1.0",
39
- "@webiny/feature": "6.5.0",
40
- "@webiny/form": "6.5.0",
41
- "@webiny/frontend-settings": "6.5.0",
42
- "@webiny/icons": "6.5.0",
43
- "@webiny/lexical-editor": "6.5.0",
44
- "@webiny/lexical-nodes": "6.5.0",
45
- "@webiny/plugins": "6.5.0",
46
- "@webiny/react-composition": "6.5.0",
47
- "@webiny/react-properties": "6.5.0",
48
- "@webiny/utils": "6.5.0",
49
- "@webiny/validation": "6.5.0",
39
+ "@webiny/feature": "6.5.1-beta.0",
40
+ "@webiny/form": "6.5.1-beta.0",
41
+ "@webiny/frontend-settings": "6.5.1-beta.0",
42
+ "@webiny/icons": "6.5.1-beta.0",
43
+ "@webiny/lexical-editor": "6.5.1-beta.0",
44
+ "@webiny/lexical-nodes": "6.5.1-beta.0",
45
+ "@webiny/plugins": "6.5.1-beta.0",
46
+ "@webiny/react-composition": "6.5.1-beta.0",
47
+ "@webiny/react-properties": "6.5.1-beta.0",
48
+ "@webiny/utils": "6.5.1-beta.0",
49
+ "@webiny/validation": "6.5.1-beta.0",
50
50
  "dot-prop-immutable": "2.1.1",
51
51
  "graphql": "16.14.2",
52
52
  "graphql-tag": "2.12.7",
@@ -63,7 +63,7 @@
63
63
  "zod": "4.6.7"
64
64
  },
65
65
  "devDependencies": {
66
- "@webiny/build-tools": "6.5.0",
66
+ "@webiny/build-tools": "6.5.1-beta.0",
67
67
  "rimraf": "6.1.3",
68
68
  "typescript": "7.0.2",
69
69
  "vitest": "5.0.5"
@@ -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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"}