@webiny/app-headless-cms 6.5.0-beta.6 → 6.5.0-beta.8
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 +5 -0
- package/ContentEntriesModule.js.map +1 -1
- package/admin/components/ContentEntries/Filters/RefFieldRenderer.d.ts +2 -0
- package/admin/components/ContentEntries/Filters/RefFieldRenderer.js +84 -0
- package/admin/components/ContentEntries/Filters/RefFieldRenderer.js.map +1 -0
- package/package.json +23 -23
- package/presentation/contentEntries/form/ContentEntryFormPresenter.js +10 -6
- package/presentation/contentEntries/form/ContentEntryFormPresenter.js.map +1 -1
- package/presentation/contentEntries/form/ContentEntryFormPresenter.test.d.ts +1 -0
- package/presentation/contentEntries/form/ContentEntryFormPresenter.test.js +110 -0
- package/presentation/contentEntries/form/ContentEntryFormPresenter.test.js.map +1 -0
- package/presentation/contentEntries/singleEntry/SingleEntryPresenter.js +7 -4
- package/presentation/contentEntries/singleEntry/SingleEntryPresenter.js.map +1 -1
- package/presentation/contentEntries/singleEntry/SingleEntryPresenter.test.d.ts +1 -0
- package/presentation/contentEntries/singleEntry/SingleEntryPresenter.test.js +122 -0
- package/presentation/contentEntries/singleEntry/SingleEntryPresenter.test.js.map +1 -0
package/ContentEntriesModule.js
CHANGED
|
@@ -9,6 +9,7 @@ import { ChangeEntryStatus, DeleteEntry, DuplicateEntry, EditEntry, MoveEntry }
|
|
|
9
9
|
import { CellActions, CellAuthor, CellCreated, CellLive, CellModified, CellName, CellStatus } from "./admin/components/ContentEntries/Table/Cells/index.js";
|
|
10
10
|
import { IsModelPublishable } from "./admin/components/IsModelPublishable.js";
|
|
11
11
|
import { FilterByStatus } from "./admin/components/ContentEntries/FilterByStatus.js";
|
|
12
|
+
import { Ref } from "./admin/components/ContentEntries/Filters/RefFieldRenderer.js";
|
|
12
13
|
import { CmsTrashBin } from "./presentation/contentEntries/trashBin/CmsTrashBin.js";
|
|
13
14
|
import { TrashEntryConfirmDialog } from "./admin/components/Dialogs/TrashEntryConfirmDialog.js";
|
|
14
15
|
import { PublishEntryConfirmDialog } from "./admin/components/Dialogs/PublishEntryConfirmDialog.js";
|
|
@@ -129,6 +130,10 @@ const ContentEntriesModule = ()=>/*#__PURE__*/ react.createElement(react.Fragmen
|
|
|
129
130
|
hideable: false,
|
|
130
131
|
truncate: false,
|
|
131
132
|
className: "flex justify-center"
|
|
133
|
+
}), /*#__PURE__*/ react.createElement(Browser.AdvancedSearch.FieldRenderer, {
|
|
134
|
+
name: "ref",
|
|
135
|
+
type: Browser.AdvancedSearch.FieldRenderer.FieldType.REF,
|
|
136
|
+
element: /*#__PURE__*/ react.createElement(Ref, null)
|
|
132
137
|
})), /*#__PURE__*/ react.createElement(InternalContentEntryEditorConfig, null, /*#__PURE__*/ react.createElement(IsModelPublishable, null, /*#__PURE__*/ react.createElement(Actions.ButtonAction, {
|
|
133
138
|
name: "revisionSelector",
|
|
134
139
|
element: /*#__PURE__*/ react.createElement(RevisionSelector, null)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentEntriesModule.js","sources":["../src/ContentEntriesModule.tsx"],"sourcesContent":["import React from \"react\";\nimport { AdminConfig } from \"@webiny/app-admin\";\nimport { AdvancedSearchConfigs } from \"@webiny/app-aco/components/AdvancedSearch/AdvancedSearchConfigs\";\nimport {\n InternalContentEntryEditorConfig,\n InternalContentEntryListConfig\n} from \"~/admin/config/contentEntries/index.js\";\n\nimport {\n ActionDelete,\n ActionMove,\n ActionPublish,\n ActionUnpublish\n} from \"~/admin/components/ContentEntries/BulkActions/index.js\";\n\nimport {\n TRASH_ENTRY_DIALOG,\n PUBLISH_ENTRY_DIALOG,\n UNPUBLISH_ENTRY_DIALOG,\n DUPLICATE_ENTRY_DIALOG\n} from \"~/presentation/contentEntries/list/ContentEntriesPresenter.js\";\nimport { DeleteFolder, EditFolder, SetFolderPermissions } from \"@webiny/app-aco\";\nimport {\n ChangeEntryStatus,\n DeleteEntry,\n DuplicateEntry,\n EditEntry,\n MoveEntry\n} from \"~/admin/components/ContentEntries/Table/Actions/index.js\";\nimport {\n CellActions,\n CellAuthor,\n CellCreated,\n CellLive,\n CellModified,\n CellName,\n CellStatus\n} from \"~/admin/components/ContentEntries/Table/Cells/index.js\";\nimport { IsModelPublishable } from \"~/admin/components/IsModelPublishable.js\";\nimport { FilterByStatus } from \"~/admin/components/ContentEntries/FilterByStatus.js\";\nimport { CmsTrashBin } from \"~/presentation/contentEntries/trashBin/CmsTrashBin.js\";\nimport { TrashEntryConfirmDialog } from \"~/admin/components/Dialogs/TrashEntryConfirmDialog.js\";\nimport { PublishEntryConfirmDialog } from \"~/admin/components/Dialogs/PublishEntryConfirmDialog.js\";\nimport { UnpublishEntryConfirmDialog } from \"~/admin/components/Dialogs/UnpublishEntryConfirmDialog.js\";\nimport { DuplicateEntryConfirmDialog } from \"~/admin/components/Dialogs/DuplicateEntryConfirmDialog.js\";\nimport { DeleteRevisionConfirmDialog } from \"~/admin/components/Dialogs/DeleteRevisionConfirmDialog.js\";\nimport { EditRevisionNoteDialog } from \"~/admin/components/Dialogs/EditRevisionNoteDialog.js\";\nimport {\n DELETE_REVISION_DIALOG,\n EDIT_REVISION_NOTE_DIALOG\n} from \"~/presentation/contentEntries/revisionsList/RevisionsListPresenter.js\";\nimport { RevisionSelector } from \"~/presentation/contentEntries/views/actions/RevisionSelector.js\";\nimport { ContentFormOptionsMenu } from \"~/presentation/contentEntries/views/actions/ContentFormOptionsMenu.js\";\nimport { SaveContentButton } from \"~/presentation/contentEntries/views/actions/SaveContentButton.js\";\nimport { SaveAndPublishButton } from \"~/presentation/contentEntries/views/actions/SaveAndPublishButton.js\";\nimport { DeleteEntryMenuItem } from \"~/presentation/contentEntries/views/actions/DeleteEntryMenuItem.js\";\nimport { ShowRevisionListMenuItem } from \"~/presentation/contentEntries/views/actions/ShowRevisionListMenuItem.js\";\nimport { CreateNewRevisionButton } from \"~/presentation/contentEntries/views/actions/CreateNewRevisionButton.js\";\nimport { PublishOnlyButton } from \"~/presentation/contentEntries/views/actions/PublishOnlyButton.js\";\n\nconst { Browser } = InternalContentEntryListConfig;\nconst { Actions } = InternalContentEntryEditorConfig;\n\nexport const ContentEntriesModule = () => {\n return (\n <>\n <AdminConfig>\n <AdminConfig.Dialog\n name={TRASH_ENTRY_DIALOG}\n element={<TrashEntryConfirmDialog />}\n />\n <AdminConfig.Dialog\n name={PUBLISH_ENTRY_DIALOG}\n element={<PublishEntryConfirmDialog />}\n />\n <AdminConfig.Dialog\n name={UNPUBLISH_ENTRY_DIALOG}\n element={<UnpublishEntryConfirmDialog />}\n />\n <AdminConfig.Dialog\n name={DUPLICATE_ENTRY_DIALOG}\n element={<DuplicateEntryConfirmDialog />}\n />\n <AdminConfig.Dialog\n name={DELETE_REVISION_DIALOG}\n element={<DeleteRevisionConfirmDialog />}\n />\n <AdminConfig.Dialog\n name={EDIT_REVISION_NOTE_DIALOG}\n element={<EditRevisionNoteDialog />}\n />\n </AdminConfig>\n <InternalContentEntryListConfig>\n <AdvancedSearchConfigs />\n <IsModelPublishable>\n <Browser.Filter name={\"status\"} element={<FilterByStatus />} />\n <Browser.BulkAction name={\"publish\"} element={<ActionPublish />} />\n <Browser.BulkAction name={\"unpublish\"} element={<ActionUnpublish />} />\n </IsModelPublishable>\n <Browser.Sidebar.Footer name={\"trashBin\"} element={<CmsTrashBin />} />\n <Browser.BulkAction name={\"move\"} element={<ActionMove />} />\n <Browser.BulkAction name={\"delete\"} element={<ActionDelete />} />\n <Browser.Folder.Action name={\"edit\"} element={<EditFolder />} />\n <Browser.Folder.Action name={\"permissions\"} element={<SetFolderPermissions />} />\n <Browser.Folder.Action name={\"delete\"} element={<DeleteFolder />} />\n <Browser.Entry.Action name={\"edit\"} element={<EditEntry />} />\n <IsModelPublishable>\n <Browser.Entry.Action name={\"status\"} element={<ChangeEntryStatus />} />\n </IsModelPublishable>\n <Browser.Entry.Action name={\"move\"} element={<MoveEntry />} />\n <Browser.Entry.Action name={\"duplicate\"} element={<DuplicateEntry />} />\n <Browser.Entry.Action name={\"delete\"} element={<DeleteEntry />} after={\"$last\"} />\n <Browser.Table.Column\n name={\"name\"}\n header={\"Name\"}\n cell={<CellName />}\n sortable={true}\n hideable={false}\n size={200}\n />\n <Browser.Table.Column name={\"createdBy\"} header={\"Author\"} cell={<CellAuthor />} />\n <Browser.Table.Column\n name={\"createdOn\"}\n header={\"Created\"}\n cell={<CellCreated />}\n sortable={true}\n />\n <Browser.Table.Column\n name={\"savedOn\"}\n header={\"Modified\"}\n cell={<CellModified />}\n sortable={true}\n />\n <IsModelPublishable>\n <Browser.Table.Column\n name={\"status\"}\n header={\"Status\"}\n cell={<CellStatus />}\n truncate={false}\n />\n <Browser.Table.Column\n name={\"live\"}\n header={\"Live\"}\n truncate={false}\n sortable={true}\n cell={<CellLive />}\n />\n </IsModelPublishable>\n <Browser.Table.Column\n name={\"actions\"}\n header={\"\"}\n cell={<CellActions />}\n size={56}\n resizable={false}\n hideable={false}\n truncate={false}\n className={\"flex justify-center\"}\n />\n </InternalContentEntryListConfig>\n <InternalContentEntryEditorConfig>\n <IsModelPublishable>\n <Actions.ButtonAction\n name={\"revisionSelector\"}\n element={<RevisionSelector />}\n />\n </IsModelPublishable>\n <Actions.ButtonAction name={\"optionsMenu\"} element={<ContentFormOptionsMenu />} />\n <Actions.ButtonAction name={\"save\"} element={<SaveContentButton />} />\n <IsModelPublishable>\n <Actions.ButtonAction\n name={\"cms/createNewRevision\"}\n element={<CreateNewRevisionButton />}\n />\n <Actions.ButtonAction name={\"publish\"} element={<SaveAndPublishButton />} />\n <Actions.ButtonAction name={\"publishOnly\"} element={<PublishOnlyButton />} />\n </IsModelPublishable>\n <Actions.MenuItemAction\n name={\"delete\"}\n element={<DeleteEntryMenuItem />}\n after={\"$last\"}\n />\n <IsModelPublishable>\n <Actions.MenuItemAction\n name={\"showRevisionsList\"}\n element={<ShowRevisionListMenuItem />}\n />\n </IsModelPublishable>\n </InternalContentEntryEditorConfig>\n </>\n );\n};\n"],"names":["Browser","InternalContentEntryListConfig","Actions","InternalContentEntryEditorConfig","ContentEntriesModule","AdminConfig","TRASH_ENTRY_DIALOG","TrashEntryConfirmDialog","PUBLISH_ENTRY_DIALOG","PublishEntryConfirmDialog","UNPUBLISH_ENTRY_DIALOG","UnpublishEntryConfirmDialog","DUPLICATE_ENTRY_DIALOG","DuplicateEntryConfirmDialog","DELETE_REVISION_DIALOG","DeleteRevisionConfirmDialog","EDIT_REVISION_NOTE_DIALOG","EditRevisionNoteDialog","AdvancedSearchConfigs","IsModelPublishable","FilterByStatus","ActionPublish","ActionUnpublish","CmsTrashBin","ActionMove","ActionDelete","EditFolder","SetFolderPermissions","DeleteFolder","EditEntry","ChangeEntryStatus","MoveEntry","DuplicateEntry","DeleteEntry","CellName","CellAuthor","CellCreated","CellModified","CellStatus","CellLive","CellActions","RevisionSelector","ContentFormOptionsMenu","SaveContentButton","CreateNewRevisionButton","SaveAndPublishButton","PublishOnlyButton","DeleteEntryMenuItem","ShowRevisionListMenuItem"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ContentEntriesModule.js","sources":["../src/ContentEntriesModule.tsx"],"sourcesContent":["import React from \"react\";\nimport { AdminConfig } from \"@webiny/app-admin\";\nimport { AdvancedSearchConfigs } from \"@webiny/app-aco/components/AdvancedSearch/AdvancedSearchConfigs\";\nimport {\n InternalContentEntryEditorConfig,\n InternalContentEntryListConfig\n} from \"~/admin/config/contentEntries/index.js\";\n\nimport {\n ActionDelete,\n ActionMove,\n ActionPublish,\n ActionUnpublish\n} from \"~/admin/components/ContentEntries/BulkActions/index.js\";\n\nimport {\n TRASH_ENTRY_DIALOG,\n PUBLISH_ENTRY_DIALOG,\n UNPUBLISH_ENTRY_DIALOG,\n DUPLICATE_ENTRY_DIALOG\n} from \"~/presentation/contentEntries/list/ContentEntriesPresenter.js\";\nimport { DeleteFolder, EditFolder, SetFolderPermissions } from \"@webiny/app-aco\";\nimport {\n ChangeEntryStatus,\n DeleteEntry,\n DuplicateEntry,\n EditEntry,\n MoveEntry\n} from \"~/admin/components/ContentEntries/Table/Actions/index.js\";\nimport {\n CellActions,\n CellAuthor,\n CellCreated,\n CellLive,\n CellModified,\n CellName,\n CellStatus\n} from \"~/admin/components/ContentEntries/Table/Cells/index.js\";\nimport { IsModelPublishable } from \"~/admin/components/IsModelPublishable.js\";\nimport { FilterByStatus } from \"~/admin/components/ContentEntries/FilterByStatus.js\";\nimport { Ref } from \"~/admin/components/ContentEntries/Filters/RefFieldRenderer.js\";\nimport { CmsTrashBin } from \"~/presentation/contentEntries/trashBin/CmsTrashBin.js\";\nimport { TrashEntryConfirmDialog } from \"~/admin/components/Dialogs/TrashEntryConfirmDialog.js\";\nimport { PublishEntryConfirmDialog } from \"~/admin/components/Dialogs/PublishEntryConfirmDialog.js\";\nimport { UnpublishEntryConfirmDialog } from \"~/admin/components/Dialogs/UnpublishEntryConfirmDialog.js\";\nimport { DuplicateEntryConfirmDialog } from \"~/admin/components/Dialogs/DuplicateEntryConfirmDialog.js\";\nimport { DeleteRevisionConfirmDialog } from \"~/admin/components/Dialogs/DeleteRevisionConfirmDialog.js\";\nimport { EditRevisionNoteDialog } from \"~/admin/components/Dialogs/EditRevisionNoteDialog.js\";\nimport {\n DELETE_REVISION_DIALOG,\n EDIT_REVISION_NOTE_DIALOG\n} from \"~/presentation/contentEntries/revisionsList/RevisionsListPresenter.js\";\nimport { RevisionSelector } from \"~/presentation/contentEntries/views/actions/RevisionSelector.js\";\nimport { ContentFormOptionsMenu } from \"~/presentation/contentEntries/views/actions/ContentFormOptionsMenu.js\";\nimport { SaveContentButton } from \"~/presentation/contentEntries/views/actions/SaveContentButton.js\";\nimport { SaveAndPublishButton } from \"~/presentation/contentEntries/views/actions/SaveAndPublishButton.js\";\nimport { DeleteEntryMenuItem } from \"~/presentation/contentEntries/views/actions/DeleteEntryMenuItem.js\";\nimport { ShowRevisionListMenuItem } from \"~/presentation/contentEntries/views/actions/ShowRevisionListMenuItem.js\";\nimport { CreateNewRevisionButton } from \"~/presentation/contentEntries/views/actions/CreateNewRevisionButton.js\";\nimport { PublishOnlyButton } from \"~/presentation/contentEntries/views/actions/PublishOnlyButton.js\";\n\nconst { Browser } = InternalContentEntryListConfig;\nconst { Actions } = InternalContentEntryEditorConfig;\n\nexport const ContentEntriesModule = () => {\n return (\n <>\n <AdminConfig>\n <AdminConfig.Dialog\n name={TRASH_ENTRY_DIALOG}\n element={<TrashEntryConfirmDialog />}\n />\n <AdminConfig.Dialog\n name={PUBLISH_ENTRY_DIALOG}\n element={<PublishEntryConfirmDialog />}\n />\n <AdminConfig.Dialog\n name={UNPUBLISH_ENTRY_DIALOG}\n element={<UnpublishEntryConfirmDialog />}\n />\n <AdminConfig.Dialog\n name={DUPLICATE_ENTRY_DIALOG}\n element={<DuplicateEntryConfirmDialog />}\n />\n <AdminConfig.Dialog\n name={DELETE_REVISION_DIALOG}\n element={<DeleteRevisionConfirmDialog />}\n />\n <AdminConfig.Dialog\n name={EDIT_REVISION_NOTE_DIALOG}\n element={<EditRevisionNoteDialog />}\n />\n </AdminConfig>\n <InternalContentEntryListConfig>\n <AdvancedSearchConfigs />\n <IsModelPublishable>\n <Browser.Filter name={\"status\"} element={<FilterByStatus />} />\n <Browser.BulkAction name={\"publish\"} element={<ActionPublish />} />\n <Browser.BulkAction name={\"unpublish\"} element={<ActionUnpublish />} />\n </IsModelPublishable>\n <Browser.Sidebar.Footer name={\"trashBin\"} element={<CmsTrashBin />} />\n <Browser.BulkAction name={\"move\"} element={<ActionMove />} />\n <Browser.BulkAction name={\"delete\"} element={<ActionDelete />} />\n <Browser.Folder.Action name={\"edit\"} element={<EditFolder />} />\n <Browser.Folder.Action name={\"permissions\"} element={<SetFolderPermissions />} />\n <Browser.Folder.Action name={\"delete\"} element={<DeleteFolder />} />\n <Browser.Entry.Action name={\"edit\"} element={<EditEntry />} />\n <IsModelPublishable>\n <Browser.Entry.Action name={\"status\"} element={<ChangeEntryStatus />} />\n </IsModelPublishable>\n <Browser.Entry.Action name={\"move\"} element={<MoveEntry />} />\n <Browser.Entry.Action name={\"duplicate\"} element={<DuplicateEntry />} />\n <Browser.Entry.Action name={\"delete\"} element={<DeleteEntry />} after={\"$last\"} />\n <Browser.Table.Column\n name={\"name\"}\n header={\"Name\"}\n cell={<CellName />}\n sortable={true}\n hideable={false}\n size={200}\n />\n <Browser.Table.Column name={\"createdBy\"} header={\"Author\"} cell={<CellAuthor />} />\n <Browser.Table.Column\n name={\"createdOn\"}\n header={\"Created\"}\n cell={<CellCreated />}\n sortable={true}\n />\n <Browser.Table.Column\n name={\"savedOn\"}\n header={\"Modified\"}\n cell={<CellModified />}\n sortable={true}\n />\n <IsModelPublishable>\n <Browser.Table.Column\n name={\"status\"}\n header={\"Status\"}\n cell={<CellStatus />}\n truncate={false}\n />\n <Browser.Table.Column\n name={\"live\"}\n header={\"Live\"}\n truncate={false}\n sortable={true}\n cell={<CellLive />}\n />\n </IsModelPublishable>\n <Browser.Table.Column\n name={\"actions\"}\n header={\"\"}\n cell={<CellActions />}\n size={56}\n resizable={false}\n hideable={false}\n truncate={false}\n className={\"flex justify-center\"}\n />\n <Browser.AdvancedSearch.FieldRenderer\n name={\"ref\"}\n type={Browser.AdvancedSearch.FieldRenderer.FieldType.REF}\n element={<Ref />}\n />\n </InternalContentEntryListConfig>\n <InternalContentEntryEditorConfig>\n <IsModelPublishable>\n <Actions.ButtonAction\n name={\"revisionSelector\"}\n element={<RevisionSelector />}\n />\n </IsModelPublishable>\n <Actions.ButtonAction name={\"optionsMenu\"} element={<ContentFormOptionsMenu />} />\n <Actions.ButtonAction name={\"save\"} element={<SaveContentButton />} />\n <IsModelPublishable>\n <Actions.ButtonAction\n name={\"cms/createNewRevision\"}\n element={<CreateNewRevisionButton />}\n />\n <Actions.ButtonAction name={\"publish\"} element={<SaveAndPublishButton />} />\n <Actions.ButtonAction name={\"publishOnly\"} element={<PublishOnlyButton />} />\n </IsModelPublishable>\n <Actions.MenuItemAction\n name={\"delete\"}\n element={<DeleteEntryMenuItem />}\n after={\"$last\"}\n />\n <IsModelPublishable>\n <Actions.MenuItemAction\n name={\"showRevisionsList\"}\n element={<ShowRevisionListMenuItem />}\n />\n </IsModelPublishable>\n </InternalContentEntryEditorConfig>\n </>\n );\n};\n"],"names":["Browser","InternalContentEntryListConfig","Actions","InternalContentEntryEditorConfig","ContentEntriesModule","AdminConfig","TRASH_ENTRY_DIALOG","TrashEntryConfirmDialog","PUBLISH_ENTRY_DIALOG","PublishEntryConfirmDialog","UNPUBLISH_ENTRY_DIALOG","UnpublishEntryConfirmDialog","DUPLICATE_ENTRY_DIALOG","DuplicateEntryConfirmDialog","DELETE_REVISION_DIALOG","DeleteRevisionConfirmDialog","EDIT_REVISION_NOTE_DIALOG","EditRevisionNoteDialog","AdvancedSearchConfigs","IsModelPublishable","FilterByStatus","ActionPublish","ActionUnpublish","CmsTrashBin","ActionMove","ActionDelete","EditFolder","SetFolderPermissions","DeleteFolder","EditEntry","ChangeEntryStatus","MoveEntry","DuplicateEntry","DeleteEntry","CellName","CellAuthor","CellCreated","CellModified","CellStatus","CellLive","CellActions","Ref","RevisionSelector","ContentFormOptionsMenu","SaveContentButton","CreateNewRevisionButton","SaveAndPublishButton","PublishOnlyButton","DeleteEntryMenuItem","ShowRevisionListMenuItem"],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import react, { useEffect, useMemo } from "react";
|
|
2
|
+
import { observer } from "mobx-react-lite";
|
|
3
|
+
import { Bind } from "@webiny/form";
|
|
4
|
+
import { AutoComplete } from "@webiny/admin-ui";
|
|
5
|
+
import { DiContainerProvider, useContainer, useFeature } from "@webiny/app";
|
|
6
|
+
import { ContentEntryListConfig } from "../../../config/contentEntries/index.js";
|
|
7
|
+
import { RefSingleAutocompletePresenterFeature } from "../../../../presentation/fieldRenderers/ref/autocomplete/single/feature.js";
|
|
8
|
+
const { useInputField: useInputField } = ContentEntryListConfig.Browser.AdvancedSearch.FieldRenderer;
|
|
9
|
+
const parseValue = (value)=>{
|
|
10
|
+
if ("string" != typeof value || !value) return null;
|
|
11
|
+
try {
|
|
12
|
+
const parsed = JSON.parse(value);
|
|
13
|
+
if (!parsed?.entryId || !parsed?.modelId) return null;
|
|
14
|
+
return {
|
|
15
|
+
entryId: parsed.entryId,
|
|
16
|
+
modelId: parsed.modelId
|
|
17
|
+
};
|
|
18
|
+
} catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const Ref = ()=>{
|
|
23
|
+
const { name, field } = useInputField();
|
|
24
|
+
const parentContainer = useContainer();
|
|
25
|
+
const scopedContainer = useMemo(()=>{
|
|
26
|
+
const child = parentContainer.createChildContainer();
|
|
27
|
+
RefSingleAutocompletePresenterFeature.register(child);
|
|
28
|
+
return child;
|
|
29
|
+
}, [
|
|
30
|
+
field.value
|
|
31
|
+
]);
|
|
32
|
+
return /*#__PURE__*/ react.createElement(DiContainerProvider, {
|
|
33
|
+
container: scopedContainer,
|
|
34
|
+
key: field.value
|
|
35
|
+
}, /*#__PURE__*/ react.createElement(Bind, {
|
|
36
|
+
name: name
|
|
37
|
+
}, (bind)=>/*#__PURE__*/ react.createElement(RefInner, {
|
|
38
|
+
bind: bind,
|
|
39
|
+
modelIds: field.settings.modelIds
|
|
40
|
+
})));
|
|
41
|
+
};
|
|
42
|
+
const RefInner = observer(({ bind, modelIds })=>{
|
|
43
|
+
const { presenter } = useFeature(RefSingleAutocompletePresenterFeature);
|
|
44
|
+
useEffect(()=>{
|
|
45
|
+
const value = parseValue(bind.value);
|
|
46
|
+
presenter.init({
|
|
47
|
+
modelIds,
|
|
48
|
+
value: value ? {
|
|
49
|
+
id: value.entryId,
|
|
50
|
+
modelId: value.modelId
|
|
51
|
+
} : null
|
|
52
|
+
});
|
|
53
|
+
}, []);
|
|
54
|
+
const vm = presenter.vm;
|
|
55
|
+
return /*#__PURE__*/ react.createElement(AutoComplete, {
|
|
56
|
+
label: "Value",
|
|
57
|
+
size: "lg",
|
|
58
|
+
loading: vm.loading,
|
|
59
|
+
value: vm.value,
|
|
60
|
+
options: vm.options,
|
|
61
|
+
validation: bind.validation,
|
|
62
|
+
onValueSearch: (query)=>presenter.search(query),
|
|
63
|
+
onValueChange: (entryId)=>{
|
|
64
|
+
if (!entryId) {
|
|
65
|
+
presenter.clear();
|
|
66
|
+
bind.onChange("");
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const ref = presenter.select(entryId);
|
|
70
|
+
if (ref) bind.onChange(JSON.stringify({
|
|
71
|
+
entryId,
|
|
72
|
+
modelId: ref.modelId
|
|
73
|
+
}));
|
|
74
|
+
},
|
|
75
|
+
onValueReset: ()=>{
|
|
76
|
+
presenter.clear();
|
|
77
|
+
bind.onChange("");
|
|
78
|
+
},
|
|
79
|
+
displayResetAction: vm.canReset
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
export { Ref };
|
|
83
|
+
|
|
84
|
+
//# sourceMappingURL=RefFieldRenderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin/components/ContentEntries/Filters/RefFieldRenderer.js","sources":["../../../../../src/admin/components/ContentEntries/Filters/RefFieldRenderer.tsx"],"sourcesContent":["import React, { useEffect, useMemo } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { Bind } from \"@webiny/form\";\nimport type { BindComponentRenderProp } from \"@webiny/form\";\nimport { AutoComplete } from \"@webiny/admin-ui\";\nimport { DiContainerProvider, useContainer, useFeature } from \"@webiny/app\";\nimport { ContentEntryListConfig } from \"~/admin/config/contentEntries/index.js\";\nimport { RefSingleAutocompletePresenterFeature } from \"~/presentation/fieldRenderers/ref/autocomplete/single/feature.js\";\n\nconst { useInputField } = ContentEntryListConfig.Browser.AdvancedSearch.FieldRenderer;\n\n/**\n * The advanced search filter stores the selected reference as a JSON string\n * `{ entryId, modelId }`. `GraphQLInputMapper` reads `entryId` from it to build the\n * `<fieldId>.entryId` where condition, and `modelId` is used to load the label back\n * when a saved filter is opened.\n */\ninterface RefFilterValue {\n entryId: string;\n modelId: string;\n}\n\nconst parseValue = (value: unknown): RefFilterValue | null => {\n if (typeof value !== \"string\" || !value) {\n return null;\n }\n try {\n const parsed = JSON.parse(value);\n if (!parsed?.entryId || !parsed?.modelId) {\n return null;\n }\n return { entryId: parsed.entryId, modelId: parsed.modelId };\n } catch {\n return null;\n }\n};\n\nexport const Ref = () => {\n const { name, field } = useInputField();\n const parentContainer = useContainer();\n\n const scopedContainer = useMemo(() => {\n const child = parentContainer.createChildContainer();\n RefSingleAutocompletePresenterFeature.register(child);\n return child;\n }, [field.value]);\n\n return (\n <DiContainerProvider container={scopedContainer} key={field.value}>\n <Bind name={name}>\n {bind => <RefInner bind={bind} modelIds={field.settings.modelIds} />}\n </Bind>\n </DiContainerProvider>\n );\n};\n\ninterface RefInnerProps {\n bind: BindComponentRenderProp;\n modelIds: string[];\n}\n\nconst RefInner = observer(({ bind, modelIds }: RefInnerProps) => {\n const { presenter } = useFeature(RefSingleAutocompletePresenterFeature);\n\n useEffect(() => {\n const value = parseValue(bind.value);\n presenter.init({\n modelIds,\n value: value ? { id: value.entryId, modelId: value.modelId } : null\n });\n }, []);\n\n const vm = presenter.vm;\n\n return (\n <AutoComplete\n label={\"Value\"}\n size={\"lg\"}\n loading={vm.loading}\n value={vm.value}\n options={vm.options}\n validation={bind.validation}\n onValueSearch={query => presenter.search(query)}\n onValueChange={entryId => {\n if (!entryId) {\n presenter.clear();\n bind.onChange(\"\");\n return;\n }\n const ref = presenter.select(entryId);\n if (ref) {\n bind.onChange(JSON.stringify({ entryId, modelId: ref.modelId }));\n }\n }}\n onValueReset={() => {\n presenter.clear();\n bind.onChange(\"\");\n }}\n displayResetAction={vm.canReset}\n />\n );\n});\n"],"names":["useInputField","ContentEntryListConfig","parseValue","value","parsed","JSON","Ref","name","field","parentContainer","useContainer","scopedContainer","useMemo","child","RefSingleAutocompletePresenterFeature","DiContainerProvider","Bind","bind","RefInner","observer","modelIds","presenter","useFeature","useEffect","vm","AutoComplete","query","entryId","ref"],"mappings":";;;;;;;AASA,MAAM,EAAEA,eAAAA,aAAa,EAAE,GAAGC,uBAAuB,OAAO,CAAC,cAAc,CAAC,aAAa;AAarF,MAAMC,aAAa,CAACC;IAChB,IAAI,AAAiB,YAAjB,OAAOA,SAAsB,CAACA,OAC9B,OAAO;IAEX,IAAI;QACA,MAAMC,SAASC,KAAK,KAAK,CAACF;QAC1B,IAAI,CAACC,QAAQ,WAAW,CAACA,QAAQ,SAC7B,OAAO;QAEX,OAAO;YAAE,SAASA,OAAO,OAAO;YAAE,SAASA,OAAO,OAAO;QAAC;IAC9D,EAAE,OAAM;QACJ,OAAO;IACX;AACJ;AAEO,MAAME,MAAM;IACf,MAAM,EAAEC,IAAI,EAAEC,KAAK,EAAE,GAAGR;IACxB,MAAMS,kBAAkBC;IAExB,MAAMC,kBAAkBC,QAAQ;QAC5B,MAAMC,QAAQJ,gBAAgB,oBAAoB;QAClDK,sCAAsC,QAAQ,CAACD;QAC/C,OAAOA;IACX,GAAG;QAACL,MAAM,KAAK;KAAC;IAEhB,OAAO,WAAP,GACI,oBAACO,qBAAmBA;QAAC,WAAWJ;QAAiB,KAAKH,MAAM,KAAK;qBAC7D,oBAACQ,MAAIA;QAAC,MAAMT;OACPU,CAAAA,OAAAA,WAAAA,GAAQ,oBAACC,UAAQA;YAAC,MAAMD;YAAM,UAAUT,MAAM,QAAQ,CAAC,QAAQ;;AAIhF;AAOA,MAAMU,WAAWC,SAAS,CAAC,EAAEF,IAAI,EAAEG,QAAQ,EAAiB;IACxD,MAAM,EAAEC,SAAS,EAAE,GAAGC,WAAWR;IAEjCS,UAAU;QACN,MAAMpB,QAAQD,WAAWe,KAAK,KAAK;QACnCI,UAAU,IAAI,CAAC;YACXD;YACA,OAAOjB,QAAQ;gBAAE,IAAIA,MAAM,OAAO;gBAAE,SAASA,MAAM,OAAO;YAAC,IAAI;QACnE;IACJ,GAAG,EAAE;IAEL,MAAMqB,KAAKH,UAAU,EAAE;IAEvB,OAAO,WAAP,GACI,oBAACI,cAAYA;QACT,OAAO;QACP,MAAM;QACN,SAASD,GAAG,OAAO;QACnB,OAAOA,GAAG,KAAK;QACf,SAASA,GAAG,OAAO;QACnB,YAAYP,KAAK,UAAU;QAC3B,eAAeS,CAAAA,QAASL,UAAU,MAAM,CAACK;QACzC,eAAeC,CAAAA;YACX,IAAI,CAACA,SAAS;gBACVN,UAAU,KAAK;gBACfJ,KAAK,QAAQ,CAAC;gBACd;YACJ;YACA,MAAMW,MAAMP,UAAU,MAAM,CAACM;YAC7B,IAAIC,KACAX,KAAK,QAAQ,CAACZ,KAAK,SAAS,CAAC;gBAAEsB;gBAAS,SAASC,IAAI,OAAO;YAAC;QAErE;QACA,cAAc;YACVP,UAAU,KAAK;YACfJ,KAAK,QAAQ,CAAC;QAClB;QACA,oBAAoBO,GAAG,QAAQ;;AAG3C"}
|
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.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./index.js",
|
|
@@ -26,32 +26,32 @@
|
|
|
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.52.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.
|
|
31
|
+
"@webiny/admin-ui": "6.5.0-beta.8",
|
|
32
|
+
"@webiny/app": "6.5.0-beta.8",
|
|
33
|
+
"@webiny/app-aco": "6.5.0-beta.8",
|
|
34
|
+
"@webiny/app-admin": "6.5.0-beta.8",
|
|
35
|
+
"@webiny/app-graphql-playground": "6.5.0-beta.8",
|
|
36
|
+
"@webiny/app-headless-cms-common": "6.5.0-beta.8",
|
|
37
|
+
"@webiny/cms-sdk": "6.5.0-beta.8",
|
|
38
38
|
"@webiny/di": "1.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.
|
|
39
|
+
"@webiny/feature": "6.5.0-beta.8",
|
|
40
|
+
"@webiny/form": "6.5.0-beta.8",
|
|
41
|
+
"@webiny/frontend-settings": "6.5.0-beta.8",
|
|
42
|
+
"@webiny/icons": "6.5.0-beta.8",
|
|
43
|
+
"@webiny/lexical-editor": "6.5.0-beta.8",
|
|
44
|
+
"@webiny/lexical-nodes": "6.5.0-beta.8",
|
|
45
|
+
"@webiny/plugins": "6.5.0-beta.8",
|
|
46
|
+
"@webiny/react-composition": "6.5.0-beta.8",
|
|
47
|
+
"@webiny/react-properties": "6.5.0-beta.8",
|
|
48
|
+
"@webiny/utils": "6.5.0-beta.8",
|
|
49
|
+
"@webiny/validation": "6.5.0-beta.8",
|
|
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": "7.0.
|
|
54
|
+
"mobx": "7.0.6",
|
|
55
55
|
"mobx-react-lite": "5.1.0",
|
|
56
56
|
"react": "18.3.1",
|
|
57
57
|
"react-dnd": "16.0.1",
|
|
@@ -63,10 +63,10 @@
|
|
|
63
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.8",
|
|
67
67
|
"rimraf": "6.1.3",
|
|
68
68
|
"typescript": "7.0.2",
|
|
69
|
-
"vitest": "5.0.
|
|
69
|
+
"vitest": "5.0.3"
|
|
70
70
|
},
|
|
71
71
|
"publishConfig": {
|
|
72
72
|
"access": "public"
|
|
@@ -79,8 +79,10 @@ class ContentEntryFormPresenterImpl {
|
|
|
79
79
|
}
|
|
80
80
|
async saveRevision(options) {
|
|
81
81
|
if (!this.form) return false;
|
|
82
|
+
const form = this.form;
|
|
83
|
+
const model = this.model;
|
|
82
84
|
const skipValidation = options?.skipValidation ?? true;
|
|
83
|
-
const data = await
|
|
85
|
+
const data = await form.submit({
|
|
84
86
|
skipValidation
|
|
85
87
|
});
|
|
86
88
|
if (!data) return false;
|
|
@@ -95,9 +97,10 @@ class ContentEntryFormPresenterImpl {
|
|
|
95
97
|
skipValidation
|
|
96
98
|
});
|
|
97
99
|
runInAction(()=>{
|
|
100
|
+
if (this.form !== form) return;
|
|
98
101
|
this.entry = entry;
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
form.setData(entry.values);
|
|
103
|
+
form.reset();
|
|
101
104
|
});
|
|
102
105
|
} else {
|
|
103
106
|
const createData = {
|
|
@@ -114,14 +117,15 @@ class ContentEntryFormPresenterImpl {
|
|
|
114
117
|
}
|
|
115
118
|
});
|
|
116
119
|
runInAction(()=>{
|
|
120
|
+
if (this.form !== form) return;
|
|
117
121
|
this.entry = entry;
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
form.setData(entry.values);
|
|
123
|
+
form.reset();
|
|
120
124
|
});
|
|
121
125
|
}
|
|
122
126
|
return true;
|
|
123
127
|
} catch (error) {
|
|
124
|
-
this.form.setErrors(toFormErrors(error,
|
|
128
|
+
if (this.form === form) form.setErrors(toFormErrors(error, model));
|
|
125
129
|
return false;
|
|
126
130
|
} finally{
|
|
127
131
|
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\";\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":"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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 /*\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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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { Container } from "@webiny/di";
|
|
3
|
+
import { FormModelFactory } from "@webiny/app-admin/features/formModel/abstractions.js";
|
|
4
|
+
import { Confirmation } from "@webiny/app-admin/features/confirmation/abstractions.js";
|
|
5
|
+
import { GetEntryUseCase } from "../../../features/contentEntry/getEntry/abstractions.js";
|
|
6
|
+
import { CreateEntryUseCase } from "../../../features/contentEntry/createEntry/abstractions.js";
|
|
7
|
+
import { UpdateEntryUseCase } from "../../../features/contentEntry/updateEntry/abstractions.js";
|
|
8
|
+
import { PublishEntryUseCase } from "../../../features/contentEntry/publishEntry/abstractions.js";
|
|
9
|
+
import { UnpublishEntryUseCase } from "../../../features/contentEntry/unpublishEntry/abstractions.js";
|
|
10
|
+
import { DeleteEntryUseCase } from "../../../features/contentEntry/deleteEntry/abstractions.js";
|
|
11
|
+
import { UpdateRevisionDescriptionUseCase } from "../../../features/contentEntry/updateRevisionDescription/abstractions.js";
|
|
12
|
+
import { CreateRevisionFromUseCase } from "../../../features/contentEntry/createRevisionFrom/abstractions.js";
|
|
13
|
+
import { CmsFormModelBuilder } from "../../../features/formModel/abstractions.js";
|
|
14
|
+
import { CmsModelContext } from "../../../features/contentEntry/abstractions.js";
|
|
15
|
+
import { ContentEntryFormPresenter } from "./abstractions.js";
|
|
16
|
+
import { ContentEntryFormPresenter as external_ContentEntryFormPresenter_js_ContentEntryFormPresenter } from "./ContentEntryFormPresenter.js";
|
|
17
|
+
const createFakeForm = ()=>({
|
|
18
|
+
vm: {},
|
|
19
|
+
isDirty: false,
|
|
20
|
+
submit: vi.fn(async ()=>({
|
|
21
|
+
title: "Draft"
|
|
22
|
+
})),
|
|
23
|
+
setData: vi.fn(),
|
|
24
|
+
reset: vi.fn(),
|
|
25
|
+
setErrors: vi.fn()
|
|
26
|
+
});
|
|
27
|
+
const deferred = ()=>{
|
|
28
|
+
let resolve;
|
|
29
|
+
let reject;
|
|
30
|
+
const promise = new Promise((res, rej)=>{
|
|
31
|
+
resolve = res;
|
|
32
|
+
reject = rej;
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
promise,
|
|
36
|
+
resolve,
|
|
37
|
+
reject
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
const setup = ()=>{
|
|
41
|
+
const forms = [];
|
|
42
|
+
const create = deferred();
|
|
43
|
+
const container = new Container();
|
|
44
|
+
container.registerInstance(FormModelFactory, {
|
|
45
|
+
create: ()=>{
|
|
46
|
+
const form = createFakeForm();
|
|
47
|
+
forms.push(form);
|
|
48
|
+
return form;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
container.registerInstance(CmsFormModelBuilder, {
|
|
52
|
+
build: ()=>({})
|
|
53
|
+
});
|
|
54
|
+
container.registerInstance(CmsModelContext, {
|
|
55
|
+
getModel: ()=>({
|
|
56
|
+
modelId: "article",
|
|
57
|
+
fields: []
|
|
58
|
+
})
|
|
59
|
+
});
|
|
60
|
+
container.registerInstance(CreateEntryUseCase, {
|
|
61
|
+
execute: ()=>create.promise
|
|
62
|
+
});
|
|
63
|
+
for (const abstraction of [
|
|
64
|
+
Confirmation,
|
|
65
|
+
GetEntryUseCase,
|
|
66
|
+
CreateRevisionFromUseCase,
|
|
67
|
+
UpdateEntryUseCase,
|
|
68
|
+
PublishEntryUseCase,
|
|
69
|
+
UnpublishEntryUseCase,
|
|
70
|
+
DeleteEntryUseCase,
|
|
71
|
+
UpdateRevisionDescriptionUseCase
|
|
72
|
+
])container.registerInstance(abstraction, {});
|
|
73
|
+
container.register(external_ContentEntryFormPresenter_js_ContentEntryFormPresenter);
|
|
74
|
+
return {
|
|
75
|
+
presenter: container.resolve(ContentEntryFormPresenter),
|
|
76
|
+
forms,
|
|
77
|
+
create
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
describe("ContentEntryFormPresenter.saveRevision", ()=>{
|
|
81
|
+
it("puts a rejected save's errors on the form", async ()=>{
|
|
82
|
+
const { presenter, forms, create } = setup();
|
|
83
|
+
presenter.newEntry();
|
|
84
|
+
const saving = presenter.saveRevision();
|
|
85
|
+
create.reject(new Error("Value must be unique."));
|
|
86
|
+
await expect(saving).resolves.toBe(false);
|
|
87
|
+
expect(forms[0].setErrors).toHaveBeenCalledTimes(1);
|
|
88
|
+
});
|
|
89
|
+
it("returns false instead of throwing when the form was reset mid-save", async ()=>{
|
|
90
|
+
const { presenter, create } = setup();
|
|
91
|
+
presenter.newEntry();
|
|
92
|
+
const saving = presenter.saveRevision();
|
|
93
|
+
presenter.reset();
|
|
94
|
+
create.reject(new Error("Value must be unique."));
|
|
95
|
+
await expect(saving).resolves.toBe(false);
|
|
96
|
+
});
|
|
97
|
+
it("leaves a form built after the save started alone", async ()=>{
|
|
98
|
+
const { presenter, forms, create } = setup();
|
|
99
|
+
presenter.newEntry();
|
|
100
|
+
const saving = presenter.saveRevision();
|
|
101
|
+
presenter.newEntry();
|
|
102
|
+
create.reject(new Error("Value must be unique."));
|
|
103
|
+
await expect(saving).resolves.toBe(false);
|
|
104
|
+
expect(forms).toHaveLength(2);
|
|
105
|
+
expect(forms[0].setErrors).not.toHaveBeenCalled();
|
|
106
|
+
expect(forms[1].setErrors).not.toHaveBeenCalled();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
//# sourceMappingURL=ContentEntryFormPresenter.test.js.map
|
|
@@ -0,0 +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"}
|
|
@@ -38,7 +38,9 @@ class SingleEntryPresenterImpl {
|
|
|
38
38
|
}
|
|
39
39
|
async save() {
|
|
40
40
|
if (!this.form) return false;
|
|
41
|
-
const
|
|
41
|
+
const form = this.form;
|
|
42
|
+
const model = this.model;
|
|
43
|
+
const data = await form.submit();
|
|
42
44
|
if (!data) return false;
|
|
43
45
|
this.loading = "Saving...";
|
|
44
46
|
try {
|
|
@@ -49,13 +51,14 @@ class SingleEntryPresenterImpl {
|
|
|
49
51
|
}
|
|
50
52
|
});
|
|
51
53
|
runInAction(()=>{
|
|
54
|
+
if (this.form !== form) return;
|
|
52
55
|
this.entry = entry;
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
form.setData(entry.values);
|
|
57
|
+
form.reset();
|
|
55
58
|
});
|
|
56
59
|
return true;
|
|
57
60
|
} catch (error) {
|
|
58
|
-
this.form.setErrors(toFormErrors(error,
|
|
61
|
+
if (this.form === form) form.setErrors(toFormErrors(error, model));
|
|
59
62
|
return false;
|
|
60
63
|
} finally{
|
|
61
64
|
runInAction(()=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/contentEntries/singleEntry/SingleEntryPresenter.js","sources":["../../../../src/presentation/contentEntries/singleEntry/SingleEntryPresenter.ts"],"sourcesContent":["import { computed, makeAutoObservable, runInAction } from \"mobx\";\nimport type { IFormModel } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { CmsContentEntry } from \"~/types.js\";\nimport { GetSingletonEntryUseCase } from \"~/features/contentEntry/singletonEntry/abstractions.js\";\nimport { UpdateSingletonEntryUseCase } from \"~/features/contentEntry/singletonEntry/abstractions.js\";\nimport { CmsFormModelBuilder } from \"~/features/formModel/abstractions.js\";\nimport { CmsModelContext } from \"~/features/contentEntry/abstractions.js\";\nimport {\n SingleEntryPresenter as Abstraction,\n type ISingleEntryPresenter,\n type ISingleEntryViewModel\n} from \"./abstractions.js\";\nimport { toFormErrors } from \"~/presentation/contentEntries/form/toFormErrors.js\";\n\nclass SingleEntryPresenterImpl implements ISingleEntryPresenter {\n private entry: CmsContentEntry | null = null;\n private form: IFormModel | null = null;\n private loading: string | null = null;\n\n constructor(\n private formModelFactory: FormModelFactory.Interface,\n private cmsFormModelBuilder: CmsFormModelBuilder.Interface,\n private modelAccessor: CmsModelContext.Interface,\n private getSingletonEntryUseCase: GetSingletonEntryUseCase.Interface,\n private updateSingletonEntryUseCase: UpdateSingletonEntryUseCase.Interface\n ) {\n makeAutoObservable<\n SingleEntryPresenterImpl,\n | \"formModelFactory\"\n | \"cmsFormModelBuilder\"\n | \"modelAccessor\"\n | \"getSingletonEntryUseCase\"\n | \"updateSingletonEntryUseCase\"\n >(this, {\n formModelFactory: false,\n cmsFormModelBuilder: false,\n modelAccessor: false,\n getSingletonEntryUseCase: false,\n updateSingletonEntryUseCase: false,\n vm: computed\n });\n }\n\n private get model() {\n return this.modelAccessor.getModel();\n }\n\n get vm(): ISingleEntryViewModel {\n return {\n loading: this.loading,\n entry: this.entry,\n form: this.form?.vm ?? null,\n canSave: this.form !== null,\n isDirty: this.form?.isDirty ?? false\n };\n }\n\n async save(): Promise<boolean> {\n if (!this.form) {\n return false;\n }\n\n const data = await
|
|
1
|
+
{"version":3,"file":"presentation/contentEntries/singleEntry/SingleEntryPresenter.js","sources":["../../../../src/presentation/contentEntries/singleEntry/SingleEntryPresenter.ts"],"sourcesContent":["import { computed, makeAutoObservable, runInAction } from \"mobx\";\nimport type { IFormModel } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { CmsContentEntry } from \"~/types.js\";\nimport { GetSingletonEntryUseCase } from \"~/features/contentEntry/singletonEntry/abstractions.js\";\nimport { UpdateSingletonEntryUseCase } from \"~/features/contentEntry/singletonEntry/abstractions.js\";\nimport { CmsFormModelBuilder } from \"~/features/formModel/abstractions.js\";\nimport { CmsModelContext } from \"~/features/contentEntry/abstractions.js\";\nimport {\n SingleEntryPresenter as Abstraction,\n type ISingleEntryPresenter,\n type ISingleEntryViewModel\n} from \"./abstractions.js\";\nimport { toFormErrors } from \"~/presentation/contentEntries/form/toFormErrors.js\";\n\nclass SingleEntryPresenterImpl implements ISingleEntryPresenter {\n private entry: CmsContentEntry | null = null;\n private form: IFormModel | null = null;\n private loading: string | null = null;\n\n constructor(\n private formModelFactory: FormModelFactory.Interface,\n private cmsFormModelBuilder: CmsFormModelBuilder.Interface,\n private modelAccessor: CmsModelContext.Interface,\n private getSingletonEntryUseCase: GetSingletonEntryUseCase.Interface,\n private updateSingletonEntryUseCase: UpdateSingletonEntryUseCase.Interface\n ) {\n makeAutoObservable<\n SingleEntryPresenterImpl,\n | \"formModelFactory\"\n | \"cmsFormModelBuilder\"\n | \"modelAccessor\"\n | \"getSingletonEntryUseCase\"\n | \"updateSingletonEntryUseCase\"\n >(this, {\n formModelFactory: false,\n cmsFormModelBuilder: false,\n modelAccessor: false,\n getSingletonEntryUseCase: false,\n updateSingletonEntryUseCase: false,\n vm: computed\n });\n }\n\n private get model() {\n return this.modelAccessor.getModel();\n }\n\n get vm(): ISingleEntryViewModel {\n return {\n loading: this.loading,\n entry: this.entry,\n form: this.form?.vm ?? null,\n canSave: this.form !== null,\n isDirty: this.form?.isDirty ?? false\n };\n }\n\n async save(): Promise<boolean> {\n if (!this.form) {\n return false;\n }\n\n // The form can be disposed or rebuilt while saving; only the form being saved gets the result.\n const form = this.form;\n const model = this.model;\n\n const data = await form.submit();\n if (!data) {\n return false;\n }\n\n this.loading = \"Saving...\";\n\n try {\n const entry = await this.updateSingletonEntryUseCase.execute({\n model: this.model,\n data: {\n values: data\n }\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 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 init(): Promise<void> {\n this.loading = \"Loading...\";\n\n try {\n const entry = await this.getSingletonEntryUseCase.execute({\n model: this.model\n });\n\n runInAction(() => {\n this.entry = entry;\n const formConfig = this.cmsFormModelBuilder.build(this.model);\n this.form = this.formModelFactory.create(formConfig);\n this.form.setData(entry.values);\n this.form.reset();\n });\n } finally {\n runInAction(() => {\n this.loading = null;\n });\n }\n }\n\n dispose(): void {\n this.form = null;\n this.entry = null;\n }\n}\n\nexport const SingleEntryPresenter = Abstraction.createImplementation({\n implementation: SingleEntryPresenterImpl,\n dependencies: [\n FormModelFactory,\n CmsFormModelBuilder,\n CmsModelContext,\n GetSingletonEntryUseCase,\n UpdateSingletonEntryUseCase\n ]\n});\n"],"names":["SingleEntryPresenterImpl","formModelFactory","cmsFormModelBuilder","modelAccessor","getSingletonEntryUseCase","updateSingletonEntryUseCase","makeAutoObservable","computed","form","model","data","entry","runInAction","error","toFormErrors","formConfig","SingleEntryPresenter","Abstraction","FormModelFactory","CmsFormModelBuilder","CmsModelContext","GetSingletonEntryUseCase","UpdateSingletonEntryUseCase"],"mappings":";;;;;;;AAeA,MAAMA;IAKF,YACYC,gBAA4C,EAC5CC,mBAAkD,EAClDC,aAAwC,EACxCC,wBAA4D,EAC5DC,2BAAkE,CAC5E;aALUJ,gBAAgB,GAAhBA;aACAC,mBAAmB,GAAnBA;aACAC,aAAa,GAAbA;aACAC,wBAAwB,GAAxBA;aACAC,2BAA2B,GAA3BA;aATJ,KAAK,GAA2B;aAChC,IAAI,GAAsB;aAC1B,OAAO,GAAkB;QAS7BC,mBAOE,IAAI,EAAE;YACJ,kBAAkB;YAClB,qBAAqB;YACrB,eAAe;YACf,0BAA0B;YAC1B,6BAA6B;YAC7B,IAAIC;QACR;IACJ;IAEA,IAAY,QAAQ;QAChB,OAAO,IAAI,CAAC,aAAa,CAAC,QAAQ;IACtC;IAEA,IAAI,KAA4B;QAC5B,OAAO;YACH,SAAS,IAAI,CAAC,OAAO;YACrB,OAAO,IAAI,CAAC,KAAK;YACjB,MAAM,IAAI,CAAC,IAAI,EAAE,MAAM;YACvB,SAAS,AAAc,SAAd,IAAI,CAAC,IAAI;YAClB,SAAS,IAAI,CAAC,IAAI,EAAE,WAAW;QACnC;IACJ;IAEA,MAAM,OAAyB;QAC3B,IAAI,CAAC,IAAI,CAAC,IAAI,EACV,OAAO;QAIX,MAAMC,OAAO,IAAI,CAAC,IAAI;QACtB,MAAMC,QAAQ,IAAI,CAAC,KAAK;QAExB,MAAMC,OAAO,MAAMF,KAAK,MAAM;QAC9B,IAAI,CAACE,MACD,OAAO;QAGX,IAAI,CAAC,OAAO,GAAG;QAEf,IAAI;YACA,MAAMC,QAAQ,MAAM,IAAI,CAAC,2BAA2B,CAAC,OAAO,CAAC;gBACzD,OAAO,IAAI,CAAC,KAAK;gBACjB,MAAM;oBACF,QAAQD;gBACZ;YACJ;YAEAE,YAAY;gBACR,IAAI,IAAI,CAAC,IAAI,KAAKJ,MACd;gBAEJ,IAAI,CAAC,KAAK,GAAGG;gBACbH,KAAK,OAAO,CAACG,MAAM,MAAM;gBACzBH,KAAK,KAAK;YACd;YAEA,OAAO;QACX,EAAE,OAAOK,OAAO;YACZ,IAAI,IAAI,CAAC,IAAI,KAAKL,MACdA,KAAK,SAAS,CAACM,aAAaD,OAAOJ;YAEvC,OAAO;QACX,SAAU;YACNG,YAAY;gBACR,IAAI,CAAC,OAAO,GAAG;YACnB;QACJ;IACJ;IAEA,MAAM,OAAsB;QACxB,IAAI,CAAC,OAAO,GAAG;QAEf,IAAI;YACA,MAAMD,QAAQ,MAAM,IAAI,CAAC,wBAAwB,CAAC,OAAO,CAAC;gBACtD,OAAO,IAAI,CAAC,KAAK;YACrB;YAEAC,YAAY;gBACR,IAAI,CAAC,KAAK,GAAGD;gBACb,MAAMI,aAAa,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK;gBAC5D,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAACA;gBACzC,IAAI,CAAC,IAAI,CAAC,OAAO,CAACJ,MAAM,MAAM;gBAC9B,IAAI,CAAC,IAAI,CAAC,KAAK;YACnB;QACJ,SAAU;YACNC,YAAY;gBACR,IAAI,CAAC,OAAO,GAAG;YACnB;QACJ;IACJ;IAEA,UAAgB;QACZ,IAAI,CAAC,IAAI,GAAG;QACZ,IAAI,CAAC,KAAK,GAAG;IACjB;AACJ;AAEO,MAAMI,4CAAuBC,qBAAAA,oBAAgC,CAAC;IACjE,gBAAgBjB;IAChB,cAAc;QACVkB;QACAC;QACAC;QACAC;QACAC;KACH;AACL"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { Container } from "@webiny/di";
|
|
3
|
+
import { FormModelFactory } from "@webiny/app-admin/features/formModel/abstractions.js";
|
|
4
|
+
import { CmsFormModelBuilder } from "../../../features/formModel/abstractions.js";
|
|
5
|
+
import { CmsModelContext } from "../../../features/contentEntry/abstractions.js";
|
|
6
|
+
import { GetSingletonEntryUseCase, UpdateSingletonEntryUseCase } from "../../../features/contentEntry/singletonEntry/abstractions.js";
|
|
7
|
+
import { SingleEntryPresenter } from "./abstractions.js";
|
|
8
|
+
import { SingleEntryPresenter as external_SingleEntryPresenter_js_SingleEntryPresenter } from "./SingleEntryPresenter.js";
|
|
9
|
+
const createFakeForm = ()=>({
|
|
10
|
+
vm: {},
|
|
11
|
+
isDirty: false,
|
|
12
|
+
submit: vi.fn(async ()=>({
|
|
13
|
+
title: "Draft"
|
|
14
|
+
})),
|
|
15
|
+
setData: vi.fn(),
|
|
16
|
+
reset: vi.fn(),
|
|
17
|
+
setErrors: vi.fn()
|
|
18
|
+
});
|
|
19
|
+
const deferred = ()=>{
|
|
20
|
+
let resolve;
|
|
21
|
+
let reject;
|
|
22
|
+
const promise = new Promise((res, rej)=>{
|
|
23
|
+
resolve = res;
|
|
24
|
+
reject = rej;
|
|
25
|
+
});
|
|
26
|
+
return {
|
|
27
|
+
promise,
|
|
28
|
+
resolve,
|
|
29
|
+
reject
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
const setup = ()=>{
|
|
33
|
+
const forms = [];
|
|
34
|
+
let pendingUpdate = deferred();
|
|
35
|
+
const container = new Container();
|
|
36
|
+
container.registerInstance(FormModelFactory, {
|
|
37
|
+
create: ()=>{
|
|
38
|
+
const form = createFakeForm();
|
|
39
|
+
forms.push(form);
|
|
40
|
+
return form;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
container.registerInstance(CmsFormModelBuilder, {
|
|
44
|
+
build: ()=>({})
|
|
45
|
+
});
|
|
46
|
+
container.registerInstance(CmsModelContext, {
|
|
47
|
+
getModel: ()=>({
|
|
48
|
+
modelId: "settings",
|
|
49
|
+
fields: []
|
|
50
|
+
})
|
|
51
|
+
});
|
|
52
|
+
container.registerInstance(GetSingletonEntryUseCase, {
|
|
53
|
+
execute: async ()=>({
|
|
54
|
+
id: "settings#0001",
|
|
55
|
+
values: {
|
|
56
|
+
title: "Saved"
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
});
|
|
60
|
+
container.registerInstance(UpdateSingletonEntryUseCase, {
|
|
61
|
+
execute: ()=>pendingUpdate.promise
|
|
62
|
+
});
|
|
63
|
+
container.register(external_SingleEntryPresenter_js_SingleEntryPresenter);
|
|
64
|
+
return {
|
|
65
|
+
presenter: container.resolve(SingleEntryPresenter),
|
|
66
|
+
forms,
|
|
67
|
+
nextUpdate: ()=>{
|
|
68
|
+
pendingUpdate = deferred();
|
|
69
|
+
return pendingUpdate;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
describe("SingleEntryPresenter.save", ()=>{
|
|
74
|
+
it("puts a rejected save's errors on the form", async ()=>{
|
|
75
|
+
const { presenter, forms, nextUpdate } = setup();
|
|
76
|
+
await presenter.init();
|
|
77
|
+
const update = nextUpdate();
|
|
78
|
+
const saving = presenter.save();
|
|
79
|
+
update.reject(new Error("Value must be unique."));
|
|
80
|
+
await expect(saving).resolves.toBe(false);
|
|
81
|
+
expect(forms[0].setErrors).toHaveBeenCalledTimes(1);
|
|
82
|
+
});
|
|
83
|
+
it("returns false instead of throwing when the form was disposed mid-save", async ()=>{
|
|
84
|
+
const { presenter, nextUpdate } = setup();
|
|
85
|
+
await presenter.init();
|
|
86
|
+
const update = nextUpdate();
|
|
87
|
+
const saving = presenter.save();
|
|
88
|
+
presenter.dispose();
|
|
89
|
+
update.reject(new Error("Value must be unique."));
|
|
90
|
+
await expect(saving).resolves.toBe(false);
|
|
91
|
+
});
|
|
92
|
+
it("doesn't put a rejected save's errors on a form built after it started", async ()=>{
|
|
93
|
+
const { presenter, forms, nextUpdate } = setup();
|
|
94
|
+
await presenter.init();
|
|
95
|
+
const update = nextUpdate();
|
|
96
|
+
const saving = presenter.save();
|
|
97
|
+
await presenter.init();
|
|
98
|
+
update.reject(new Error("Value must be unique."));
|
|
99
|
+
await expect(saving).resolves.toBe(false);
|
|
100
|
+
expect(forms).toHaveLength(2);
|
|
101
|
+
expect(forms[0].setErrors).not.toHaveBeenCalled();
|
|
102
|
+
expect(forms[1].setErrors).not.toHaveBeenCalled();
|
|
103
|
+
});
|
|
104
|
+
it("doesn't overwrite a form built after a successful save started", async ()=>{
|
|
105
|
+
const { presenter, forms, nextUpdate } = setup();
|
|
106
|
+
await presenter.init();
|
|
107
|
+
const update = nextUpdate();
|
|
108
|
+
const saving = presenter.save();
|
|
109
|
+
await presenter.init();
|
|
110
|
+
const setDataCallsBefore = forms[1].setData.mock.calls.length;
|
|
111
|
+
update.resolve({
|
|
112
|
+
id: "settings#0002",
|
|
113
|
+
values: {
|
|
114
|
+
title: "From the old save"
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
await expect(saving).resolves.toBe(true);
|
|
118
|
+
expect(forms[1].setData).toHaveBeenCalledTimes(setDataCallsBefore);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
//# sourceMappingURL=SingleEntryPresenter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation/contentEntries/singleEntry/SingleEntryPresenter.test.js","sources":["../../../../src/presentation/contentEntries/singleEntry/SingleEntryPresenter.test.ts"],"sourcesContent":["import { describe, it, expect, vi } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { CmsFormModelBuilder } from \"~/features/formModel/abstractions.js\";\nimport { CmsModelContext } from \"~/features/contentEntry/abstractions.js\";\nimport {\n GetSingletonEntryUseCase,\n UpdateSingletonEntryUseCase\n} from \"~/features/contentEntry/singletonEntry/abstractions.js\";\nimport { SingleEntryPresenter as Abstraction } from \"./abstractions.js\";\nimport { SingleEntryPresenter } from \"./SingleEntryPresenter.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 let pendingUpdate = 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: \"settings\", fields: [] })\n } as unknown as CmsModelContext.Interface);\n container.registerInstance(GetSingletonEntryUseCase, {\n execute: async () => ({ id: \"settings#0001\", values: { title: \"Saved\" } })\n } as unknown as GetSingletonEntryUseCase.Interface);\n container.registerInstance(UpdateSingletonEntryUseCase, {\n execute: () => pendingUpdate.promise\n } as unknown as UpdateSingletonEntryUseCase.Interface);\n container.register(SingleEntryPresenter);\n\n return {\n presenter: container.resolve(Abstraction),\n forms,\n nextUpdate: () => {\n pendingUpdate = deferred<any>();\n return pendingUpdate;\n }\n };\n};\n\ndescribe(\"SingleEntryPresenter.save\", () => {\n it(\"puts a rejected save's errors on the form\", async () => {\n const { presenter, forms, nextUpdate } = setup();\n await presenter.init();\n const update = nextUpdate();\n\n const saving = presenter.save();\n update.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 disposed mid-save\", async () => {\n const { presenter, nextUpdate } = setup();\n await presenter.init();\n const update = nextUpdate();\n\n const saving = presenter.save();\n presenter.dispose();\n update.reject(new Error(\"Value must be unique.\"));\n\n await expect(saving).resolves.toBe(false);\n });\n\n it(\"doesn't put a rejected save's errors on a form built after it started\", async () => {\n const { presenter, forms, nextUpdate } = setup();\n await presenter.init();\n const update = nextUpdate();\n\n const saving = presenter.save();\n await presenter.init();\n update.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(\"doesn't overwrite a form built after a successful save started\", async () => {\n const { presenter, forms, nextUpdate } = setup();\n await presenter.init();\n const update = nextUpdate();\n\n const saving = presenter.save();\n await presenter.init();\n const setDataCallsBefore = forms[1].setData.mock.calls.length;\n update.resolve({ id: \"settings#0002\", values: { title: \"From the old save\" } });\n\n await expect(saving).resolves.toBe(true);\n expect(forms[1].setData).toHaveBeenCalledTimes(setDataCallsBefore);\n });\n});\n"],"names":["createFakeForm","vi","deferred","resolve","reject","promise","Promise","res","rej","setup","forms","pendingUpdate","container","Container","FormModelFactory","form","CmsFormModelBuilder","CmsModelContext","GetSingletonEntryUseCase","UpdateSingletonEntryUseCase","SingleEntryPresenter","Abstraction","describe","it","presenter","nextUpdate","update","saving","Error","expect","setDataCallsBefore"],"mappings":"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"}
|