@webiny/app-headless-cms 6.5.0-beta.3 → 6.5.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ContentEntriesModule.js +9 -2
- package/ContentEntriesModule.js.map +1 -1
- package/admin/components/ContentEntries/BulkActions/ActionDelete.d.ts +2 -2
- package/admin/components/ContentEntries/BulkActions/ActionDelete.js.map +1 -1
- package/admin/components/ContentEntries/BulkActions/ActionMove.d.ts +2 -2
- package/admin/components/ContentEntries/BulkActions/ActionMove.js.map +1 -1
- package/admin/components/ContentEntries/BulkActions/ActionPublish.d.ts +2 -2
- package/admin/components/ContentEntries/BulkActions/ActionPublish.js.map +1 -1
- package/admin/components/ContentEntries/BulkActions/ActionUnpublish.d.ts +2 -2
- package/admin/components/ContentEntries/BulkActions/ActionUnpublish.js.map +1 -1
- package/admin/components/ContentEntries/Table/Actions/DuplicateEntry.d.ts +2 -0
- package/admin/components/ContentEntries/Table/Actions/DuplicateEntry.js +34 -0
- package/admin/components/ContentEntries/Table/Actions/DuplicateEntry.js.map +1 -0
- package/admin/components/ContentEntries/Table/Actions/index.d.ts +1 -0
- package/admin/components/ContentEntries/Table/Actions/index.js +1 -0
- package/admin/components/ContentModelEditor/ContentModelEditor.js +1 -1
- package/admin/components/ContentModelEditor/ContentModelEditor.js.map +1 -1
- package/admin/components/Dialogs/DuplicateEntryConfirmDialog.d.ts +2 -0
- package/admin/components/Dialogs/DuplicateEntryConfirmDialog.js +22 -0
- package/admin/components/Dialogs/DuplicateEntryConfirmDialog.js.map +1 -0
- package/admin/components/FieldEditor/EditFieldDialog.d.ts +2 -2
- package/admin/components/FieldEditor/Field.js +4 -4
- package/admin/components/FieldEditor/Field.js.map +1 -1
- package/features/contentEntry/CmsEntryError.d.ts +10 -0
- package/features/contentEntry/CmsEntryError.js +11 -0
- package/features/contentEntry/CmsEntryError.js.map +1 -0
- package/features/contentEntry/createEntry/CreateEntryGateway.d.ts +0 -1
- package/features/contentEntry/createEntry/CreateEntryGateway.js +3 -10
- package/features/contentEntry/createEntry/CreateEntryGateway.js.map +1 -1
- package/features/contentEntry/createRevisionFrom/CreateRevisionFromGateway.d.ts +3 -1
- package/features/contentEntry/createRevisionFrom/CreateRevisionFromGateway.js +8 -3
- package/features/contentEntry/createRevisionFrom/CreateRevisionFromGateway.js.map +1 -1
- package/features/contentEntry/duplicateEntry/DuplicateEntryGateway.d.ts +14 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryGateway.js +43 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryGateway.js.map +1 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryRepository.d.ts +15 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryRepository.js +34 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryRepository.js.map +1 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryUseCase.d.ts +11 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryUseCase.js +18 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryUseCase.js.map +1 -0
- package/features/contentEntry/duplicateEntry/abstractions.d.ts +26 -0
- package/features/contentEntry/duplicateEntry/abstractions.js +7 -0
- package/features/contentEntry/duplicateEntry/abstractions.js.map +1 -0
- package/features/contentEntry/duplicateEntry/feature.d.ts +3 -0
- package/features/contentEntry/duplicateEntry/feature.js +21 -0
- package/features/contentEntry/duplicateEntry/feature.js.map +1 -0
- package/features/contentEntry/entryValueGateways.test.d.ts +1 -0
- package/features/contentEntry/entryValueGateways.test.js +106 -0
- package/features/contentEntry/entryValueGateways.test.js.map +1 -0
- package/features/contentEntry/feature.js +2 -0
- package/features/contentEntry/feature.js.map +1 -1
- package/features/contentEntry/singletonEntry/UpdateSingletonEntryGateway.d.ts +0 -1
- package/features/contentEntry/singletonEntry/UpdateSingletonEntryGateway.js +3 -10
- package/features/contentEntry/singletonEntry/UpdateSingletonEntryGateway.js.map +1 -1
- package/features/contentEntry/updateEntry/UpdateEntryGateway.d.ts +0 -1
- package/features/contentEntry/updateEntry/UpdateEntryGateway.js +3 -10
- package/features/contentEntry/updateEntry/UpdateEntryGateway.js.map +1 -1
- package/features/contentEntry/valueTransformers/EntryDataPreparer.d.ts +9 -0
- package/features/contentEntry/valueTransformers/EntryDataPreparer.js +8 -0
- package/features/contentEntry/valueTransformers/EntryDataPreparer.js.map +1 -1
- package/features/contentEntry/valueTransformers/EntryDataPreparer.test.d.ts +1 -0
- package/features/contentEntry/valueTransformers/EntryDataPreparer.test.js +113 -0
- package/features/contentEntry/valueTransformers/EntryDataPreparer.test.js.map +1 -0
- package/features/contentEntry/valueTransformers/entryValueFixtures.d.ts +146 -0
- package/features/contentEntry/valueTransformers/entryValueFixtures.js +171 -0
- package/features/contentEntry/valueTransformers/entryValueFixtures.js.map +1 -0
- package/features/formModel/CmsFormModelBuilder.d.ts +8 -0
- package/features/formModel/CmsFormModelBuilder.js +25 -2
- package/features/formModel/CmsFormModelBuilder.js.map +1 -1
- package/features/formModel/CmsFormModelBuilder.test.d.ts +1 -0
- package/features/formModel/CmsFormModelBuilder.test.js +111 -0
- package/features/formModel/CmsFormModelBuilder.test.js.map +1 -0
- package/features/formModel/mappers/DynamicZoneFieldMapper.js +1 -0
- package/features/formModel/mappers/DynamicZoneFieldMapper.js.map +1 -1
- package/features/model/exportModels/ExportModelsGateway.d.ts +1 -1
- package/features/model/exportModels/ExportModelsGateway.js.map +1 -1
- package/features/model/exportModels/ExportModelsUseCase.js +7 -1
- package/features/model/exportModels/ExportModelsUseCase.js.map +1 -1
- package/features/model/exportModels/abstractions.d.ts +8 -2
- package/features/model/exportModels/abstractions.js.map +1 -1
- package/package.json +26 -26
- package/presentation/contentEntries/form/ContentEntryFormPresenter.js +3 -1
- package/presentation/contentEntries/form/ContentEntryFormPresenter.js.map +1 -1
- package/presentation/contentEntries/form/toFormErrors.d.ts +7 -0
- package/presentation/contentEntries/form/toFormErrors.js +49 -0
- package/presentation/contentEntries/form/toFormErrors.js.map +1 -0
- package/presentation/contentEntries/form/toFormErrors.test.d.ts +1 -0
- package/presentation/contentEntries/form/toFormErrors.test.js +175 -0
- package/presentation/contentEntries/form/toFormErrors.test.js.map +1 -0
- package/presentation/contentEntries/list/ContentEntriesPresenter.d.ts +6 -2
- package/presentation/contentEntries/list/ContentEntriesPresenter.js +27 -2
- package/presentation/contentEntries/list/ContentEntriesPresenter.js.map +1 -1
- package/presentation/contentEntries/list/ContentEntriesPresenter.test.js +58 -1
- package/presentation/contentEntries/list/ContentEntriesPresenter.test.js.map +1 -1
- package/presentation/contentEntries/list/abstractions.d.ts +12 -0
- package/presentation/contentEntries/list/abstractions.js.map +1 -1
- package/presentation/contentEntries/singleEntry/SingleEntryPresenter.js +3 -1
- package/presentation/contentEntries/singleEntry/SingleEntryPresenter.js.map +1 -1
- package/presentation/contentEntries/trashBin/CmsTrashBin.d.ts +2 -2
- package/presentation/contentEntries/views/CmsAdvancedSearch.d.ts +2 -2
- package/presentation/contentEntries/views/ContentEntriesListLayout.d.ts +2 -2
- package/presentation/contentEntries/views/ContentEntryFormView.d.ts +2 -2
- package/presentation/contentEntries/views/OlderRevisionAlert.d.ts +2 -2
- package/presentation/contentEntries/views/RevisionDrawer.d.ts +2 -2
- package/presentation/contentEntries/views/RevisionsList.d.ts +2 -2
- package/presentation/contentEntries/views/SingleEntryLayout.d.ts +2 -2
- package/presentation/contentEntries/views/Table/Table.d.ts +2 -2
- package/presentation/contentEntries/views/actions/CreateNewRevisionButton.d.ts +2 -2
- package/presentation/contentEntries/views/actions/DeleteEntryMenuItem.d.ts +2 -2
- package/presentation/contentEntries/views/actions/PublishOnlyButton.d.ts +2 -2
- package/presentation/contentEntries/views/actions/RevisionSelector.d.ts +2 -2
- package/presentation/contentEntries/views/actions/SaveAndPublishButton.d.ts +2 -2
- package/presentation/contentEntries/views/actions/SaveContentButton.d.ts +2 -2
- package/presentation/contentEntries/views/actions/ShowRevisionListMenuItem.d.ts +2 -2
- package/presentation/contentEntries/views/layout/ContentEntryForm.d.ts +12 -12
- package/presentation/contentModels/ContentModelsPresenter.d.ts +5 -5
- package/presentation/contentModels/ContentModelsPresenter.js +1 -1
- package/presentation/contentModels/ContentModelsPresenter.js.map +1 -1
- package/presentation/contentModels/abstractions.d.ts +7 -2
- package/presentation/contentModels/abstractions.js.map +1 -1
- package/presentation/contentModels/components/CloneContentModelDialog.d.ts +2 -2
- package/presentation/contentModels/components/ContentModels.d.ts +2 -2
- package/presentation/contentModels/components/ContentModelsDataList.d.ts +2 -2
- package/presentation/contentModels/components/ContentModelsDataList.js +6 -5
- package/presentation/contentModels/components/ContentModelsDataList.js.map +1 -1
- package/presentation/contentModels/components/NewContentModelDialog.d.ts +2 -2
- package/presentation/contentModels/components/fullDelete/dialog/Content.js +2 -2
- package/presentation/contentModels/components/fullDelete/dialog/Content.js.map +1 -1
- package/presentation/contentModels/components/fullDelete/types.js.map +1 -1
- package/presentation/fieldRenderers/ref/components/RefFieldOptions.d.ts +2 -2
- package/presentation/fieldRenderers/ref/components/RefFieldOptions.js +3 -2
- package/presentation/fieldRenderers/ref/components/RefFieldOptions.js.map +1 -1
- package/presentation/importContentModels/ImportContentModelsDialog.d.ts +2 -2
- package/presentation/importContentModels/ImportContentModelsPresenter.js +1 -1
- package/presentation/importContentModels/ImportContentModelsPresenter.js.map +1 -1
- package/presentation/importContentModels/components/DataList.d.ts +2 -2
- package/presentation/importContentModels/components/FileUpload.d.ts +2 -2
- package/presentation/importContentModels/components/FileUpload.js +1 -1
- package/presentation/importContentModels/components/FileUpload.js.map +1 -1
- package/presentation/importContentModels/components/Model/DataListModelItem.js +3 -3
- package/presentation/importContentModels/components/Model/DataListModelItem.js.map +1 -1
- package/presentation/importContentModels/components/Model/DataListModelItemInfo.js +2 -2
- package/presentation/importContentModels/components/Model/DataListModelItemInfo.js.map +1 -1
- package/presentation/importContentModels/components/Model/DataListModels.d.ts +2 -2
- package/presentation/menus/ContentGroupsMenuItems.d.ts +2 -2
- package/presentation/modelGroup/ModelGroupPresenter.js +1 -2
- package/presentation/modelGroup/ModelGroupPresenter.js.map +1 -1
- package/presentation/modelGroup/components/ContentModelGroups.d.ts +2 -2
- package/presentation/modelGroup/components/ContentModelGroupsDataList.d.ts +6 -2
- package/presentation/modelGroup/components/ContentModelGroupsForm.d.ts +8 -2
- package/utils/normalizeIcon.d.ts +4 -0
- package/utils/normalizeIcon.js +9 -6
- package/utils/normalizeIcon.js.map +1 -1
|
@@ -10,7 +10,11 @@ class CmsFormModelBuilderImpl {
|
|
|
10
10
|
for (const mapper of createBuiltInMappers())this.mappers.set(mapper.type, mapper);
|
|
11
11
|
for (const mapper of customMappers || [])this.mappers.set(mapper.type, mapper);
|
|
12
12
|
this.rendererMap = new Map();
|
|
13
|
-
|
|
13
|
+
this.renderers = new Map();
|
|
14
|
+
for (const renderer of fieldRenderers || []){
|
|
15
|
+
this.rendererMap.set(renderer.rendererName, renderer.formRenderer);
|
|
16
|
+
this.renderers.set(renderer.rendererName, renderer);
|
|
17
|
+
}
|
|
14
18
|
}
|
|
15
19
|
build(model) {
|
|
16
20
|
const context = {
|
|
@@ -34,11 +38,30 @@ class CmsFormModelBuilderImpl {
|
|
|
34
38
|
layout: model.layout ? (layout)=>mapCmsLayout(model.layout, layout, idToFieldId) : void 0
|
|
35
39
|
};
|
|
36
40
|
}
|
|
37
|
-
mapField(
|
|
41
|
+
mapField(modelField, registry, context) {
|
|
42
|
+
const field = this.withCompatibleRenderer(modelField, context.model);
|
|
38
43
|
const mapper = this.mappers.get(field.type);
|
|
39
44
|
if (mapper) return mapper.map(field, registry, context);
|
|
40
45
|
return applyFieldProps(registry.text(), field, context.rendererMap);
|
|
41
46
|
}
|
|
47
|
+
withCompatibleRenderer(field, model) {
|
|
48
|
+
if (field.list || !field.renderer || "object" != typeof field.renderer) return field;
|
|
49
|
+
const renderer = this.renderers.get(field.renderer.name);
|
|
50
|
+
if (!renderer || renderer.canUse({
|
|
51
|
+
field,
|
|
52
|
+
model
|
|
53
|
+
})) return field;
|
|
54
|
+
if (!renderer.canUse({
|
|
55
|
+
field: {
|
|
56
|
+
...field,
|
|
57
|
+
list: true
|
|
58
|
+
},
|
|
59
|
+
model
|
|
60
|
+
})) return field;
|
|
61
|
+
if ("development" === process.env.NODE_ENV) console.warn(`[CmsFormModelBuilder] Renderer "${field.renderer.name}" is for list fields; field "${field.fieldId}" is not a list and uses its default renderer instead.`);
|
|
62
|
+
const { renderer: _renderer, ...rest } = field;
|
|
63
|
+
return rest;
|
|
64
|
+
}
|
|
42
65
|
}
|
|
43
66
|
const CmsFormModelBuilder_CmsFormModelBuilder = CmsFormModelBuilder.createImplementation({
|
|
44
67
|
implementation: CmsFormModelBuilderImpl,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/formModel/CmsFormModelBuilder.js","sources":["../../../src/features/formModel/CmsFormModelBuilder.ts"],"sourcesContent":["import type {\n IFieldBuilder,\n IFieldBuilderRegistry,\n IFormModelConfig\n} from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport {\n isLayoutField,\n type CmsEditorFieldsLayout,\n type CmsModel,\n type CmsModelField\n} from \"~/types.js\";\nimport type {\n ICmsFieldTypeMapper,\n ICmsFieldMapperContext,\n ICmsFormModelBuilder\n} from \"./abstractions.js\";\nimport { CmsFormModelBuilder as BuilderAbstraction } from \"./abstractions.js\";\nimport { CmsFieldTypeMapper } from \"./abstractions.js\";\nimport { CmsFieldRenderer } from \"~/presentation/fieldRenderers/abstractions.js\";\nimport type { ICmsFieldRenderer } from \"~/presentation/fieldRenderers/abstractions.js\";\nimport { mapCmsLayout } from \"./CmsLayoutMapper.js\";\nimport { createBuiltInMappers } from \"./mappers/index.js\";\nimport { applyFieldProps } from \"./mappers/applyFieldProps.js\";\n\nclass CmsFormModelBuilderImpl implements ICmsFormModelBuilder {\n private mappers: Map<string, ICmsFieldTypeMapper>;\n private rendererMap: Map<string, string>;\n\n constructor(\n customMappers: ICmsFieldTypeMapper[] | undefined,\n fieldRenderers: ICmsFieldRenderer[] | undefined\n ) {\n this.mappers = new Map();\n for (const mapper of createBuiltInMappers()) {\n this.mappers.set(mapper.type, mapper);\n }\n for (const mapper of customMappers || []) {\n this.mappers.set(mapper.type, mapper);\n }\n\n this.rendererMap = new Map();\n for (const renderer of fieldRenderers || []) {\n this.rendererMap.set(renderer.rendererName, renderer.formRenderer);\n }\n }\n\n build(model: CmsModel): IFormModelConfig {\n const context: ICmsFieldMapperContext = {\n model,\n rendererMap: this.rendererMap,\n mapField: (field, registry) => this.mapField(field, registry, context)\n };\n\n const idToFieldId = new Map<string, string>();\n for (const field of model.fields) {\n idToFieldId.set(field.id, field.fieldId);\n }\n\n const fieldIdsInLayout = model.layout ? collectFieldIds(model.layout, idToFieldId) : null;\n\n return {\n fields: registry => {\n const result: Record<string, IFieldBuilder> = {};\n for (const field of model.fields) {\n const builder = this.mapField(field, registry, context);\n if (fieldIdsInLayout && !fieldIdsInLayout.has(field.fieldId)) {\n builder.hidden();\n }\n result[field.fieldId] = builder;\n }\n return result;\n },\n layout: model.layout\n ? layout => mapCmsLayout(model.layout!, layout, idToFieldId)\n : undefined\n };\n }\n\n private mapField(\n
|
|
1
|
+
{"version":3,"file":"features/formModel/CmsFormModelBuilder.js","sources":["../../../src/features/formModel/CmsFormModelBuilder.ts"],"sourcesContent":["import type {\n IFieldBuilder,\n IFieldBuilderRegistry,\n IFormModelConfig\n} from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport {\n isLayoutField,\n type CmsEditorFieldsLayout,\n type CmsModel,\n type CmsModelField\n} from \"~/types.js\";\nimport type {\n ICmsFieldTypeMapper,\n ICmsFieldMapperContext,\n ICmsFormModelBuilder\n} from \"./abstractions.js\";\nimport { CmsFormModelBuilder as BuilderAbstraction } from \"./abstractions.js\";\nimport { CmsFieldTypeMapper } from \"./abstractions.js\";\nimport { CmsFieldRenderer } from \"~/presentation/fieldRenderers/abstractions.js\";\nimport type { ICmsFieldRenderer } from \"~/presentation/fieldRenderers/abstractions.js\";\nimport { mapCmsLayout } from \"./CmsLayoutMapper.js\";\nimport { createBuiltInMappers } from \"./mappers/index.js\";\nimport { applyFieldProps } from \"./mappers/applyFieldProps.js\";\n\nclass CmsFormModelBuilderImpl implements ICmsFormModelBuilder {\n private mappers: Map<string, ICmsFieldTypeMapper>;\n private rendererMap: Map<string, string>;\n private renderers: Map<string, ICmsFieldRenderer>;\n\n constructor(\n customMappers: ICmsFieldTypeMapper[] | undefined,\n fieldRenderers: ICmsFieldRenderer[] | undefined\n ) {\n this.mappers = new Map();\n for (const mapper of createBuiltInMappers()) {\n this.mappers.set(mapper.type, mapper);\n }\n for (const mapper of customMappers || []) {\n this.mappers.set(mapper.type, mapper);\n }\n\n this.rendererMap = new Map();\n this.renderers = new Map();\n for (const renderer of fieldRenderers || []) {\n this.rendererMap.set(renderer.rendererName, renderer.formRenderer);\n this.renderers.set(renderer.rendererName, renderer);\n }\n }\n\n build(model: CmsModel): IFormModelConfig {\n const context: ICmsFieldMapperContext = {\n model,\n rendererMap: this.rendererMap,\n mapField: (field, registry) => this.mapField(field, registry, context)\n };\n\n const idToFieldId = new Map<string, string>();\n for (const field of model.fields) {\n idToFieldId.set(field.id, field.fieldId);\n }\n\n const fieldIdsInLayout = model.layout ? collectFieldIds(model.layout, idToFieldId) : null;\n\n return {\n fields: registry => {\n const result: Record<string, IFieldBuilder> = {};\n for (const field of model.fields) {\n const builder = this.mapField(field, registry, context);\n if (fieldIdsInLayout && !fieldIdsInLayout.has(field.fieldId)) {\n builder.hidden();\n }\n result[field.fieldId] = builder;\n }\n return result;\n },\n layout: model.layout\n ? layout => mapCmsLayout(model.layout!, layout, idToFieldId)\n : undefined\n };\n }\n\n private mapField(\n modelField: CmsModelField,\n registry: IFieldBuilderRegistry,\n context: ICmsFieldMapperContext\n ): IFieldBuilder {\n const field = this.withCompatibleRenderer(modelField, context.model);\n const mapper = this.mappers.get(field.type);\n if (mapper) {\n return mapper.map(field, registry, context);\n }\n\n return applyFieldProps(registry.text(), field, context.rendererMap);\n }\n\n /**\n * A list renderer can't render a single value: `dateTimeInputs` calls `.map()` on a\n * stored date string and crashes the form. When a single-value field is configured with\n * a renderer that only accepts list fields, drop it so the field type's default\n * single-value renderer is used instead.\n */\n private withCompatibleRenderer(field: CmsModelField, model: CmsModel): CmsModelField {\n if (field.list || !field.renderer || typeof field.renderer !== \"object\") {\n return field;\n }\n const renderer = this.renderers.get(field.renderer.name);\n if (!renderer || renderer.canUse({ field, model })) {\n return field;\n }\n if (!renderer.canUse({ field: { ...field, list: true }, model })) {\n return field;\n }\n if (process.env.NODE_ENV === \"development\") {\n console.warn(\n `[CmsFormModelBuilder] Renderer \"${field.renderer.name}\" is for list fields; ` +\n `field \"${field.fieldId}\" is not a list and uses its default renderer instead.`\n );\n }\n // Mappers treat a missing renderer as \"use the field type's default\".\n const { renderer: _renderer, ...rest } = field;\n return rest as CmsModelField;\n }\n}\n\nexport const CmsFormModelBuilder = BuilderAbstraction.createImplementation({\n implementation: CmsFormModelBuilderImpl,\n dependencies: [\n [CmsFieldTypeMapper, { multiple: true, optional: true }],\n [CmsFieldRenderer, { multiple: true, optional: true }]\n ]\n});\n\nfunction collectFieldIds(\n layout: CmsEditorFieldsLayout,\n idToFieldId: Map<string, string>\n): Set<string> {\n const fieldIds = new Set<string>();\n\n for (const row of layout) {\n for (const cell of row) {\n if (typeof cell === \"string\") {\n const fieldId = idToFieldId.get(cell);\n if (fieldId) {\n fieldIds.add(fieldId);\n }\n } else if (isLayoutField(cell) && cell.type === \"tabs\") {\n const tabsField = cell as { tabs: Array<{ layout: CmsEditorFieldsLayout }> };\n for (const tab of tabsField.tabs) {\n for (const id of collectFieldIds(tab.layout, idToFieldId)) {\n fieldIds.add(id);\n }\n }\n }\n }\n }\n\n return fieldIds;\n}\n"],"names":["CmsFormModelBuilderImpl","customMappers","fieldRenderers","Map","mapper","createBuiltInMappers","renderer","model","context","field","registry","idToFieldId","fieldIdsInLayout","collectFieldIds","result","builder","layout","mapCmsLayout","undefined","modelField","applyFieldProps","process","console","_renderer","rest","CmsFormModelBuilder","BuilderAbstraction","CmsFieldTypeMapper","CmsFieldRenderer","fieldIds","Set","row","cell","fieldId","isLayoutField","tabsField","tab","id"],"mappings":";;;;;;AAwBA,MAAMA;IAKF,YACIC,aAAgD,EAChDC,cAA+C,CACjD;QACE,IAAI,CAAC,OAAO,GAAG,IAAIC;QACnB,KAAK,MAAMC,UAAUC,uBACjB,IAAI,CAAC,OAAO,CAAC,GAAG,CAACD,OAAO,IAAI,EAAEA;QAElC,KAAK,MAAMA,UAAUH,iBAAiB,EAAE,CACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAACG,OAAO,IAAI,EAAEA;QAGlC,IAAI,CAAC,WAAW,GAAG,IAAID;QACvB,IAAI,CAAC,SAAS,GAAG,IAAIA;QACrB,KAAK,MAAMG,YAAYJ,kBAAkB,EAAE,CAAE;YACzC,IAAI,CAAC,WAAW,CAAC,GAAG,CAACI,SAAS,YAAY,EAAEA,SAAS,YAAY;YACjE,IAAI,CAAC,SAAS,CAAC,GAAG,CAACA,SAAS,YAAY,EAAEA;QAC9C;IACJ;IAEA,MAAMC,KAAe,EAAoB;QACrC,MAAMC,UAAkC;YACpCD;YACA,aAAa,IAAI,CAAC,WAAW;YAC7B,UAAU,CAACE,OAAOC,WAAa,IAAI,CAAC,QAAQ,CAACD,OAAOC,UAAUF;QAClE;QAEA,MAAMG,cAAc,IAAIR;QACxB,KAAK,MAAMM,SAASF,MAAM,MAAM,CAC5BI,YAAY,GAAG,CAACF,MAAM,EAAE,EAAEA,MAAM,OAAO;QAG3C,MAAMG,mBAAmBL,MAAM,MAAM,GAAGM,gBAAgBN,MAAM,MAAM,EAAEI,eAAe;QAErF,OAAO;YACH,QAAQD,CAAAA;gBACJ,MAAMI,SAAwC,CAAC;gBAC/C,KAAK,MAAML,SAASF,MAAM,MAAM,CAAE;oBAC9B,MAAMQ,UAAU,IAAI,CAAC,QAAQ,CAACN,OAAOC,UAAUF;oBAC/C,IAAII,oBAAoB,CAACA,iBAAiB,GAAG,CAACH,MAAM,OAAO,GACvDM,QAAQ,MAAM;oBAElBD,MAAM,CAACL,MAAM,OAAO,CAAC,GAAGM;gBAC5B;gBACA,OAAOD;YACX;YACA,QAAQP,MAAM,MAAM,GACdS,CAAAA,SAAUC,aAAaV,MAAM,MAAM,EAAGS,QAAQL,eAC9CO;QACV;IACJ;IAEQ,SACJC,UAAyB,EACzBT,QAA+B,EAC/BF,OAA+B,EAClB;QACb,MAAMC,QAAQ,IAAI,CAAC,sBAAsB,CAACU,YAAYX,QAAQ,KAAK;QACnE,MAAMJ,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,CAACK,MAAM,IAAI;QAC1C,IAAIL,QACA,OAAOA,OAAO,GAAG,CAACK,OAAOC,UAAUF;QAGvC,OAAOY,gBAAgBV,SAAS,IAAI,IAAID,OAAOD,QAAQ,WAAW;IACtE;IAQQ,uBAAuBC,KAAoB,EAAEF,KAAe,EAAiB;QACjF,IAAIE,MAAM,IAAI,IAAI,CAACA,MAAM,QAAQ,IAAI,AAA0B,YAA1B,OAAOA,MAAM,QAAQ,EACtD,OAAOA;QAEX,MAAMH,WAAW,IAAI,CAAC,SAAS,CAAC,GAAG,CAACG,MAAM,QAAQ,CAAC,IAAI;QACvD,IAAI,CAACH,YAAYA,SAAS,MAAM,CAAC;YAAEG;YAAOF;QAAM,IAC5C,OAAOE;QAEX,IAAI,CAACH,SAAS,MAAM,CAAC;YAAE,OAAO;gBAAE,GAAGG,KAAK;gBAAE,MAAM;YAAK;YAAGF;QAAM,IAC1D,OAAOE;QAEX,IAAIY,AAAyB,kBAAzBA,QAAQ,GAAG,CAAC,QAAQ,EACpBC,QAAQ,IAAI,CACR,CAAC,gCAAgC,EAAEb,MAAM,QAAQ,CAAC,IAAI,CACjD,6BAAO,EAAEA,MAAM,OAAO,CAAC,sDAAsD,CADJ;QAKtF,MAAM,EAAE,UAAUc,SAAS,EAAE,GAAGC,MAAM,GAAGf;QACzC,OAAOe;IACX;AACJ;AAEO,MAAMC,0CAAsBC,oBAAAA,oBAAuC,CAAC;IACvE,gBAAgB1B;IAChB,cAAc;QACV;YAAC2B;YAAoB;gBAAE,UAAU;gBAAM,UAAU;YAAK;SAAE;QACxD;YAACC;YAAkB;gBAAE,UAAU;gBAAM,UAAU;YAAK;SAAE;KACzD;AACL;AAEA,SAASf,gBACLG,MAA6B,EAC7BL,WAAgC;IAEhC,MAAMkB,WAAW,IAAIC;IAErB,KAAK,MAAMC,OAAOf,OACd,KAAK,MAAMgB,QAAQD,IACf,IAAI,AAAgB,YAAhB,OAAOC,MAAmB;QAC1B,MAAMC,UAAUtB,YAAY,GAAG,CAACqB;QAChC,IAAIC,SACAJ,SAAS,GAAG,CAACI;IAErB,OAAO,IAAIC,cAAcF,SAASA,AAAc,WAAdA,KAAK,IAAI,EAAa;QACpD,MAAMG,YAAYH;QAClB,KAAK,MAAMI,OAAOD,UAAU,IAAI,CAC5B,KAAK,MAAME,MAAMxB,gBAAgBuB,IAAI,MAAM,EAAEzB,aACzCkB,SAAS,GAAG,CAACQ;IAGzB;IAIR,OAAOR;AACX"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { Container } from "@webiny/di";
|
|
3
|
+
import { FormModelFeature } from "@webiny/app-admin/features/formModel/feature.js";
|
|
4
|
+
import { IdentityContextFeature } from "@webiny/app-admin/features/security/IdentityContext/feature.js";
|
|
5
|
+
import { FormModelFactory } from "@webiny/app-admin/features/formModel/abstractions.js";
|
|
6
|
+
import { CmsFormModelBuilder } from "./abstractions.js";
|
|
7
|
+
import { CmsFormModelFeature } from "./feature.js";
|
|
8
|
+
import { DateTimeInputRenderer } from "../../presentation/fieldTypes/renderers/dateTime/DateTimeInputRenderer.js";
|
|
9
|
+
import { DateTimeInputsRenderer } from "../../presentation/fieldTypes/renderers/dateTime/DateTimeInputsRenderer.js";
|
|
10
|
+
import { TextInputRenderer } from "../../presentation/fieldTypes/renderers/text/TextInputRenderer.js";
|
|
11
|
+
import { TextInputsRenderer } from "../../presentation/fieldTypes/renderers/text/TextInputsRenderer.js";
|
|
12
|
+
const field = (fieldId, type, list, renderer, extra = {})=>({
|
|
13
|
+
id: fieldId,
|
|
14
|
+
fieldId,
|
|
15
|
+
type,
|
|
16
|
+
label: fieldId,
|
|
17
|
+
tags: [],
|
|
18
|
+
list,
|
|
19
|
+
renderer: {
|
|
20
|
+
name: renderer,
|
|
21
|
+
settings: {}
|
|
22
|
+
},
|
|
23
|
+
validation: [],
|
|
24
|
+
listValidation: [],
|
|
25
|
+
settings: {},
|
|
26
|
+
predefinedValues: {
|
|
27
|
+
enabled: false,
|
|
28
|
+
values: []
|
|
29
|
+
},
|
|
30
|
+
...extra
|
|
31
|
+
});
|
|
32
|
+
function createCmsForm(fields) {
|
|
33
|
+
const container = new Container();
|
|
34
|
+
IdentityContextFeature.register(container);
|
|
35
|
+
FormModelFeature.register(container);
|
|
36
|
+
CmsFormModelFeature.register(container);
|
|
37
|
+
container.register(DateTimeInputRenderer);
|
|
38
|
+
container.register(DateTimeInputsRenderer);
|
|
39
|
+
container.register(TextInputRenderer);
|
|
40
|
+
container.register(TextInputsRenderer);
|
|
41
|
+
const model = {
|
|
42
|
+
modelId: "test",
|
|
43
|
+
fields,
|
|
44
|
+
layout: fields.map((f)=>[
|
|
45
|
+
f.fieldId
|
|
46
|
+
])
|
|
47
|
+
};
|
|
48
|
+
const config = container.resolve(CmsFormModelBuilder).build(model);
|
|
49
|
+
return container.resolve(FormModelFactory).create(config);
|
|
50
|
+
}
|
|
51
|
+
describe("CmsFormModelBuilder renderer cardinality", ()=>{
|
|
52
|
+
it("keeps renderers that match the field's cardinality", ()=>{
|
|
53
|
+
const form = createCmsForm([
|
|
54
|
+
field("single", "datetime", false, "date-time-input"),
|
|
55
|
+
field("many", "datetime", true, "date-time-inputs")
|
|
56
|
+
]);
|
|
57
|
+
expect(form.field("single").vm.renderer).toBe("dateTimeInput");
|
|
58
|
+
expect(form.field("many").vm.renderer).toBe("dateTimeInputs");
|
|
59
|
+
});
|
|
60
|
+
it("falls back to the single-value renderer when a list renderer is set on a non-list field", ()=>{
|
|
61
|
+
const form = createCmsForm([
|
|
62
|
+
field("openTime", "datetime", false, "date-time-inputs"),
|
|
63
|
+
field("name", "text", false, "text-inputs")
|
|
64
|
+
]);
|
|
65
|
+
expect(form.field("openTime").vm.renderer).toBe("dateTimeInput");
|
|
66
|
+
expect(form.field("name").vm.renderer).toBe("textInput");
|
|
67
|
+
});
|
|
68
|
+
it("keeps the list renderer for list datetime fields with a subtype", ()=>{
|
|
69
|
+
const form = createCmsForm([
|
|
70
|
+
"date",
|
|
71
|
+
"time",
|
|
72
|
+
"dateTimeWithTimezone",
|
|
73
|
+
"dateTimeWithoutTimezone"
|
|
74
|
+
].map((type)=>field(type, "datetime", true, "date-time-inputs", {
|
|
75
|
+
settings: {
|
|
76
|
+
type
|
|
77
|
+
}
|
|
78
|
+
})));
|
|
79
|
+
expect(form.field("date").vm.renderer).toBe("dateTimeInputs");
|
|
80
|
+
expect(form.field("time").vm.renderer).toBe("dateTimeInputs");
|
|
81
|
+
expect(form.field("dateTimeWithTimezone").vm.renderer).toBe("dateTimeInputs");
|
|
82
|
+
expect(form.field("dateTimeWithoutTimezone").vm.renderer).toBe("dateTimeInputs");
|
|
83
|
+
});
|
|
84
|
+
it("applies the fallback to fields nested in object lists", ()=>{
|
|
85
|
+
const form = createCmsForm([
|
|
86
|
+
field("holidayHours", "object", true, "objects-accordion", {
|
|
87
|
+
settings: {
|
|
88
|
+
fields: [
|
|
89
|
+
field("openTime", "datetime", false, "date-time-inputs")
|
|
90
|
+
],
|
|
91
|
+
layout: [
|
|
92
|
+
[
|
|
93
|
+
"openTime"
|
|
94
|
+
]
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
]);
|
|
99
|
+
form.setData({
|
|
100
|
+
holidayHours: [
|
|
101
|
+
{
|
|
102
|
+
openTime: "2026-12-24T09:00:00.000Z"
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
});
|
|
106
|
+
const item = form.field("holidayHours").items[0];
|
|
107
|
+
expect(item.children.get("openTime").vm.renderer).toBe("dateTimeInput");
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
//# sourceMappingURL=CmsFormModelBuilder.test.js.map
|
|
@@ -0,0 +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"],"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"],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@ class DynamicZoneFieldMapper {
|
|
|
6
6
|
const templates = field.settings?.templates;
|
|
7
7
|
if (templates) for (const template of templates)builder.template(template.id, (t)=>{
|
|
8
8
|
t.label(template.name);
|
|
9
|
+
if (template.description) t.description(template.description);
|
|
9
10
|
if (template.icon) {
|
|
10
11
|
const icon = template.icon;
|
|
11
12
|
if ("object" == typeof icon && "name" in icon) t.icon(icon);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/formModel/mappers/DynamicZoneFieldMapper.js","sources":["../../../../src/features/formModel/mappers/DynamicZoneFieldMapper.ts"],"sourcesContent":["import type { ICmsFieldTypeMapper, ICmsFieldMapperContext } from \"../abstractions.js\";\nimport type {\n IFieldBuilder,\n IFieldBuilderRegistry,\n IObjectFieldBuilder\n} from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { CmsModelField, CmsDynamicZoneTemplate } from \"~/types.js\";\nimport { applyFieldProps } from \"./applyFieldProps.js\";\nimport type { ITemplateIcon } from \"@webiny/app-admin/features/formModel/index.js\";\nimport { generateAlphaNumericLowerCaseId } from \"@webiny/utils/generateId\";\n\nexport class DynamicZoneFieldMapper implements ICmsFieldTypeMapper {\n readonly type = \"dynamicZone\";\n\n map(\n field: CmsModelField,\n registry: IFieldBuilderRegistry,\n context: ICmsFieldMapperContext\n ): IFieldBuilder {\n const builder = registry.object() as IObjectFieldBuilder;\n\n const templates = field.settings?.templates as CmsDynamicZoneTemplate[] | undefined;\n if (templates) {\n for (const template of templates) {\n builder.template(template.id, t => {\n t.label(template.name);\n if (template.icon) {\n const icon = template.icon;\n if (typeof icon === \"object\" && \"name\" in icon) {\n t.icon(icon as ITemplateIcon);\n } else if (typeof icon === \"string\") {\n t.icon({ type: \"icon\", name: icon });\n }\n }\n t.fields(childRegistry => {\n const result: Record<string, IFieldBuilder> = {};\n result[\"_id\"] = childRegistry\n .text()\n .hidden()\n .defaultValue(() => generateAlphaNumericLowerCaseId(12))\n .cloneValue(() => generateAlphaNumericLowerCaseId(12));\n if (template.fields && template.fields.length > 0) {\n for (const child of template.fields) {\n result[child.fieldId] = context.mapField(child, childRegistry);\n }\n }\n return result;\n });\n });\n }\n }\n\n return applyFieldProps(builder, field, context.rendererMap);\n }\n}\n"],"names":["DynamicZoneFieldMapper","field","registry","context","builder","templates","template","t","icon","childRegistry","result","generateAlphaNumericLowerCaseId","child","applyFieldProps"],"mappings":";;AAWO,MAAMA;IAGT,IACIC,KAAoB,EACpBC,QAA+B,EAC/BC,OAA+B,EAClB;QACb,MAAMC,UAAUF,SAAS,MAAM;QAE/B,MAAMG,YAAYJ,MAAM,QAAQ,EAAE;QAClC,IAAII,WACA,KAAK,MAAMC,YAAYD,UACnBD,QAAQ,QAAQ,CAACE,SAAS,EAAE,EAAEC,CAAAA;YAC1BA,EAAE,KAAK,CAACD,SAAS,IAAI;YACrB,IAAIA,SAAS,IAAI,EAAE;gBACf,MAAME,OAAOF,SAAS,IAAI;gBAC1B,IAAI,AAAgB,YAAhB,OAAOE,QAAqB,UAAUA,MACtCD,EAAE,IAAI,CAACC;qBACJ,IAAI,AAAgB,YAAhB,OAAOA,MACdD,EAAE,IAAI,CAAC;oBAAE,MAAM;oBAAQ,MAAMC;gBAAK;YAE1C;YACAD,EAAE,MAAM,CAACE,CAAAA;gBACL,MAAMC,SAAwC,CAAC;gBAC/CA,MAAM,CAAC,MAAM,GAAGD,cACX,IAAI,GACJ,MAAM,GACN,YAAY,CAAC,IAAME,gCAAgC,KACnD,UAAU,CAAC,IAAMA,gCAAgC;gBACtD,IAAIL,SAAS,MAAM,IAAIA,SAAS,MAAM,CAAC,MAAM,GAAG,GAC5C,KAAK,MAAMM,SAASN,SAAS,MAAM,CAC/BI,MAAM,CAACE,MAAM,OAAO,CAAC,GAAGT,QAAQ,QAAQ,CAACS,OAAOH;gBAGxD,OAAOC;YACX;QACJ;QAIR,OAAOG,gBAAgBT,SAASH,OAAOE,QAAQ,WAAW;IAC9D;;
|
|
1
|
+
{"version":3,"file":"features/formModel/mappers/DynamicZoneFieldMapper.js","sources":["../../../../src/features/formModel/mappers/DynamicZoneFieldMapper.ts"],"sourcesContent":["import type { ICmsFieldTypeMapper, ICmsFieldMapperContext } from \"../abstractions.js\";\nimport type {\n IFieldBuilder,\n IFieldBuilderRegistry,\n IObjectFieldBuilder\n} from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { CmsModelField, CmsDynamicZoneTemplate } from \"~/types.js\";\nimport { applyFieldProps } from \"./applyFieldProps.js\";\nimport type { ITemplateIcon } from \"@webiny/app-admin/features/formModel/index.js\";\nimport { generateAlphaNumericLowerCaseId } from \"@webiny/utils/generateId\";\n\nexport class DynamicZoneFieldMapper implements ICmsFieldTypeMapper {\n readonly type = \"dynamicZone\";\n\n map(\n field: CmsModelField,\n registry: IFieldBuilderRegistry,\n context: ICmsFieldMapperContext\n ): IFieldBuilder {\n const builder = registry.object() as IObjectFieldBuilder;\n\n const templates = field.settings?.templates as CmsDynamicZoneTemplate[] | undefined;\n if (templates) {\n for (const template of templates) {\n builder.template(template.id, t => {\n t.label(template.name);\n if (template.description) {\n t.description(template.description);\n }\n if (template.icon) {\n const icon = template.icon;\n if (typeof icon === \"object\" && \"name\" in icon) {\n t.icon(icon as ITemplateIcon);\n } else if (typeof icon === \"string\") {\n t.icon({ type: \"icon\", name: icon });\n }\n }\n t.fields(childRegistry => {\n const result: Record<string, IFieldBuilder> = {};\n result[\"_id\"] = childRegistry\n .text()\n .hidden()\n .defaultValue(() => generateAlphaNumericLowerCaseId(12))\n .cloneValue(() => generateAlphaNumericLowerCaseId(12));\n if (template.fields && template.fields.length > 0) {\n for (const child of template.fields) {\n result[child.fieldId] = context.mapField(child, childRegistry);\n }\n }\n return result;\n });\n });\n }\n }\n\n return applyFieldProps(builder, field, context.rendererMap);\n }\n}\n"],"names":["DynamicZoneFieldMapper","field","registry","context","builder","templates","template","t","icon","childRegistry","result","generateAlphaNumericLowerCaseId","child","applyFieldProps"],"mappings":";;AAWO,MAAMA;IAGT,IACIC,KAAoB,EACpBC,QAA+B,EAC/BC,OAA+B,EAClB;QACb,MAAMC,UAAUF,SAAS,MAAM;QAE/B,MAAMG,YAAYJ,MAAM,QAAQ,EAAE;QAClC,IAAII,WACA,KAAK,MAAMC,YAAYD,UACnBD,QAAQ,QAAQ,CAACE,SAAS,EAAE,EAAEC,CAAAA;YAC1BA,EAAE,KAAK,CAACD,SAAS,IAAI;YACrB,IAAIA,SAAS,WAAW,EACpBC,EAAE,WAAW,CAACD,SAAS,WAAW;YAEtC,IAAIA,SAAS,IAAI,EAAE;gBACf,MAAME,OAAOF,SAAS,IAAI;gBAC1B,IAAI,AAAgB,YAAhB,OAAOE,QAAqB,UAAUA,MACtCD,EAAE,IAAI,CAACC;qBACJ,IAAI,AAAgB,YAAhB,OAAOA,MACdD,EAAE,IAAI,CAAC;oBAAE,MAAM;oBAAQ,MAAMC;gBAAK;YAE1C;YACAD,EAAE,MAAM,CAACE,CAAAA;gBACL,MAAMC,SAAwC,CAAC;gBAC/CA,MAAM,CAAC,MAAM,GAAGD,cACX,IAAI,GACJ,MAAM,GACN,YAAY,CAAC,IAAME,gCAAgC,KACnD,UAAU,CAAC,IAAMA,gCAAgC;gBACtD,IAAIL,SAAS,MAAM,IAAIA,SAAS,MAAM,CAAC,MAAM,GAAG,GAC5C,KAAK,MAAMM,SAASN,SAAS,MAAM,CAC/BI,MAAM,CAACE,MAAM,OAAO,CAAC,GAAGT,QAAQ,QAAQ,CAACS,OAAOH;gBAGxD,OAAOC;YACX;QACJ;QAIR,OAAOG,gBAAgBT,SAASH,OAAOE,QAAQ,WAAW;IAC9D;;aA5CS,IAAI,GAAG;;AA6CpB"}
|
|
@@ -3,7 +3,7 @@ import { ExportModelsGateway as GatewayAbstraction } from "./abstractions.js";
|
|
|
3
3
|
declare class ExportModelsGatewayImpl implements GatewayAbstraction.Interface {
|
|
4
4
|
private client;
|
|
5
5
|
constructor(client: CmsGraphQLClient.Interface);
|
|
6
|
-
execute(models?: string[]): Promise<
|
|
6
|
+
execute(models?: string[]): Promise<string>;
|
|
7
7
|
}
|
|
8
8
|
export declare const ExportModelsGateway: typeof ExportModelsGatewayImpl & {
|
|
9
9
|
__abstraction: import("@webiny/di").Abstraction<import("./abstractions.js").IExportModelsGateway>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/model/exportModels/ExportModelsGateway.js","sources":["../../../../src/features/model/exportModels/ExportModelsGateway.ts"],"sourcesContent":["import { CmsGraphQLClient } from \"~/features/graphQLClient/abstractions.js\";\nimport type { CmsErrorResponse } from \"~/types.js\";\nimport { ExportModelsGateway as GatewayAbstraction } from \"./abstractions.js\";\n\ninterface ExportModelsResponse {\n exportStructure: {\n data:
|
|
1
|
+
{"version":3,"file":"features/model/exportModels/ExportModelsGateway.js","sources":["../../../../src/features/model/exportModels/ExportModelsGateway.ts"],"sourcesContent":["import { CmsGraphQLClient } from \"~/features/graphQLClient/abstractions.js\";\nimport type { CmsErrorResponse } from \"~/types.js\";\nimport { ExportModelsGateway as GatewayAbstraction } from \"./abstractions.js\";\n\ninterface ExportModelsResponse {\n exportStructure: {\n data: string;\n error: CmsErrorResponse | null;\n };\n}\n\ninterface ExportModelsVariables {\n models?: string[];\n}\n\nconst CMS_EXPORT_STRUCTURE_QUERY = /* GraphQL */ `\n query CmsExportStructure($models: [String!]) {\n exportStructure(models: $models) {\n data\n error {\n message\n code\n data\n }\n }\n }\n`;\n\nclass ExportModelsGatewayImpl implements GatewayAbstraction.Interface {\n constructor(private client: CmsGraphQLClient.Interface) {}\n\n async execute(models?: string[]) {\n const response = await this.client.execute<ExportModelsResponse, ExportModelsVariables>({\n query: CMS_EXPORT_STRUCTURE_QUERY,\n variables: { models }\n });\n\n const { data, error } = response.exportStructure;\n\n if (error) {\n throw new Error(error.message);\n }\n\n return data;\n }\n}\n\nexport const ExportModelsGateway = GatewayAbstraction.createImplementation({\n implementation: ExportModelsGatewayImpl,\n dependencies: [CmsGraphQLClient]\n});\n"],"names":["CMS_EXPORT_STRUCTURE_QUERY","ExportModelsGatewayImpl","client","models","response","data","error","Error","ExportModelsGateway","GatewayAbstraction","CmsGraphQLClient"],"mappings":";;AAeA,MAAMA,6BAA2C,CAAC;;;;;;;;;;;AAWlD,CAAC;AAED,MAAMC;IACF,YAAoBC,MAAkC,CAAE;aAApCA,MAAM,GAANA;IAAqC;IAEzD,MAAM,QAAQC,MAAiB,EAAE;QAC7B,MAAMC,WAAW,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAA8C;YACpF,OAAOJ;YACP,WAAW;gBAAEG;YAAO;QACxB;QAEA,MAAM,EAAEE,IAAI,EAAEC,KAAK,EAAE,GAAGF,SAAS,eAAe;QAEhD,IAAIE,OACA,MAAM,IAAIC,MAAMD,MAAM,OAAO;QAGjC,OAAOD;IACX;AACJ;AAEO,MAAMG,0CAAsBC,oBAAAA,oBAAuC,CAAC;IACvE,gBAAgBR;IAChB,cAAc;QAACS;KAAiB;AACpC"}
|
|
@@ -4,7 +4,13 @@ class ExportModelsUseCaseImpl {
|
|
|
4
4
|
this.gateway = gateway;
|
|
5
5
|
}
|
|
6
6
|
async execute(models) {
|
|
7
|
-
|
|
7
|
+
const result = await this.gateway.execute(models);
|
|
8
|
+
try {
|
|
9
|
+
return JSON.parse(result);
|
|
10
|
+
} catch (ex) {
|
|
11
|
+
console.error(ex);
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
8
14
|
}
|
|
9
15
|
}
|
|
10
16
|
const ExportModelsUseCase_ExportModelsUseCase = ExportModelsUseCase.createImplementation({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/model/exportModels/ExportModelsUseCase.js","sources":["../../../../src/features/model/exportModels/ExportModelsUseCase.ts"],"sourcesContent":["import { ExportModelsUseCase as UseCaseAbstraction, ExportModelsGateway } from \"./abstractions.js\";\n\nclass ExportModelsUseCaseImpl implements UseCaseAbstraction.Interface {\n constructor(private gateway: ExportModelsGateway.Interface) {}\n\n async execute(models?: string[]) {\n
|
|
1
|
+
{"version":3,"file":"features/model/exportModels/ExportModelsUseCase.js","sources":["../../../../src/features/model/exportModels/ExportModelsUseCase.ts"],"sourcesContent":["import { ExportModelsUseCase as UseCaseAbstraction, ExportModelsGateway } from \"./abstractions.js\";\n\nclass ExportModelsUseCaseImpl implements UseCaseAbstraction.Interface {\n constructor(private gateway: ExportModelsGateway.Interface) {}\n\n async execute(models?: string[]) {\n const result = await this.gateway.execute(models);\n try {\n return JSON.parse(result);\n } catch (ex) {\n console.error(ex);\n return null;\n }\n }\n}\n\nexport const ExportModelsUseCase = UseCaseAbstraction.createImplementation({\n implementation: ExportModelsUseCaseImpl,\n dependencies: [ExportModelsGateway]\n});\n"],"names":["ExportModelsUseCaseImpl","gateway","models","result","JSON","ex","console","ExportModelsUseCase","UseCaseAbstraction","ExportModelsGateway"],"mappings":";AAEA,MAAMA;IACF,YAAoBC,OAAsC,CAAE;aAAxCA,OAAO,GAAPA;IAAyC;IAE7D,MAAM,QAAQC,MAAiB,EAAE;QAC7B,MAAMC,SAAS,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAACD;QAC1C,IAAI;YACA,OAAOE,KAAK,KAAK,CAACD;QACtB,EAAE,OAAOE,IAAI;YACTC,QAAQ,KAAK,CAACD;YACd,OAAO;QACX;IACJ;AACJ;AAEO,MAAME,0CAAsBC,oBAAAA,oBAAuC,CAAC;IACvE,gBAAgBR;IAChB,cAAc;QAACS;KAAoB;AACvC"}
|
|
@@ -1,14 +1,20 @@
|
|
|
1
|
+
import type { CmsModel, CmsGroup } from "../../../types.js";
|
|
1
2
|
export interface IExportModelsGateway {
|
|
2
|
-
execute(models?: string[]): Promise<
|
|
3
|
+
execute(models?: string[]): Promise<string>;
|
|
4
|
+
}
|
|
5
|
+
export interface IExportModelsUseCaseResponse {
|
|
6
|
+
models: CmsModel[];
|
|
7
|
+
groups: CmsGroup[];
|
|
3
8
|
}
|
|
4
9
|
export declare const ExportModelsGateway: import("@webiny/di").Abstraction<IExportModelsGateway>;
|
|
5
10
|
export declare namespace ExportModelsGateway {
|
|
6
11
|
type Interface = IExportModelsGateway;
|
|
7
12
|
}
|
|
8
13
|
export interface IExportModelsUseCase {
|
|
9
|
-
execute(models?: string[]): Promise<
|
|
14
|
+
execute(models?: string[]): Promise<IExportModelsUseCaseResponse | null>;
|
|
10
15
|
}
|
|
11
16
|
export declare const ExportModelsUseCase: import("@webiny/di").Abstraction<IExportModelsUseCase>;
|
|
12
17
|
export declare namespace ExportModelsUseCase {
|
|
13
18
|
type Interface = IExportModelsUseCase;
|
|
19
|
+
type Response = IExportModelsUseCaseResponse;
|
|
14
20
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/model/exportModels/abstractions.js","sources":["../../../../src/features/model/exportModels/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/admin\";\n\nexport interface IExportModelsGateway {\n execute(models?: string[]): Promise<
|
|
1
|
+
{"version":3,"file":"features/model/exportModels/abstractions.js","sources":["../../../../src/features/model/exportModels/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/admin\";\nimport type { CmsModel, CmsGroup } from \"~/types.js\";\n\nexport interface IExportModelsGateway {\n execute(models?: string[]): Promise<string>;\n}\n\nexport interface IExportModelsUseCaseResponse {\n models: CmsModel[];\n groups: CmsGroup[];\n}\n\nexport const ExportModelsGateway = createAbstraction<IExportModelsGateway>(\"ExportModelsGateway\");\n\nexport namespace ExportModelsGateway {\n export type Interface = IExportModelsGateway;\n}\n\nexport interface IExportModelsUseCase {\n execute(models?: string[]): Promise<IExportModelsUseCaseResponse | null>;\n}\n\nexport const ExportModelsUseCase = createAbstraction<IExportModelsUseCase>(\"ExportModelsUseCase\");\n\nexport namespace ExportModelsUseCase {\n export type Interface = IExportModelsUseCase;\n export type Response = IExportModelsUseCaseResponse;\n}\n"],"names":["ExportModelsGateway","createAbstraction","ExportModelsUseCase"],"mappings":";AAYO,MAAMA,sBAAsBC,kBAAwC;AAUpE,MAAMC,sBAAsBD,kBAAwC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webiny/app-headless-cms",
|
|
3
|
-
"version": "6.5.0-beta.
|
|
3
|
+
"version": "6.5.0-beta.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./index.js",
|
|
@@ -26,33 +26,33 @@
|
|
|
26
26
|
"@fortawesome/free-regular-svg-icons": "7.3.1",
|
|
27
27
|
"@fortawesome/free-solid-svg-icons": "7.3.1",
|
|
28
28
|
"@fortawesome/react-fontawesome": "3.5.0",
|
|
29
|
-
"@lexical/utils": "0.
|
|
29
|
+
"@lexical/utils": "0.51.0",
|
|
30
30
|
"@types/react": "18.3.31",
|
|
31
|
-
"@webiny/admin-ui": "6.5.0-beta.
|
|
32
|
-
"@webiny/app": "6.5.0-beta.
|
|
33
|
-
"@webiny/app-aco": "6.5.0-beta.
|
|
34
|
-
"@webiny/app-admin": "6.5.0-beta.
|
|
35
|
-
"@webiny/app-graphql-playground": "6.5.0-beta.
|
|
36
|
-
"@webiny/app-headless-cms-common": "6.5.0-beta.
|
|
37
|
-
"@webiny/cms-sdk": "6.5.0-beta.
|
|
38
|
-
"@webiny/di": "1.0
|
|
39
|
-
"@webiny/feature": "6.5.0-beta.
|
|
40
|
-
"@webiny/form": "6.5.0-beta.
|
|
41
|
-
"@webiny/frontend-settings": "6.5.0-beta.
|
|
42
|
-
"@webiny/icons": "6.5.0-beta.
|
|
43
|
-
"@webiny/lexical-editor": "6.5.0-beta.
|
|
44
|
-
"@webiny/lexical-nodes": "6.5.0-beta.
|
|
45
|
-
"@webiny/plugins": "6.5.0-beta.
|
|
46
|
-
"@webiny/react-composition": "6.5.0-beta.
|
|
47
|
-
"@webiny/react-properties": "6.5.0-beta.
|
|
48
|
-
"@webiny/utils": "6.5.0-beta.
|
|
49
|
-
"@webiny/validation": "6.5.0-beta.
|
|
31
|
+
"@webiny/admin-ui": "6.5.0-beta.5",
|
|
32
|
+
"@webiny/app": "6.5.0-beta.5",
|
|
33
|
+
"@webiny/app-aco": "6.5.0-beta.5",
|
|
34
|
+
"@webiny/app-admin": "6.5.0-beta.5",
|
|
35
|
+
"@webiny/app-graphql-playground": "6.5.0-beta.5",
|
|
36
|
+
"@webiny/app-headless-cms-common": "6.5.0-beta.5",
|
|
37
|
+
"@webiny/cms-sdk": "6.5.0-beta.5",
|
|
38
|
+
"@webiny/di": "1.1.0",
|
|
39
|
+
"@webiny/feature": "6.5.0-beta.5",
|
|
40
|
+
"@webiny/form": "6.5.0-beta.5",
|
|
41
|
+
"@webiny/frontend-settings": "6.5.0-beta.5",
|
|
42
|
+
"@webiny/icons": "6.5.0-beta.5",
|
|
43
|
+
"@webiny/lexical-editor": "6.5.0-beta.5",
|
|
44
|
+
"@webiny/lexical-nodes": "6.5.0-beta.5",
|
|
45
|
+
"@webiny/plugins": "6.5.0-beta.5",
|
|
46
|
+
"@webiny/react-composition": "6.5.0-beta.5",
|
|
47
|
+
"@webiny/react-properties": "6.5.0-beta.5",
|
|
48
|
+
"@webiny/utils": "6.5.0-beta.5",
|
|
49
|
+
"@webiny/validation": "6.5.0-beta.5",
|
|
50
50
|
"dot-prop-immutable": "2.1.1",
|
|
51
51
|
"graphql": "16.14.2",
|
|
52
52
|
"graphql-tag": "2.12.7",
|
|
53
53
|
"lodash": "4.18.1",
|
|
54
|
-
"mobx": "
|
|
55
|
-
"mobx-react-lite": "
|
|
54
|
+
"mobx": "7.0.5",
|
|
55
|
+
"mobx-react-lite": "5.1.0",
|
|
56
56
|
"react": "18.3.1",
|
|
57
57
|
"react-dnd": "16.0.1",
|
|
58
58
|
"react-dnd-html5-backend": "16.0.1",
|
|
@@ -60,13 +60,13 @@
|
|
|
60
60
|
"react-helmet": "6.1.0",
|
|
61
61
|
"slugify": "1.6.9",
|
|
62
62
|
"use-deep-compare-effect": "1.8.1",
|
|
63
|
-
"zod": "4.
|
|
63
|
+
"zod": "4.6.5"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@webiny/build-tools": "6.5.0-beta.
|
|
66
|
+
"@webiny/build-tools": "6.5.0-beta.5",
|
|
67
67
|
"rimraf": "6.1.3",
|
|
68
68
|
"typescript": "7.0.2",
|
|
69
|
-
"vitest": "
|
|
69
|
+
"vitest": "5.0.2"
|
|
70
70
|
},
|
|
71
71
|
"publishConfig": {
|
|
72
72
|
"access": "public"
|
|
@@ -13,6 +13,7 @@ import { CmsModelContext } from "../../../features/contentEntry/abstractions.js"
|
|
|
13
13
|
import { ContentEntryFormModelModifier, ContentEntryFormPresenter } from "./abstractions.js";
|
|
14
14
|
import { TRASH_ENTRY_DIALOG } from "../list/ContentEntriesPresenter.js";
|
|
15
15
|
import { CreateRevisionFromUseCase } from "../../../features/contentEntry/createRevisionFrom/abstractions.js";
|
|
16
|
+
import { toFormErrors } from "./toFormErrors.js";
|
|
16
17
|
const PUBLISH_ENTRY_DIALOG = "publish-entry";
|
|
17
18
|
class ContentEntryFormPresenterImpl {
|
|
18
19
|
constructor(formModelFactory, cmsFormModelBuilder, confirmation, modelAccessor, getEntryUseCase, createEntryUseCase, createRevisionFromUseCase, updateEntryUseCase, publishEntryUseCase, unpublishEntryUseCase, deleteEntryUseCase, updateRevisionDescriptionUseCase, formModelModifiers){
|
|
@@ -119,7 +120,8 @@ class ContentEntryFormPresenterImpl {
|
|
|
119
120
|
});
|
|
120
121
|
}
|
|
121
122
|
return true;
|
|
122
|
-
} catch
|
|
123
|
+
} catch (error) {
|
|
124
|
+
this.form.setErrors(toFormErrors(error, this.model));
|
|
123
125
|
return false;
|
|
124
126
|
} finally{
|
|
125
127
|
runInAction(()=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/contentEntries/form/ContentEntryFormPresenter.js","sources":["../../../../src/presentation/contentEntries/form/ContentEntryFormPresenter.ts"],"sourcesContent":["import { computed, makeAutoObservable, runInAction, toJS } from \"mobx\";\nimport { FormModel, FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { Confirmation } from \"@webiny/app-admin/features/confirmation/abstractions.js\";\nimport type { CmsContentEntry } from \"~/types.js\";\nimport { GetEntryUseCase } from \"~/features/contentEntry/getEntry/abstractions.js\";\nimport { CreateEntryUseCase } from \"~/features/contentEntry/createEntry/abstractions.js\";\nimport { UpdateEntryUseCase } from \"~/features/contentEntry/updateEntry/abstractions.js\";\nimport { PublishEntryUseCase } from \"~/features/contentEntry/publishEntry/abstractions.js\";\nimport { UnpublishEntryUseCase } from \"~/features/contentEntry/unpublishEntry/abstractions.js\";\nimport { DeleteEntryUseCase } from \"~/features/contentEntry/deleteEntry/abstractions.js\";\nimport { UpdateRevisionDescriptionUseCase } from \"~/features/contentEntry/updateRevisionDescription/abstractions.js\";\nimport { CmsFormModelBuilder } from \"~/features/formModel/abstractions.js\";\nimport { CmsModelContext } from \"~/features/contentEntry/abstractions.js\";\nimport {\n ContentEntryFormModelModifier,\n ContentEntryFormPresenter as Abstraction\n} from \"./abstractions.js\";\nimport { TRASH_ENTRY_DIALOG } from \"~/presentation/contentEntries/list/ContentEntriesPresenter.js\";\nimport { CreateRevisionFromUseCase } from \"~/features/contentEntry/createRevisionFrom/abstractions.js\";\n\ninterface PublishEntryDialogData {\n revisionDescription: string;\n}\n\ninterface SaveEntryParams {\n entry: CmsContentEntry;\n data: Record<string, unknown>;\n skipValidation?: boolean;\n}\n\nexport const PUBLISH_ENTRY_DIALOG = \"publish-entry\";\n\nclass ContentEntryFormPresenterImpl implements Abstraction.Interface {\n private entry: CmsContentEntry | null = null;\n private form: FormModel.Interface | null = null;\n private loading: string | null = null;\n private folderId: string | null = null;\n\n constructor(\n private readonly formModelFactory: FormModelFactory.Interface,\n private readonly cmsFormModelBuilder: CmsFormModelBuilder.Interface,\n private readonly confirmation: Confirmation.Interface,\n private readonly modelAccessor: CmsModelContext.Interface,\n private readonly getEntryUseCase: GetEntryUseCase.Interface,\n private readonly createEntryUseCase: CreateEntryUseCase.Interface,\n private readonly createRevisionFromUseCase: CreateRevisionFromUseCase.Interface,\n private readonly updateEntryUseCase: UpdateEntryUseCase.Interface,\n private readonly publishEntryUseCase: PublishEntryUseCase.Interface,\n private readonly unpublishEntryUseCase: UnpublishEntryUseCase.Interface,\n private readonly deleteEntryUseCase: DeleteEntryUseCase.Interface,\n private readonly updateRevisionDescriptionUseCase: UpdateRevisionDescriptionUseCase.Interface,\n private readonly formModelModifiers: ContentEntryFormModelModifier.Interface[]\n ) {\n makeAutoObservable<\n ContentEntryFormPresenterImpl,\n | \"formModelFactory\"\n | \"cmsFormModelBuilder\"\n | \"confirmation\"\n | \"modelAccessor\"\n | \"getEntryUseCase\"\n | \"createEntryUseCase\"\n | \"updateEntryUseCase\"\n | \"publishEntryUseCase\"\n | \"unpublishEntryUseCase\"\n | \"deleteEntryUseCase\"\n | \"updateRevisionDescriptionUseCase\"\n | \"formModelModifiers\"\n >(this, {\n formModelFactory: false,\n cmsFormModelBuilder: false,\n confirmation: false,\n modelAccessor: false,\n getEntryUseCase: false,\n createEntryUseCase: false,\n updateEntryUseCase: false,\n publishEntryUseCase: false,\n unpublishEntryUseCase: false,\n deleteEntryUseCase: false,\n updateRevisionDescriptionUseCase: false,\n formModelModifiers: false,\n vm: computed\n });\n }\n\n private get model() {\n return this.modelAccessor.getModel();\n }\n\n get vm(): Abstraction.ViewModel {\n const entry = this.entry;\n const meta = entry?.meta;\n const isLocked = meta?.locked ?? false;\n const status = meta?.status;\n /**\n * Can save if the entry is locked and published/unpublished - it will trigger create new revision.\n * Or if the entry is not locked and the form is not null (meaning we are creating a new entry or editing an existing one).\n */\n const canSave =\n (isLocked && (status === \"published\" || status === \"unpublished\")) ||\n (!isLocked && this.form !== null);\n\n return {\n loading: this.loading,\n model: this.model,\n entry: toJS(this.entry),\n form: this.form?.vm ?? null,\n canSave,\n status,\n canCreateNewRevision:\n !!status && canSave && [\"published\", \"unpublished\"].includes(status),\n canPublish: this.entry !== null && status !== \"published\",\n canUnpublish: this.entry !== null && status === \"published\",\n canDelete: this.entry !== null,\n isNewEntry: this.entry === null && this.form !== null,\n isDirty: this.form?.isDirty ?? false\n };\n }\n\n async saveRevision(options?: { skipValidation?: boolean }): Promise<boolean> {\n if (!this.form) {\n return false;\n }\n\n const skipValidation = options?.skipValidation ?? true;\n const data = await this.form.submit({ skipValidation });\n\n if (!data) {\n return false;\n }\n\n runInAction(() => {\n this.loading = \"Saving...\";\n });\n\n try {\n if (this.entry) {\n /**\n * In case the entry already exists, and it is NOT locked, we will update the existing revision.\n * If it is locked, we will create a new revision from the existing one, and then update that new revision.\n */\n const entry = await this.saveEntry({\n entry: this.entry,\n data,\n skipValidation\n });\n\n runInAction(() => {\n this.entry = entry;\n this.form!.setData(entry.values);\n this.form!.reset();\n });\n } else {\n const createData: Record<string, unknown> = { values: data };\n if (this.folderId) {\n createData.wbyAco_location = { folderId: this.folderId };\n }\n\n const entry = await this.createEntryUseCase.execute({\n model: this.model,\n data: createData,\n options: { skipValidation }\n });\n\n runInAction(() => {\n this.entry = entry;\n this.form!.setData(entry.values);\n this.form!.reset();\n });\n }\n\n return true;\n } catch {\n return false;\n } finally {\n runInAction(() => {\n this.loading = null;\n });\n }\n }\n\n async publishRevision(): Promise<boolean> {\n if (!this.entry) {\n return false;\n }\n\n const result = await this.confirmation.confirm<PublishEntryDialogData>(\n PUBLISH_ENTRY_DIALOG,\n { entry: this.entry }\n );\n\n if (result === false) {\n return false;\n }\n\n runInAction(() => {\n this.loading = \"Publishing...\";\n });\n\n try {\n if (result.revisionDescription) {\n await this.updateRevisionDescriptionUseCase.execute({\n model: this.model,\n id: this.entry.id,\n revisionDescription: result.revisionDescription\n });\n }\n\n const entry = await this.publishEntryUseCase.execute({\n model: this.model,\n revisionId: this.entry.id\n });\n\n runInAction(() => {\n this.entry = entry;\n });\n\n return true;\n } catch {\n return false;\n } finally {\n runInAction(() => {\n this.loading = null;\n });\n }\n }\n\n async unpublishRevision(): Promise<boolean> {\n if (!this.entry) {\n return false;\n }\n\n this.loading = \"Unpublishing...\";\n\n try {\n const entry = await this.unpublishEntryUseCase.execute({\n model: this.model,\n revisionId: this.entry.id\n });\n\n runInAction(() => {\n this.entry = entry;\n });\n\n return true;\n } catch {\n return false;\n } finally {\n runInAction(() => {\n this.loading = null;\n });\n }\n }\n\n async deleteEntry(): Promise<boolean> {\n if (!this.entry) {\n return false;\n }\n\n const model = this.model;\n const entry = this.entry;\n\n return this.confirmation.confirm(\n TRASH_ENTRY_DIALOG,\n { entryId: entry.entryId },\n async () => {\n try {\n await this.deleteEntryUseCase.execute({\n model,\n id: entry.entryId\n });\n\n runInAction(() => {\n this.entry = null;\n this.form = null;\n });\n\n return true;\n } catch {\n return false;\n }\n }\n );\n }\n\n async loadRevision(id: string): Promise<void> {\n this.loading = \"Loading entry...\";\n\n try {\n const entry = await this.getEntryUseCase.execute({\n model: this.model,\n id\n });\n\n runInAction(() => {\n this.entry = entry;\n this.buildAndPopulateForm(entry);\n });\n } finally {\n runInAction(() => {\n this.loading = null;\n });\n }\n }\n\n setFolderId(folderId: string | null): void {\n this.folderId = folderId;\n }\n\n newEntry(initialValues?: Record<string, unknown>): void {\n this.entry = null;\n this.form = this.buildForm();\n if (initialValues) {\n this.form.setData(initialValues, { dirty: true });\n }\n }\n\n patchEntryMeta(meta: Partial<CmsContentEntry[\"meta\"]>): void {\n if (!this.entry) {\n return;\n }\n this.entry = {\n ...this.entry,\n meta: { ...this.entry.meta, ...meta }\n };\n }\n\n reset(): void {\n this.form = null;\n this.entry = null;\n }\n\n private buildForm(): FormModel.Interface {\n const formConfig = this.cmsFormModelBuilder.build(this.model);\n const form = this.formModelFactory.create(formConfig);\n for (const modifier of this.formModelModifiers) {\n modifier.modifyForm(form, this.model);\n }\n return form;\n }\n\n private buildAndPopulateForm(entry: CmsContentEntry): void {\n this.form = this.buildForm();\n this.form.setData(entry.values);\n this.form.reset();\n }\n /**\n * Depending on whether the entry is locked or not, this method will either create a new revision from the existing one and update it, or simply update the existing revision.\n */\n private async saveEntry(params: SaveEntryParams): Promise<any> {\n const { entry, data, skipValidation } = params;\n\n if (entry.meta.locked) {\n return await this.createRevisionFromUseCase.execute({\n model: this.model,\n revisionId: entry.id,\n data: {\n values: data\n },\n options: { skipValidation }\n });\n }\n return await this.updateEntryUseCase.execute({\n model: this.model,\n revisionId: entry.id,\n data: {\n values: data\n },\n options: { skipValidation }\n });\n }\n}\n\nexport const ContentEntryFormPresenter = Abstraction.createImplementation({\n implementation: ContentEntryFormPresenterImpl,\n dependencies: [\n FormModelFactory,\n CmsFormModelBuilder,\n Confirmation,\n CmsModelContext,\n GetEntryUseCase,\n CreateEntryUseCase,\n CreateRevisionFromUseCase,\n UpdateEntryUseCase,\n PublishEntryUseCase,\n UnpublishEntryUseCase,\n DeleteEntryUseCase,\n UpdateRevisionDescriptionUseCase,\n [ContentEntryFormModelModifier, { multiple: true }]\n ]\n});\n"],"names":["PUBLISH_ENTRY_DIALOG","ContentEntryFormPresenterImpl","formModelFactory","cmsFormModelBuilder","confirmation","modelAccessor","getEntryUseCase","createEntryUseCase","createRevisionFromUseCase","updateEntryUseCase","publishEntryUseCase","unpublishEntryUseCase","deleteEntryUseCase","updateRevisionDescriptionUseCase","formModelModifiers","makeAutoObservable","computed","entry","meta","isLocked","status","canSave","toJS","options","skipValidation","data","runInAction","createData","result","model","TRASH_ENTRY_DIALOG","id","folderId","initialValues","formConfig","form","modifier","params","ContentEntryFormPresenter","Abstraction","FormModelFactory","CmsFormModelBuilder","Confirmation","CmsModelContext","GetEntryUseCase","CreateEntryUseCase","CreateRevisionFromUseCase","UpdateEntryUseCase","PublishEntryUseCase","UnpublishEntryUseCase","DeleteEntryUseCase","UpdateRevisionDescriptionUseCase","ContentEntryFormModelModifier"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"presentation/contentEntries/form/ContentEntryFormPresenter.js","sources":["../../../../src/presentation/contentEntries/form/ContentEntryFormPresenter.ts"],"sourcesContent":["import { computed, makeAutoObservable, runInAction, toJS } from \"mobx\";\nimport { FormModel, FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { Confirmation } from \"@webiny/app-admin/features/confirmation/abstractions.js\";\nimport type { CmsContentEntry } from \"~/types.js\";\nimport { GetEntryUseCase } from \"~/features/contentEntry/getEntry/abstractions.js\";\nimport { CreateEntryUseCase } from \"~/features/contentEntry/createEntry/abstractions.js\";\nimport { UpdateEntryUseCase } from \"~/features/contentEntry/updateEntry/abstractions.js\";\nimport { PublishEntryUseCase } from \"~/features/contentEntry/publishEntry/abstractions.js\";\nimport { UnpublishEntryUseCase } from \"~/features/contentEntry/unpublishEntry/abstractions.js\";\nimport { DeleteEntryUseCase } from \"~/features/contentEntry/deleteEntry/abstractions.js\";\nimport { UpdateRevisionDescriptionUseCase } from \"~/features/contentEntry/updateRevisionDescription/abstractions.js\";\nimport { CmsFormModelBuilder } from \"~/features/formModel/abstractions.js\";\nimport { CmsModelContext } from \"~/features/contentEntry/abstractions.js\";\nimport {\n ContentEntryFormModelModifier,\n ContentEntryFormPresenter as Abstraction\n} from \"./abstractions.js\";\nimport { TRASH_ENTRY_DIALOG } from \"~/presentation/contentEntries/list/ContentEntriesPresenter.js\";\nimport { CreateRevisionFromUseCase } from \"~/features/contentEntry/createRevisionFrom/abstractions.js\";\nimport { toFormErrors } from \"./toFormErrors.js\";\n\ninterface PublishEntryDialogData {\n revisionDescription: string;\n}\n\ninterface SaveEntryParams {\n entry: CmsContentEntry;\n data: Record<string, unknown>;\n skipValidation?: boolean;\n}\n\nexport const PUBLISH_ENTRY_DIALOG = \"publish-entry\";\n\nclass ContentEntryFormPresenterImpl implements Abstraction.Interface {\n private entry: CmsContentEntry | null = null;\n private form: FormModel.Interface | null = null;\n private loading: string | null = null;\n private folderId: string | null = null;\n\n constructor(\n private readonly formModelFactory: FormModelFactory.Interface,\n private readonly cmsFormModelBuilder: CmsFormModelBuilder.Interface,\n private readonly confirmation: Confirmation.Interface,\n private readonly modelAccessor: CmsModelContext.Interface,\n private readonly getEntryUseCase: GetEntryUseCase.Interface,\n private readonly createEntryUseCase: CreateEntryUseCase.Interface,\n private readonly createRevisionFromUseCase: CreateRevisionFromUseCase.Interface,\n private readonly updateEntryUseCase: UpdateEntryUseCase.Interface,\n private readonly publishEntryUseCase: PublishEntryUseCase.Interface,\n private readonly unpublishEntryUseCase: UnpublishEntryUseCase.Interface,\n private readonly deleteEntryUseCase: DeleteEntryUseCase.Interface,\n private readonly updateRevisionDescriptionUseCase: UpdateRevisionDescriptionUseCase.Interface,\n private readonly formModelModifiers: ContentEntryFormModelModifier.Interface[]\n ) {\n makeAutoObservable<\n ContentEntryFormPresenterImpl,\n | \"formModelFactory\"\n | \"cmsFormModelBuilder\"\n | \"confirmation\"\n | \"modelAccessor\"\n | \"getEntryUseCase\"\n | \"createEntryUseCase\"\n | \"updateEntryUseCase\"\n | \"publishEntryUseCase\"\n | \"unpublishEntryUseCase\"\n | \"deleteEntryUseCase\"\n | \"updateRevisionDescriptionUseCase\"\n | \"formModelModifiers\"\n >(this, {\n formModelFactory: false,\n cmsFormModelBuilder: false,\n confirmation: false,\n modelAccessor: false,\n getEntryUseCase: false,\n createEntryUseCase: false,\n updateEntryUseCase: false,\n publishEntryUseCase: false,\n unpublishEntryUseCase: false,\n deleteEntryUseCase: false,\n updateRevisionDescriptionUseCase: false,\n formModelModifiers: false,\n vm: computed\n });\n }\n\n private get model() {\n return this.modelAccessor.getModel();\n }\n\n get vm(): Abstraction.ViewModel {\n const entry = this.entry;\n const meta = entry?.meta;\n const isLocked = meta?.locked ?? false;\n const status = meta?.status;\n /**\n * Can save if the entry is locked and published/unpublished - it will trigger create new revision.\n * Or if the entry is not locked and the form is not null (meaning we are creating a new entry or editing an existing one).\n */\n const canSave =\n (isLocked && (status === \"published\" || status === \"unpublished\")) ||\n (!isLocked && this.form !== null);\n\n return {\n loading: this.loading,\n model: this.model,\n entry: toJS(this.entry),\n form: this.form?.vm ?? null,\n canSave,\n status,\n canCreateNewRevision:\n !!status && canSave && [\"published\", \"unpublished\"].includes(status),\n canPublish: this.entry !== null && status !== \"published\",\n canUnpublish: this.entry !== null && status === \"published\",\n canDelete: this.entry !== null,\n isNewEntry: this.entry === null && this.form !== null,\n isDirty: this.form?.isDirty ?? false\n };\n }\n\n async saveRevision(options?: { skipValidation?: boolean }): Promise<boolean> {\n if (!this.form) {\n return false;\n }\n\n const skipValidation = options?.skipValidation ?? true;\n const data = await this.form.submit({ skipValidation });\n\n if (!data) {\n return false;\n }\n\n runInAction(() => {\n this.loading = \"Saving...\";\n });\n\n try {\n if (this.entry) {\n /**\n * In case the entry already exists, and it is NOT locked, we will update the existing revision.\n * If it is locked, we will create a new revision from the existing one, and then update that new revision.\n */\n const entry = await this.saveEntry({\n entry: this.entry,\n data,\n skipValidation\n });\n\n runInAction(() => {\n this.entry = entry;\n this.form!.setData(entry.values);\n this.form!.reset();\n });\n } else {\n const createData: Record<string, unknown> = { values: data };\n if (this.folderId) {\n createData.wbyAco_location = { folderId: this.folderId };\n }\n\n const entry = await this.createEntryUseCase.execute({\n model: this.model,\n data: createData,\n options: { skipValidation }\n });\n\n runInAction(() => {\n this.entry = entry;\n this.form!.setData(entry.values);\n this.form!.reset();\n });\n }\n\n return true;\n } catch (error) {\n this.form.setErrors(toFormErrors(error, this.model));\n return false;\n } finally {\n runInAction(() => {\n this.loading = null;\n });\n }\n }\n\n async publishRevision(): Promise<boolean> {\n if (!this.entry) {\n return false;\n }\n\n const result = await this.confirmation.confirm<PublishEntryDialogData>(\n PUBLISH_ENTRY_DIALOG,\n { entry: this.entry }\n );\n\n if (result === false) {\n return false;\n }\n\n runInAction(() => {\n this.loading = \"Publishing...\";\n });\n\n try {\n if (result.revisionDescription) {\n await this.updateRevisionDescriptionUseCase.execute({\n model: this.model,\n id: this.entry.id,\n revisionDescription: result.revisionDescription\n });\n }\n\n const entry = await this.publishEntryUseCase.execute({\n model: this.model,\n revisionId: this.entry.id\n });\n\n runInAction(() => {\n this.entry = entry;\n });\n\n return true;\n } catch {\n return false;\n } finally {\n runInAction(() => {\n this.loading = null;\n });\n }\n }\n\n async unpublishRevision(): Promise<boolean> {\n if (!this.entry) {\n return false;\n }\n\n this.loading = \"Unpublishing...\";\n\n try {\n const entry = await this.unpublishEntryUseCase.execute({\n model: this.model,\n revisionId: this.entry.id\n });\n\n runInAction(() => {\n this.entry = entry;\n });\n\n return true;\n } catch {\n return false;\n } finally {\n runInAction(() => {\n this.loading = null;\n });\n }\n }\n\n async deleteEntry(): Promise<boolean> {\n if (!this.entry) {\n return false;\n }\n\n const model = this.model;\n const entry = this.entry;\n\n return this.confirmation.confirm(\n TRASH_ENTRY_DIALOG,\n { entryId: entry.entryId },\n async () => {\n try {\n await this.deleteEntryUseCase.execute({\n model,\n id: entry.entryId\n });\n\n runInAction(() => {\n this.entry = null;\n this.form = null;\n });\n\n return true;\n } catch {\n return false;\n }\n }\n );\n }\n\n async loadRevision(id: string): Promise<void> {\n this.loading = \"Loading entry...\";\n\n try {\n const entry = await this.getEntryUseCase.execute({\n model: this.model,\n id\n });\n\n runInAction(() => {\n this.entry = entry;\n this.buildAndPopulateForm(entry);\n });\n } finally {\n runInAction(() => {\n this.loading = null;\n });\n }\n }\n\n setFolderId(folderId: string | null): void {\n this.folderId = folderId;\n }\n\n newEntry(initialValues?: Record<string, unknown>): void {\n this.entry = null;\n this.form = this.buildForm();\n if (initialValues) {\n this.form.setData(initialValues, { dirty: true });\n }\n }\n\n patchEntryMeta(meta: Partial<CmsContentEntry[\"meta\"]>): void {\n if (!this.entry) {\n return;\n }\n this.entry = {\n ...this.entry,\n meta: { ...this.entry.meta, ...meta }\n };\n }\n\n reset(): void {\n this.form = null;\n this.entry = null;\n }\n\n private buildForm(): FormModel.Interface {\n const formConfig = this.cmsFormModelBuilder.build(this.model);\n const form = this.formModelFactory.create(formConfig);\n for (const modifier of this.formModelModifiers) {\n modifier.modifyForm(form, this.model);\n }\n return form;\n }\n\n private buildAndPopulateForm(entry: CmsContentEntry): void {\n this.form = this.buildForm();\n this.form.setData(entry.values);\n this.form.reset();\n }\n /**\n * Depending on whether the entry is locked or not, this method will either create a new revision from the existing one and update it, or simply update the existing revision.\n */\n private async saveEntry(params: SaveEntryParams): Promise<any> {\n const { entry, data, skipValidation } = params;\n\n if (entry.meta.locked) {\n return await this.createRevisionFromUseCase.execute({\n model: this.model,\n revisionId: entry.id,\n data: {\n values: data\n },\n options: { skipValidation }\n });\n }\n return await this.updateEntryUseCase.execute({\n model: this.model,\n revisionId: entry.id,\n data: {\n values: data\n },\n options: { skipValidation }\n });\n }\n}\n\nexport const ContentEntryFormPresenter = Abstraction.createImplementation({\n implementation: ContentEntryFormPresenterImpl,\n dependencies: [\n FormModelFactory,\n CmsFormModelBuilder,\n Confirmation,\n CmsModelContext,\n GetEntryUseCase,\n CreateEntryUseCase,\n CreateRevisionFromUseCase,\n UpdateEntryUseCase,\n PublishEntryUseCase,\n UnpublishEntryUseCase,\n DeleteEntryUseCase,\n UpdateRevisionDescriptionUseCase,\n [ContentEntryFormModelModifier, { multiple: true }]\n ]\n});\n"],"names":["PUBLISH_ENTRY_DIALOG","ContentEntryFormPresenterImpl","formModelFactory","cmsFormModelBuilder","confirmation","modelAccessor","getEntryUseCase","createEntryUseCase","createRevisionFromUseCase","updateEntryUseCase","publishEntryUseCase","unpublishEntryUseCase","deleteEntryUseCase","updateRevisionDescriptionUseCase","formModelModifiers","makeAutoObservable","computed","entry","meta","isLocked","status","canSave","toJS","options","skipValidation","data","runInAction","createData","error","toFormErrors","result","model","TRASH_ENTRY_DIALOG","id","folderId","initialValues","formConfig","form","modifier","params","ContentEntryFormPresenter","Abstraction","FormModelFactory","CmsFormModelBuilder","Confirmation","CmsModelContext","GetEntryUseCase","CreateEntryUseCase","CreateRevisionFromUseCase","UpdateEntryUseCase","PublishEntryUseCase","UnpublishEntryUseCase","DeleteEntryUseCase","UpdateRevisionDescriptionUseCase","ContentEntryFormModelModifier"],"mappings":";;;;;;;;;;;;;;;;AA+BO,MAAMA,uBAAuB;AAEpC,MAAMC;IAMF,YACqBC,gBAA4C,EAC5CC,mBAAkD,EAClDC,YAAoC,EACpCC,aAAwC,EACxCC,eAA0C,EAC1CC,kBAAgD,EAChDC,yBAA8D,EAC9DC,kBAAgD,EAChDC,mBAAkD,EAClDC,qBAAsD,EACtDC,kBAAgD,EAChDC,gCAA4E,EAC5EC,kBAA6D,CAChF;aAbmBZ,gBAAgB,GAAhBA;aACAC,mBAAmB,GAAnBA;aACAC,YAAY,GAAZA;aACAC,aAAa,GAAbA;aACAC,eAAe,GAAfA;aACAC,kBAAkB,GAAlBA;aACAC,yBAAyB,GAAzBA;aACAC,kBAAkB,GAAlBA;aACAC,mBAAmB,GAAnBA;aACAC,qBAAqB,GAArBA;aACAC,kBAAkB,GAAlBA;aACAC,gCAAgC,GAAhCA;aACAC,kBAAkB,GAAlBA;aAlBb,KAAK,GAA2B;aAChC,IAAI,GAA+B;aACnC,OAAO,GAAkB;aACzB,QAAQ,GAAkB;QAiB9BC,mBAcE,IAAI,EAAE;YACJ,kBAAkB;YAClB,qBAAqB;YACrB,cAAc;YACd,eAAe;YACf,iBAAiB;YACjB,oBAAoB;YACpB,oBAAoB;YACpB,qBAAqB;YACrB,uBAAuB;YACvB,oBAAoB;YACpB,kCAAkC;YAClC,oBAAoB;YACpB,IAAIC;QACR;IACJ;IAEA,IAAY,QAAQ;QAChB,OAAO,IAAI,CAAC,aAAa,CAAC,QAAQ;IACtC;IAEA,IAAI,KAA4B;QAC5B,MAAMC,QAAQ,IAAI,CAAC,KAAK;QACxB,MAAMC,OAAOD,OAAO;QACpB,MAAME,WAAWD,MAAM,UAAU;QACjC,MAAME,SAASF,MAAM;QAKrB,MAAMG,UACDF,YAAaC,CAAAA,AAAW,gBAAXA,UAA0BA,AAAW,kBAAXA,MAAuB,KAC9D,CAACD,YAAY,AAAc,SAAd,IAAI,CAAC,IAAI;QAE3B,OAAO;YACH,SAAS,IAAI,CAAC,OAAO;YACrB,OAAO,IAAI,CAAC,KAAK;YACjB,OAAOG,KAAK,IAAI,CAAC,KAAK;YACtB,MAAM,IAAI,CAAC,IAAI,EAAE,MAAM;YACvBD;YACAD;YACA,sBACI,CAAC,CAACA,UAAUC,WAAW;gBAAC;gBAAa;aAAc,CAAC,QAAQ,CAACD;YACjE,YAAY,AAAe,SAAf,IAAI,CAAC,KAAK,IAAaA,AAAW,gBAAXA;YACnC,cAAc,AAAe,SAAf,IAAI,CAAC,KAAK,IAAaA,AAAW,gBAAXA;YACrC,WAAW,AAAe,SAAf,IAAI,CAAC,KAAK;YACrB,YAAY,AAAe,SAAf,IAAI,CAAC,KAAK,IAAa,AAAc,SAAd,IAAI,CAAC,IAAI;YAC5C,SAAS,IAAI,CAAC,IAAI,EAAE,WAAW;QACnC;IACJ;IAEA,MAAM,aAAaG,OAAsC,EAAoB;QACzE,IAAI,CAAC,IAAI,CAAC,IAAI,EACV,OAAO;QAGX,MAAMC,iBAAiBD,SAAS,kBAAkB;QAClD,MAAME,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;YAAED;QAAe;QAErD,IAAI,CAACC,MACD,OAAO;QAGXC,YAAY;YACR,IAAI,CAAC,OAAO,GAAG;QACnB;QAEA,IAAI;YACA,IAAI,IAAI,CAAC,KAAK,EAAE;gBAKZ,MAAMT,QAAQ,MAAM,IAAI,CAAC,SAAS,CAAC;oBAC/B,OAAO,IAAI,CAAC,KAAK;oBACjBQ;oBACAD;gBACJ;gBAEAE,YAAY;oBACR,IAAI,CAAC,KAAK,GAAGT;oBACb,IAAI,CAAC,IAAI,CAAE,OAAO,CAACA,MAAM,MAAM;oBAC/B,IAAI,CAAC,IAAI,CAAE,KAAK;gBACpB;YACJ,OAAO;gBACH,MAAMU,aAAsC;oBAAE,QAAQF;gBAAK;gBAC3D,IAAI,IAAI,CAAC,QAAQ,EACbE,WAAW,eAAe,GAAG;oBAAE,UAAU,IAAI,CAAC,QAAQ;gBAAC;gBAG3D,MAAMV,QAAQ,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC;oBAChD,OAAO,IAAI,CAAC,KAAK;oBACjB,MAAMU;oBACN,SAAS;wBAAEH;oBAAe;gBAC9B;gBAEAE,YAAY;oBACR,IAAI,CAAC,KAAK,GAAGT;oBACb,IAAI,CAAC,IAAI,CAAE,OAAO,CAACA,MAAM,MAAM;oBAC/B,IAAI,CAAC,IAAI,CAAE,KAAK;gBACpB;YACJ;YAEA,OAAO;QACX,EAAE,OAAOW,OAAO;YACZ,IAAI,CAAC,IAAI,CAAC,SAAS,CAACC,aAAaD,OAAO,IAAI,CAAC,KAAK;YAClD,OAAO;QACX,SAAU;YACNF,YAAY;gBACR,IAAI,CAAC,OAAO,GAAG;YACnB;QACJ;IACJ;IAEA,MAAM,kBAAoC;QACtC,IAAI,CAAC,IAAI,CAAC,KAAK,EACX,OAAO;QAGX,MAAMI,SAAS,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAC1C9B,sBACA;YAAE,OAAO,IAAI,CAAC,KAAK;QAAC;QAGxB,IAAI8B,AAAW,UAAXA,QACA,OAAO;QAGXJ,YAAY;YACR,IAAI,CAAC,OAAO,GAAG;QACnB;QAEA,IAAI;YACA,IAAII,OAAO,mBAAmB,EAC1B,MAAM,IAAI,CAAC,gCAAgC,CAAC,OAAO,CAAC;gBAChD,OAAO,IAAI,CAAC,KAAK;gBACjB,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE;gBACjB,qBAAqBA,OAAO,mBAAmB;YACnD;YAGJ,MAAMb,QAAQ,MAAM,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC;gBACjD,OAAO,IAAI,CAAC,KAAK;gBACjB,YAAY,IAAI,CAAC,KAAK,CAAC,EAAE;YAC7B;YAEAS,YAAY;gBACR,IAAI,CAAC,KAAK,GAAGT;YACjB;YAEA,OAAO;QACX,EAAE,OAAM;YACJ,OAAO;QACX,SAAU;YACNS,YAAY;gBACR,IAAI,CAAC,OAAO,GAAG;YACnB;QACJ;IACJ;IAEA,MAAM,oBAAsC;QACxC,IAAI,CAAC,IAAI,CAAC,KAAK,EACX,OAAO;QAGX,IAAI,CAAC,OAAO,GAAG;QAEf,IAAI;YACA,MAAMT,QAAQ,MAAM,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC;gBACnD,OAAO,IAAI,CAAC,KAAK;gBACjB,YAAY,IAAI,CAAC,KAAK,CAAC,EAAE;YAC7B;YAEAS,YAAY;gBACR,IAAI,CAAC,KAAK,GAAGT;YACjB;YAEA,OAAO;QACX,EAAE,OAAM;YACJ,OAAO;QACX,SAAU;YACNS,YAAY;gBACR,IAAI,CAAC,OAAO,GAAG;YACnB;QACJ;IACJ;IAEA,MAAM,cAAgC;QAClC,IAAI,CAAC,IAAI,CAAC,KAAK,EACX,OAAO;QAGX,MAAMK,QAAQ,IAAI,CAAC,KAAK;QACxB,MAAMd,QAAQ,IAAI,CAAC,KAAK;QAExB,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAC5Be,oBACA;YAAE,SAASf,MAAM,OAAO;QAAC,GACzB;YACI,IAAI;gBACA,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC;oBAClCc;oBACA,IAAId,MAAM,OAAO;gBACrB;gBAEAS,YAAY;oBACR,IAAI,CAAC,KAAK,GAAG;oBACb,IAAI,CAAC,IAAI,GAAG;gBAChB;gBAEA,OAAO;YACX,EAAE,OAAM;gBACJ,OAAO;YACX;QACJ;IAER;IAEA,MAAM,aAAaO,EAAU,EAAiB;QAC1C,IAAI,CAAC,OAAO,GAAG;QAEf,IAAI;YACA,MAAMhB,QAAQ,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;gBAC7C,OAAO,IAAI,CAAC,KAAK;gBACjBgB;YACJ;YAEAP,YAAY;gBACR,IAAI,CAAC,KAAK,GAAGT;gBACb,IAAI,CAAC,oBAAoB,CAACA;YAC9B;QACJ,SAAU;YACNS,YAAY;gBACR,IAAI,CAAC,OAAO,GAAG;YACnB;QACJ;IACJ;IAEA,YAAYQ,QAAuB,EAAQ;QACvC,IAAI,CAAC,QAAQ,GAAGA;IACpB;IAEA,SAASC,aAAuC,EAAQ;QACpD,IAAI,CAAC,KAAK,GAAG;QACb,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS;QAC1B,IAAIA,eACA,IAAI,CAAC,IAAI,CAAC,OAAO,CAACA,eAAe;YAAE,OAAO;QAAK;IAEvD;IAEA,eAAejB,IAAsC,EAAQ;QACzD,IAAI,CAAC,IAAI,CAAC,KAAK,EACX;QAEJ,IAAI,CAAC,KAAK,GAAG;YACT,GAAG,IAAI,CAAC,KAAK;YACb,MAAM;gBAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI;gBAAE,GAAGA,IAAI;YAAC;QACxC;IACJ;IAEA,QAAc;QACV,IAAI,CAAC,IAAI,GAAG;QACZ,IAAI,CAAC,KAAK,GAAG;IACjB;IAEQ,YAAiC;QACrC,MAAMkB,aAAa,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK;QAC5D,MAAMC,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAACD;QAC1C,KAAK,MAAME,YAAY,IAAI,CAAC,kBAAkB,CAC1CA,SAAS,UAAU,CAACD,MAAM,IAAI,CAAC,KAAK;QAExC,OAAOA;IACX;IAEQ,qBAAqBpB,KAAsB,EAAQ;QACvD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS;QAC1B,IAAI,CAAC,IAAI,CAAC,OAAO,CAACA,MAAM,MAAM;QAC9B,IAAI,CAAC,IAAI,CAAC,KAAK;IACnB;IAIA,MAAc,UAAUsB,MAAuB,EAAgB;QAC3D,MAAM,EAAEtB,KAAK,EAAEQ,IAAI,EAAED,cAAc,EAAE,GAAGe;QAExC,IAAItB,MAAM,IAAI,CAAC,MAAM,EACjB,OAAO,MAAM,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAAC;YAChD,OAAO,IAAI,CAAC,KAAK;YACjB,YAAYA,MAAM,EAAE;YACpB,MAAM;gBACF,QAAQQ;YACZ;YACA,SAAS;gBAAED;YAAe;QAC9B;QAEJ,OAAO,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC;YACzC,OAAO,IAAI,CAAC,KAAK;YACjB,YAAYP,MAAM,EAAE;YACpB,MAAM;gBACF,QAAQQ;YACZ;YACA,SAAS;gBAAED;YAAe;QAC9B;IACJ;AACJ;AAEO,MAAMgB,sDAA4BC,0BAAAA,oBAAgC,CAAC;IACtE,gBAAgBxC;IAChB,cAAc;QACVyC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACA;YAACC;YAA+B;gBAAE,UAAU;YAAK;SAAE;KACtD;AACL"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FormModel } from "@webiny/app-admin/features/formModel/abstractions.js";
|
|
2
|
+
import type { CmsModel } from "../../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Converts a rejected save into form errors: per-field validation errors from the API are
|
|
5
|
+
* placed on their fields, anything else is shown as a form-level error.
|
|
6
|
+
*/
|
|
7
|
+
export declare const toFormErrors: (error: unknown, model: CmsModel) => FormModel.FormError[];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { CmsEntryError } from "../../../features/contentEntry/CmsEntryError.js";
|
|
2
|
+
const isApiFieldError = (value)=>{
|
|
3
|
+
const item = value;
|
|
4
|
+
return "string" == typeof item?.fieldId && "string" == typeof item.error;
|
|
5
|
+
};
|
|
6
|
+
const isIndex = (value)=>/^\d+$/.test(String(value));
|
|
7
|
+
const toFieldPath = (model, error)=>{
|
|
8
|
+
const parents = error.parents ?? [];
|
|
9
|
+
const path = [];
|
|
10
|
+
let fields = model.fields;
|
|
11
|
+
for(let i = 0; i < parents.length; i++){
|
|
12
|
+
const field = fields.find((f)=>f.fieldId === String(parents[i]));
|
|
13
|
+
if (!field) return [
|
|
14
|
+
...parents,
|
|
15
|
+
error.fieldId
|
|
16
|
+
].join(".");
|
|
17
|
+
path.push(field.fieldId);
|
|
18
|
+
if (field.list && isIndex(parents[i + 1])) path.push(String(parents[++i]));
|
|
19
|
+
if ("dynamicZone" === field.type) {
|
|
20
|
+
const templates = field.settings?.templates ?? [];
|
|
21
|
+
const template = templates.find((t)=>t.gqlTypeName === String(parents[i + 1]));
|
|
22
|
+
i++;
|
|
23
|
+
fields = template?.fields ?? [];
|
|
24
|
+
} else fields = field.settings?.fields ?? [];
|
|
25
|
+
}
|
|
26
|
+
return [
|
|
27
|
+
...path,
|
|
28
|
+
error.fieldId
|
|
29
|
+
].join(".");
|
|
30
|
+
};
|
|
31
|
+
const toFormErrors = (error, model)=>{
|
|
32
|
+
if (error instanceof CmsEntryError && Array.isArray(error.data)) {
|
|
33
|
+
const fieldErrors = error.data.filter(isApiFieldError);
|
|
34
|
+
if (fieldErrors.length > 0) return fieldErrors.map((item)=>({
|
|
35
|
+
path: toFieldPath(model, item),
|
|
36
|
+
message: item.error
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
const message = error instanceof Error ? error.message : "Could not save the entry.";
|
|
40
|
+
return [
|
|
41
|
+
{
|
|
42
|
+
path: "",
|
|
43
|
+
message
|
|
44
|
+
}
|
|
45
|
+
];
|
|
46
|
+
};
|
|
47
|
+
export { toFormErrors };
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=toFormErrors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation/contentEntries/form/toFormErrors.js","sources":["../../../../src/presentation/contentEntries/form/toFormErrors.ts"],"sourcesContent":["import type { FormModel } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { CmsDynamicZoneTemplate, CmsModel, CmsModelField } from \"~/types.js\";\nimport { CmsEntryError } from \"~/features/contentEntry/CmsEntryError.js\";\n\ninterface ApiFieldError {\n fieldId: string;\n error: string;\n parents?: (string | number)[];\n}\n\nconst isApiFieldError = (value: unknown): value is ApiFieldError => {\n const item = value as ApiFieldError;\n return typeof item?.fieldId === \"string\" && typeof item.error === \"string\";\n};\n\nconst isIndex = (value: unknown): boolean => /^\\d+$/.test(String(value));\n\n/**\n * The API lists the parents of a nested field as `fieldId`, then the item index for list\n * fields, then the template's `gqlTypeName` for dynamic zones. Form paths have no template\n * segment, so walk the model to drop it: `blocks.0.PageHero.title` → `blocks.0.title`.\n */\nconst toFieldPath = (model: CmsModel, error: ApiFieldError): string => {\n const parents = error.parents ?? [];\n const path: string[] = [];\n let fields: CmsModelField[] = model.fields;\n\n for (let i = 0; i < parents.length; i++) {\n const field = fields.find(f => f.fieldId === String(parents[i]));\n if (!field) {\n return [...parents, error.fieldId].join(\".\");\n }\n path.push(field.fieldId);\n\n if (field.list && isIndex(parents[i + 1])) {\n path.push(String(parents[++i]));\n }\n\n if (field.type === \"dynamicZone\") {\n const templates = (field.settings?.templates ?? []) as CmsDynamicZoneTemplate[];\n const template = templates.find(t => t.gqlTypeName === String(parents[i + 1]));\n i++;\n fields = template?.fields ?? [];\n } else {\n fields = (field.settings?.fields ?? []) as CmsModelField[];\n }\n }\n\n return [...path, error.fieldId].join(\".\");\n};\n\n/**\n * Converts a rejected save into form errors: per-field validation errors from the API are\n * placed on their fields, anything else is shown as a form-level error.\n */\nexport const toFormErrors = (error: unknown, model: CmsModel): FormModel.FormError[] => {\n if (error instanceof CmsEntryError && Array.isArray(error.data)) {\n const fieldErrors = error.data.filter(isApiFieldError);\n if (fieldErrors.length > 0) {\n return fieldErrors.map(item => ({\n path: toFieldPath(model, item),\n message: item.error\n }));\n }\n }\n\n const message = error instanceof Error ? error.message : \"Could not save the entry.\";\n return [{ path: \"\", message }];\n};\n"],"names":["isApiFieldError","value","item","isIndex","String","toFieldPath","model","error","parents","path","fields","i","field","f","templates","template","t","toFormErrors","CmsEntryError","Array","fieldErrors","message","Error"],"mappings":";AAUA,MAAMA,kBAAkB,CAACC;IACrB,MAAMC,OAAOD;IACb,OAAO,AAAyB,YAAzB,OAAOC,MAAM,WAAwB,AAAsB,YAAtB,OAAOA,KAAK,KAAK;AACjE;AAEA,MAAMC,UAAU,CAACF,QAA4B,QAAQ,IAAI,CAACG,OAAOH;AAOjE,MAAMI,cAAc,CAACC,OAAiBC;IAClC,MAAMC,UAAUD,MAAM,OAAO,IAAI,EAAE;IACnC,MAAME,OAAiB,EAAE;IACzB,IAAIC,SAA0BJ,MAAM,MAAM;IAE1C,IAAK,IAAIK,IAAI,GAAGA,IAAIH,QAAQ,MAAM,EAAEG,IAAK;QACrC,MAAMC,QAAQF,OAAO,IAAI,CAACG,CAAAA,IAAKA,EAAE,OAAO,KAAKT,OAAOI,OAAO,CAACG,EAAE;QAC9D,IAAI,CAACC,OACD,OAAO;eAAIJ;YAASD,MAAM,OAAO;SAAC,CAAC,IAAI,CAAC;QAE5CE,KAAK,IAAI,CAACG,MAAM,OAAO;QAEvB,IAAIA,MAAM,IAAI,IAAIT,QAAQK,OAAO,CAACG,IAAI,EAAE,GACpCF,KAAK,IAAI,CAACL,OAAOI,OAAO,CAAC,EAAEG,EAAE;QAGjC,IAAIC,AAAe,kBAAfA,MAAM,IAAI,EAAoB;YAC9B,MAAME,YAAaF,MAAM,QAAQ,EAAE,aAAa,EAAE;YAClD,MAAMG,WAAWD,UAAU,IAAI,CAACE,CAAAA,IAAKA,EAAE,WAAW,KAAKZ,OAAOI,OAAO,CAACG,IAAI,EAAE;YAC5EA;YACAD,SAASK,UAAU,UAAU,EAAE;QACnC,OACIL,SAAUE,MAAM,QAAQ,EAAE,UAAU,EAAE;IAE9C;IAEA,OAAO;WAAIH;QAAMF,MAAM,OAAO;KAAC,CAAC,IAAI,CAAC;AACzC;AAMO,MAAMU,eAAe,CAACV,OAAgBD;IACzC,IAAIC,iBAAiBW,iBAAiBC,MAAM,OAAO,CAACZ,MAAM,IAAI,GAAG;QAC7D,MAAMa,cAAcb,MAAM,IAAI,CAAC,MAAM,CAACP;QACtC,IAAIoB,YAAY,MAAM,GAAG,GACrB,OAAOA,YAAY,GAAG,CAAClB,CAAAA,OAAS;gBAC5B,MAAMG,YAAYC,OAAOJ;gBACzB,SAASA,KAAK,KAAK;YACvB;IAER;IAEA,MAAMmB,UAAUd,iBAAiBe,QAAQf,MAAM,OAAO,GAAG;IACzD,OAAO;QAAC;YAAE,MAAM;YAAIc;QAAQ;KAAE;AAClC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|