@webiny/app-headless-cms 6.5.0-beta.9 → 6.5.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/components/ContentEntries/Filters/RefFieldRenderer.js +1 -0
- package/admin/components/ContentEntries/Filters/RefFieldRenderer.js.map +1 -1
- package/admin/plugins/editor/defaultBar/Name/Name.d.ts +0 -5
- package/admin/plugins/editor/defaultBar/Name/Name.js +0 -2
- package/admin/plugins/editor/defaultBar/Name/Name.js.map +1 -1
- package/features/contentEntry/feature.js +2 -0
- package/features/contentEntry/feature.js.map +1 -1
- package/features/contentEntry/referenceTitles/ReferenceTitles.d.ts +18 -0
- package/features/contentEntry/referenceTitles/ReferenceTitles.js +58 -0
- package/features/contentEntry/referenceTitles/ReferenceTitles.js.map +1 -0
- package/features/contentEntry/referenceTitles/ReferenceTitles.test.d.ts +1 -0
- package/features/contentEntry/referenceTitles/ReferenceTitles.test.js +173 -0
- package/features/contentEntry/referenceTitles/ReferenceTitles.test.js.map +1 -0
- package/features/contentEntry/referenceTitles/RememberTitlesDecorators.d.ts +22 -0
- package/features/contentEntry/referenceTitles/RememberTitlesDecorators.js +40 -0
- package/features/contentEntry/referenceTitles/RememberTitlesDecorators.js.map +1 -0
- package/features/contentEntry/referenceTitles/abstractions.d.ts +16 -0
- package/features/contentEntry/referenceTitles/abstractions.js +5 -0
- package/features/contentEntry/referenceTitles/abstractions.js.map +1 -0
- package/features/contentEntry/referenceTitles/feature.d.ts +3 -0
- package/features/contentEntry/referenceTitles/feature.js +20 -0
- package/features/contentEntry/referenceTitles/feature.js.map +1 -0
- package/features/formModel/CmsFormModelBuilder.test.js +213 -0
- package/features/formModel/CmsFormModelBuilder.test.js.map +1 -1
- package/features/formModel/CmsRefFieldValueFormatter.d.ts +12 -0
- package/features/formModel/CmsRefFieldValueFormatter.js +29 -0
- package/features/formModel/CmsRefFieldValueFormatter.js.map +1 -0
- package/features/formModel/CmsValidationMapper.d.ts +9 -0
- package/features/formModel/CmsValidationMapper.js +25 -19
- package/features/formModel/CmsValidationMapper.js.map +1 -1
- package/features/formModel/feature.js +2 -0
- package/features/formModel/feature.js.map +1 -1
- package/features/formModel/mappers/DateTimeFieldMapper.js +3 -0
- package/features/formModel/mappers/DateTimeFieldMapper.js.map +1 -1
- package/package.json +22 -22
- package/presentation/contentEntries/form/ContentEntryFormPresenter.js +30 -30
- package/presentation/contentEntries/form/ContentEntryFormPresenter.js.map +1 -1
- package/presentation/contentEntries/form/ContentEntryFormPresenter.test.js +144 -10
- package/presentation/contentEntries/form/ContentEntryFormPresenter.test.js.map +1 -1
- package/presentation/contentEntries/preview/ModelEditorComponentDiscovery.js +1 -1
- package/presentation/contentEntries/preview/ModelEditorComponentDiscovery.js.map +1 -1
- package/presentation/contentEntries/preview/PreviewDecorator.js +9 -3
- package/presentation/contentEntries/preview/PreviewDecorator.js.map +1 -1
- package/presentation/contentEntries/preview/PreviewDomainStatus.d.ts +10 -0
- package/presentation/contentEntries/preview/PreviewDomainStatus.js +19 -0
- package/presentation/contentEntries/preview/PreviewDomainStatus.js.map +1 -0
- package/presentation/contentEntries/preview/PreviewPane.d.ts +6 -1
- package/presentation/contentEntries/preview/PreviewPane.js +80 -44
- package/presentation/contentEntries/preview/PreviewPane.js.map +1 -1
- package/presentation/contentEntries/views/ContentEntryFormView.js +1 -0
- package/presentation/contentEntries/views/ContentEntryFormView.js.map +1 -1
- package/presentation/fieldEditor/groups/AppearanceGroup.js +12 -0
- package/presentation/fieldEditor/groups/AppearanceGroup.js.map +1 -1
- package/presentation/fieldEditor/groups/ValidationsGroup.d.ts +2 -0
- package/presentation/fieldEditor/groups/ValidationsGroup.js +20 -6
- package/presentation/fieldEditor/groups/ValidationsGroup.js.map +1 -1
- package/presentation/fieldEditor/renderers/CmsValidatorsRenderer.js +2 -2
- package/presentation/fieldEditor/renderers/CmsValidatorsRenderer.js.map +1 -1
- package/presentation/fieldRenderers/feature.js +2 -1
- package/presentation/fieldRenderers/feature.js.map +1 -1
- package/presentation/fieldRenderers/ref/CmsRefInputRenderer.js +1 -0
- package/presentation/fieldRenderers/ref/CmsRefInputRenderer.js.map +1 -1
- package/presentation/fieldRenderers/ref/CmsRefInputsRenderer.js +1 -0
- package/presentation/fieldRenderers/ref/CmsRefInputsRenderer.js.map +1 -1
- package/presentation/fieldRenderers/ref/autocomplete/BaseAutocompletePresenter.d.ts +1 -0
- package/presentation/fieldRenderers/ref/autocomplete/BaseAutocompletePresenter.js +8 -2
- package/presentation/fieldRenderers/ref/autocomplete/BaseAutocompletePresenter.js.map +1 -1
- package/presentation/fieldRenderers/ref/autocomplete/RefAutocompletePresenters.test.js +52 -0
- package/presentation/fieldRenderers/ref/autocomplete/RefAutocompletePresenters.test.js.map +1 -1
- package/presentation/fieldTypes/renderers/dateTime/BirthdayInputRenderer.d.ts +15 -0
- package/presentation/fieldTypes/renderers/dateTime/BirthdayInputRenderer.js +19 -0
- package/presentation/fieldTypes/renderers/dateTime/BirthdayInputRenderer.js.map +1 -0
- package/presentation/fieldTypes/renderers/index.d.ts +1 -0
- package/presentation/fieldTypes/renderers/index.js +1 -0
- package/presentation/fieldValidators/abstractions.d.ts +7 -0
- package/presentation/fieldValidators/abstractions.js.map +1 -1
- package/presentation/fieldValidators/validators/DateGteValidator.d.ts +6 -0
- package/presentation/fieldValidators/validators/DateGteValidator.js +17 -25
- package/presentation/fieldValidators/validators/DateGteValidator.js.map +1 -1
- package/presentation/fieldValidators/validators/DateLteValidator.d.ts +6 -0
- package/presentation/fieldValidators/validators/DateLteValidator.js +17 -25
- package/presentation/fieldValidators/validators/DateLteValidator.js.map +1 -1
- package/presentation/fieldValidators/validators/dateLimitSettings.d.ts +20 -0
- package/presentation/fieldValidators/validators/dateLimitSettings.js +124 -0
- package/presentation/fieldValidators/validators/dateLimitSettings.js.map +1 -0
- package/presentation/fieldValidators/validators/dateLimitSettings.test.d.ts +1 -0
- package/presentation/fieldValidators/validators/dateLimitSettings.test.js +111 -0
- package/presentation/fieldValidators/validators/dateLimitSettings.test.js.map +1 -0
|
@@ -15,6 +15,7 @@ import { TRASH_ENTRY_DIALOG } from "../list/ContentEntriesPresenter.js";
|
|
|
15
15
|
import { CreateRevisionFromUseCase } from "../../../features/contentEntry/createRevisionFrom/abstractions.js";
|
|
16
16
|
import { toFormErrors } from "./toFormErrors.js";
|
|
17
17
|
const PUBLISH_ENTRY_DIALOG = "publish-entry";
|
|
18
|
+
const SAVING = "Saving...";
|
|
18
19
|
class ContentEntryFormPresenterImpl {
|
|
19
20
|
constructor(formModelFactory, cmsFormModelBuilder, confirmation, modelAccessor, getEntryUseCase, createEntryUseCase, createRevisionFromUseCase, updateEntryUseCase, publishEntryUseCase, unpublishEntryUseCase, deleteEntryUseCase, updateRevisionDescriptionUseCase, formModelModifiers){
|
|
20
21
|
this.formModelFactory = formModelFactory;
|
|
@@ -81,55 +82,53 @@ class ContentEntryFormPresenterImpl {
|
|
|
81
82
|
if (!this.form) return false;
|
|
82
83
|
const form = this.form;
|
|
83
84
|
const model = this.model;
|
|
85
|
+
const isCurrent = ()=>this.form === form && this.model.modelId === model.modelId;
|
|
84
86
|
const skipValidation = options?.skipValidation ?? true;
|
|
85
87
|
const data = await form.submit({
|
|
86
88
|
skipValidation
|
|
87
89
|
});
|
|
88
|
-
if (!data) return false;
|
|
90
|
+
if (!data || !isCurrent()) return false;
|
|
91
|
+
const entry = this.entry;
|
|
92
|
+
const folderId = this.folderId;
|
|
89
93
|
runInAction(()=>{
|
|
90
|
-
this.loading =
|
|
94
|
+
this.loading = SAVING;
|
|
91
95
|
});
|
|
92
96
|
try {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
this.entry = entry;
|
|
102
|
-
form.setData(entry.values);
|
|
103
|
-
form.reset();
|
|
104
|
-
});
|
|
105
|
-
} else {
|
|
97
|
+
let savedEntry;
|
|
98
|
+
if (entry) savedEntry = await this.saveEntry({
|
|
99
|
+
model,
|
|
100
|
+
entry,
|
|
101
|
+
data,
|
|
102
|
+
skipValidation
|
|
103
|
+
});
|
|
104
|
+
else {
|
|
106
105
|
const createData = {
|
|
107
106
|
values: data
|
|
108
107
|
};
|
|
109
|
-
if (
|
|
110
|
-
folderId
|
|
108
|
+
if (folderId) createData.wbyAco_location = {
|
|
109
|
+
folderId
|
|
111
110
|
};
|
|
112
|
-
|
|
113
|
-
model
|
|
111
|
+
savedEntry = await this.createEntryUseCase.execute({
|
|
112
|
+
model,
|
|
114
113
|
data: createData,
|
|
115
114
|
options: {
|
|
116
115
|
skipValidation
|
|
117
116
|
}
|
|
118
117
|
});
|
|
119
|
-
runInAction(()=>{
|
|
120
|
-
if (this.form !== form) return;
|
|
121
|
-
this.entry = entry;
|
|
122
|
-
form.setData(entry.values);
|
|
123
|
-
form.reset();
|
|
124
|
-
});
|
|
125
118
|
}
|
|
119
|
+
if (!isCurrent()) return false;
|
|
120
|
+
runInAction(()=>{
|
|
121
|
+
this.entry = savedEntry;
|
|
122
|
+
form.setData(savedEntry.values);
|
|
123
|
+
form.reset();
|
|
124
|
+
});
|
|
126
125
|
return true;
|
|
127
126
|
} catch (error) {
|
|
128
|
-
if (
|
|
127
|
+
if (isCurrent()) form.setErrors(toFormErrors(error, model));
|
|
129
128
|
return false;
|
|
130
129
|
} finally{
|
|
131
130
|
runInAction(()=>{
|
|
132
|
-
this.loading = null;
|
|
131
|
+
if (this.loading === SAVING) this.loading = null;
|
|
133
132
|
});
|
|
134
133
|
}
|
|
135
134
|
}
|
|
@@ -246,6 +245,7 @@ class ContentEntryFormPresenterImpl {
|
|
|
246
245
|
reset() {
|
|
247
246
|
this.form = null;
|
|
248
247
|
this.entry = null;
|
|
248
|
+
this.folderId = null;
|
|
249
249
|
}
|
|
250
250
|
buildForm() {
|
|
251
251
|
const formConfig = this.cmsFormModelBuilder.build(this.model);
|
|
@@ -259,9 +259,9 @@ class ContentEntryFormPresenterImpl {
|
|
|
259
259
|
this.form.reset();
|
|
260
260
|
}
|
|
261
261
|
async saveEntry(params) {
|
|
262
|
-
const { entry, data, skipValidation } = params;
|
|
262
|
+
const { model, entry, data, skipValidation } = params;
|
|
263
263
|
if (entry.meta.locked) return await this.createRevisionFromUseCase.execute({
|
|
264
|
-
model
|
|
264
|
+
model,
|
|
265
265
|
revisionId: entry.id,
|
|
266
266
|
data: {
|
|
267
267
|
values: data
|
|
@@ -271,7 +271,7 @@ class ContentEntryFormPresenterImpl {
|
|
|
271
271
|
}
|
|
272
272
|
});
|
|
273
273
|
return await this.updateEntryUseCase.execute({
|
|
274
|
-
model
|
|
274
|
+
model,
|
|
275
275
|
revisionId: entry.id,
|
|
276
276
|
data: {
|
|
277
277
|
values: data
|
|
@@ -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\";\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 /*\n * Saving is async, and the form can be reset or replaced by another entry before it\n * finishes. Keep hold of the form and model being saved, and only write the result back\n * while that form is still the one on screen.\n */\n const form = this.form;\n const model = this.model;\n\n const skipValidation = options?.skipValidation ?? true;\n const data = await 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 if (this.form !== form) {\n return;\n }\n this.entry = entry;\n form.setData(entry.values);\n 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 if (this.form !== form) {\n return;\n }\n this.entry = entry;\n form.setData(entry.values);\n form.reset();\n });\n }\n\n return true;\n } catch (error) {\n if (this.form === form) {\n form.setErrors(toFormErrors(error, model));\n }\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","form","model","skipValidation","data","runInAction","createData","error","toFormErrors","result","TRASH_ENTRY_DIALOG","id","folderId","initialValues","formConfig","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, CmsModel } 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 model: CmsModel;\n entry: CmsContentEntry;\n data: Record<string, unknown>;\n skipValidation?: boolean;\n}\n\nexport const PUBLISH_ENTRY_DIALOG = \"publish-entry\";\n\nconst SAVING = \"Saving...\";\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 /*\n * Saving is async, and the form can be reset or replaced by another entry before it\n * finishes. Keep hold of the form and model being saved, and only write the result back\n * while that form is still the one on screen.\n */\n const form = this.form;\n const model = this.model;\n const isCurrent = () => this.form === form && this.model.modelId === model.modelId;\n\n const skipValidation = options?.skipValidation ?? true;\n const data = await form.submit({ skipValidation });\n\n /*\n * Validation is async too. If another entry was opened in the meantime, `this.entry`\n * already points at it, and saving now would write this form's values onto that entry.\n */\n if (!data || !isCurrent()) {\n return false;\n }\n\n // Read the write target once, before the first await, so the write stays on this entry.\n const entry = this.entry;\n const folderId = this.folderId;\n\n runInAction(() => {\n this.loading = SAVING;\n });\n\n try {\n let savedEntry: CmsContentEntry;\n if (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 savedEntry = await this.saveEntry({ model, entry, data, skipValidation });\n } else {\n const createData: Record<string, unknown> = { values: data };\n if (folderId) {\n createData.wbyAco_location = { folderId };\n }\n\n savedEntry = await this.createEntryUseCase.execute({\n model,\n data: createData,\n options: { skipValidation }\n });\n }\n\n /*\n * The write went to the right entry, but another form is on screen now. Leave it\n * alone and return false, so callers don't select, toast or publish the entry that\n * is open now instead of the one that was saved.\n */\n if (!isCurrent()) {\n return false;\n }\n\n runInAction(() => {\n this.entry = savedEntry;\n form.setData(savedEntry.values);\n form.reset();\n });\n\n return true;\n } catch (error) {\n if (isCurrent()) {\n form.setErrors(toFormErrors(error, model));\n }\n return false;\n } finally {\n runInAction(() => {\n // Opening another entry sets its own loading message. Don't clear that one.\n if (this.loading === SAVING) {\n this.loading = null;\n }\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 this.folderId = 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<CmsContentEntry> {\n const { model, entry, data, skipValidation } = params;\n\n if (entry.meta.locked) {\n return await this.createRevisionFromUseCase.execute({\n model,\n revisionId: entry.id,\n data: {\n values: data\n },\n options: { skipValidation }\n });\n }\n return await this.updateEntryUseCase.execute({\n 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","SAVING","ContentEntryFormPresenterImpl","formModelFactory","cmsFormModelBuilder","confirmation","modelAccessor","getEntryUseCase","createEntryUseCase","createRevisionFromUseCase","updateEntryUseCase","publishEntryUseCase","unpublishEntryUseCase","deleteEntryUseCase","updateRevisionDescriptionUseCase","formModelModifiers","makeAutoObservable","computed","entry","meta","isLocked","status","canSave","toJS","options","form","model","isCurrent","skipValidation","data","folderId","runInAction","savedEntry","createData","error","toFormErrors","result","TRASH_ENTRY_DIALOG","id","initialValues","formConfig","modifier","params","ContentEntryFormPresenter","Abstraction","FormModelFactory","CmsFormModelBuilder","Confirmation","CmsModelContext","GetEntryUseCase","CreateEntryUseCase","CreateRevisionFromUseCase","UpdateEntryUseCase","PublishEntryUseCase","UnpublishEntryUseCase","DeleteEntryUseCase","UpdateRevisionDescriptionUseCase","ContentEntryFormModelModifier"],"mappings":"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"}
|
|
@@ -14,12 +14,12 @@ import { CmsFormModelBuilder } from "../../../features/formModel/abstractions.js
|
|
|
14
14
|
import { CmsModelContext } from "../../../features/contentEntry/abstractions.js";
|
|
15
15
|
import { ContentEntryFormPresenter } from "./abstractions.js";
|
|
16
16
|
import { ContentEntryFormPresenter as external_ContentEntryFormPresenter_js_ContentEntryFormPresenter } from "./ContentEntryFormPresenter.js";
|
|
17
|
-
const createFakeForm = ()=>({
|
|
17
|
+
const createFakeForm = (validation)=>({
|
|
18
18
|
vm: {},
|
|
19
19
|
isDirty: false,
|
|
20
|
-
submit: vi.fn(async ()=>
|
|
20
|
+
submit: vi.fn(async ()=>validation ? validation : {
|
|
21
21
|
title: "Draft"
|
|
22
|
-
})
|
|
22
|
+
}),
|
|
23
23
|
setData: vi.fn(),
|
|
24
24
|
reset: vi.fn(),
|
|
25
25
|
setErrors: vi.fn()
|
|
@@ -37,13 +37,31 @@ const deferred = ()=>{
|
|
|
37
37
|
reject
|
|
38
38
|
};
|
|
39
39
|
};
|
|
40
|
+
const createEntry = (entryId)=>({
|
|
41
|
+
id: `${entryId}#0001`,
|
|
42
|
+
entryId,
|
|
43
|
+
meta: {
|
|
44
|
+
locked: false,
|
|
45
|
+
status: "draft",
|
|
46
|
+
title: entryId
|
|
47
|
+
},
|
|
48
|
+
values: {
|
|
49
|
+
title: entryId
|
|
50
|
+
}
|
|
51
|
+
});
|
|
40
52
|
const setup = ()=>{
|
|
41
53
|
const forms = [];
|
|
42
54
|
const create = deferred();
|
|
55
|
+
const update = deferred();
|
|
56
|
+
let nextValidation;
|
|
57
|
+
const pendingLoads = new Map();
|
|
58
|
+
const createExecute = vi.fn(()=>create.promise);
|
|
59
|
+
const updateExecute = vi.fn(()=>update.promise);
|
|
43
60
|
const container = new Container();
|
|
44
61
|
container.registerInstance(FormModelFactory, {
|
|
45
62
|
create: ()=>{
|
|
46
|
-
const form = createFakeForm();
|
|
63
|
+
const form = createFakeForm(nextValidation);
|
|
64
|
+
nextValidation = void 0;
|
|
47
65
|
forms.push(form);
|
|
48
66
|
return form;
|
|
49
67
|
}
|
|
@@ -58,13 +76,17 @@ const setup = ()=>{
|
|
|
58
76
|
})
|
|
59
77
|
});
|
|
60
78
|
container.registerInstance(CreateEntryUseCase, {
|
|
61
|
-
execute:
|
|
79
|
+
execute: createExecute
|
|
80
|
+
});
|
|
81
|
+
container.registerInstance(UpdateEntryUseCase, {
|
|
82
|
+
execute: updateExecute
|
|
83
|
+
});
|
|
84
|
+
container.registerInstance(GetEntryUseCase, {
|
|
85
|
+
execute: async ({ id })=>pendingLoads.get(id) ?? createEntry(id)
|
|
62
86
|
});
|
|
63
87
|
for (const abstraction of [
|
|
64
88
|
Confirmation,
|
|
65
|
-
GetEntryUseCase,
|
|
66
89
|
CreateRevisionFromUseCase,
|
|
67
|
-
UpdateEntryUseCase,
|
|
68
90
|
PublishEntryUseCase,
|
|
69
91
|
UnpublishEntryUseCase,
|
|
70
92
|
DeleteEntryUseCase,
|
|
@@ -74,7 +96,16 @@ const setup = ()=>{
|
|
|
74
96
|
return {
|
|
75
97
|
presenter: container.resolve(ContentEntryFormPresenter),
|
|
76
98
|
forms,
|
|
77
|
-
create
|
|
99
|
+
create,
|
|
100
|
+
createExecute,
|
|
101
|
+
update,
|
|
102
|
+
updateExecute,
|
|
103
|
+
pendingLoads,
|
|
104
|
+
slowValidation: ()=>{
|
|
105
|
+
const validation = deferred();
|
|
106
|
+
nextValidation = validation.promise;
|
|
107
|
+
return validation;
|
|
108
|
+
}
|
|
78
109
|
};
|
|
79
110
|
};
|
|
80
111
|
describe("ContentEntryFormPresenter.saveRevision", ()=>{
|
|
@@ -86,18 +117,55 @@ describe("ContentEntryFormPresenter.saveRevision", ()=>{
|
|
|
86
117
|
await expect(saving).resolves.toBe(false);
|
|
87
118
|
expect(forms[0].setErrors).toHaveBeenCalledTimes(1);
|
|
88
119
|
});
|
|
120
|
+
it("creates a new entry in the folder it was started in", async ()=>{
|
|
121
|
+
const { presenter, create, createExecute } = setup();
|
|
122
|
+
presenter.setFolderId("folder-1");
|
|
123
|
+
presenter.newEntry();
|
|
124
|
+
const saving = presenter.saveRevision();
|
|
125
|
+
create.resolve(createEntry("A"));
|
|
126
|
+
await expect(saving).resolves.toBe(true);
|
|
127
|
+
expect(createExecute).toHaveBeenCalledWith(expect.objectContaining({
|
|
128
|
+
data: {
|
|
129
|
+
values: {
|
|
130
|
+
title: "Draft"
|
|
131
|
+
},
|
|
132
|
+
wbyAco_location: {
|
|
133
|
+
folderId: "folder-1"
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}));
|
|
137
|
+
});
|
|
138
|
+
it("does not carry the folder over to an entry started after a reset", async ()=>{
|
|
139
|
+
const { presenter, create, createExecute } = setup();
|
|
140
|
+
presenter.setFolderId("folder-1");
|
|
141
|
+
presenter.reset();
|
|
142
|
+
presenter.newEntry();
|
|
143
|
+
const saving = presenter.saveRevision();
|
|
144
|
+
create.resolve(createEntry("A"));
|
|
145
|
+
await expect(saving).resolves.toBe(true);
|
|
146
|
+
expect(createExecute).toHaveBeenCalledWith(expect.objectContaining({
|
|
147
|
+
data: {
|
|
148
|
+
values: {
|
|
149
|
+
title: "Draft"
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}));
|
|
153
|
+
});
|
|
89
154
|
it("returns false instead of throwing when the form was reset mid-save", async ()=>{
|
|
90
|
-
const { presenter, create } = setup();
|
|
155
|
+
const { presenter, create, createExecute } = setup();
|
|
91
156
|
presenter.newEntry();
|
|
92
157
|
const saving = presenter.saveRevision();
|
|
158
|
+
await vi.waitFor(()=>expect(createExecute).toHaveBeenCalled());
|
|
93
159
|
presenter.reset();
|
|
94
160
|
create.reject(new Error("Value must be unique."));
|
|
95
161
|
await expect(saving).resolves.toBe(false);
|
|
162
|
+
expect(presenter.vm.loading).toBe(null);
|
|
96
163
|
});
|
|
97
164
|
it("leaves a form built after the save started alone", async ()=>{
|
|
98
|
-
const { presenter, forms, create } = setup();
|
|
165
|
+
const { presenter, forms, create, createExecute } = setup();
|
|
99
166
|
presenter.newEntry();
|
|
100
167
|
const saving = presenter.saveRevision();
|
|
168
|
+
await vi.waitFor(()=>expect(createExecute).toHaveBeenCalled());
|
|
101
169
|
presenter.newEntry();
|
|
102
170
|
create.reject(new Error("Value must be unique."));
|
|
103
171
|
await expect(saving).resolves.toBe(false);
|
|
@@ -105,6 +173,72 @@ describe("ContentEntryFormPresenter.saveRevision", ()=>{
|
|
|
105
173
|
expect(forms[0].setErrors).not.toHaveBeenCalled();
|
|
106
174
|
expect(forms[1].setErrors).not.toHaveBeenCalled();
|
|
107
175
|
});
|
|
176
|
+
it("saves the open entry and puts the saved values on the form", async ()=>{
|
|
177
|
+
const { presenter, forms, update, updateExecute } = setup();
|
|
178
|
+
await presenter.loadRevision("A");
|
|
179
|
+
const saving = presenter.saveRevision();
|
|
180
|
+
await vi.waitFor(()=>expect(updateExecute).toHaveBeenCalled());
|
|
181
|
+
update.resolve(createEntry("A"));
|
|
182
|
+
await expect(saving).resolves.toBe(true);
|
|
183
|
+
expect(updateExecute).toHaveBeenCalledWith(expect.objectContaining({
|
|
184
|
+
revisionId: "A#0001",
|
|
185
|
+
data: {
|
|
186
|
+
values: {
|
|
187
|
+
title: "Draft"
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}));
|
|
191
|
+
expect(forms[0].setData).toHaveBeenLastCalledWith({
|
|
192
|
+
title: "A"
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
it("does not write to an entry opened while the form was validating", async ()=>{
|
|
196
|
+
const { presenter, update, updateExecute, slowValidation } = setup();
|
|
197
|
+
const validation = slowValidation();
|
|
198
|
+
await presenter.loadRevision("A");
|
|
199
|
+
const saving = presenter.saveRevision();
|
|
200
|
+
await presenter.loadRevision("B");
|
|
201
|
+
validation.resolve({
|
|
202
|
+
title: "Values typed into A"
|
|
203
|
+
});
|
|
204
|
+
update.resolve(createEntry("B"));
|
|
205
|
+
await expect(saving).resolves.toBe(false);
|
|
206
|
+
expect(updateExecute).not.toHaveBeenCalled();
|
|
207
|
+
expect(presenter.vm.entry?.entryId).toBe("B");
|
|
208
|
+
});
|
|
209
|
+
it("keeps a write on its entry and reports false when another entry was opened", async ()=>{
|
|
210
|
+
const { presenter, forms, update, updateExecute } = setup();
|
|
211
|
+
await presenter.loadRevision("A");
|
|
212
|
+
const saving = presenter.saveRevision();
|
|
213
|
+
await vi.waitFor(()=>expect(updateExecute).toHaveBeenCalled());
|
|
214
|
+
await presenter.loadRevision("B");
|
|
215
|
+
update.resolve(createEntry("A"));
|
|
216
|
+
await expect(saving).resolves.toBe(false);
|
|
217
|
+
expect(updateExecute).toHaveBeenCalledTimes(1);
|
|
218
|
+
expect(updateExecute).toHaveBeenCalledWith(expect.objectContaining({
|
|
219
|
+
revisionId: "A#0001"
|
|
220
|
+
}));
|
|
221
|
+
expect(presenter.vm.entry?.entryId).toBe("B");
|
|
222
|
+
expect(forms[1].setData).toHaveBeenCalledTimes(1);
|
|
223
|
+
expect(forms[1].setData).toHaveBeenCalledWith({
|
|
224
|
+
title: "B"
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
it("does not clear the loading message of an entry being opened", async ()=>{
|
|
228
|
+
const { presenter, update, updateExecute, pendingLoads } = setup();
|
|
229
|
+
await presenter.loadRevision("A");
|
|
230
|
+
const saving = presenter.saveRevision();
|
|
231
|
+
await vi.waitFor(()=>expect(updateExecute).toHaveBeenCalled());
|
|
232
|
+
const loadB = deferred();
|
|
233
|
+
pendingLoads.set("B", loadB.promise);
|
|
234
|
+
const loading = presenter.loadRevision("B");
|
|
235
|
+
update.resolve(createEntry("A"));
|
|
236
|
+
await expect(saving).resolves.toBe(true);
|
|
237
|
+
expect(presenter.vm.loading).toBe("Loading entry...");
|
|
238
|
+
loadB.resolve(createEntry("B"));
|
|
239
|
+
await loading;
|
|
240
|
+
expect(presenter.vm.loading).toBe(null);
|
|
241
|
+
});
|
|
108
242
|
});
|
|
109
243
|
|
|
110
244
|
//# sourceMappingURL=ContentEntryFormPresenter.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/contentEntries/form/ContentEntryFormPresenter.test.js","sources":["../../../../src/presentation/contentEntries/form/ContentEntryFormPresenter.test.ts"],"sourcesContent":["// @vitest-environment jsdom\nimport { describe, it, expect, vi } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { Confirmation } from \"@webiny/app-admin/features/confirmation/abstractions.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 { CreateRevisionFromUseCase } from \"~/features/contentEntry/createRevisionFrom/abstractions.js\";\nimport { CmsFormModelBuilder } from \"~/features/formModel/abstractions.js\";\nimport { CmsModelContext } from \"~/features/contentEntry/abstractions.js\";\nimport { ContentEntryFormPresenter as Abstraction } from \"./abstractions.js\";\nimport { ContentEntryFormPresenter } from \"./ContentEntryFormPresenter.js\";\n\nconst createFakeForm = () => ({\n vm: {},\n isDirty: false,\n submit: vi.fn(async () => ({ title: \"Draft\" })),\n setData: vi.fn(),\n reset: vi.fn(),\n setErrors: vi.fn()\n});\n\n/** A promise the test settles by hand, so it can act while a save is still in flight. */\nconst deferred = <T>() => {\n let resolve!: (value: T) => void;\n let reject!: (reason: unknown) => void;\n const promise = new Promise<T>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n return { promise, resolve, reject };\n};\n\nconst setup = () => {\n const forms: ReturnType<typeof createFakeForm>[] = [];\n const create = deferred<any>();\n\n const container = new Container();\n container.registerInstance(FormModelFactory, {\n create: () => {\n const form = createFakeForm();\n forms.push(form);\n return form;\n }\n } as unknown as FormModelFactory.Interface);\n container.registerInstance(CmsFormModelBuilder, {\n build: () => ({})\n } as unknown as CmsFormModelBuilder.Interface);\n container.registerInstance(CmsModelContext, {\n getModel: () => ({ modelId: \"article\", fields: [] })\n } as unknown as CmsModelContext.Interface);\n container.registerInstance(CreateEntryUseCase, {\n execute: () => create.promise\n } as unknown as CreateEntryUseCase.Interface);\n\n // Not reached by the create path these tests exercise.\n for (const abstraction of [\n Confirmation,\n GetEntryUseCase,\n CreateRevisionFromUseCase,\n UpdateEntryUseCase,\n PublishEntryUseCase,\n UnpublishEntryUseCase,\n DeleteEntryUseCase,\n UpdateRevisionDescriptionUseCase\n ]) {\n container.registerInstance(abstraction as any, {});\n }\n container.register(ContentEntryFormPresenter);\n\n return { presenter: container.resolve(Abstraction), forms, create };\n};\n\ndescribe(\"ContentEntryFormPresenter.saveRevision\", () => {\n it(\"puts a rejected save's errors on the form\", async () => {\n const { presenter, forms, create } = setup();\n presenter.newEntry();\n\n const saving = presenter.saveRevision();\n create.reject(new Error(\"Value must be unique.\"));\n\n await expect(saving).resolves.toBe(false);\n expect(forms[0].setErrors).toHaveBeenCalledTimes(1);\n });\n\n it(\"returns false instead of throwing when the form was reset mid-save\", async () => {\n const { presenter, create } = setup();\n presenter.newEntry();\n\n const saving = presenter.saveRevision();\n presenter.reset();\n create.reject(new Error(\"Value must be unique.\"));\n\n await expect(saving).resolves.toBe(false);\n });\n\n it(\"leaves a form built after the save started alone\", async () => {\n const { presenter, forms, create } = setup();\n presenter.newEntry();\n\n const saving = presenter.saveRevision();\n presenter.newEntry();\n create.reject(new Error(\"Value must be unique.\"));\n\n await expect(saving).resolves.toBe(false);\n expect(forms).toHaveLength(2);\n expect(forms[0].setErrors).not.toHaveBeenCalled();\n expect(forms[1].setErrors).not.toHaveBeenCalled();\n });\n});\n"],"names":["createFakeForm","vi","deferred","resolve","reject","promise","Promise","res","rej","setup","forms","create","container","Container","FormModelFactory","form","CmsFormModelBuilder","CmsModelContext","CreateEntryUseCase","abstraction","Confirmation","GetEntryUseCase","CreateRevisionFromUseCase","UpdateEntryUseCase","PublishEntryUseCase","UnpublishEntryUseCase","DeleteEntryUseCase","UpdateRevisionDescriptionUseCase","ContentEntryFormPresenter","Abstraction","describe","it","presenter","saving","Error","expect"],"mappings":";;;;;;;;;;;;;;;;AAkBA,MAAMA,iBAAiB,IAAO;QAC1B,IAAI,CAAC;QACL,SAAS;QACT,QAAQC,GAAG,EAAE,CAAC,UAAa;gBAAE,OAAO;YAAQ;QAC5C,SAASA,GAAG,EAAE;QACd,OAAOA,GAAG,EAAE;QACZ,WAAWA,GAAG,EAAE;IACpB;AAGA,MAAMC,WAAW;IACb,IAAIC;IACJ,IAAIC;IACJ,MAAMC,UAAU,IAAIC,QAAW,CAACC,KAAKC;QACjCL,UAAUI;QACVH,SAASI;IACb;IACA,OAAO;QAAEH;QAASF;QAASC;IAAO;AACtC;AAEA,MAAMK,QAAQ;IACV,MAAMC,QAA6C,EAAE;IACrD,MAAMC,SAAST;IAEf,MAAMU,YAAY,IAAIC;IACtBD,UAAU,gBAAgB,CAACE,kBAAkB;QACzC,QAAQ;YACJ,MAAMC,OAAOf;YACbU,MAAM,IAAI,CAACK;YACX,OAAOA;QACX;IACJ;IACAH,UAAU,gBAAgB,CAACI,qBAAqB;QAC5C,OAAO,IAAO,EAAC;IACnB;IACAJ,UAAU,gBAAgB,CAACK,iBAAiB;QACxC,UAAU,IAAO;gBAAE,SAAS;gBAAW,QAAQ,EAAE;YAAC;IACtD;IACAL,UAAU,gBAAgB,CAACM,oBAAoB;QAC3C,SAAS,IAAMP,OAAO,OAAO;IACjC;IAGA,KAAK,MAAMQ,eAAe;QACtBC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;KACH,CACGf,UAAU,gBAAgB,CAACO,aAAoB,CAAC;IAEpDP,UAAU,QAAQ,CAACgB;IAEnB,OAAO;QAAE,WAAWhB,UAAU,OAAO,CAACiB;QAAcnB;QAAOC;IAAO;AACtE;AAEAmB,SAAS,0CAA0C;IAC/CC,GAAG,6CAA6C;QAC5C,MAAM,EAAEC,SAAS,EAAEtB,KAAK,EAAEC,MAAM,EAAE,GAAGF;QACrCuB,UAAU,QAAQ;QAElB,MAAMC,SAASD,UAAU,YAAY;QACrCrB,OAAO,MAAM,CAAC,IAAIuB,MAAM;QAExB,MAAMC,OAAOF,QAAQ,QAAQ,CAAC,IAAI,CAAC;QACnCE,OAAOzB,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,qBAAqB,CAAC;IACrD;IAEAqB,GAAG,sEAAsE;QACrE,MAAM,EAAEC,SAAS,EAAErB,MAAM,EAAE,GAAGF;QAC9BuB,UAAU,QAAQ;QAElB,MAAMC,SAASD,UAAU,YAAY;QACrCA,UAAU,KAAK;QACfrB,OAAO,MAAM,CAAC,IAAIuB,MAAM;QAExB,MAAMC,OAAOF,QAAQ,QAAQ,CAAC,IAAI,CAAC;IACvC;IAEAF,GAAG,oDAAoD;QACnD,MAAM,EAAEC,SAAS,EAAEtB,KAAK,EAAEC,MAAM,EAAE,GAAGF;QACrCuB,UAAU,QAAQ;QAElB,MAAMC,SAASD,UAAU,YAAY;QACrCA,UAAU,QAAQ;QAClBrB,OAAO,MAAM,CAAC,IAAIuB,MAAM;QAExB,MAAMC,OAAOF,QAAQ,QAAQ,CAAC,IAAI,CAAC;QACnCE,OAAOzB,OAAO,YAAY,CAAC;QAC3ByB,OAAOzB,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,gBAAgB;QAC/CyB,OAAOzB,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,gBAAgB;IACnD;AACJ"}
|
|
1
|
+
{"version":3,"file":"presentation/contentEntries/form/ContentEntryFormPresenter.test.js","sources":["../../../../src/presentation/contentEntries/form/ContentEntryFormPresenter.test.ts"],"sourcesContent":["// @vitest-environment jsdom\nimport { describe, it, expect, vi } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { Confirmation } from \"@webiny/app-admin/features/confirmation/abstractions.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 { CreateRevisionFromUseCase } from \"~/features/contentEntry/createRevisionFrom/abstractions.js\";\nimport { CmsFormModelBuilder } from \"~/features/formModel/abstractions.js\";\nimport { CmsModelContext } from \"~/features/contentEntry/abstractions.js\";\nimport { ContentEntryFormPresenter as Abstraction } from \"./abstractions.js\";\nimport { ContentEntryFormPresenter } from \"./ContentEntryFormPresenter.js\";\n\nconst createFakeForm = (validation?: Promise<unknown>) => ({\n vm: {},\n isDirty: false,\n submit: vi.fn(async () => (validation ? validation : { title: \"Draft\" })),\n setData: vi.fn(),\n reset: vi.fn(),\n setErrors: vi.fn()\n});\n\n/** A promise the test settles by hand, so it can act while a save is still in flight. */\nconst deferred = <T>() => {\n let resolve!: (value: T) => void;\n let reject!: (reason: unknown) => void;\n const promise = new Promise<T>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n return { promise, resolve, reject };\n};\n\nconst createEntry = (entryId: string) => ({\n id: `${entryId}#0001`,\n entryId,\n meta: { locked: false, status: \"draft\", title: entryId },\n values: { title: entryId }\n});\n\nconst setup = () => {\n const forms: ReturnType<typeof createFakeForm>[] = [];\n const create = deferred<any>();\n const update = deferred<any>();\n /** When set, the next form built validates only once the test resolves this. */\n let nextValidation: Promise<unknown> | undefined;\n /** Entries whose load the test settles by hand. */\n const pendingLoads = new Map<string, Promise<any>>();\n\n const createExecute = vi.fn(() => create.promise);\n const updateExecute = vi.fn(() => update.promise);\n\n const container = new Container();\n container.registerInstance(FormModelFactory, {\n create: () => {\n const form = createFakeForm(nextValidation);\n nextValidation = undefined;\n forms.push(form);\n return form;\n }\n } as unknown as FormModelFactory.Interface);\n container.registerInstance(CmsFormModelBuilder, {\n build: () => ({})\n } as unknown as CmsFormModelBuilder.Interface);\n container.registerInstance(CmsModelContext, {\n getModel: () => ({ modelId: \"article\", fields: [] })\n } as unknown as CmsModelContext.Interface);\n container.registerInstance(CreateEntryUseCase, {\n execute: createExecute\n } as unknown as CreateEntryUseCase.Interface);\n container.registerInstance(UpdateEntryUseCase, {\n execute: updateExecute\n } as unknown as UpdateEntryUseCase.Interface);\n container.registerInstance(GetEntryUseCase, {\n execute: async ({ id }: { id: string }) => pendingLoads.get(id) ?? createEntry(id)\n } as unknown as GetEntryUseCase.Interface);\n\n // Not reached by the paths these tests exercise.\n for (const abstraction of [\n Confirmation,\n CreateRevisionFromUseCase,\n PublishEntryUseCase,\n UnpublishEntryUseCase,\n DeleteEntryUseCase,\n UpdateRevisionDescriptionUseCase\n ]) {\n container.registerInstance(abstraction as any, {});\n }\n container.register(ContentEntryFormPresenter);\n\n return {\n presenter: container.resolve(Abstraction),\n forms,\n create,\n createExecute,\n update,\n updateExecute,\n pendingLoads,\n slowValidation: () => {\n const validation = deferred<unknown>();\n nextValidation = validation.promise;\n return validation;\n }\n };\n};\n\ndescribe(\"ContentEntryFormPresenter.saveRevision\", () => {\n it(\"puts a rejected save's errors on the form\", async () => {\n const { presenter, forms, create } = setup();\n presenter.newEntry();\n\n const saving = presenter.saveRevision();\n create.reject(new Error(\"Value must be unique.\"));\n\n await expect(saving).resolves.toBe(false);\n expect(forms[0].setErrors).toHaveBeenCalledTimes(1);\n });\n\n it(\"creates a new entry in the folder it was started in\", async () => {\n const { presenter, create, createExecute } = setup();\n presenter.setFolderId(\"folder-1\");\n presenter.newEntry();\n\n const saving = presenter.saveRevision();\n create.resolve(createEntry(\"A\"));\n\n await expect(saving).resolves.toBe(true);\n expect(createExecute).toHaveBeenCalledWith(\n expect.objectContaining({\n data: { values: { title: \"Draft\" }, wbyAco_location: { folderId: \"folder-1\" } }\n })\n );\n });\n\n it(\"does not carry the folder over to an entry started after a reset\", async () => {\n const { presenter, create, createExecute } = setup();\n presenter.setFolderId(\"folder-1\");\n presenter.reset();\n presenter.newEntry();\n\n const saving = presenter.saveRevision();\n create.resolve(createEntry(\"A\"));\n\n await expect(saving).resolves.toBe(true);\n expect(createExecute).toHaveBeenCalledWith(\n expect.objectContaining({ data: { values: { title: \"Draft\" } } })\n );\n });\n\n it(\"returns false instead of throwing when the form was reset mid-save\", async () => {\n const { presenter, create, createExecute } = setup();\n presenter.newEntry();\n\n const saving = presenter.saveRevision();\n await vi.waitFor(() => expect(createExecute).toHaveBeenCalled());\n presenter.reset();\n create.reject(new Error(\"Value must be unique.\"));\n\n await expect(saving).resolves.toBe(false);\n expect(presenter.vm.loading).toBe(null);\n });\n\n it(\"leaves a form built after the save started alone\", async () => {\n const { presenter, forms, create, createExecute } = setup();\n presenter.newEntry();\n\n const saving = presenter.saveRevision();\n await vi.waitFor(() => expect(createExecute).toHaveBeenCalled());\n presenter.newEntry();\n create.reject(new Error(\"Value must be unique.\"));\n\n await expect(saving).resolves.toBe(false);\n expect(forms).toHaveLength(2);\n expect(forms[0].setErrors).not.toHaveBeenCalled();\n expect(forms[1].setErrors).not.toHaveBeenCalled();\n });\n\n it(\"saves the open entry and puts the saved values on the form\", async () => {\n const { presenter, forms, update, updateExecute } = setup();\n await presenter.loadRevision(\"A\");\n\n const saving = presenter.saveRevision();\n await vi.waitFor(() => expect(updateExecute).toHaveBeenCalled());\n update.resolve(createEntry(\"A\"));\n\n await expect(saving).resolves.toBe(true);\n expect(updateExecute).toHaveBeenCalledWith(\n expect.objectContaining({ revisionId: \"A#0001\", data: { values: { title: \"Draft\" } } })\n );\n expect(forms[0].setData).toHaveBeenLastCalledWith({ title: \"A\" });\n });\n\n it(\"does not write to an entry opened while the form was validating\", async () => {\n const { presenter, update, updateExecute, slowValidation } = setup();\n const validation = slowValidation();\n await presenter.loadRevision(\"A\");\n\n const saving = presenter.saveRevision();\n await presenter.loadRevision(\"B\");\n validation.resolve({ title: \"Values typed into A\" });\n // Settled up front, so a write that wrongly goes out finishes instead of hanging.\n update.resolve(createEntry(\"B\"));\n\n await expect(saving).resolves.toBe(false);\n expect(updateExecute).not.toHaveBeenCalled();\n expect(presenter.vm.entry?.entryId).toBe(\"B\");\n });\n\n it(\"keeps a write on its entry and reports false when another entry was opened\", async () => {\n const { presenter, forms, update, updateExecute } = setup();\n await presenter.loadRevision(\"A\");\n\n const saving = presenter.saveRevision();\n await vi.waitFor(() => expect(updateExecute).toHaveBeenCalled());\n await presenter.loadRevision(\"B\");\n update.resolve(createEntry(\"A\"));\n\n // False, so \"Save & Publish\" does not go on to publish B.\n await expect(saving).resolves.toBe(false);\n expect(updateExecute).toHaveBeenCalledTimes(1);\n expect(updateExecute).toHaveBeenCalledWith(\n expect.objectContaining({ revisionId: \"A#0001\" })\n );\n expect(presenter.vm.entry?.entryId).toBe(\"B\");\n expect(forms[1].setData).toHaveBeenCalledTimes(1);\n expect(forms[1].setData).toHaveBeenCalledWith({ title: \"B\" });\n });\n\n it(\"does not clear the loading message of an entry being opened\", async () => {\n const { presenter, update, updateExecute, pendingLoads } = setup();\n await presenter.loadRevision(\"A\");\n\n const saving = presenter.saveRevision();\n await vi.waitFor(() => expect(updateExecute).toHaveBeenCalled());\n\n const loadB = deferred<any>();\n pendingLoads.set(\"B\", loadB.promise);\n const loading = presenter.loadRevision(\"B\");\n update.resolve(createEntry(\"A\"));\n\n // A's form is still on screen, because B hasn't loaded yet.\n await expect(saving).resolves.toBe(true);\n expect(presenter.vm.loading).toBe(\"Loading entry...\");\n\n loadB.resolve(createEntry(\"B\"));\n await loading;\n expect(presenter.vm.loading).toBe(null);\n });\n});\n"],"names":["createFakeForm","validation","vi","deferred","resolve","reject","promise","Promise","res","rej","createEntry","entryId","setup","forms","create","update","nextValidation","pendingLoads","Map","createExecute","updateExecute","container","Container","FormModelFactory","form","undefined","CmsFormModelBuilder","CmsModelContext","CreateEntryUseCase","UpdateEntryUseCase","GetEntryUseCase","id","abstraction","Confirmation","CreateRevisionFromUseCase","PublishEntryUseCase","UnpublishEntryUseCase","DeleteEntryUseCase","UpdateRevisionDescriptionUseCase","ContentEntryFormPresenter","Abstraction","describe","it","presenter","saving","Error","expect","slowValidation","loadB","loading"],"mappings":"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"}
|
|
@@ -20,7 +20,7 @@ const ModelEditorComponentDiscovery = ContentModelEditor.createDecorator((Origin
|
|
|
20
20
|
}, [
|
|
21
21
|
presenter
|
|
22
22
|
]);
|
|
23
|
-
return /*#__PURE__*/ react.createElement(react.Fragment, null, previewPath ? /*#__PURE__*/ react.createElement(ComponentDiscoveryIframe, {
|
|
23
|
+
return /*#__PURE__*/ react.createElement(react.Fragment, null, previewPath && previewDomain ? /*#__PURE__*/ react.createElement(ComponentDiscoveryIframe, {
|
|
24
24
|
domain: previewDomain,
|
|
25
25
|
previewPath: previewPath
|
|
26
26
|
}) : null, /*#__PURE__*/ react.createElement(Original, null));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/contentEntries/preview/ModelEditorComponentDiscovery.js","sources":["../../../../src/presentation/contentEntries/preview/ModelEditorComponentDiscovery.tsx"],"sourcesContent":["import React, { useEffect } from \"react\";\nimport { ContentModelEditor } from \"~/admin/components/ContentModelEditor/ContentModelEditor.js\";\nimport { useModelEditor } from \"~/admin/components/ContentModelEditor/useModelEditor.js\";\nimport { usePreviewDomain } from \"@webiny/frontend-settings/exports/admin.js\";\nimport { ComponentDiscoveryIframe } from \"./ComponentDiscoveryIframe.js\";\nimport { useLivePreviewPresenter } from \"./useLivePreviewPresenter.js\";\n\nexport const ModelEditorComponentDiscovery = ContentModelEditor.createDecorator(Original => {\n return function ModelEditorWithDiscovery() {\n const { data } = useModelEditor();\n const presenter = useLivePreviewPresenter();\n const previewPath = data?.settings?.previewPath as string | undefined;\n const { previewDomain } = usePreviewDomain();\n\n useEffect(() => {\n if (!previewPath) {\n presenter.clearComponents();\n }\n }, [previewPath, presenter]);\n\n useEffect(() => {\n return () => {\n presenter.clearComponents();\n };\n }, [presenter]);\n\n return (\n <>\n {previewPath ? (\n <ComponentDiscoveryIframe domain={previewDomain} previewPath={previewPath} />\n ) : null}\n <Original />\n </>\n );\n };\n});\n"],"names":["ModelEditorComponentDiscovery","ContentModelEditor","Original","data","useModelEditor","presenter","useLivePreviewPresenter","previewPath","previewDomain","usePreviewDomain","useEffect","ComponentDiscoveryIframe"],"mappings":";;;;;;AAOO,MAAMA,gCAAgCC,mBAAmB,eAAe,CAACC,CAAAA,WACrE;QACH,MAAM,EAAEC,IAAI,EAAE,GAAGC;QACjB,MAAMC,YAAYC;QAClB,MAAMC,cAAcJ,MAAM,UAAU;QACpC,MAAM,EAAEK,aAAa,EAAE,GAAGC;QAE1BC,UAAU;YACN,IAAI,CAACH,aACDF,UAAU,eAAe;QAEjC,GAAG;YAACE;YAAaF;SAAU;QAE3BK,UAAU,IACC;gBACHL,UAAU,eAAe;YAC7B,GACD;YAACA;SAAU;QAEd,OAAO,WAAP,GACI,0CACKE,
|
|
1
|
+
{"version":3,"file":"presentation/contentEntries/preview/ModelEditorComponentDiscovery.js","sources":["../../../../src/presentation/contentEntries/preview/ModelEditorComponentDiscovery.tsx"],"sourcesContent":["import React, { useEffect } from \"react\";\nimport { ContentModelEditor } from \"~/admin/components/ContentModelEditor/ContentModelEditor.js\";\nimport { useModelEditor } from \"~/admin/components/ContentModelEditor/useModelEditor.js\";\nimport { usePreviewDomain } from \"@webiny/frontend-settings/exports/admin.js\";\nimport { ComponentDiscoveryIframe } from \"./ComponentDiscoveryIframe.js\";\nimport { useLivePreviewPresenter } from \"./useLivePreviewPresenter.js\";\n\nexport const ModelEditorComponentDiscovery = ContentModelEditor.createDecorator(Original => {\n return function ModelEditorWithDiscovery() {\n const { data } = useModelEditor();\n const presenter = useLivePreviewPresenter();\n const previewPath = data?.settings?.previewPath as string | undefined;\n const { previewDomain } = usePreviewDomain();\n\n useEffect(() => {\n if (!previewPath) {\n presenter.clearComponents();\n }\n }, [previewPath, presenter]);\n\n useEffect(() => {\n return () => {\n presenter.clearComponents();\n };\n }, [presenter]);\n\n return (\n <>\n {previewPath && previewDomain ? (\n <ComponentDiscoveryIframe domain={previewDomain} previewPath={previewPath} />\n ) : null}\n <Original />\n </>\n );\n };\n});\n"],"names":["ModelEditorComponentDiscovery","ContentModelEditor","Original","data","useModelEditor","presenter","useLivePreviewPresenter","previewPath","previewDomain","usePreviewDomain","useEffect","ComponentDiscoveryIframe"],"mappings":";;;;;;AAOO,MAAMA,gCAAgCC,mBAAmB,eAAe,CAACC,CAAAA,WACrE;QACH,MAAM,EAAEC,IAAI,EAAE,GAAGC;QACjB,MAAMC,YAAYC;QAClB,MAAMC,cAAcJ,MAAM,UAAU;QACpC,MAAM,EAAEK,aAAa,EAAE,GAAGC;QAE1BC,UAAU;YACN,IAAI,CAACH,aACDF,UAAU,eAAe;QAEjC,GAAG;YAACE;YAAaF;SAAU;QAE3BK,UAAU,IACC;gBACHL,UAAU,eAAe;YAC7B,GACD;YAACA;SAAU;QAEd,OAAO,WAAP,GACI,0CACKE,eAAeC,gBAAgB,WAAhBA,GACZ,oBAACG,0BAAwBA;YAAC,QAAQH;YAAe,aAAaD;aAC9D,oBACJ,oBAACL,UAAAA;IAGb"}
|
|
@@ -5,6 +5,7 @@ import { usePreviewDomain } from "@webiny/frontend-settings/exports/admin.js";
|
|
|
5
5
|
import { ContentEntryFormContent } from "../views/layout/ContentEntryFormContent.js";
|
|
6
6
|
import { useContentEntryFormPresenter } from "../form/useContentEntryFormPresenter.js";
|
|
7
7
|
import { PreviewPane } from "./PreviewPane.js";
|
|
8
|
+
import { PreviewDomainStatus } from "./PreviewDomainStatus.js";
|
|
8
9
|
import { useLivePreviewPresenter } from "./useLivePreviewPresenter.js";
|
|
9
10
|
import { getPatternRefFieldIds, getRefValues, withRefValues } from "./resolvePreviewUrl.js";
|
|
10
11
|
const PreviewDecorator = ContentEntryFormContent.createDecorator((Original)=>createReactiveComponent((props)=>{
|
|
@@ -12,7 +13,7 @@ const PreviewDecorator = ContentEntryFormContent.createDecorator((Original)=>cre
|
|
|
12
13
|
const livePreview = useLivePreviewPresenter();
|
|
13
14
|
const model = presenter.vm.model;
|
|
14
15
|
const previewPath = model?.settings?.previewPath;
|
|
15
|
-
const
|
|
16
|
+
const domain = usePreviewDomain();
|
|
16
17
|
const form = presenter.vm.form;
|
|
17
18
|
const entry = presenter.vm.entry;
|
|
18
19
|
const formValues = form ? form.getData() : null;
|
|
@@ -49,12 +50,17 @@ const PreviewDecorator = ContentEntryFormContent.createDecorator((Original)=>cre
|
|
|
49
50
|
style: {
|
|
50
51
|
overflowY: "hidden"
|
|
51
52
|
}
|
|
52
|
-
}, /*#__PURE__*/ react.createElement(PreviewPane, {
|
|
53
|
-
domain: previewDomain,
|
|
53
|
+
}, domain.previewDomain ? /*#__PURE__*/ react.createElement(PreviewPane, {
|
|
54
|
+
domain: domain.previewDomain,
|
|
55
|
+
settingsDomain: domain.isOverridden ? domain.settingsDomain : null,
|
|
56
|
+
onResetDomain: domain.unsetPreviewDomain,
|
|
54
57
|
previewPath: previewPath,
|
|
55
58
|
entryId: entryId,
|
|
56
59
|
entryData: entryData,
|
|
57
60
|
urlEntryData: urlEntryData
|
|
61
|
+
}) : /*#__PURE__*/ react.createElement(PreviewDomainStatus, {
|
|
62
|
+
error: domain.error,
|
|
63
|
+
onRetry: domain.retry
|
|
58
64
|
})));
|
|
59
65
|
}));
|
|
60
66
|
export { PreviewDecorator };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/contentEntries/preview/PreviewDecorator.js","sources":["../../../../src/presentation/contentEntries/preview/PreviewDecorator.tsx"],"sourcesContent":["import React, { useEffect } from \"react\";\nimport { createReactiveComponent } from \"@webiny/app-admin\";\nimport {\n SplitView,\n LeftPanel,\n RightPanel\n} from \"@webiny/app-admin/components/SplitView/SplitView.js\";\nimport { usePreviewDomain } from \"@webiny/frontend-settings/exports/admin.js\";\nimport { ContentEntryFormContent } from \"~/presentation/contentEntries/views/layout/ContentEntryFormContent.js\";\nimport { useContentEntryFormPresenter } from \"~/presentation/contentEntries/form/useContentEntryFormPresenter.js\";\nimport { PreviewPane } from \"./PreviewPane.js\";\nimport { useLivePreviewPresenter } from \"./useLivePreviewPresenter.js\";\nimport { getPatternRefFieldIds, getRefValues, withRefValues } from \"./resolvePreviewUrl.js\";\n\nexport const PreviewDecorator = ContentEntryFormContent.createDecorator(Original => {\n return createReactiveComponent(\n (props: React.HTMLAttributes<HTMLDivElement> & { width?: string }) => {\n const presenter = useContentEntryFormPresenter();\n const livePreview = useLivePreviewPresenter();\n const model = presenter.vm.model;\n const previewPath = model?.settings?.previewPath as string | undefined;\n const
|
|
1
|
+
{"version":3,"file":"presentation/contentEntries/preview/PreviewDecorator.js","sources":["../../../../src/presentation/contentEntries/preview/PreviewDecorator.tsx"],"sourcesContent":["import React, { useEffect } from \"react\";\nimport { createReactiveComponent } from \"@webiny/app-admin\";\nimport {\n SplitView,\n LeftPanel,\n RightPanel\n} from \"@webiny/app-admin/components/SplitView/SplitView.js\";\nimport { usePreviewDomain } from \"@webiny/frontend-settings/exports/admin.js\";\nimport { ContentEntryFormContent } from \"~/presentation/contentEntries/views/layout/ContentEntryFormContent.js\";\nimport { useContentEntryFormPresenter } from \"~/presentation/contentEntries/form/useContentEntryFormPresenter.js\";\nimport { PreviewPane } from \"./PreviewPane.js\";\nimport { PreviewDomainStatus } from \"./PreviewDomainStatus.js\";\nimport { useLivePreviewPresenter } from \"./useLivePreviewPresenter.js\";\nimport { getPatternRefFieldIds, getRefValues, withRefValues } from \"./resolvePreviewUrl.js\";\n\nexport const PreviewDecorator = ContentEntryFormContent.createDecorator(Original => {\n return createReactiveComponent(\n (props: React.HTMLAttributes<HTMLDivElement> & { width?: string }) => {\n const presenter = useContentEntryFormPresenter();\n const livePreview = useLivePreviewPresenter();\n const model = presenter.vm.model;\n const previewPath = model?.settings?.previewPath as string | undefined;\n const domain = usePreviewDomain();\n\n const form = presenter.vm.form;\n const entry = presenter.vm.entry;\n const formValues = form ? (form.getData() as Record<string, unknown>) : null;\n const entryData = formValues ? { ...entry, values: formValues } : null;\n\n const refFieldIds =\n previewPath && model ? getPatternRefFieldIds(previewPath, model.fields) : [];\n const refs = formValues ? getRefValues(formValues, refFieldIds) : [];\n const refsKey = refs.map(ref => ref.id).join(\",\");\n\n useEffect(() => {\n if (refs.length > 0) {\n livePreview.loadRefValues(refs);\n }\n }, [refsKey]);\n\n if (!previewPath) {\n return <Original {...props} />;\n }\n\n // Only the preview URL gets the referenced values; the iframe receives the raw form data.\n const urlEntryData = entryData\n ? withRefValues(entryData, refFieldIds, livePreview.vm.refValues)\n : null;\n\n const entryId = entry?.id || \"new\";\n\n return (\n <SplitView namespace={\"cms-live-preview\"} className=\"h-full\">\n <LeftPanel span={5} minSize={20} className=\"bg-white overflow-y-auto\">\n <Original\n {...props}\n width={\"100%\"}\n className={\"!pt-0 [&>div]:!rounded-none\"}\n />\n </LeftPanel>\n <RightPanel\n span={7}\n minSize={20}\n className=\"overflow-hidden p-md\"\n style={{ overflowY: \"hidden\" }}\n >\n {domain.previewDomain ? (\n <PreviewPane\n domain={domain.previewDomain}\n settingsDomain={domain.isOverridden ? domain.settingsDomain : null}\n onResetDomain={domain.unsetPreviewDomain}\n previewPath={previewPath}\n entryId={entryId}\n entryData={entryData}\n urlEntryData={urlEntryData}\n />\n ) : (\n <PreviewDomainStatus error={domain.error} onRetry={domain.retry} />\n )}\n </RightPanel>\n </SplitView>\n );\n }\n );\n});\n"],"names":["PreviewDecorator","ContentEntryFormContent","Original","createReactiveComponent","props","presenter","useContentEntryFormPresenter","livePreview","useLivePreviewPresenter","model","previewPath","domain","usePreviewDomain","form","entry","formValues","entryData","refFieldIds","getPatternRefFieldIds","refs","getRefValues","refsKey","ref","useEffect","urlEntryData","withRefValues","entryId","SplitView","LeftPanel","RightPanel","PreviewPane","PreviewDomainStatus"],"mappings":";;;;;;;;;;AAeO,MAAMA,mBAAmBC,wBAAwB,eAAe,CAACC,CAAAA,WAC7DC,wBACH,CAACC;QACG,MAAMC,YAAYC;QAClB,MAAMC,cAAcC;QACpB,MAAMC,QAAQJ,UAAU,EAAE,CAAC,KAAK;QAChC,MAAMK,cAAcD,OAAO,UAAU;QACrC,MAAME,SAASC;QAEf,MAAMC,OAAOR,UAAU,EAAE,CAAC,IAAI;QAC9B,MAAMS,QAAQT,UAAU,EAAE,CAAC,KAAK;QAChC,MAAMU,aAAaF,OAAQA,KAAK,OAAO,KAAiC;QACxE,MAAMG,YAAYD,aAAa;YAAE,GAAGD,KAAK;YAAE,QAAQC;QAAW,IAAI;QAElE,MAAME,cACFP,eAAeD,QAAQS,sBAAsBR,aAAaD,MAAM,MAAM,IAAI,EAAE;QAChF,MAAMU,OAAOJ,aAAaK,aAAaL,YAAYE,eAAe,EAAE;QACpE,MAAMI,UAAUF,KAAK,GAAG,CAACG,CAAAA,MAAOA,IAAI,EAAE,EAAE,IAAI,CAAC;QAE7CC,UAAU;YACN,IAAIJ,KAAK,MAAM,GAAG,GACdZ,YAAY,aAAa,CAACY;QAElC,GAAG;YAACE;SAAQ;QAEZ,IAAI,CAACX,aACD,OAAO,WAAP,GAAO,oBAACR,UAAaE;QAIzB,MAAMoB,eAAeR,YACfS,cAAcT,WAAWC,aAAaV,YAAY,EAAE,CAAC,SAAS,IAC9D;QAEN,MAAMmB,UAAUZ,OAAO,MAAM;QAE7B,OAAO,WAAP,GACI,oBAACa,WAASA;YAAC,WAAW;YAAoB,WAAU;yBAChD,oBAACC,WAASA;YAAC,MAAM;YAAG,SAAS;YAAI,WAAU;yBACvC,oBAAC1B,UAAAA;YACI,GAAGE,KAAK;YACT,OAAO;YACP,WAAW;2BAGnB,oBAACyB,YAAUA;YACP,MAAM;YACN,SAAS;YACT,WAAU;YACV,OAAO;gBAAE,WAAW;YAAS;WAE5BlB,OAAO,aAAa,GAAG,WAAH,GACjB,oBAACmB,aAAWA;YACR,QAAQnB,OAAO,aAAa;YAC5B,gBAAgBA,OAAO,YAAY,GAAGA,OAAO,cAAc,GAAG;YAC9D,eAAeA,OAAO,kBAAkB;YACxC,aAAaD;YACb,SAASgB;YACT,WAAWV;YACX,cAAcQ;2BAGlB,oBAACO,qBAAmBA;YAAC,OAAOpB,OAAO,KAAK;YAAE,SAASA,OAAO,KAAK;;IAKnF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface PreviewDomainStatusProps {
|
|
3
|
+
error: string | null;
|
|
4
|
+
onRetry: () => void;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Shown in place of the preview while the Frontend Domain setting loads, or when it fails to load.
|
|
8
|
+
*/
|
|
9
|
+
export declare const PreviewDomainStatus: ({ error, onRetry }: PreviewDomainStatusProps) => React.JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import react from "react";
|
|
2
|
+
import { Alert, OverlayLoader } from "@webiny/admin-ui";
|
|
3
|
+
const PreviewDomainStatus = ({ error, onRetry })=>/*#__PURE__*/ react.createElement("div", {
|
|
4
|
+
className: "relative border border-neutral-dimmed rounded-t-lg flex flex-col flex-1 h-full overflow-hidden fill-grid"
|
|
5
|
+
}, error ? /*#__PURE__*/ react.createElement("div", {
|
|
6
|
+
className: "p-md"
|
|
7
|
+
}, /*#__PURE__*/ react.createElement(Alert, {
|
|
8
|
+
type: "danger",
|
|
9
|
+
variant: "subtle",
|
|
10
|
+
actions: /*#__PURE__*/ react.createElement(Alert.Action, {
|
|
11
|
+
text: "Retry",
|
|
12
|
+
onClick: onRetry
|
|
13
|
+
})
|
|
14
|
+
}, "Could not load the Frontend Domain setting, so the live preview cannot start. ", error)) : /*#__PURE__*/ react.createElement(OverlayLoader, {
|
|
15
|
+
text: "Loading preview settings..."
|
|
16
|
+
}));
|
|
17
|
+
export { PreviewDomainStatus };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=PreviewDomainStatus.js.map
|