slice-machine-ui 1.22.2 → 1.22.3-alpha.chore-introduce-css-modules.1
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/.depcheckrc +4 -1
- package/.eslintignore +1 -0
- package/components/DeleteVariationModal/index.tsx +12 -11
- package/components/Forms/CreateSliceModal/CreateSliceModal.tsx +2 -5
- package/components/Forms/RenameCustomTypeModal/RenameCustomTypeModal.tsx +9 -5
- package/components/Forms/RenameVariationModal/RenameVariationModal.tsx +12 -11
- package/components/ItemHeader/index.tsx +1 -0
- package/components/ListItem/index.tsx +5 -2
- package/components/ScreenshotChangesModal/VariationDropZone.tsx +31 -9
- package/components/ScreenshotChangesModal/index.tsx +3 -0
- package/components/ScreenshotChangesModal/useCustomScreenshot.tsx +5 -5
- package/components/Simulator/index.tsx +9 -3
- package/lib/builders/CustomTypeBuilder/SliceZone/SlicesTemplatesModal.tsx +2 -2
- package/lib/builders/CustomTypeBuilder/SliceZone/UpdateSliceZoneModal.tsx +2 -2
- package/lib/builders/CustomTypeBuilder/SliceZone/index.tsx +12 -20
- package/lib/builders/CustomTypeBuilder/TabModal/update.tsx +3 -1
- package/lib/builders/CustomTypeBuilder/TabZone/index.tsx +119 -52
- package/lib/builders/CustomTypeBuilder/index.tsx +39 -42
- package/lib/builders/SliceBuilder/FieldZones/index.tsx +81 -56
- package/lib/builders/SliceBuilder/Sidebar/AddVariationModal.tsx +24 -16
- package/lib/builders/SliceBuilder/Sidebar/index.tsx +44 -46
- package/lib/builders/SliceBuilder/SimulatorButton/index.tsx +4 -28
- package/lib/builders/SliceBuilder/index.tsx +10 -96
- package/lib/builders/common/Zone/Card/components/Hints/CodeBlock.tsx +5 -1
- package/lib/builders/common/Zone/Card/components/NewField.tsx +16 -15
- package/lib/builders/common/Zone/Card/index.jsx +2 -0
- package/lib/builders/common/Zone/index.jsx +3 -1
- package/lib/models/common/ComponentUI.ts +0 -14
- package/lib/models/common/CustomType/sliceZone.ts +0 -29
- package/lib/models/common/CustomType/tab.ts +10 -142
- package/lib/models/common/widgets/Group/ListItem/index.jsx +61 -23
- package/out/404.html +1 -1
- package/out/_next/static/QLcban0JdGEoFu6NgapR9/_buildManifest.js +1 -0
- package/out/_next/static/chunks/065a3ddb-9a38ca0d60f0bf2f.js +1 -0
- package/out/_next/static/chunks/183-4feb6bb3eddbc768.js +1 -0
- package/out/_next/static/chunks/18539003-7b2711e6c51d6fac.js +97 -0
- package/out/_next/static/chunks/1cc2734a-2c5b6c0367fcde86.js +1 -0
- package/out/_next/static/chunks/25-8fedd33ad9b6de5b.js +1 -0
- package/out/_next/static/chunks/286-ed90373e9a469944.js +1 -0
- package/out/_next/static/chunks/318-541db69860d31138.js +1 -0
- package/out/_next/static/chunks/{505-3f1cf09a086dcba8.js → 376-0ed5822f8afcaa7c.js} +3 -3
- package/out/_next/static/chunks/4c744e84-e3161d754618373f.js +1 -0
- package/out/_next/static/chunks/50-cfc2514205b86001.js +1 -0
- package/out/_next/static/chunks/543-f8766685f7f451e2.js +1 -0
- package/out/_next/static/chunks/59b4e022-7a3b5554b806349f.js +1 -0
- package/out/_next/static/chunks/696-b12edad30a3617e5.js +31 -0
- package/out/_next/static/chunks/727-15cf3f2fea9a37e5.js +1 -0
- package/out/_next/static/chunks/731-501990ebe6a71b32.js +1 -0
- package/out/_next/static/chunks/904-ccd8ca3368ce29fc.js +1 -0
- package/out/_next/static/chunks/{918-38d08f1e885b222d.js → 918-5bb55fb464e34768.js} +1 -1
- package/out/_next/static/chunks/f36c6662-03bb5e9d9aa0b0aa.js +1 -0
- package/out/_next/static/chunks/pages/_app-3bb7f58b43c87166.js +430 -0
- package/out/_next/static/chunks/pages/changelog-68d115a14f1423d7.js +1 -0
- package/out/_next/static/chunks/pages/{changes-52c9d917808d1461.js → changes-1cf9e7888029f113.js} +1 -1
- package/out/_next/static/chunks/pages/custom-types/{[customTypeId]-3a37eb3373bb8823.js → [customTypeId]-3f862ad6111a1fc0.js} +1 -1
- package/out/_next/static/chunks/pages/{custom-types-2f5664d9492b13fb.js → custom-types-94b8f8dbf7727412.js} +1 -1
- package/out/_next/static/chunks/pages/{index-d8e3a2c0d712904f.js → index-64cfb8b0948ba8ef.js} +1 -1
- package/out/_next/static/chunks/pages/page-types/{[pageTypeId]-733f3890c0466a05.js → [pageTypeId]-d1ffca11c42f2603.js} +1 -1
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/simulator-897ca93c114a1435.js +1 -0
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-73dd999915509965.js +1 -0
- package/out/_next/static/chunks/pages/slices-7b09cb5130c63bb3.js +1 -0
- package/out/_next/static/css/37153180c3b0dd66.css +1 -0
- package/out/_next/static/css/538ecf581b0e7c11.css +1 -0
- package/out/_next/static/css/{5da5d3cd7a87c3cf.css → 72465cc1225f28a2.css} +1 -1
- package/out/_next/static/css/{77abb01eee0e43a7.css → b22c0750c14cc089.css} +1 -1
- package/out/_next/static/css/f8eb526e10bc2441.css +1 -0
- package/out/changelog.html +1 -1
- package/out/changes.html +1 -1
- package/out/custom-types/[customTypeId].html +1 -1
- package/out/custom-types.html +1 -1
- package/out/index.html +1 -1
- package/out/labs.html +1 -1
- package/out/page-types/[pageTypeId].html +1 -1
- package/out/slices/[lib]/[sliceName]/[variation]/simulator.html +1 -1
- package/out/slices/[lib]/[sliceName]/[variation].html +1 -1
- package/out/slices.html +1 -1
- package/package.json +21 -11
- package/pages/slices/[lib]/[sliceName]/[variation]/index.tsx +25 -11
- package/pages/slices/[lib]/[sliceName]/[variation]/simulator.tsx +12 -9
- package/src/apiClient.ts +7 -6
- package/src/components/CodeBlock/CodeBlock.tsx +1 -0
- package/src/components/Kbd/Kbd.module.css +10 -0
- package/src/components/Kbd/Kbd.module.css.d.ts +5 -0
- package/src/components/Kbd/Kbd.tsx +1 -1
- package/src/components/Window/Window.tsx +7 -1
- package/src/domain/__tests__/customType.test.ts +785 -0
- package/src/domain/customType.ts +519 -6
- package/src/domain/slice.ts +166 -1
- package/src/features/autoSave/AutoSaveStatusIndicator.tsx +43 -0
- package/src/features/autoSave/useAutoSave.tsx +177 -0
- package/src/features/customTypes/EditDropdown.tsx +3 -0
- package/src/features/customTypes/actions/convertCustomToPageType.ts +2 -4
- package/src/features/customTypes/customTypesBuilder/CustomTypeProvider.tsx +90 -0
- package/src/features/customTypes/customTypesBuilder/CustomTypesBuilderPage.tsx +46 -79
- package/src/features/customTypes/customTypesMessages.ts +4 -0
- package/src/features/slices/actions/addSlicesToSliceZone.ts +2 -7
- package/src/features/slices/actions/uploadSliceScreenshot.ts +45 -0
- package/src/features/slices/convertLegacySlice/ConvertLegacySliceAsNewVariationDialog.tsx +5 -5
- package/src/features/slices/convertLegacySlice/ConvertLegacySliceButton.tsx +4 -10
- package/src/features/slices/sliceBuilder/SliceBuilderProvider.tsx +110 -0
- package/src/features/slices/sliceBuilder/actions/deleteVariation.ts +8 -24
- package/src/features/slices/sliceBuilder/actions/renameVariation.ts +8 -24
- package/src/features/slices/sliceCards/SharedSliceCard.tsx +1 -0
- package/src/hooks/useCurrentSlice.tsx +4 -16
- package/src/hooks/useScreenshotChangesModal.ts +1 -0
- package/src/hooks/useServerState.ts +1 -58
- package/src/modules/availableCustomTypes/index.ts +8 -3
- package/src/modules/simulator/index.ts +0 -2
- package/src/modules/slices/index.ts +32 -25
- package/src/modules/slices/selector.ts +30 -0
- package/src/modules/useSliceMachineActions.ts +20 -270
- package/src/redux/reducer.ts +0 -4
- package/src/redux/saga.ts +0 -6
- package/src/redux/type.ts +0 -4
- package/stylelint.config.js +17 -0
- package/test/src/modules/availableCustomTypes/index.test.ts +8 -10
- package/test/src/modules/simulator.test.ts +0 -2
- package/lib/models/common/CustomType/group.ts +0 -80
- package/lib/models/common/Variation.ts +0 -100
- package/out/_next/static/3vLhj_JZ10e4rwC2sTZNQ/_buildManifest.js +0 -1
- package/out/_next/static/chunks/18539003-4460ccbfe3109578.js +0 -97
- package/out/_next/static/chunks/482-49264466566eac99.js +0 -1
- package/out/_next/static/chunks/550-c80fd46fb64d1eef.js +0 -1
- package/out/_next/static/chunks/80-7b8a97d0122ff74a.js +0 -1
- package/out/_next/static/chunks/840-163f8a1040e6820d.js +0 -1
- package/out/_next/static/chunks/904-fe1af089657fb0cc.js +0 -1
- package/out/_next/static/chunks/958-3d829456f4f5632c.js +0 -1
- package/out/_next/static/chunks/pages/_app-f88a66f6532a8e87.js +0 -458
- package/out/_next/static/chunks/pages/changelog-4d0f2f1222e403fe.js +0 -1
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/simulator-7b17cb59d0db03b5.js +0 -1
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-ef11594ce026b650.js +0 -1
- package/out/_next/static/chunks/pages/slices-884a936a9a062a65.js +0 -1
- package/out/_next/static/css/1bbf650dfd37ce69.css +0 -1
- package/out/_next/static/css/7d650bca12dc4061.css +0 -1
- package/out/_next/static/css/cb33580e45d01b59.css +0 -1
- package/postcss.config.js +0 -2
- package/src/components/Kbd/Kbd.css.ts +0 -16
- package/src/domain/__tests__/CustomTypeModel.test.ts +0 -247
- package/src/layouts/WithSlice.tsx +0 -26
- package/src/modules/screenshots/actions.ts +0 -21
- package/src/modules/screenshots/sagas.ts +0 -70
- package/src/modules/selectedCustomType/actions.ts +0 -147
- package/src/modules/selectedCustomType/index.ts +0 -11
- package/src/modules/selectedCustomType/reducer.ts +0 -287
- package/src/modules/selectedCustomType/sagas.ts +0 -72
- package/src/modules/selectedCustomType/selectors.ts +0 -33
- package/src/modules/selectedCustomType/stateHelpers.ts +0 -42
- package/src/modules/selectedCustomType/types.ts +0 -9
- package/src/modules/selectedSlice/actions.ts +0 -106
- package/src/modules/selectedSlice/reducer.ts +0 -175
- package/src/modules/selectedSlice/sagas.ts +0 -72
- package/src/modules/selectedSlice/selectors.ts +0 -55
- package/src/modules/selectedSlice/types.ts +0 -3
- package/src/modules/toaster/utils.tsx +0 -23
- package/test/lib/models/common/CustomType/sliceZone.test.ts +0 -49
- package/test/pages/custom-types.test.tsx +0 -625
- package/test/src/modules/selectedCustomType/__fixtures__/model.json +0 -119
- package/test/src/modules/selectedCustomType/reducer.test.ts +0 -322
- package/test/src/modules/selectedCustomType/sagas.test.ts +0 -89
- package/test/src/modules/selectedCustomType/selectors.test.ts +0 -54
- package/test/src/modules/selectedSlice/__fixtures__/mocks.json +0 -171
- package/test/src/modules/selectedSlice/__fixtures__/model.json +0 -35
- package/test/src/modules/selectedSlice/__testutils__/getRefreshStateCreatorPayloadData.ts +0 -72
- package/test/src/modules/selectedSlice/__testutils__/getSelectedSliceDummyData.ts +0 -30
- package/test/src/modules/selectedSlice/reducer.test.ts +0 -170
- package/test/src/modules/selectedSlice/sagas.test.ts +0 -82
- package/test/src/modules/toaster/utils.test.ts +0 -50
- /package/out/_next/static/{3vLhj_JZ10e4rwC2sTZNQ → QLcban0JdGEoFu6NgapR9}/_ssgManifest.js +0 -0
package/src/domain/slice.ts
CHANGED
|
@@ -2,9 +2,49 @@ import type {
|
|
|
2
2
|
CompositeSlice,
|
|
3
3
|
LegacySlice,
|
|
4
4
|
} from "@prismicio/types-internal/lib/customtypes/widgets/slices";
|
|
5
|
+
import { NestableWidget } from "@prismicio/types-internal/lib/customtypes";
|
|
5
6
|
|
|
6
7
|
import type { ComponentUI } from "@lib/models/common/ComponentUI";
|
|
7
|
-
import type { VariationSM } from "@lib/models/common/Slice";
|
|
8
|
+
import type { VariationSM, WidgetsArea } from "@lib/models/common/Slice";
|
|
9
|
+
|
|
10
|
+
type CopySliceVariationArgs = {
|
|
11
|
+
copiedVariation: VariationSM;
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
slice: ComponentUI;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type DeleteFieldArgs = {
|
|
18
|
+
slice: ComponentUI;
|
|
19
|
+
variationId: string;
|
|
20
|
+
widgetArea: WidgetsArea;
|
|
21
|
+
fieldId: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type UpdateFieldArgs = {
|
|
25
|
+
slice: ComponentUI;
|
|
26
|
+
variationId: string;
|
|
27
|
+
widgetArea: WidgetsArea;
|
|
28
|
+
previousFieldId: string;
|
|
29
|
+
newFieldId: string;
|
|
30
|
+
newField: NestableWidget;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type AddFieldArgs = {
|
|
34
|
+
slice: ComponentUI;
|
|
35
|
+
variationId: string;
|
|
36
|
+
widgetArea: WidgetsArea;
|
|
37
|
+
newFieldId: string;
|
|
38
|
+
newField: NestableWidget;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
type ReorderFieldArgs = {
|
|
42
|
+
slice: ComponentUI;
|
|
43
|
+
variationId: string;
|
|
44
|
+
widgetArea: WidgetsArea;
|
|
45
|
+
sourceIndex: number;
|
|
46
|
+
destinationIndex: number;
|
|
47
|
+
};
|
|
8
48
|
|
|
9
49
|
export function countMissingScreenshots(slice: ComponentUI): number {
|
|
10
50
|
return slice.model.variations.length - Object.keys(slice.screenshots).length;
|
|
@@ -78,3 +118,128 @@ export function getFieldMappingFingerprint(
|
|
|
78
118
|
),
|
|
79
119
|
};
|
|
80
120
|
}
|
|
121
|
+
|
|
122
|
+
export function copySliceVariation(args: CopySliceVariationArgs) {
|
|
123
|
+
const { slice, id, name, copiedVariation } = args;
|
|
124
|
+
const newVariation = { ...copiedVariation, id, name };
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
slice: {
|
|
128
|
+
...slice,
|
|
129
|
+
model: {
|
|
130
|
+
...slice.model,
|
|
131
|
+
variations: slice.model.variations.concat([newVariation]),
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
variation: newVariation,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function deleteField(args: DeleteFieldArgs): ComponentUI {
|
|
139
|
+
const { slice, variationId, widgetArea, fieldId } = args;
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
...slice,
|
|
143
|
+
model: {
|
|
144
|
+
...slice.model,
|
|
145
|
+
variations: slice.model.variations.map((v) => {
|
|
146
|
+
if (v.id === variationId) {
|
|
147
|
+
return {
|
|
148
|
+
...v,
|
|
149
|
+
[widgetArea]: v[widgetArea]?.filter((w) => w.key !== fieldId),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
return v;
|
|
153
|
+
}),
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function updateField(args: UpdateFieldArgs): ComponentUI {
|
|
159
|
+
const {
|
|
160
|
+
slice,
|
|
161
|
+
variationId,
|
|
162
|
+
widgetArea,
|
|
163
|
+
previousFieldId,
|
|
164
|
+
newFieldId,
|
|
165
|
+
newField,
|
|
166
|
+
} = args;
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
...slice,
|
|
170
|
+
model: {
|
|
171
|
+
...slice.model,
|
|
172
|
+
variations: slice.model.variations.map((v) => {
|
|
173
|
+
if (v.id === variationId) {
|
|
174
|
+
return {
|
|
175
|
+
...v,
|
|
176
|
+
[widgetArea]: v[widgetArea]?.map((w) => {
|
|
177
|
+
if (w.key === previousFieldId) {
|
|
178
|
+
return {
|
|
179
|
+
key: newFieldId,
|
|
180
|
+
value: newField,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
return w;
|
|
184
|
+
}),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
return v;
|
|
188
|
+
}),
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function addField(args: AddFieldArgs): ComponentUI {
|
|
194
|
+
const { slice, variationId, widgetArea, newFieldId, newField } = args;
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
...slice,
|
|
198
|
+
model: {
|
|
199
|
+
...slice.model,
|
|
200
|
+
variations: slice.model.variations.map((v) => {
|
|
201
|
+
if (v.id === variationId) {
|
|
202
|
+
return {
|
|
203
|
+
...v,
|
|
204
|
+
[widgetArea]: v[widgetArea]?.concat([
|
|
205
|
+
{
|
|
206
|
+
key: newFieldId,
|
|
207
|
+
value: newField,
|
|
208
|
+
},
|
|
209
|
+
]),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
return v;
|
|
213
|
+
}),
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function reorderField(args: ReorderFieldArgs): ComponentUI {
|
|
219
|
+
const { slice, variationId, widgetArea, sourceIndex, destinationIndex } =
|
|
220
|
+
args;
|
|
221
|
+
|
|
222
|
+
const fields =
|
|
223
|
+
slice.model.variations.find((v) => v.id === variationId)?.[widgetArea] ??
|
|
224
|
+
[];
|
|
225
|
+
|
|
226
|
+
const reorderedFields = [...fields];
|
|
227
|
+
const [removedField] = reorderedFields.splice(sourceIndex, 1);
|
|
228
|
+
reorderedFields.splice(destinationIndex, 0, removedField);
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
...slice,
|
|
232
|
+
model: {
|
|
233
|
+
...slice.model,
|
|
234
|
+
variations: slice.model.variations.map((v) => {
|
|
235
|
+
if (v.id === variationId) {
|
|
236
|
+
return {
|
|
237
|
+
...v,
|
|
238
|
+
[widgetArea]: reorderedFields,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
return v;
|
|
242
|
+
}),
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { Box, Icon, ProgressCircle, Text } from "@prismicio/editor-ui";
|
|
3
|
+
|
|
4
|
+
import { AutoSaveStatus } from "./useAutoSave";
|
|
5
|
+
|
|
6
|
+
type AutoSaveStatusIndicatorProps = {
|
|
7
|
+
status: AutoSaveStatus;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const AutoSaveStatusIndicator: FC<AutoSaveStatusIndicatorProps> = (
|
|
11
|
+
props,
|
|
12
|
+
) => {
|
|
13
|
+
const { status } = props;
|
|
14
|
+
let autoSaveStatusInfo;
|
|
15
|
+
|
|
16
|
+
switch (status) {
|
|
17
|
+
case "saving":
|
|
18
|
+
autoSaveStatusInfo = {
|
|
19
|
+
icon: <ProgressCircle color="grey11" />,
|
|
20
|
+
text: "Saving...",
|
|
21
|
+
};
|
|
22
|
+
break;
|
|
23
|
+
case "failed":
|
|
24
|
+
autoSaveStatusInfo = {
|
|
25
|
+
icon: <Icon name="close" color="tomato11" size="medium" />,
|
|
26
|
+
text: "Failed to save",
|
|
27
|
+
};
|
|
28
|
+
break;
|
|
29
|
+
case "saved":
|
|
30
|
+
autoSaveStatusInfo = {
|
|
31
|
+
icon: <Icon name="check" color="green11" size="medium" />,
|
|
32
|
+
text: "Auto-saved",
|
|
33
|
+
};
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Box gap={8} alignItems="center">
|
|
39
|
+
{autoSaveStatusInfo.icon}
|
|
40
|
+
<Text color="grey11">{autoSaveStatusInfo.text}</Text>
|
|
41
|
+
</Box>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useCallback,
|
|
3
|
+
useState,
|
|
4
|
+
useEffect,
|
|
5
|
+
SetStateAction,
|
|
6
|
+
Dispatch,
|
|
7
|
+
useMemo,
|
|
8
|
+
} from "react";
|
|
9
|
+
import { uniqueId } from "lodash";
|
|
10
|
+
import { toast } from "react-toastify";
|
|
11
|
+
import { Box, Button, Text } from "@prismicio/editor-ui";
|
|
12
|
+
|
|
13
|
+
export type AutoSaveStatus = "saving" | "saved" | "failed";
|
|
14
|
+
|
|
15
|
+
type UseAutoSaveArgs = {
|
|
16
|
+
autoSaveStatusDelay?: number;
|
|
17
|
+
errorMessage?: string;
|
|
18
|
+
retryDelay?: number;
|
|
19
|
+
retryMessage?: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type UseAutoSaveReturnType = {
|
|
23
|
+
autoSaveStatus: AutoSaveStatus;
|
|
24
|
+
setNextSave: (nextSave: NextSave) => void;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type AutoSaveStack = {
|
|
28
|
+
pendingSave: NextSave | undefined;
|
|
29
|
+
nextSave: NextSave | undefined;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type NextSave = () => Promise<unknown>;
|
|
33
|
+
|
|
34
|
+
export const useAutoSave = (
|
|
35
|
+
args: UseAutoSaveArgs = {},
|
|
36
|
+
): UseAutoSaveReturnType => {
|
|
37
|
+
const {
|
|
38
|
+
autoSaveStatusDelay = 300,
|
|
39
|
+
errorMessage = "An error happened while saving",
|
|
40
|
+
retryDelay = 1000,
|
|
41
|
+
retryMessage = "Retry",
|
|
42
|
+
} = args;
|
|
43
|
+
|
|
44
|
+
const [autoSaveStack, setAutoSaveStack] = useState<AutoSaveStack>({
|
|
45
|
+
pendingSave: undefined,
|
|
46
|
+
nextSave: undefined,
|
|
47
|
+
});
|
|
48
|
+
const [autoSaveStatusActual, setAutoSaveStatusActual] =
|
|
49
|
+
useState<AutoSaveStatus>("saved");
|
|
50
|
+
const [autoSaveStatusDelayed, setAutoSaveStatusDelayed] =
|
|
51
|
+
useState<AutoSaveStatus>(autoSaveStatusActual);
|
|
52
|
+
|
|
53
|
+
const setNextSave = useCallback((nextSave: NextSave) => {
|
|
54
|
+
setAutoSaveStack((prevState) => ({
|
|
55
|
+
...prevState,
|
|
56
|
+
nextSave,
|
|
57
|
+
}));
|
|
58
|
+
}, []);
|
|
59
|
+
|
|
60
|
+
const executeSave = useCallback(
|
|
61
|
+
async (nextSave?: NextSave) => {
|
|
62
|
+
if (nextSave) {
|
|
63
|
+
setAutoSaveStatusActual("saving");
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
await nextSave();
|
|
67
|
+
|
|
68
|
+
setAutoSaveStatusActual("saved");
|
|
69
|
+
} catch (error) {
|
|
70
|
+
setAutoSaveStatusActual("failed");
|
|
71
|
+
console.error(errorMessage, error);
|
|
72
|
+
|
|
73
|
+
toastError({
|
|
74
|
+
errorMessage,
|
|
75
|
+
retryDelay,
|
|
76
|
+
retryMessage,
|
|
77
|
+
setAutoSaveStatusActual,
|
|
78
|
+
setAutoSaveStack,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
[errorMessage, retryDelay, retryMessage],
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (autoSaveStatusActual === "saved" && autoSaveStack.nextSave) {
|
|
88
|
+
void executeSave(autoSaveStack.nextSave);
|
|
89
|
+
|
|
90
|
+
setAutoSaveStack({
|
|
91
|
+
pendingSave: autoSaveStack.nextSave,
|
|
92
|
+
nextSave: undefined,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}, [autoSaveStatusActual, autoSaveStack, executeSave]);
|
|
96
|
+
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (autoSaveStatusActual === "saving") {
|
|
99
|
+
setAutoSaveStatusDelayed("saving");
|
|
100
|
+
} else {
|
|
101
|
+
const debounceTimeout = setTimeout(() => {
|
|
102
|
+
setAutoSaveStatusDelayed(autoSaveStatusActual);
|
|
103
|
+
}, autoSaveStatusDelay);
|
|
104
|
+
|
|
105
|
+
return () => {
|
|
106
|
+
clearTimeout(debounceTimeout);
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return;
|
|
111
|
+
}, [autoSaveStatusActual, autoSaveStatusDelay]);
|
|
112
|
+
|
|
113
|
+
return useMemo(
|
|
114
|
+
() => ({
|
|
115
|
+
autoSaveStatus: autoSaveStatusDelayed,
|
|
116
|
+
setNextSave,
|
|
117
|
+
}),
|
|
118
|
+
[autoSaveStatusDelayed, setNextSave],
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
type ToastErrorArgs = {
|
|
123
|
+
errorMessage: string;
|
|
124
|
+
retryDelay: number;
|
|
125
|
+
retryMessage: string;
|
|
126
|
+
setAutoSaveStatusActual: Dispatch<SetStateAction<AutoSaveStatus>>;
|
|
127
|
+
setAutoSaveStack: Dispatch<SetStateAction<AutoSaveStack>>;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
function toastError(args: ToastErrorArgs) {
|
|
131
|
+
const {
|
|
132
|
+
errorMessage,
|
|
133
|
+
retryDelay,
|
|
134
|
+
retryMessage,
|
|
135
|
+
setAutoSaveStatusActual,
|
|
136
|
+
setAutoSaveStack,
|
|
137
|
+
} = args;
|
|
138
|
+
const toastId = uniqueId();
|
|
139
|
+
|
|
140
|
+
toast.error(
|
|
141
|
+
() => (
|
|
142
|
+
<Box gap={8} alignItems="center">
|
|
143
|
+
<Text color="grey1" variant="small">
|
|
144
|
+
{errorMessage}
|
|
145
|
+
</Text>
|
|
146
|
+
<Button
|
|
147
|
+
size="small"
|
|
148
|
+
color="grey"
|
|
149
|
+
onClick={() => {
|
|
150
|
+
toast.dismiss(toastId);
|
|
151
|
+
|
|
152
|
+
// Ensure saving is directly propagated before waiting for the retry
|
|
153
|
+
setAutoSaveStatusActual("saving");
|
|
154
|
+
|
|
155
|
+
setTimeout(() => {
|
|
156
|
+
// By setting the status to saved, the save effect will be triggered
|
|
157
|
+
// with the latest data to save.
|
|
158
|
+
setAutoSaveStatusActual("saved");
|
|
159
|
+
setAutoSaveStack((prevState) => ({
|
|
160
|
+
nextSave: prevState.nextSave ?? prevState.pendingSave,
|
|
161
|
+
pendingSave: undefined,
|
|
162
|
+
}));
|
|
163
|
+
}, retryDelay);
|
|
164
|
+
}}
|
|
165
|
+
>
|
|
166
|
+
{retryMessage}
|
|
167
|
+
</Button>
|
|
168
|
+
</Box>
|
|
169
|
+
),
|
|
170
|
+
{
|
|
171
|
+
autoClose: false,
|
|
172
|
+
closeOnClick: false,
|
|
173
|
+
draggable: false,
|
|
174
|
+
toastId,
|
|
175
|
+
},
|
|
176
|
+
);
|
|
177
|
+
}
|
|
@@ -25,12 +25,14 @@ type EditDropdownProps = {
|
|
|
25
25
|
isChangesLocal: boolean;
|
|
26
26
|
format: CustomTypeFormat;
|
|
27
27
|
customType: CustomType;
|
|
28
|
+
setLocalCustomType?: (customType: CustomType) => void;
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
export const EditDropdown: FC<EditDropdownProps> = ({
|
|
31
32
|
format,
|
|
32
33
|
customType,
|
|
33
34
|
isChangesLocal,
|
|
35
|
+
setLocalCustomType,
|
|
34
36
|
}) => {
|
|
35
37
|
const router = useRouter();
|
|
36
38
|
const { saveCustomTypeSuccess } = useSliceMachineActions();
|
|
@@ -123,6 +125,7 @@ export const EditDropdown: FC<EditDropdownProps> = ({
|
|
|
123
125
|
customType={customType}
|
|
124
126
|
isChangesLocal={isChangesLocal}
|
|
125
127
|
onClose={() => setIsRenameCustomTypeModalOpen(false)}
|
|
128
|
+
setLocalCustomType={setLocalCustomType}
|
|
126
129
|
/>
|
|
127
130
|
) : null}
|
|
128
131
|
</>
|
|
@@ -3,7 +3,7 @@ import { CustomType } from "@prismicio/types-internal/lib/customtypes";
|
|
|
3
3
|
|
|
4
4
|
import { CustomTypeFormat } from "@slicemachine/manager";
|
|
5
5
|
import { convertToPageType } from "@src/domain/customType";
|
|
6
|
-
import {
|
|
6
|
+
import { updateCustomType } from "@src/apiClient";
|
|
7
7
|
|
|
8
8
|
import { CUSTOM_TYPES_MESSAGES } from "../customTypesMessages";
|
|
9
9
|
|
|
@@ -16,9 +16,7 @@ export async function convertCustomToPageType(
|
|
|
16
16
|
|
|
17
17
|
try {
|
|
18
18
|
const newCustomType = convertToPageType(customType);
|
|
19
|
-
await
|
|
20
|
-
model: newCustomType,
|
|
21
|
-
});
|
|
19
|
+
await updateCustomType(newCustomType);
|
|
22
20
|
|
|
23
21
|
// Update the custom type in the redux store
|
|
24
22
|
saveCustomType(newCustomType);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ReactNode,
|
|
3
|
+
createContext,
|
|
4
|
+
useCallback,
|
|
5
|
+
useContext,
|
|
6
|
+
useMemo,
|
|
7
|
+
useState,
|
|
8
|
+
} from "react";
|
|
9
|
+
import { CustomType } from "@prismicio/types-internal/lib/customtypes";
|
|
10
|
+
import { useStableCallback } from "@prismicio/editor-support/React";
|
|
11
|
+
|
|
12
|
+
import useSliceMachineActions from "@src/modules/useSliceMachineActions";
|
|
13
|
+
import {
|
|
14
|
+
AutoSaveStatus,
|
|
15
|
+
useAutoSave,
|
|
16
|
+
} from "@src/features/autoSave/useAutoSave";
|
|
17
|
+
import { getFormat } from "@src/domain/customType";
|
|
18
|
+
import { updateCustomType } from "@src/apiClient";
|
|
19
|
+
|
|
20
|
+
import { CUSTOM_TYPES_MESSAGES } from "../customTypesMessages";
|
|
21
|
+
|
|
22
|
+
type CustomTypeContext = {
|
|
23
|
+
customType: CustomType;
|
|
24
|
+
autoSaveStatus: AutoSaveStatus;
|
|
25
|
+
setCustomType: (customType: CustomType) => void;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
type CustomTypeProviderProps = {
|
|
29
|
+
children: ReactNode | ((value: CustomTypeContext) => ReactNode);
|
|
30
|
+
initialCustomType: CustomType;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const CustomTypeContextValue = createContext<CustomTypeContext | undefined>(
|
|
34
|
+
undefined,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
export function CustomTypeProvider(props: CustomTypeProviderProps) {
|
|
38
|
+
const { children, initialCustomType } = props;
|
|
39
|
+
|
|
40
|
+
const [customType, setCustomTypeState] = useState(initialCustomType);
|
|
41
|
+
const format = getFormat(customType);
|
|
42
|
+
const customTypeMessages = CUSTOM_TYPES_MESSAGES[format];
|
|
43
|
+
const { autoSaveStatus, setNextSave } = useAutoSave({
|
|
44
|
+
errorMessage: customTypeMessages.autoSaveFailed,
|
|
45
|
+
});
|
|
46
|
+
const { saveCustomTypeSuccess } = useSliceMachineActions();
|
|
47
|
+
const stableSaveCustomTypeSuccess = useStableCallback(saveCustomTypeSuccess);
|
|
48
|
+
|
|
49
|
+
const setCustomType = useCallback(
|
|
50
|
+
(customType: CustomType) => {
|
|
51
|
+
setCustomTypeState(customType);
|
|
52
|
+
setNextSave(async () => {
|
|
53
|
+
const { errors } = await updateCustomType(customType);
|
|
54
|
+
|
|
55
|
+
if (errors.length > 0) {
|
|
56
|
+
throw errors;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Update available custom types store with new custom type
|
|
60
|
+
stableSaveCustomTypeSuccess(customType);
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
[setNextSave, stableSaveCustomTypeSuccess],
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const contextValue: CustomTypeContext = useMemo(
|
|
67
|
+
() => ({
|
|
68
|
+
autoSaveStatus,
|
|
69
|
+
customType,
|
|
70
|
+
setCustomType,
|
|
71
|
+
}),
|
|
72
|
+
[autoSaveStatus, customType, setCustomType],
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<CustomTypeContextValue.Provider value={contextValue}>
|
|
77
|
+
{typeof children === "function" ? children(contextValue) : children}
|
|
78
|
+
</CustomTypeContextValue.Provider>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function useCustomTypeState() {
|
|
83
|
+
const customTypeState = useContext(CustomTypeContextValue);
|
|
84
|
+
|
|
85
|
+
if (!customTypeState) {
|
|
86
|
+
throw new Error("CustomTypeProvider not found");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return customTypeState;
|
|
90
|
+
}
|