@webiny/app-headless-cms 6.5.0-beta.3 → 6.5.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ContentEntriesModule.js +9 -2
- package/ContentEntriesModule.js.map +1 -1
- package/admin/components/ContentEntries/BulkActions/ActionDelete.d.ts +2 -2
- package/admin/components/ContentEntries/BulkActions/ActionDelete.js.map +1 -1
- package/admin/components/ContentEntries/BulkActions/ActionMove.d.ts +2 -2
- package/admin/components/ContentEntries/BulkActions/ActionMove.js.map +1 -1
- package/admin/components/ContentEntries/BulkActions/ActionPublish.d.ts +2 -2
- package/admin/components/ContentEntries/BulkActions/ActionPublish.js.map +1 -1
- package/admin/components/ContentEntries/BulkActions/ActionUnpublish.d.ts +2 -2
- package/admin/components/ContentEntries/BulkActions/ActionUnpublish.js.map +1 -1
- package/admin/components/ContentEntries/Table/Actions/DuplicateEntry.d.ts +2 -0
- package/admin/components/ContentEntries/Table/Actions/DuplicateEntry.js +34 -0
- package/admin/components/ContentEntries/Table/Actions/DuplicateEntry.js.map +1 -0
- package/admin/components/ContentEntries/Table/Actions/index.d.ts +1 -0
- package/admin/components/ContentEntries/Table/Actions/index.js +1 -0
- package/admin/components/ContentModelEditor/ContentModelEditor.js +1 -1
- package/admin/components/ContentModelEditor/ContentModelEditor.js.map +1 -1
- package/admin/components/Dialogs/DuplicateEntryConfirmDialog.d.ts +2 -0
- package/admin/components/Dialogs/DuplicateEntryConfirmDialog.js +22 -0
- package/admin/components/Dialogs/DuplicateEntryConfirmDialog.js.map +1 -0
- package/admin/components/FieldEditor/EditFieldDialog.d.ts +2 -2
- package/admin/components/FieldEditor/Field.js +4 -4
- package/admin/components/FieldEditor/Field.js.map +1 -1
- package/features/contentEntry/CmsEntryError.d.ts +10 -0
- package/features/contentEntry/CmsEntryError.js +11 -0
- package/features/contentEntry/CmsEntryError.js.map +1 -0
- package/features/contentEntry/createEntry/CreateEntryGateway.d.ts +0 -1
- package/features/contentEntry/createEntry/CreateEntryGateway.js +3 -10
- package/features/contentEntry/createEntry/CreateEntryGateway.js.map +1 -1
- package/features/contentEntry/createRevisionFrom/CreateRevisionFromGateway.d.ts +3 -1
- package/features/contentEntry/createRevisionFrom/CreateRevisionFromGateway.js +8 -3
- package/features/contentEntry/createRevisionFrom/CreateRevisionFromGateway.js.map +1 -1
- package/features/contentEntry/duplicateEntry/DuplicateEntryGateway.d.ts +14 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryGateway.js +43 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryGateway.js.map +1 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryRepository.d.ts +15 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryRepository.js +34 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryRepository.js.map +1 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryUseCase.d.ts +11 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryUseCase.js +18 -0
- package/features/contentEntry/duplicateEntry/DuplicateEntryUseCase.js.map +1 -0
- package/features/contentEntry/duplicateEntry/abstractions.d.ts +26 -0
- package/features/contentEntry/duplicateEntry/abstractions.js +7 -0
- package/features/contentEntry/duplicateEntry/abstractions.js.map +1 -0
- package/features/contentEntry/duplicateEntry/feature.d.ts +3 -0
- package/features/contentEntry/duplicateEntry/feature.js +21 -0
- package/features/contentEntry/duplicateEntry/feature.js.map +1 -0
- package/features/contentEntry/entryValueGateways.test.d.ts +1 -0
- package/features/contentEntry/entryValueGateways.test.js +106 -0
- package/features/contentEntry/entryValueGateways.test.js.map +1 -0
- package/features/contentEntry/feature.js +2 -0
- package/features/contentEntry/feature.js.map +1 -1
- package/features/contentEntry/singletonEntry/UpdateSingletonEntryGateway.d.ts +0 -1
- package/features/contentEntry/singletonEntry/UpdateSingletonEntryGateway.js +3 -10
- package/features/contentEntry/singletonEntry/UpdateSingletonEntryGateway.js.map +1 -1
- package/features/contentEntry/updateEntry/UpdateEntryGateway.d.ts +0 -1
- package/features/contentEntry/updateEntry/UpdateEntryGateway.js +3 -10
- package/features/contentEntry/updateEntry/UpdateEntryGateway.js.map +1 -1
- package/features/contentEntry/valueTransformers/EntryDataPreparer.d.ts +9 -0
- package/features/contentEntry/valueTransformers/EntryDataPreparer.js +8 -0
- package/features/contentEntry/valueTransformers/EntryDataPreparer.js.map +1 -1
- package/features/contentEntry/valueTransformers/EntryDataPreparer.test.d.ts +1 -0
- package/features/contentEntry/valueTransformers/EntryDataPreparer.test.js +113 -0
- package/features/contentEntry/valueTransformers/EntryDataPreparer.test.js.map +1 -0
- package/features/contentEntry/valueTransformers/entryValueFixtures.d.ts +146 -0
- package/features/contentEntry/valueTransformers/entryValueFixtures.js +171 -0
- package/features/contentEntry/valueTransformers/entryValueFixtures.js.map +1 -0
- package/features/formModel/CmsFormModelBuilder.d.ts +8 -0
- package/features/formModel/CmsFormModelBuilder.js +25 -2
- package/features/formModel/CmsFormModelBuilder.js.map +1 -1
- package/features/formModel/CmsFormModelBuilder.test.d.ts +1 -0
- package/features/formModel/CmsFormModelBuilder.test.js +111 -0
- package/features/formModel/CmsFormModelBuilder.test.js.map +1 -0
- package/features/formModel/mappers/DynamicZoneFieldMapper.js +1 -0
- package/features/formModel/mappers/DynamicZoneFieldMapper.js.map +1 -1
- package/features/model/exportModels/ExportModelsGateway.d.ts +1 -1
- package/features/model/exportModels/ExportModelsGateway.js.map +1 -1
- package/features/model/exportModels/ExportModelsUseCase.js +7 -1
- package/features/model/exportModels/ExportModelsUseCase.js.map +1 -1
- package/features/model/exportModels/abstractions.d.ts +8 -2
- package/features/model/exportModels/abstractions.js.map +1 -1
- package/package.json +26 -26
- package/presentation/contentEntries/form/ContentEntryFormPresenter.js +3 -1
- package/presentation/contentEntries/form/ContentEntryFormPresenter.js.map +1 -1
- package/presentation/contentEntries/form/toFormErrors.d.ts +7 -0
- package/presentation/contentEntries/form/toFormErrors.js +49 -0
- package/presentation/contentEntries/form/toFormErrors.js.map +1 -0
- package/presentation/contentEntries/form/toFormErrors.test.d.ts +1 -0
- package/presentation/contentEntries/form/toFormErrors.test.js +175 -0
- package/presentation/contentEntries/form/toFormErrors.test.js.map +1 -0
- package/presentation/contentEntries/list/ContentEntriesPresenter.d.ts +6 -2
- package/presentation/contentEntries/list/ContentEntriesPresenter.js +27 -2
- package/presentation/contentEntries/list/ContentEntriesPresenter.js.map +1 -1
- package/presentation/contentEntries/list/ContentEntriesPresenter.test.js +58 -1
- package/presentation/contentEntries/list/ContentEntriesPresenter.test.js.map +1 -1
- package/presentation/contentEntries/list/abstractions.d.ts +12 -0
- package/presentation/contentEntries/list/abstractions.js.map +1 -1
- package/presentation/contentEntries/singleEntry/SingleEntryPresenter.js +3 -1
- package/presentation/contentEntries/singleEntry/SingleEntryPresenter.js.map +1 -1
- package/presentation/contentEntries/trashBin/CmsTrashBin.d.ts +2 -2
- package/presentation/contentEntries/views/CmsAdvancedSearch.d.ts +2 -2
- package/presentation/contentEntries/views/ContentEntriesListLayout.d.ts +2 -2
- package/presentation/contentEntries/views/ContentEntryFormView.d.ts +2 -2
- package/presentation/contentEntries/views/OlderRevisionAlert.d.ts +2 -2
- package/presentation/contentEntries/views/RevisionDrawer.d.ts +2 -2
- package/presentation/contentEntries/views/RevisionsList.d.ts +2 -2
- package/presentation/contentEntries/views/SingleEntryLayout.d.ts +2 -2
- package/presentation/contentEntries/views/Table/Table.d.ts +2 -2
- package/presentation/contentEntries/views/actions/CreateNewRevisionButton.d.ts +2 -2
- package/presentation/contentEntries/views/actions/DeleteEntryMenuItem.d.ts +2 -2
- package/presentation/contentEntries/views/actions/PublishOnlyButton.d.ts +2 -2
- package/presentation/contentEntries/views/actions/RevisionSelector.d.ts +2 -2
- package/presentation/contentEntries/views/actions/SaveAndPublishButton.d.ts +2 -2
- package/presentation/contentEntries/views/actions/SaveContentButton.d.ts +2 -2
- package/presentation/contentEntries/views/actions/ShowRevisionListMenuItem.d.ts +2 -2
- package/presentation/contentEntries/views/layout/ContentEntryForm.d.ts +12 -12
- package/presentation/contentModels/ContentModelsPresenter.d.ts +5 -5
- package/presentation/contentModels/ContentModelsPresenter.js +1 -1
- package/presentation/contentModels/ContentModelsPresenter.js.map +1 -1
- package/presentation/contentModels/abstractions.d.ts +7 -2
- package/presentation/contentModels/abstractions.js.map +1 -1
- package/presentation/contentModels/components/CloneContentModelDialog.d.ts +2 -2
- package/presentation/contentModels/components/ContentModels.d.ts +2 -2
- package/presentation/contentModels/components/ContentModelsDataList.d.ts +2 -2
- package/presentation/contentModels/components/ContentModelsDataList.js +6 -5
- package/presentation/contentModels/components/ContentModelsDataList.js.map +1 -1
- package/presentation/contentModels/components/NewContentModelDialog.d.ts +2 -2
- package/presentation/contentModels/components/fullDelete/dialog/Content.js +2 -2
- package/presentation/contentModels/components/fullDelete/dialog/Content.js.map +1 -1
- package/presentation/contentModels/components/fullDelete/types.js.map +1 -1
- package/presentation/fieldRenderers/ref/components/RefFieldOptions.d.ts +2 -2
- package/presentation/fieldRenderers/ref/components/RefFieldOptions.js +3 -2
- package/presentation/fieldRenderers/ref/components/RefFieldOptions.js.map +1 -1
- package/presentation/importContentModels/ImportContentModelsDialog.d.ts +2 -2
- package/presentation/importContentModels/ImportContentModelsPresenter.js +1 -1
- package/presentation/importContentModels/ImportContentModelsPresenter.js.map +1 -1
- package/presentation/importContentModels/components/DataList.d.ts +2 -2
- package/presentation/importContentModels/components/FileUpload.d.ts +2 -2
- package/presentation/importContentModels/components/FileUpload.js +1 -1
- package/presentation/importContentModels/components/FileUpload.js.map +1 -1
- package/presentation/importContentModels/components/Model/DataListModelItem.js +3 -3
- package/presentation/importContentModels/components/Model/DataListModelItem.js.map +1 -1
- package/presentation/importContentModels/components/Model/DataListModelItemInfo.js +2 -2
- package/presentation/importContentModels/components/Model/DataListModelItemInfo.js.map +1 -1
- package/presentation/importContentModels/components/Model/DataListModels.d.ts +2 -2
- package/presentation/menus/ContentGroupsMenuItems.d.ts +2 -2
- package/presentation/modelGroup/ModelGroupPresenter.js +1 -2
- package/presentation/modelGroup/ModelGroupPresenter.js.map +1 -1
- package/presentation/modelGroup/components/ContentModelGroups.d.ts +2 -2
- package/presentation/modelGroup/components/ContentModelGroupsDataList.d.ts +6 -2
- package/presentation/modelGroup/components/ContentModelGroupsForm.d.ts +8 -2
- package/utils/normalizeIcon.d.ts +4 -0
- package/utils/normalizeIcon.js +9 -6
- package/utils/normalizeIcon.js.map +1 -1
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { toFormErrors } from "./toFormErrors.js";
|
|
3
|
+
import { CmsEntryError } from "../../../features/contentEntry/CmsEntryError.js";
|
|
4
|
+
const field = (fieldId, type, extra = {})=>({
|
|
5
|
+
id: fieldId,
|
|
6
|
+
fieldId,
|
|
7
|
+
type,
|
|
8
|
+
label: fieldId,
|
|
9
|
+
...extra
|
|
10
|
+
});
|
|
11
|
+
const model = {
|
|
12
|
+
modelId: "page",
|
|
13
|
+
fields: [
|
|
14
|
+
field("sku", "text"),
|
|
15
|
+
field("variants", "object", {
|
|
16
|
+
list: true,
|
|
17
|
+
settings: {
|
|
18
|
+
fields: [
|
|
19
|
+
field("code", "text")
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
}),
|
|
23
|
+
field("blocks", "dynamicZone", {
|
|
24
|
+
list: true,
|
|
25
|
+
settings: {
|
|
26
|
+
templates: [
|
|
27
|
+
{
|
|
28
|
+
id: "hero",
|
|
29
|
+
gqlTypeName: "PageHero",
|
|
30
|
+
fields: [
|
|
31
|
+
field("title", "text"),
|
|
32
|
+
field("links", "object", {
|
|
33
|
+
list: true,
|
|
34
|
+
settings: {
|
|
35
|
+
fields: [
|
|
36
|
+
field("url", "text")
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
}),
|
|
45
|
+
field("single", "dynamicZone", {
|
|
46
|
+
settings: {
|
|
47
|
+
templates: [
|
|
48
|
+
{
|
|
49
|
+
id: "plain",
|
|
50
|
+
gqlTypeName: "PagePlain",
|
|
51
|
+
fields: [
|
|
52
|
+
field("ctrl", "text")
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
]
|
|
59
|
+
};
|
|
60
|
+
const validationError = (data)=>new CmsEntryError({
|
|
61
|
+
message: "Validation failed.",
|
|
62
|
+
code: "Cms/Entry/ValidationError",
|
|
63
|
+
data: data
|
|
64
|
+
}, "Could not update entry");
|
|
65
|
+
describe("toFormErrors", ()=>{
|
|
66
|
+
it("maps a top-level field error to its field", ()=>{
|
|
67
|
+
const error = validationError([
|
|
68
|
+
{
|
|
69
|
+
id: "sku",
|
|
70
|
+
fieldId: "sku",
|
|
71
|
+
error: "Value must be unique.",
|
|
72
|
+
parents: []
|
|
73
|
+
}
|
|
74
|
+
]);
|
|
75
|
+
expect(toFormErrors(error, model)).toEqual([
|
|
76
|
+
{
|
|
77
|
+
path: "sku",
|
|
78
|
+
message: "Value must be unique."
|
|
79
|
+
}
|
|
80
|
+
]);
|
|
81
|
+
});
|
|
82
|
+
it("keeps list item indexes in the path", ()=>{
|
|
83
|
+
const error = validationError([
|
|
84
|
+
{
|
|
85
|
+
fieldId: "code",
|
|
86
|
+
error: "Required.",
|
|
87
|
+
parents: [
|
|
88
|
+
"variants",
|
|
89
|
+
"1"
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
]);
|
|
93
|
+
expect(toFormErrors(error, model)).toEqual([
|
|
94
|
+
{
|
|
95
|
+
path: "variants.1.code",
|
|
96
|
+
message: "Required."
|
|
97
|
+
}
|
|
98
|
+
]);
|
|
99
|
+
});
|
|
100
|
+
it("drops dynamic zone template names from the path", ()=>{
|
|
101
|
+
const error = validationError([
|
|
102
|
+
{
|
|
103
|
+
fieldId: "title",
|
|
104
|
+
error: "Required.",
|
|
105
|
+
parents: [
|
|
106
|
+
"blocks",
|
|
107
|
+
"0",
|
|
108
|
+
"PageHero"
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
fieldId: "url",
|
|
113
|
+
error: "Invalid URL.",
|
|
114
|
+
parents: [
|
|
115
|
+
"blocks",
|
|
116
|
+
"2",
|
|
117
|
+
"PageHero",
|
|
118
|
+
"links",
|
|
119
|
+
"1"
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
fieldId: "ctrl",
|
|
124
|
+
error: "Required.",
|
|
125
|
+
parents: [
|
|
126
|
+
"single",
|
|
127
|
+
"PagePlain"
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
]);
|
|
131
|
+
expect(toFormErrors(error, model)).toEqual([
|
|
132
|
+
{
|
|
133
|
+
path: "blocks.0.title",
|
|
134
|
+
message: "Required."
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
path: "blocks.2.links.1.url",
|
|
138
|
+
message: "Invalid URL."
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
path: "single.ctrl",
|
|
142
|
+
message: "Required."
|
|
143
|
+
}
|
|
144
|
+
]);
|
|
145
|
+
});
|
|
146
|
+
it("falls back to the error message when there are no field errors", ()=>{
|
|
147
|
+
const error = new CmsEntryError({
|
|
148
|
+
message: "Entry is locked.",
|
|
149
|
+
code: "Cms/Entry/Locked",
|
|
150
|
+
data: null
|
|
151
|
+
}, "Could not update entry");
|
|
152
|
+
expect(toFormErrors(error, model)).toEqual([
|
|
153
|
+
{
|
|
154
|
+
path: "",
|
|
155
|
+
message: "Entry is locked."
|
|
156
|
+
}
|
|
157
|
+
]);
|
|
158
|
+
});
|
|
159
|
+
it("uses the message of any other error", ()=>{
|
|
160
|
+
expect(toFormErrors(new Error("Network error: Failed to fetch"), model)).toEqual([
|
|
161
|
+
{
|
|
162
|
+
path: "",
|
|
163
|
+
message: "Network error: Failed to fetch"
|
|
164
|
+
}
|
|
165
|
+
]);
|
|
166
|
+
expect(toFormErrors("boom", model)).toEqual([
|
|
167
|
+
{
|
|
168
|
+
path: "",
|
|
169
|
+
message: "Could not save the entry."
|
|
170
|
+
}
|
|
171
|
+
]);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
//# sourceMappingURL=toFormErrors.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation/contentEntries/form/toFormErrors.test.js","sources":["../../../../src/presentation/contentEntries/form/toFormErrors.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { toFormErrors } from \"./toFormErrors.js\";\nimport { CmsEntryError } from \"~/features/contentEntry/CmsEntryError.js\";\n\nconst field = (fieldId: string, type: string, extra: Record<string, unknown> = {}) => ({\n id: fieldId,\n fieldId,\n type,\n label: fieldId,\n ...extra\n});\n\nconst model = {\n modelId: \"page\",\n fields: [\n field(\"sku\", \"text\"),\n field(\"variants\", \"object\", {\n list: true,\n settings: { fields: [field(\"code\", \"text\")] }\n }),\n field(\"blocks\", \"dynamicZone\", {\n list: true,\n settings: {\n templates: [\n {\n id: \"hero\",\n gqlTypeName: \"PageHero\",\n fields: [\n field(\"title\", \"text\"),\n field(\"links\", \"object\", {\n list: true,\n settings: { fields: [field(\"url\", \"text\")] }\n })\n ]\n }\n ]\n }\n }),\n field(\"single\", \"dynamicZone\", {\n settings: {\n templates: [\n { id: \"plain\", gqlTypeName: \"PagePlain\", fields: [field(\"ctrl\", \"text\")] }\n ]\n }\n })\n ]\n} as any;\n\nconst validationError = (data: unknown[]) =>\n new CmsEntryError(\n { message: \"Validation failed.\", code: \"Cms/Entry/ValidationError\", data: data as any },\n \"Could not update entry\"\n );\n\ndescribe(\"toFormErrors\", () => {\n it(\"maps a top-level field error to its field\", () => {\n const error = validationError([\n { id: \"sku\", fieldId: \"sku\", error: \"Value must be unique.\", parents: [] }\n ]);\n\n expect(toFormErrors(error, model)).toEqual([\n { path: \"sku\", message: \"Value must be unique.\" }\n ]);\n });\n\n it(\"keeps list item indexes in the path\", () => {\n const error = validationError([\n { fieldId: \"code\", error: \"Required.\", parents: [\"variants\", \"1\"] }\n ]);\n\n expect(toFormErrors(error, model)).toEqual([\n { path: \"variants.1.code\", message: \"Required.\" }\n ]);\n });\n\n it(\"drops dynamic zone template names from the path\", () => {\n const error = validationError([\n { fieldId: \"title\", error: \"Required.\", parents: [\"blocks\", \"0\", \"PageHero\"] },\n {\n fieldId: \"url\",\n error: \"Invalid URL.\",\n parents: [\"blocks\", \"2\", \"PageHero\", \"links\", \"1\"]\n },\n { fieldId: \"ctrl\", error: \"Required.\", parents: [\"single\", \"PagePlain\"] }\n ]);\n\n expect(toFormErrors(error, model)).toEqual([\n { path: \"blocks.0.title\", message: \"Required.\" },\n { path: \"blocks.2.links.1.url\", message: \"Invalid URL.\" },\n { path: \"single.ctrl\", message: \"Required.\" }\n ]);\n });\n\n it(\"falls back to the error message when there are no field errors\", () => {\n const error = new CmsEntryError(\n { message: \"Entry is locked.\", code: \"Cms/Entry/Locked\", data: null },\n \"Could not update entry\"\n );\n\n expect(toFormErrors(error, model)).toEqual([{ path: \"\", message: \"Entry is locked.\" }]);\n });\n\n it(\"uses the message of any other error\", () => {\n expect(toFormErrors(new Error(\"Network error: Failed to fetch\"), model)).toEqual([\n { path: \"\", message: \"Network error: Failed to fetch\" }\n ]);\n expect(toFormErrors(\"boom\", model)).toEqual([\n { path: \"\", message: \"Could not save the entry.\" }\n ]);\n });\n});\n"],"names":["field","fieldId","type","extra","model","validationError","data","CmsEntryError","describe","it","error","expect","toFormErrors","Error"],"mappings":";;;AAIA,MAAMA,QAAQ,CAACC,SAAiBC,MAAcC,QAAiC,CAAC,CAAC,GAAM;QACnF,IAAIF;QACJA;QACAC;QACA,OAAOD;QACP,GAAGE,KAAK;IACZ;AAEA,MAAMC,QAAQ;IACV,SAAS;IACT,QAAQ;QACJJ,MAAM,OAAO;QACbA,MAAM,YAAY,UAAU;YACxB,MAAM;YACN,UAAU;gBAAE,QAAQ;oBAACA,MAAM,QAAQ;iBAAQ;YAAC;QAChD;QACAA,MAAM,UAAU,eAAe;YAC3B,MAAM;YACN,UAAU;gBACN,WAAW;oBACP;wBACI,IAAI;wBACJ,aAAa;wBACb,QAAQ;4BACJA,MAAM,SAAS;4BACfA,MAAM,SAAS,UAAU;gCACrB,MAAM;gCACN,UAAU;oCAAE,QAAQ;wCAACA,MAAM,OAAO;qCAAQ;gCAAC;4BAC/C;yBACH;oBACL;iBACH;YACL;QACJ;QACAA,MAAM,UAAU,eAAe;YAC3B,UAAU;gBACN,WAAW;oBACP;wBAAE,IAAI;wBAAS,aAAa;wBAAa,QAAQ;4BAACA,MAAM,QAAQ;yBAAQ;oBAAC;iBAC5E;YACL;QACJ;KACH;AACL;AAEA,MAAMK,kBAAkB,CAACC,OACrB,IAAIC,cACA;QAAE,SAAS;QAAsB,MAAM;QAA6B,MAAMD;IAAY,GACtF;AAGRE,SAAS,gBAAgB;IACrBC,GAAG,6CAA6C;QAC5C,MAAMC,QAAQL,gBAAgB;YAC1B;gBAAE,IAAI;gBAAO,SAAS;gBAAO,OAAO;gBAAyB,SAAS,EAAE;YAAC;SAC5E;QAEDM,OAAOC,aAAaF,OAAON,QAAQ,OAAO,CAAC;YACvC;gBAAE,MAAM;gBAAO,SAAS;YAAwB;SACnD;IACL;IAEAK,GAAG,uCAAuC;QACtC,MAAMC,QAAQL,gBAAgB;YAC1B;gBAAE,SAAS;gBAAQ,OAAO;gBAAa,SAAS;oBAAC;oBAAY;iBAAI;YAAC;SACrE;QAEDM,OAAOC,aAAaF,OAAON,QAAQ,OAAO,CAAC;YACvC;gBAAE,MAAM;gBAAmB,SAAS;YAAY;SACnD;IACL;IAEAK,GAAG,mDAAmD;QAClD,MAAMC,QAAQL,gBAAgB;YAC1B;gBAAE,SAAS;gBAAS,OAAO;gBAAa,SAAS;oBAAC;oBAAU;oBAAK;iBAAW;YAAC;YAC7E;gBACI,SAAS;gBACT,OAAO;gBACP,SAAS;oBAAC;oBAAU;oBAAK;oBAAY;oBAAS;iBAAI;YACtD;YACA;gBAAE,SAAS;gBAAQ,OAAO;gBAAa,SAAS;oBAAC;oBAAU;iBAAY;YAAC;SAC3E;QAEDM,OAAOC,aAAaF,OAAON,QAAQ,OAAO,CAAC;YACvC;gBAAE,MAAM;gBAAkB,SAAS;YAAY;YAC/C;gBAAE,MAAM;gBAAwB,SAAS;YAAe;YACxD;gBAAE,MAAM;gBAAe,SAAS;YAAY;SAC/C;IACL;IAEAK,GAAG,kEAAkE;QACjE,MAAMC,QAAQ,IAAIH,cACd;YAAE,SAAS;YAAoB,MAAM;YAAoB,MAAM;QAAK,GACpE;QAGJI,OAAOC,aAAaF,OAAON,QAAQ,OAAO,CAAC;YAAC;gBAAE,MAAM;gBAAI,SAAS;YAAmB;SAAE;IAC1F;IAEAK,GAAG,uCAAuC;QACtCE,OAAOC,aAAa,IAAIC,MAAM,mCAAmCT,QAAQ,OAAO,CAAC;YAC7E;gBAAE,MAAM;gBAAI,SAAS;YAAiC;SACzD;QACDO,OAAOC,aAAa,QAAQR,QAAQ,OAAO,CAAC;YACxC;gBAAE,MAAM;gBAAI,SAAS;YAA4B;SACpD;IACL;AACJ"}
|
|
@@ -8,12 +8,14 @@ import { DeleteEntryUseCase } from "../../../features/contentEntry/deleteEntry/a
|
|
|
8
8
|
import { PublishEntryUseCase } from "../../../features/contentEntry/publishEntry/abstractions.js";
|
|
9
9
|
import { UnpublishEntryUseCase } from "../../../features/contentEntry/unpublishEntry/abstractions.js";
|
|
10
10
|
import { MoveEntryUseCase } from "../../../features/contentEntry/moveEntry/abstractions.js";
|
|
11
|
+
import { DuplicateEntryUseCase } from "../../../features/contentEntry/duplicateEntry/abstractions.js";
|
|
11
12
|
import { UpdateRevisionDescriptionUseCase } from "../../../features/contentEntry/updateRevisionDescription/abstractions.js";
|
|
12
13
|
import { ContentEntriesCacheProvider, CmsModelContext } from "../../../features/contentEntry/abstractions.js";
|
|
13
|
-
import { ContentEntriesPresenter as Abstraction, type IContentEntriesViewModel } from "./abstractions.js";
|
|
14
|
+
import { ContentEntriesPresenter as Abstraction, type IContentEntriesViewModel, type IDuplicateEntryResult } from "./abstractions.js";
|
|
14
15
|
export declare const TRASH_ENTRY_DIALOG = "trash-entry";
|
|
15
16
|
export declare const PUBLISH_ENTRY_DIALOG = "publish-entry";
|
|
16
17
|
export declare const UNPUBLISH_ENTRY_DIALOG = "unpublish-entry";
|
|
18
|
+
export declare const DUPLICATE_ENTRY_DIALOG = "duplicate-entry";
|
|
17
19
|
declare class ContentEntriesPresenterImpl implements Abstraction.Interface {
|
|
18
20
|
private listPresenter;
|
|
19
21
|
private foldersPresenter;
|
|
@@ -24,12 +26,13 @@ declare class ContentEntriesPresenterImpl implements Abstraction.Interface {
|
|
|
24
26
|
private publishEntryUseCase;
|
|
25
27
|
private unpublishEntryUseCase;
|
|
26
28
|
private moveEntryUseCase;
|
|
29
|
+
private duplicateEntryUseCase;
|
|
27
30
|
private updateRevisionDescriptionUseCase;
|
|
28
31
|
private cacheProvider;
|
|
29
32
|
private getDescendantFoldersUseCase;
|
|
30
33
|
private selectedEntryId;
|
|
31
34
|
private disposeReaction;
|
|
32
|
-
constructor(listPresenter: ListPresenter.Interface<CmsContentEntry>, foldersPresenter: FolderTreePresenter.Interface, confirmation: Confirmation.Interface, modelAccessor: CmsModelContext.Interface, listEntriesUseCase: ListEntriesUseCase.Interface, deleteEntryUseCase: DeleteEntryUseCase.Interface, publishEntryUseCase: PublishEntryUseCase.Interface, unpublishEntryUseCase: UnpublishEntryUseCase.Interface, moveEntryUseCase: MoveEntryUseCase.Interface, updateRevisionDescriptionUseCase: UpdateRevisionDescriptionUseCase.Interface, cacheProvider: ContentEntriesCacheProvider.Interface, getDescendantFoldersUseCase: GetDescendantFoldersUseCase.Interface);
|
|
35
|
+
constructor(listPresenter: ListPresenter.Interface<CmsContentEntry>, foldersPresenter: FolderTreePresenter.Interface, confirmation: Confirmation.Interface, modelAccessor: CmsModelContext.Interface, listEntriesUseCase: ListEntriesUseCase.Interface, deleteEntryUseCase: DeleteEntryUseCase.Interface, publishEntryUseCase: PublishEntryUseCase.Interface, unpublishEntryUseCase: UnpublishEntryUseCase.Interface, moveEntryUseCase: MoveEntryUseCase.Interface, duplicateEntryUseCase: DuplicateEntryUseCase.Interface, updateRevisionDescriptionUseCase: UpdateRevisionDescriptionUseCase.Interface, cacheProvider: ContentEntriesCacheProvider.Interface, getDescendantFoldersUseCase: GetDescendantFoldersUseCase.Interface);
|
|
33
36
|
private get model();
|
|
34
37
|
get vm(): IContentEntriesViewModel;
|
|
35
38
|
init(config?: Abstraction.InitConfig): void;
|
|
@@ -42,6 +45,7 @@ declare class ContentEntriesPresenterImpl implements Abstraction.Interface {
|
|
|
42
45
|
publishEntry(id: string): Promise<boolean>;
|
|
43
46
|
unpublishEntry(id: string): Promise<boolean>;
|
|
44
47
|
moveEntry(id: string, folderId: string): Promise<boolean>;
|
|
48
|
+
duplicateEntry(entry: CmsContentEntry): Promise<IDuplicateEntryResult | false>;
|
|
45
49
|
dispose(): void;
|
|
46
50
|
}
|
|
47
51
|
export declare const ContentEntriesPresenter: typeof ContentEntriesPresenterImpl & {
|
|
@@ -9,6 +9,7 @@ import { DeleteEntryUseCase } from "../../../features/contentEntry/deleteEntry/a
|
|
|
9
9
|
import { PublishEntryUseCase } from "../../../features/contentEntry/publishEntry/abstractions.js";
|
|
10
10
|
import { UnpublishEntryUseCase } from "../../../features/contentEntry/unpublishEntry/abstractions.js";
|
|
11
11
|
import { MoveEntryUseCase } from "../../../features/contentEntry/moveEntry/abstractions.js";
|
|
12
|
+
import { DuplicateEntryUseCase } from "../../../features/contentEntry/duplicateEntry/abstractions.js";
|
|
12
13
|
import { UpdateRevisionDescriptionUseCase } from "../../../features/contentEntry/updateRevisionDescription/abstractions.js";
|
|
13
14
|
import { CmsModelContext, ContentEntriesCacheProvider } from "../../../features/contentEntry/abstractions.js";
|
|
14
15
|
import { ContentEntriesPresenter } from "./abstractions.js";
|
|
@@ -16,8 +17,9 @@ import { ContentEntriesDataSource } from "./ContentEntriesDataSource.js";
|
|
|
16
17
|
const TRASH_ENTRY_DIALOG = "trash-entry";
|
|
17
18
|
const PUBLISH_ENTRY_DIALOG = "publish-entry";
|
|
18
19
|
const UNPUBLISH_ENTRY_DIALOG = "unpublish-entry";
|
|
20
|
+
const DUPLICATE_ENTRY_DIALOG = "duplicate-entry";
|
|
19
21
|
class ContentEntriesPresenterImpl {
|
|
20
|
-
constructor(listPresenter, foldersPresenter, confirmation, modelAccessor, listEntriesUseCase, deleteEntryUseCase, publishEntryUseCase, unpublishEntryUseCase, moveEntryUseCase, updateRevisionDescriptionUseCase, cacheProvider, getDescendantFoldersUseCase){
|
|
22
|
+
constructor(listPresenter, foldersPresenter, confirmation, modelAccessor, listEntriesUseCase, deleteEntryUseCase, publishEntryUseCase, unpublishEntryUseCase, moveEntryUseCase, duplicateEntryUseCase, updateRevisionDescriptionUseCase, cacheProvider, getDescendantFoldersUseCase){
|
|
21
23
|
this.listPresenter = listPresenter;
|
|
22
24
|
this.foldersPresenter = foldersPresenter;
|
|
23
25
|
this.confirmation = confirmation;
|
|
@@ -27,6 +29,7 @@ class ContentEntriesPresenterImpl {
|
|
|
27
29
|
this.publishEntryUseCase = publishEntryUseCase;
|
|
28
30
|
this.unpublishEntryUseCase = unpublishEntryUseCase;
|
|
29
31
|
this.moveEntryUseCase = moveEntryUseCase;
|
|
32
|
+
this.duplicateEntryUseCase = duplicateEntryUseCase;
|
|
30
33
|
this.updateRevisionDescriptionUseCase = updateRevisionDescriptionUseCase;
|
|
31
34
|
this.cacheProvider = cacheProvider;
|
|
32
35
|
this.getDescendantFoldersUseCase = getDescendantFoldersUseCase;
|
|
@@ -41,6 +44,7 @@ class ContentEntriesPresenterImpl {
|
|
|
41
44
|
publishEntryUseCase: false,
|
|
42
45
|
unpublishEntryUseCase: false,
|
|
43
46
|
moveEntryUseCase: false,
|
|
47
|
+
duplicateEntryUseCase: false,
|
|
44
48
|
updateRevisionDescriptionUseCase: false,
|
|
45
49
|
cacheProvider: false,
|
|
46
50
|
getDescendantFoldersUseCase: false,
|
|
@@ -153,6 +157,26 @@ class ContentEntriesPresenterImpl {
|
|
|
153
157
|
});
|
|
154
158
|
return true;
|
|
155
159
|
}
|
|
160
|
+
async duplicateEntry(entry) {
|
|
161
|
+
const model = this.model;
|
|
162
|
+
return this.confirmation.confirm(DUPLICATE_ENTRY_DIALOG, {
|
|
163
|
+
entry
|
|
164
|
+
}, async ()=>{
|
|
165
|
+
try {
|
|
166
|
+
const duplicate = await this.duplicateEntryUseCase.execute({
|
|
167
|
+
model,
|
|
168
|
+
revisionId: entry.id
|
|
169
|
+
});
|
|
170
|
+
return {
|
|
171
|
+
entry: duplicate
|
|
172
|
+
};
|
|
173
|
+
} catch (error) {
|
|
174
|
+
return {
|
|
175
|
+
error: error
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
156
180
|
dispose() {
|
|
157
181
|
if (this.disposeReaction) {
|
|
158
182
|
this.disposeReaction();
|
|
@@ -172,11 +196,12 @@ const ContentEntriesPresenter_ContentEntriesPresenter = ContentEntriesPresenter.
|
|
|
172
196
|
PublishEntryUseCase,
|
|
173
197
|
UnpublishEntryUseCase,
|
|
174
198
|
MoveEntryUseCase,
|
|
199
|
+
DuplicateEntryUseCase,
|
|
175
200
|
UpdateRevisionDescriptionUseCase,
|
|
176
201
|
ContentEntriesCacheProvider,
|
|
177
202
|
GetDescendantFoldersUseCase
|
|
178
203
|
]
|
|
179
204
|
});
|
|
180
|
-
export { ContentEntriesPresenter_ContentEntriesPresenter as ContentEntriesPresenter, PUBLISH_ENTRY_DIALOG, TRASH_ENTRY_DIALOG, UNPUBLISH_ENTRY_DIALOG };
|
|
205
|
+
export { ContentEntriesPresenter_ContentEntriesPresenter as ContentEntriesPresenter, DUPLICATE_ENTRY_DIALOG, PUBLISH_ENTRY_DIALOG, TRASH_ENTRY_DIALOG, UNPUBLISH_ENTRY_DIALOG };
|
|
181
206
|
|
|
182
207
|
//# sourceMappingURL=ContentEntriesPresenter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/contentEntries/list/ContentEntriesPresenter.js","sources":["../../../../src/presentation/contentEntries/list/ContentEntriesPresenter.ts"],"sourcesContent":["import { computed, makeAutoObservable, reaction } from \"mobx\";\nimport type { IReactionDisposer } from \"mobx\";\nimport { ListPresenter } from \"@webiny/app-admin/presentation/listPresenter/abstractions.js\";\nimport { FolderTreePresenter } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\nimport { GetDescendantFoldersUseCase } from \"@webiny/app-aco/features/folders/getDescendantFolders/abstractions.js\";\nimport { sortFolders } from \"@webiny/app-aco\";\nimport { Confirmation } from \"@webiny/app-admin/features/confirmation/abstractions.js\";\nimport type { CmsContentEntry } from \"~/types.js\";\nimport { ListEntriesUseCase } from \"~/features/contentEntry/listEntries/abstractions.js\";\nimport { DeleteEntryUseCase } from \"~/features/contentEntry/deleteEntry/abstractions.js\";\nimport { PublishEntryUseCase } from \"~/features/contentEntry/publishEntry/abstractions.js\";\nimport { UnpublishEntryUseCase } from \"~/features/contentEntry/unpublishEntry/abstractions.js\";\nimport { MoveEntryUseCase } from \"~/features/contentEntry/moveEntry/abstractions.js\";\nimport { UpdateRevisionDescriptionUseCase } from \"~/features/contentEntry/updateRevisionDescription/abstractions.js\";\nimport {\n ContentEntriesCacheProvider,\n CmsModelContext\n} from \"~/features/contentEntry/abstractions.js\";\nimport {\n ContentEntriesPresenter as Abstraction,\n type IContentEntriesViewModel\n} from \"./abstractions.js\";\nimport { ContentEntriesDataSource } from \"./ContentEntriesDataSource.js\";\n\nexport const TRASH_ENTRY_DIALOG = \"trash-entry\";\nexport const PUBLISH_ENTRY_DIALOG = \"publish-entry\";\nexport const UNPUBLISH_ENTRY_DIALOG = \"unpublish-entry\";\n\nclass ContentEntriesPresenterImpl implements Abstraction.Interface {\n private selectedEntryId: string | null = null;\n private disposeReaction: IReactionDisposer | null = null;\n\n constructor(\n private listPresenter: ListPresenter.Interface<CmsContentEntry>,\n private foldersPresenter: FolderTreePresenter.Interface,\n private confirmation: Confirmation.Interface,\n private modelAccessor: CmsModelContext.Interface,\n private listEntriesUseCase: ListEntriesUseCase.Interface,\n private deleteEntryUseCase: DeleteEntryUseCase.Interface,\n private publishEntryUseCase: PublishEntryUseCase.Interface,\n private unpublishEntryUseCase: UnpublishEntryUseCase.Interface,\n private moveEntryUseCase: MoveEntryUseCase.Interface,\n private updateRevisionDescriptionUseCase: UpdateRevisionDescriptionUseCase.Interface,\n private cacheProvider: ContentEntriesCacheProvider.Interface,\n private getDescendantFoldersUseCase: GetDescendantFoldersUseCase.Interface\n ) {\n makeAutoObservable<\n ContentEntriesPresenterImpl,\n | \"disposeReaction\"\n | \"confirmation\"\n | \"modelAccessor\"\n | \"listEntriesUseCase\"\n | \"deleteEntryUseCase\"\n | \"publishEntryUseCase\"\n | \"unpublishEntryUseCase\"\n | \"moveEntryUseCase\"\n | \"updateRevisionDescriptionUseCase\"\n | \"cacheProvider\"\n | \"getDescendantFoldersUseCase\"\n >(this, {\n disposeReaction: false,\n confirmation: false,\n modelAccessor: false,\n listEntriesUseCase: false,\n deleteEntryUseCase: false,\n publishEntryUseCase: false,\n unpublishEntryUseCase: false,\n moveEntryUseCase: false,\n updateRevisionDescriptionUseCase: false,\n cacheProvider: false,\n getDescendantFoldersUseCase: false,\n vm: computed\n });\n }\n\n private get model() {\n return this.modelAccessor.getModel();\n }\n\n get vm(): IContentEntriesViewModel {\n const appliedQuery = this.listPresenter.vm.appliedQuery;\n const hasSearch = !!appliedQuery?.search;\n const hasFilters = Object.keys(this.listPresenter.vm.filters).some(k => k !== \"folderId\");\n const showFolders = !hasSearch && !hasFilters;\n\n const childFolders = showFolders\n ? sortFolders(this.foldersPresenter.vm.childFolders ?? [], appliedQuery?.sort)\n : [];\n\n return {\n model: this.model,\n selectedEntryId: this.selectedEntryId,\n showingEntry: this.selectedEntryId !== null,\n showFolders,\n childFolders\n };\n }\n\n init(config: Abstraction.InitConfig = {}): void {\n const initialFolderId = config.initialFolderId ?? \"root\";\n\n const cache = this.cacheProvider.get(this.model.modelId);\n const dataSource = new ContentEntriesDataSource(\n this.model,\n this.listEntriesUseCase,\n cache,\n this.getDescendantFoldersUseCase,\n config.filterNames\n );\n\n this.listPresenter.init({\n dataSource,\n initialSort: { field: \"savedOn\", direction: \"DESC\" },\n initialFilters: { folderId: initialFolderId },\n initialSearch: config.initialSearch,\n limit: 50,\n itemLabel: { singular: \"entry\", plural: \"entries\" }\n });\n\n if (initialFolderId !== \"root\") {\n this.foldersPresenter.selectFolder(initialFolderId);\n }\n\n this.disposeReaction = reaction(\n () => this.foldersPresenter.vm.currentFolderId,\n folderId => {\n const effectiveFolderId = folderId ?? \"root\";\n this.listPresenter.actions.filter.set(\"folderId\", effectiveFolderId);\n }\n );\n }\n\n get list(): ListPresenter.Interface<CmsContentEntry> {\n return this.listPresenter;\n }\n\n get folders(): FolderTreePresenter.Interface {\n return this.foldersPresenter;\n }\n\n selectEntry(id: string): void {\n this.selectedEntryId = id;\n }\n\n deselectEntry(): void {\n this.selectedEntryId = null;\n }\n\n createEntry(): void {\n this.selectedEntryId = \"new\";\n }\n\n async deleteEntry(id: string): Promise<boolean> {\n const model = this.model;\n const result = await this.confirmation.confirm(TRASH_ENTRY_DIALOG, { entryId: id }, () =>\n this.deleteEntryUseCase.execute({ model, id })\n );\n return result !== false;\n }\n\n async publishEntry(id: string): Promise<boolean> {\n const model = this.model;\n const cache = this.cacheProvider.get(model.modelId);\n const entry = cache.getItem(item => item.id === id);\n if (!entry) {\n return false;\n }\n\n const result = await this.confirmation.confirm<{ revisionDescription: string }>(\n PUBLISH_ENTRY_DIALOG,\n { entry },\n async data => {\n if (data.revisionDescription) {\n await this.updateRevisionDescriptionUseCase.execute({\n model,\n id,\n revisionDescription: data.revisionDescription\n });\n }\n await this.publishEntryUseCase.execute({ model, revisionId: id });\n }\n );\n return result !== false;\n }\n\n async unpublishEntry(id: string): Promise<boolean> {\n const model = this.model;\n const result = await this.confirmation.confirm(\n UNPUBLISH_ENTRY_DIALOG,\n { entryId: id },\n () => this.unpublishEntryUseCase.execute({ model, revisionId: id })\n );\n return result !== false;\n }\n\n async moveEntry(id: string, folderId: string): Promise<boolean> {\n await this.moveEntryUseCase.execute({ model: this.model, id, folderId });\n return true;\n }\n\n dispose(): void {\n if (this.disposeReaction) {\n this.disposeReaction();\n this.disposeReaction = null;\n }\n }\n}\n\nexport const ContentEntriesPresenter = Abstraction.createImplementation({\n implementation: ContentEntriesPresenterImpl,\n dependencies: [\n ListPresenter,\n FolderTreePresenter,\n Confirmation,\n CmsModelContext,\n ListEntriesUseCase,\n DeleteEntryUseCase,\n PublishEntryUseCase,\n UnpublishEntryUseCase,\n MoveEntryUseCase,\n UpdateRevisionDescriptionUseCase,\n ContentEntriesCacheProvider,\n GetDescendantFoldersUseCase\n ]\n});\n"],"names":["TRASH_ENTRY_DIALOG","PUBLISH_ENTRY_DIALOG","UNPUBLISH_ENTRY_DIALOG","ContentEntriesPresenterImpl","listPresenter","foldersPresenter","confirmation","modelAccessor","listEntriesUseCase","deleteEntryUseCase","publishEntryUseCase","unpublishEntryUseCase","moveEntryUseCase","updateRevisionDescriptionUseCase","cacheProvider","getDescendantFoldersUseCase","makeAutoObservable","computed","appliedQuery","hasSearch","hasFilters","Object","k","showFolders","childFolders","sortFolders","config","initialFolderId","cache","dataSource","ContentEntriesDataSource","reaction","folderId","effectiveFolderId","id","model","result","entry","item","data","ContentEntriesPresenter","Abstraction","ListPresenter","FolderTreePresenter","Confirmation","CmsModelContext","ListEntriesUseCase","DeleteEntryUseCase","PublishEntryUseCase","UnpublishEntryUseCase","MoveEntryUseCase","UpdateRevisionDescriptionUseCase","ContentEntriesCacheProvider","GetDescendantFoldersUseCase"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"presentation/contentEntries/list/ContentEntriesPresenter.js","sources":["../../../../src/presentation/contentEntries/list/ContentEntriesPresenter.ts"],"sourcesContent":["import { computed, makeAutoObservable, reaction } from \"mobx\";\nimport type { IReactionDisposer } from \"mobx\";\nimport { ListPresenter } from \"@webiny/app-admin/presentation/listPresenter/abstractions.js\";\nimport { FolderTreePresenter } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\nimport { GetDescendantFoldersUseCase } from \"@webiny/app-aco/features/folders/getDescendantFolders/abstractions.js\";\nimport { sortFolders } from \"@webiny/app-aco\";\nimport { Confirmation } from \"@webiny/app-admin/features/confirmation/abstractions.js\";\nimport type { CmsContentEntry } from \"~/types.js\";\nimport { ListEntriesUseCase } from \"~/features/contentEntry/listEntries/abstractions.js\";\nimport { DeleteEntryUseCase } from \"~/features/contentEntry/deleteEntry/abstractions.js\";\nimport { PublishEntryUseCase } from \"~/features/contentEntry/publishEntry/abstractions.js\";\nimport { UnpublishEntryUseCase } from \"~/features/contentEntry/unpublishEntry/abstractions.js\";\nimport { MoveEntryUseCase } from \"~/features/contentEntry/moveEntry/abstractions.js\";\nimport { DuplicateEntryUseCase } from \"~/features/contentEntry/duplicateEntry/abstractions.js\";\nimport { UpdateRevisionDescriptionUseCase } from \"~/features/contentEntry/updateRevisionDescription/abstractions.js\";\nimport {\n ContentEntriesCacheProvider,\n CmsModelContext\n} from \"~/features/contentEntry/abstractions.js\";\nimport {\n ContentEntriesPresenter as Abstraction,\n type IContentEntriesViewModel,\n type IDuplicateEntryResult\n} from \"./abstractions.js\";\nimport { ContentEntriesDataSource } from \"./ContentEntriesDataSource.js\";\n\nexport const TRASH_ENTRY_DIALOG = \"trash-entry\";\nexport const PUBLISH_ENTRY_DIALOG = \"publish-entry\";\nexport const UNPUBLISH_ENTRY_DIALOG = \"unpublish-entry\";\nexport const DUPLICATE_ENTRY_DIALOG = \"duplicate-entry\";\n\nclass ContentEntriesPresenterImpl implements Abstraction.Interface {\n private selectedEntryId: string | null = null;\n private disposeReaction: IReactionDisposer | null = null;\n\n constructor(\n private listPresenter: ListPresenter.Interface<CmsContentEntry>,\n private foldersPresenter: FolderTreePresenter.Interface,\n private confirmation: Confirmation.Interface,\n private modelAccessor: CmsModelContext.Interface,\n private listEntriesUseCase: ListEntriesUseCase.Interface,\n private deleteEntryUseCase: DeleteEntryUseCase.Interface,\n private publishEntryUseCase: PublishEntryUseCase.Interface,\n private unpublishEntryUseCase: UnpublishEntryUseCase.Interface,\n private moveEntryUseCase: MoveEntryUseCase.Interface,\n private duplicateEntryUseCase: DuplicateEntryUseCase.Interface,\n private updateRevisionDescriptionUseCase: UpdateRevisionDescriptionUseCase.Interface,\n private cacheProvider: ContentEntriesCacheProvider.Interface,\n private getDescendantFoldersUseCase: GetDescendantFoldersUseCase.Interface\n ) {\n makeAutoObservable<\n ContentEntriesPresenterImpl,\n | \"disposeReaction\"\n | \"confirmation\"\n | \"modelAccessor\"\n | \"listEntriesUseCase\"\n | \"deleteEntryUseCase\"\n | \"publishEntryUseCase\"\n | \"unpublishEntryUseCase\"\n | \"moveEntryUseCase\"\n | \"duplicateEntryUseCase\"\n | \"updateRevisionDescriptionUseCase\"\n | \"cacheProvider\"\n | \"getDescendantFoldersUseCase\"\n >(this, {\n disposeReaction: false,\n confirmation: false,\n modelAccessor: false,\n listEntriesUseCase: false,\n deleteEntryUseCase: false,\n publishEntryUseCase: false,\n unpublishEntryUseCase: false,\n moveEntryUseCase: false,\n duplicateEntryUseCase: false,\n updateRevisionDescriptionUseCase: false,\n cacheProvider: false,\n getDescendantFoldersUseCase: false,\n vm: computed\n });\n }\n\n private get model() {\n return this.modelAccessor.getModel();\n }\n\n get vm(): IContentEntriesViewModel {\n const appliedQuery = this.listPresenter.vm.appliedQuery;\n const hasSearch = !!appliedQuery?.search;\n const hasFilters = Object.keys(this.listPresenter.vm.filters).some(k => k !== \"folderId\");\n const showFolders = !hasSearch && !hasFilters;\n\n const childFolders = showFolders\n ? sortFolders(this.foldersPresenter.vm.childFolders ?? [], appliedQuery?.sort)\n : [];\n\n return {\n model: this.model,\n selectedEntryId: this.selectedEntryId,\n showingEntry: this.selectedEntryId !== null,\n showFolders,\n childFolders\n };\n }\n\n init(config: Abstraction.InitConfig = {}): void {\n const initialFolderId = config.initialFolderId ?? \"root\";\n\n const cache = this.cacheProvider.get(this.model.modelId);\n const dataSource = new ContentEntriesDataSource(\n this.model,\n this.listEntriesUseCase,\n cache,\n this.getDescendantFoldersUseCase,\n config.filterNames\n );\n\n this.listPresenter.init({\n dataSource,\n initialSort: { field: \"savedOn\", direction: \"DESC\" },\n initialFilters: { folderId: initialFolderId },\n initialSearch: config.initialSearch,\n limit: 50,\n itemLabel: { singular: \"entry\", plural: \"entries\" }\n });\n\n if (initialFolderId !== \"root\") {\n this.foldersPresenter.selectFolder(initialFolderId);\n }\n\n this.disposeReaction = reaction(\n () => this.foldersPresenter.vm.currentFolderId,\n folderId => {\n const effectiveFolderId = folderId ?? \"root\";\n this.listPresenter.actions.filter.set(\"folderId\", effectiveFolderId);\n }\n );\n }\n\n get list(): ListPresenter.Interface<CmsContentEntry> {\n return this.listPresenter;\n }\n\n get folders(): FolderTreePresenter.Interface {\n return this.foldersPresenter;\n }\n\n selectEntry(id: string): void {\n this.selectedEntryId = id;\n }\n\n deselectEntry(): void {\n this.selectedEntryId = null;\n }\n\n createEntry(): void {\n this.selectedEntryId = \"new\";\n }\n\n async deleteEntry(id: string): Promise<boolean> {\n const model = this.model;\n const result = await this.confirmation.confirm(TRASH_ENTRY_DIALOG, { entryId: id }, () =>\n this.deleteEntryUseCase.execute({ model, id })\n );\n return result !== false;\n }\n\n async publishEntry(id: string): Promise<boolean> {\n const model = this.model;\n const cache = this.cacheProvider.get(model.modelId);\n const entry = cache.getItem(item => item.id === id);\n if (!entry) {\n return false;\n }\n\n const result = await this.confirmation.confirm<{ revisionDescription: string }>(\n PUBLISH_ENTRY_DIALOG,\n { entry },\n async data => {\n if (data.revisionDescription) {\n await this.updateRevisionDescriptionUseCase.execute({\n model,\n id,\n revisionDescription: data.revisionDescription\n });\n }\n await this.publishEntryUseCase.execute({ model, revisionId: id });\n }\n );\n return result !== false;\n }\n\n async unpublishEntry(id: string): Promise<boolean> {\n const model = this.model;\n const result = await this.confirmation.confirm(\n UNPUBLISH_ENTRY_DIALOG,\n { entryId: id },\n () => this.unpublishEntryUseCase.execute({ model, revisionId: id })\n );\n return result !== false;\n }\n\n async moveEntry(id: string, folderId: string): Promise<boolean> {\n await this.moveEntryUseCase.execute({ model: this.model, id, folderId });\n return true;\n }\n\n async duplicateEntry(entry: CmsContentEntry): Promise<IDuplicateEntryResult | false> {\n const model = this.model;\n return this.confirmation.confirm(\n DUPLICATE_ENTRY_DIALOG,\n { entry },\n async (): Promise<IDuplicateEntryResult> => {\n try {\n const duplicate = await this.duplicateEntryUseCase.execute({\n model,\n revisionId: entry.id\n });\n return { entry: duplicate };\n } catch (error) {\n return { error: error as Error };\n }\n }\n );\n }\n\n dispose(): void {\n if (this.disposeReaction) {\n this.disposeReaction();\n this.disposeReaction = null;\n }\n }\n}\n\nexport const ContentEntriesPresenter = Abstraction.createImplementation({\n implementation: ContentEntriesPresenterImpl,\n dependencies: [\n ListPresenter,\n FolderTreePresenter,\n Confirmation,\n CmsModelContext,\n ListEntriesUseCase,\n DeleteEntryUseCase,\n PublishEntryUseCase,\n UnpublishEntryUseCase,\n MoveEntryUseCase,\n DuplicateEntryUseCase,\n UpdateRevisionDescriptionUseCase,\n ContentEntriesCacheProvider,\n GetDescendantFoldersUseCase\n ]\n});\n"],"names":["TRASH_ENTRY_DIALOG","PUBLISH_ENTRY_DIALOG","UNPUBLISH_ENTRY_DIALOG","DUPLICATE_ENTRY_DIALOG","ContentEntriesPresenterImpl","listPresenter","foldersPresenter","confirmation","modelAccessor","listEntriesUseCase","deleteEntryUseCase","publishEntryUseCase","unpublishEntryUseCase","moveEntryUseCase","duplicateEntryUseCase","updateRevisionDescriptionUseCase","cacheProvider","getDescendantFoldersUseCase","makeAutoObservable","computed","appliedQuery","hasSearch","hasFilters","Object","k","showFolders","childFolders","sortFolders","config","initialFolderId","cache","dataSource","ContentEntriesDataSource","reaction","folderId","effectiveFolderId","id","model","result","entry","item","data","duplicate","error","ContentEntriesPresenter","Abstraction","ListPresenter","FolderTreePresenter","Confirmation","CmsModelContext","ListEntriesUseCase","DeleteEntryUseCase","PublishEntryUseCase","UnpublishEntryUseCase","MoveEntryUseCase","DuplicateEntryUseCase","UpdateRevisionDescriptionUseCase","ContentEntriesCacheProvider","GetDescendantFoldersUseCase"],"mappings":"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"}
|
|
@@ -13,12 +13,14 @@ import { DeleteEntryFeature } from "../../../features/contentEntry/deleteEntry/f
|
|
|
13
13
|
import { PublishEntryFeature } from "../../../features/contentEntry/publishEntry/feature.js";
|
|
14
14
|
import { UnpublishEntryFeature } from "../../../features/contentEntry/unpublishEntry/feature.js";
|
|
15
15
|
import { MoveEntryFeature } from "../../../features/contentEntry/moveEntry/feature.js";
|
|
16
|
+
import { DuplicateEntryFeature } from "../../../features/contentEntry/duplicateEntry/feature.js";
|
|
16
17
|
import { UpdateRevisionDescriptionFeature } from "../../../features/contentEntry/updateRevisionDescription/feature.js";
|
|
17
18
|
import { ListEntriesGateway } from "../../../features/contentEntry/listEntries/abstractions.js";
|
|
18
19
|
import { DeleteEntryGateway } from "../../../features/contentEntry/deleteEntry/abstractions.js";
|
|
19
20
|
import { PublishEntryGateway, PublishEntryUseCase } from "../../../features/contentEntry/publishEntry/abstractions.js";
|
|
20
21
|
import { UnpublishEntryGateway } from "../../../features/contentEntry/unpublishEntry/abstractions.js";
|
|
21
22
|
import { MoveEntryGateway } from "../../../features/contentEntry/moveEntry/abstractions.js";
|
|
23
|
+
import { DuplicateEntryGateway } from "../../../features/contentEntry/duplicateEntry/abstractions.js";
|
|
22
24
|
import { UpdateRevisionDescriptionGateway } from "../../../features/contentEntry/updateRevisionDescription/abstractions.js";
|
|
23
25
|
import { EventPublisher } from "@webiny/app/features/eventPublisher/index.js";
|
|
24
26
|
import { ContentEntriesPresenter } from "./abstractions.js";
|
|
@@ -112,7 +114,7 @@ function setup() {
|
|
|
112
114
|
container.registerInstance(FolderTreePresenter, foldersPresenter);
|
|
113
115
|
container.registerInstance(Confirmation, {
|
|
114
116
|
confirm: vi.fn(async (_name, _params, execute)=>{
|
|
115
|
-
if (execute) await execute(void 0);
|
|
117
|
+
if (execute) return await execute(void 0);
|
|
116
118
|
return true;
|
|
117
119
|
})
|
|
118
120
|
});
|
|
@@ -131,6 +133,7 @@ function setup() {
|
|
|
131
133
|
PublishEntryFeature.register(container);
|
|
132
134
|
UnpublishEntryFeature.register(container);
|
|
133
135
|
MoveEntryFeature.register(container);
|
|
136
|
+
DuplicateEntryFeature.register(container);
|
|
134
137
|
UpdateRevisionDescriptionFeature.register(container);
|
|
135
138
|
const listEntriesGateway = {
|
|
136
139
|
execute: vi.fn()
|
|
@@ -144,6 +147,10 @@ function setup() {
|
|
|
144
147
|
container.registerInstance(ListEntriesGateway, listEntriesGateway);
|
|
145
148
|
container.registerInstance(MoveEntryGateway, moveEntryGateway);
|
|
146
149
|
container.registerInstance(DeleteEntryGateway, deleteEntryGateway);
|
|
150
|
+
const duplicateEntryGateway = {
|
|
151
|
+
execute: vi.fn()
|
|
152
|
+
};
|
|
153
|
+
container.registerInstance(DuplicateEntryGateway, duplicateEntryGateway);
|
|
147
154
|
const publishEntryGateway = {
|
|
148
155
|
execute: vi.fn()
|
|
149
156
|
};
|
|
@@ -161,6 +168,7 @@ function setup() {
|
|
|
161
168
|
listEntriesGateway,
|
|
162
169
|
moveEntryGateway,
|
|
163
170
|
deleteEntryGateway,
|
|
171
|
+
duplicateEntryGateway,
|
|
164
172
|
getDescendantFolders,
|
|
165
173
|
foldersPresenter,
|
|
166
174
|
publishEntryGateway,
|
|
@@ -517,6 +525,55 @@ describe("ContentEntriesPresenter", ()=>{
|
|
|
517
525
|
});
|
|
518
526
|
});
|
|
519
527
|
});
|
|
528
|
+
describe("duplicate entry", ()=>{
|
|
529
|
+
it("should add the duplicated entry to the current view", async ()=>{
|
|
530
|
+
const entries = [
|
|
531
|
+
createEntry("entry-2", "root", {
|
|
532
|
+
savedOn: "2024-01-02T00:00:00.000Z"
|
|
533
|
+
}),
|
|
534
|
+
createEntry("entry-1", "root", {
|
|
535
|
+
savedOn: "2024-01-01T00:00:00.000Z"
|
|
536
|
+
})
|
|
537
|
+
];
|
|
538
|
+
await initPresenter(t, {
|
|
539
|
+
data: entries
|
|
540
|
+
});
|
|
541
|
+
const duplicate = createEntry("entry-3", "root", {
|
|
542
|
+
savedOn: "2024-01-03T00:00:00.000Z"
|
|
543
|
+
});
|
|
544
|
+
t.duplicateEntryGateway.execute.mockResolvedValueOnce(duplicate);
|
|
545
|
+
const result = await t.presenter.duplicateEntry(entries[1]);
|
|
546
|
+
expect(result).toEqual({
|
|
547
|
+
entry: duplicate
|
|
548
|
+
});
|
|
549
|
+
expect(t.duplicateEntryGateway.execute).toHaveBeenCalledWith({
|
|
550
|
+
model: MODEL,
|
|
551
|
+
revisionId: "entry-1#0001"
|
|
552
|
+
});
|
|
553
|
+
await vi.waitFor(()=>{
|
|
554
|
+
expect(t.presenter.list.vm.rows.map((r)=>r.entryId)).toEqual([
|
|
555
|
+
"entry-3",
|
|
556
|
+
"entry-2",
|
|
557
|
+
"entry-1"
|
|
558
|
+
]);
|
|
559
|
+
});
|
|
560
|
+
});
|
|
561
|
+
it("should return the error when duplication fails", async ()=>{
|
|
562
|
+
const entries = [
|
|
563
|
+
createEntry("entry-1", "root")
|
|
564
|
+
];
|
|
565
|
+
await initPresenter(t, {
|
|
566
|
+
data: entries
|
|
567
|
+
});
|
|
568
|
+
const error = new Error("Not allowed.");
|
|
569
|
+
t.duplicateEntryGateway.execute.mockRejectedValueOnce(error);
|
|
570
|
+
const result = await t.presenter.duplicateEntry(entries[0]);
|
|
571
|
+
expect(result).toEqual({
|
|
572
|
+
error
|
|
573
|
+
});
|
|
574
|
+
expect(t.presenter.list.vm.rows).toHaveLength(1);
|
|
575
|
+
});
|
|
576
|
+
});
|
|
520
577
|
describe("delete entry", ()=>{
|
|
521
578
|
it("should remove entry from current view after delete", async ()=>{
|
|
522
579
|
const entries = [
|