slice-machine-ui 2.20.5-alpha.jp-import-slices-2.1 → 2.20.5-alpha.lg-import-slices.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/out/404.html +1 -1
- package/out/_next/static/GzPwmcuyHg0TUP7cX7YSA/_buildManifest.js +1 -0
- package/out/_next/static/chunks/{248-2902bda47821f37b.js → 248-84a5987f0499b074.js} +1 -1
- package/out/_next/static/chunks/422-c7a16d95b75c9e1c.js +1 -0
- package/out/_next/static/chunks/489-c9535ef34da63d1a.js +1 -0
- package/out/_next/static/chunks/585-c89bb2471e85b9f8.js +1 -0
- package/out/_next/static/chunks/{630-4fe1e982234bd925.js → 630-2bf927bca082a191.js} +1 -1
- package/out/_next/static/chunks/{647-a29bee23cb9ac7a2.js → 647-aa094286bc248d52.js} +1 -1
- package/out/_next/static/chunks/{882-8ab59c0c72307c87.js → 882-48d61b2fabee28d8.js} +1 -1
- package/out/_next/static/chunks/954-bedaaabf664584a0.js +1 -0
- package/out/_next/static/chunks/a6495ab1.00190ac98e794d8f.js +28 -0
- package/out/_next/static/chunks/pages/{_app-a60aecdbaa4efedd.js → _app-0668d41463a0a907.js} +217 -217
- package/out/_next/static/chunks/pages/{changelog-bc83e25e8d316ca9.js → changelog-8514e0696e90a1b2.js} +1 -1
- package/out/_next/static/chunks/pages/{changes-6f371ebe52dbe76a.js → changes-e66094f57453cf9c.js} +1 -1
- package/out/_next/static/chunks/pages/custom-types/{[customTypeId]-80defa14b6ea36f7.js → [customTypeId]-273e9a82c085b596.js} +1 -1
- package/out/_next/static/chunks/pages/{labs-16d118a80936d583.js → labs-56fd818a63553497.js} +1 -1
- package/out/_next/static/chunks/pages/page-types/{[pageTypeId]-f4ff9ad74b44bf09.js → [pageTypeId]-3fa7667de1a790d9.js} +1 -1
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/{simulator-873c0c89aaf50b3c.js → simulator-8c70298caf51bed0.js} +1 -1
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/{[variation]-0e9aa745ed9fe1ec.js → [variation]-22ffa2561ac66557.js} +1 -1
- package/out/_next/static/chunks/pages/slices-76679cf064761d2b.js +1 -0
- package/out/_next/static/chunks/{webpack-e986dd216b883a74.js → webpack-24ddb02bea621501.js} +1 -1
- package/out/_next/static/css/bc89f2cd4e4781f5.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 +6 -6
- package/src/features/customTypes/customTypesBuilder/ImportSlicesFromLibraryModal/ImportSlicesFromLibraryModal.tsx +285 -104
- package/src/features/customTypes/customTypesBuilder/ImportSlicesFromLibraryModal/hooks/useImportSlicesFromGithub.ts +4 -7
- package/src/features/customTypes/customTypesBuilder/SliceZoneBlankSlate.tsx +18 -4
- package/src/features/customTypes/customTypesBuilder/shared/getSubmitButtonLabel.ts +5 -3
- package/src/features/customTypes/customTypesBuilder/sliceCreationOptions.tsx +14 -0
- package/src/legacy/lib/builders/CustomTypeBuilder/SliceZone/UpdateSliceZoneModal.tsx +72 -0
- package/src/legacy/lib/builders/CustomTypeBuilder/SliceZone/UpdateSliceZoneModalList.tsx +3 -1
- package/src/legacy/lib/builders/CustomTypeBuilder/SliceZone/index.tsx +79 -31
- package/src/pages/slices.tsx +30 -0
- package/out/_next/static/60BSwFmsh1-aNIyMe29hH/_buildManifest.js +0 -1
- package/out/_next/static/chunks/21-f3962d02eda0a46e.js +0 -1
- package/out/_next/static/chunks/633-2d20c3e815c79c7f.js +0 -1
- package/out/_next/static/chunks/660-a3ec593dcfbb44c9.js +0 -1
- package/out/_next/static/chunks/6611d287.1714222015f895ea.js +0 -28
- package/out/_next/static/chunks/pages/slices-93fc784c443a996c.js +0 -1
- package/out/_next/static/css/b30fbbc3ed00a725.css +0 -1
- package/src/features/customTypes/customTypesBuilder/ImportSlicesFromLibraryModal/LibrarySlicesTab.tsx +0 -125
- package/src/features/customTypes/customTypesBuilder/ImportSlicesFromLibraryModal/LocalSlicesTab.tsx +0 -67
- package/src/features/customTypes/customTypesBuilder/ImportSlicesFromLibraryModal/ReuseExistingSlicesContext.tsx +0 -279
- /package/out/_next/static/{60BSwFmsh1-aNIyMe29hH → GzPwmcuyHg0TUP7cX7YSA}/_ssgManifest.js +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slice-machine-ui",
|
|
3
|
-
"version": "2.20.5-alpha.
|
|
3
|
+
"version": "2.20.5-alpha.lg-import-slices.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "A visual builder for your Slice Models with all the tools you need to generate data models and mock CMS content locally.",
|
|
6
6
|
"repository": {
|
|
@@ -35,16 +35,16 @@
|
|
|
35
35
|
"start-slicemachine": "./bin/start-slicemachine.cjs"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@slicemachine/manager": "0.26.5-alpha.
|
|
39
|
-
"start-slicemachine": "0.12.70-alpha.
|
|
38
|
+
"@slicemachine/manager": "0.26.5-alpha.lg-import-slices.1",
|
|
39
|
+
"start-slicemachine": "0.12.70-alpha.lg-import-slices.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@emotion/react": "11.11.1",
|
|
43
43
|
"@extractus/oembed-extractor": "3.1.8",
|
|
44
44
|
"@prismicio/client": "7.17.0",
|
|
45
|
-
"@prismicio/editor-fields": "0.4.
|
|
46
|
-
"@prismicio/editor-support": "0.4.
|
|
47
|
-
"@prismicio/editor-ui": "0.4.
|
|
45
|
+
"@prismicio/editor-fields": "0.4.88",
|
|
46
|
+
"@prismicio/editor-support": "0.4.88",
|
|
47
|
+
"@prismicio/editor-ui": "0.4.88",
|
|
48
48
|
"@prismicio/mock": "0.7.1",
|
|
49
49
|
"@prismicio/mocks": "2.14.0",
|
|
50
50
|
"@prismicio/simulator": "0.1.4",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Box,
|
|
3
|
+
Button,
|
|
4
|
+
Checkbox,
|
|
3
5
|
Dialog,
|
|
4
6
|
DialogActionButton,
|
|
5
7
|
DialogActions,
|
|
@@ -7,149 +9,328 @@ import {
|
|
|
7
9
|
DialogContent,
|
|
8
10
|
DialogDescription,
|
|
9
11
|
DialogHeader,
|
|
10
|
-
|
|
12
|
+
InlineLabel,
|
|
13
|
+
ScrollArea,
|
|
14
|
+
Text,
|
|
15
|
+
TextInput,
|
|
11
16
|
} from "@prismicio/editor-ui";
|
|
12
17
|
import { SharedSlice } from "@prismicio/types-internal/lib/customtypes";
|
|
13
|
-
import {
|
|
18
|
+
import { useEffect, useRef, useState } from "react";
|
|
19
|
+
import { toast } from "react-toastify";
|
|
14
20
|
|
|
15
|
-
import {
|
|
21
|
+
import { getState, telemetry } from "@/apiClient";
|
|
22
|
+
import { useOnboarding } from "@/features/onboarding/useOnboarding";
|
|
23
|
+
import { useAutoSync } from "@/features/sync/AutoSyncProvider";
|
|
24
|
+
import useSliceMachineActions from "@/modules/useSliceMachineActions";
|
|
16
25
|
|
|
17
26
|
import { getSubmitButtonLabel } from "../shared/getSubmitButtonLabel";
|
|
18
27
|
import { useExistingSlices } from "../shared/useExistingSlices";
|
|
19
28
|
import { useImportSlicesFromGithub } from "./hooks/useImportSlicesFromGithub";
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
useReuseExistingSlicesContext,
|
|
25
|
-
} from "./ReuseExistingSlicesContext";
|
|
29
|
+
import { SliceCard } from "./SliceCard";
|
|
30
|
+
import { NewSlice } from "./types";
|
|
31
|
+
import { addSlices } from "./utils/addSlices";
|
|
32
|
+
import { sliceWithoutConflicts } from "./utils/sliceWithoutConflicts";
|
|
26
33
|
|
|
27
|
-
interface
|
|
34
|
+
interface ImportSlicesFromLibraryModalProps {
|
|
28
35
|
open: boolean;
|
|
29
|
-
location: "custom_type" | "page_type";
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
location: "custom_type" | "page_type" | "slices";
|
|
37
|
+
onSuccess: (args: {
|
|
38
|
+
slices: {
|
|
39
|
+
model: SharedSlice;
|
|
40
|
+
langSmithUrl?: string;
|
|
41
|
+
}[];
|
|
42
|
+
library: string;
|
|
43
|
+
}) => void;
|
|
33
44
|
onClose: () => void;
|
|
34
45
|
}
|
|
35
46
|
|
|
36
|
-
function
|
|
37
|
-
props:
|
|
47
|
+
export function ImportSlicesFromLibraryModal(
|
|
48
|
+
props: ImportSlicesFromLibraryModalProps,
|
|
38
49
|
) {
|
|
39
|
-
const {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
} = props;
|
|
47
|
-
const [selectedTab, setSelectedTab] = useState("local");
|
|
50
|
+
const { open, location, onSuccess, onClose } = props;
|
|
51
|
+
|
|
52
|
+
const [isCreatingSlices, setIsCreatingSlices] = useState(false);
|
|
53
|
+
const [githubUrl, setGithubUrl] = useState("");
|
|
54
|
+
const [selectedSliceIds, setSelectedSliceIds] = useState<Set<string>>(
|
|
55
|
+
new Set(),
|
|
56
|
+
);
|
|
48
57
|
|
|
58
|
+
const { syncChanges } = useAutoSync();
|
|
59
|
+
const { createSliceSuccess, updateSliceMockSuccess } =
|
|
60
|
+
useSliceMachineActions();
|
|
61
|
+
const { completeStep } = useOnboarding();
|
|
49
62
|
const existingSlices = useExistingSlices({ open });
|
|
50
|
-
const { resetSlices } =
|
|
51
|
-
|
|
52
|
-
|
|
63
|
+
const { isLoadingSlices, handleImportFromGithub, slices, resetSlices } =
|
|
64
|
+
useImportSlicesFromGithub();
|
|
65
|
+
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (slices.length === 0) return;
|
|
68
|
+
|
|
69
|
+
// Set all slices as selected by default
|
|
70
|
+
const allSliceIds = new Set<string>();
|
|
71
|
+
for (const slice of slices) {
|
|
72
|
+
allSliceIds.add(slice.model.id);
|
|
73
|
+
}
|
|
74
|
+
setSelectedSliceIds(allSliceIds);
|
|
75
|
+
}, [slices]);
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Keeps track of the current instance id.
|
|
79
|
+
* When the modal is closed, the id is reset.
|
|
80
|
+
*/
|
|
81
|
+
const id = useRef(crypto.randomUUID());
|
|
53
82
|
|
|
54
83
|
const onOpenChange = (open: boolean) => {
|
|
55
|
-
if (open ||
|
|
84
|
+
if (open || isCreatingSlices) return;
|
|
56
85
|
onClose();
|
|
57
|
-
|
|
86
|
+
id.current = crypto.randomUUID();
|
|
87
|
+
setGithubUrl("");
|
|
88
|
+
setSelectedSliceIds(new Set());
|
|
58
89
|
resetSlices();
|
|
59
|
-
setSelectedTab("local");
|
|
60
90
|
};
|
|
61
91
|
|
|
62
|
-
const onSubmit =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
92
|
+
const onSubmit = () => {
|
|
93
|
+
const newSlices = slices.reduce<NewSlice[]>((acc, slice) => {
|
|
94
|
+
if (selectedSliceIds.has(slice.model.id)) {
|
|
95
|
+
acc.push({
|
|
96
|
+
image: slice.image,
|
|
97
|
+
model: slice.model,
|
|
98
|
+
files: slice.files,
|
|
99
|
+
componentContents: slice.componentContents,
|
|
100
|
+
mocks: slice.mocks,
|
|
101
|
+
screenshots: slice.screenshots,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return acc;
|
|
105
|
+
}, []);
|
|
106
|
+
if (!newSlices.length) {
|
|
107
|
+
toast.error("Please select at least one slice to import");
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Ensure ids and names are conflict-free against existing and newly-added slices
|
|
112
|
+
const conflictFreeSlices: NewSlice[] = [];
|
|
113
|
+
for (const s of newSlices) {
|
|
114
|
+
const adjustedModel = sliceWithoutConflicts({
|
|
115
|
+
existingSlices: existingSlices.current,
|
|
116
|
+
newSlices: conflictFreeSlices,
|
|
117
|
+
slice: s.model,
|
|
118
|
+
});
|
|
119
|
+
conflictFreeSlices.push({ ...s, model: adjustedModel });
|
|
68
120
|
}
|
|
121
|
+
|
|
122
|
+
const currentId = id.current;
|
|
123
|
+
setIsCreatingSlices(true);
|
|
124
|
+
addSlices(conflictFreeSlices)
|
|
125
|
+
.then(async ({ slices, library }) => {
|
|
126
|
+
if (currentId !== id.current) return;
|
|
127
|
+
|
|
128
|
+
// Wait a moment to ensure all file writes are complete
|
|
129
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
130
|
+
|
|
131
|
+
const serverState = await getState();
|
|
132
|
+
|
|
133
|
+
// Ensure mocks are included in the libraries data before updating store
|
|
134
|
+
const librariesWithMocks = serverState.libraries.map((lib) => {
|
|
135
|
+
if (lib.name !== library) return lib;
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
...lib,
|
|
139
|
+
components: lib.components.map((component) => {
|
|
140
|
+
// Find the corresponding slice from newSlices to get its mocks
|
|
141
|
+
const importedSlice = conflictFreeSlices.find(
|
|
142
|
+
(s) => s.model.id === component.model.id,
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
// If mocks are already in component, use them; otherwise use imported mocks
|
|
146
|
+
const mocks =
|
|
147
|
+
component.mocks && component.mocks.length > 0
|
|
148
|
+
? component.mocks
|
|
149
|
+
: importedSlice?.mocks;
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
...component,
|
|
153
|
+
mocks: mocks ?? component.mocks,
|
|
154
|
+
};
|
|
155
|
+
}),
|
|
156
|
+
};
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
createSliceSuccess(librariesWithMocks);
|
|
160
|
+
|
|
161
|
+
// Also update mocks individually to ensure they're in the store
|
|
162
|
+
for (const slice of newSlices) {
|
|
163
|
+
if (
|
|
164
|
+
slice.mocks &&
|
|
165
|
+
Array.isArray(slice.mocks) &&
|
|
166
|
+
slice.mocks.length > 0
|
|
167
|
+
) {
|
|
168
|
+
updateSliceMockSuccess({
|
|
169
|
+
libraryID: library,
|
|
170
|
+
sliceID: slice.model.id,
|
|
171
|
+
mocks: slice.mocks,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
syncChanges();
|
|
177
|
+
|
|
178
|
+
onSuccess({ slices, library });
|
|
179
|
+
|
|
180
|
+
setIsCreatingSlices(false);
|
|
181
|
+
id.current = crypto.randomUUID();
|
|
182
|
+
resetSlices();
|
|
183
|
+
|
|
184
|
+
void completeStep("createSlice");
|
|
185
|
+
|
|
186
|
+
for (const { model } of slices) {
|
|
187
|
+
void telemetry.track({
|
|
188
|
+
event: "slice:created",
|
|
189
|
+
id: model.id,
|
|
190
|
+
name: model.name,
|
|
191
|
+
library,
|
|
192
|
+
location,
|
|
193
|
+
mode: "import",
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
})
|
|
197
|
+
.catch(() => {
|
|
198
|
+
if (currentId !== id.current) return;
|
|
199
|
+
setIsCreatingSlices(false);
|
|
200
|
+
toast.error("An unexpected error happened while adding slices.");
|
|
201
|
+
});
|
|
69
202
|
};
|
|
70
203
|
|
|
204
|
+
const selectedSlices = slices.filter((slice) =>
|
|
205
|
+
selectedSliceIds.has(slice.model.id),
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
const allSelected =
|
|
209
|
+
slices.length > 0 && selectedSliceIds.size === slices.length;
|
|
210
|
+
const someSelected =
|
|
211
|
+
selectedSliceIds.size > 0 && selectedSliceIds.size < slices.length;
|
|
212
|
+
|
|
213
|
+
const handleSelectAll = (selected: boolean) => {
|
|
214
|
+
if (selected) {
|
|
215
|
+
const allSliceIds = new Set<string>();
|
|
216
|
+
for (const slice of slices) {
|
|
217
|
+
allSliceIds.add(slice.model.id);
|
|
218
|
+
}
|
|
219
|
+
setSelectedSliceIds(allSliceIds);
|
|
220
|
+
} else {
|
|
221
|
+
setSelectedSliceIds(new Set());
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
let selectAllLabel = "Select all slices";
|
|
226
|
+
if (allSelected) {
|
|
227
|
+
selectAllLabel = `Selected all slices (${selectedSliceIds.size})`;
|
|
228
|
+
} else if (someSelected) {
|
|
229
|
+
selectAllLabel = `${selectedSliceIds.size} of ${slices.length} selected`;
|
|
230
|
+
}
|
|
231
|
+
|
|
71
232
|
return (
|
|
72
233
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
73
|
-
<DialogHeader title="
|
|
234
|
+
<DialogHeader title="Import slices from library" />
|
|
74
235
|
<DialogContent gap={0}>
|
|
75
236
|
<DialogDescription hidden>
|
|
76
|
-
|
|
237
|
+
Import slices from a github repository
|
|
77
238
|
</DialogDescription>
|
|
78
|
-
|
|
79
|
-
<Box
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
239
|
+
{slices.length === 0 ? (
|
|
240
|
+
<Box padding={16} height="100%" flexDirection="column" gap={16}>
|
|
241
|
+
<Box flexDirection="column" gap={8}>
|
|
242
|
+
<Box
|
|
243
|
+
display="flex"
|
|
244
|
+
flexDirection="column"
|
|
245
|
+
gap={8}
|
|
246
|
+
padding={16}
|
|
247
|
+
border
|
|
248
|
+
borderRadius={8}
|
|
88
249
|
>
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
250
|
+
<Text color="grey11">Import from GitHub</Text>
|
|
251
|
+
<TextInput
|
|
252
|
+
placeholder="https://github.com/username/repository"
|
|
253
|
+
value={githubUrl}
|
|
254
|
+
onValueChange={setGithubUrl}
|
|
255
|
+
/>
|
|
256
|
+
<Button
|
|
257
|
+
onClick={() => void handleImportFromGithub(githubUrl)}
|
|
258
|
+
disabled={!githubUrl.trim() || isLoadingSlices}
|
|
259
|
+
loading={isLoadingSlices}
|
|
260
|
+
color="purple"
|
|
261
|
+
>
|
|
262
|
+
{isLoadingSlices ? "Loading slices..." : "Import from GitHub"}
|
|
263
|
+
</Button>
|
|
264
|
+
</Box>
|
|
97
265
|
</Box>
|
|
98
|
-
{selectedTab === "library" && "<repo-select>"}
|
|
99
266
|
</Box>
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
267
|
+
) : (
|
|
268
|
+
<>
|
|
269
|
+
<Box
|
|
270
|
+
display="flex"
|
|
271
|
+
alignItems="center"
|
|
272
|
+
justifyContent="space-between"
|
|
273
|
+
padding={16}
|
|
274
|
+
border={{ bottom: true }}
|
|
275
|
+
>
|
|
276
|
+
<Box display="flex" alignItems="center" gap={8}>
|
|
277
|
+
<InlineLabel value={selectAllLabel}>
|
|
278
|
+
<Checkbox
|
|
279
|
+
checked={allSelected}
|
|
280
|
+
indeterminate={someSelected}
|
|
281
|
+
onCheckedChange={handleSelectAll}
|
|
282
|
+
/>
|
|
283
|
+
</InlineLabel>
|
|
284
|
+
</Box>
|
|
285
|
+
</Box>
|
|
286
|
+
<ScrollArea stableScrollbar={false}>
|
|
287
|
+
<Box
|
|
288
|
+
display="grid"
|
|
289
|
+
gridTemplateColumns="1fr 1fr 1fr"
|
|
290
|
+
gap={16}
|
|
291
|
+
padding={16}
|
|
292
|
+
>
|
|
293
|
+
{slices.map((slice) => {
|
|
294
|
+
return (
|
|
295
|
+
<SliceCard
|
|
296
|
+
model={slice.model}
|
|
297
|
+
thumbnailUrl={slice.thumbnailUrl}
|
|
298
|
+
key={slice.model.id}
|
|
299
|
+
selected={selectedSliceIds.has(slice.model.id)}
|
|
300
|
+
onSelectedChange={(selected) => {
|
|
301
|
+
if (selected) {
|
|
302
|
+
setSelectedSliceIds((prev) => {
|
|
303
|
+
const next = new Set(prev);
|
|
304
|
+
next.add(slice.model.id);
|
|
305
|
+
return next;
|
|
306
|
+
});
|
|
307
|
+
} else {
|
|
308
|
+
setSelectedSliceIds((prev) => {
|
|
309
|
+
const next = new Set(prev);
|
|
310
|
+
next.delete(slice.model.id);
|
|
311
|
+
return next;
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}}
|
|
315
|
+
/>
|
|
316
|
+
);
|
|
317
|
+
})}
|
|
318
|
+
</Box>
|
|
319
|
+
</ScrollArea>
|
|
320
|
+
</>
|
|
321
|
+
)}
|
|
107
322
|
|
|
108
323
|
<DialogActions>
|
|
109
|
-
<DialogCancelButton disabled={
|
|
324
|
+
<DialogCancelButton disabled={isCreatingSlices} />
|
|
110
325
|
<DialogActionButton
|
|
111
|
-
disabled={
|
|
112
|
-
loading={
|
|
113
|
-
onClick={
|
|
114
|
-
size="medium"
|
|
326
|
+
disabled={selectedSlices.length === 0}
|
|
327
|
+
loading={isCreatingSlices}
|
|
328
|
+
onClick={onSubmit}
|
|
115
329
|
>
|
|
116
|
-
{getSubmitButtonLabel(location
|
|
330
|
+
{getSubmitButtonLabel(location)} ({selectedSlices.length})
|
|
117
331
|
</DialogActionButton>
|
|
118
332
|
</DialogActions>
|
|
119
333
|
</DialogContent>
|
|
120
334
|
</Dialog>
|
|
121
335
|
);
|
|
122
336
|
}
|
|
123
|
-
|
|
124
|
-
interface TabContentProps {
|
|
125
|
-
children: ReactNode;
|
|
126
|
-
selected: boolean;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function TabContent(args: TabContentProps) {
|
|
130
|
-
const { children, selected } = args;
|
|
131
|
-
|
|
132
|
-
if (!selected) {
|
|
133
|
-
return (
|
|
134
|
-
<Box display="none" minHeight={0}>
|
|
135
|
-
{children}
|
|
136
|
-
</Box>
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return (
|
|
141
|
-
<Box display="flex" flexDirection="column" flexGrow={1} minHeight={0}>
|
|
142
|
-
{children}
|
|
143
|
-
</Box>
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export function ImportSlicesFromLibraryModal(
|
|
148
|
-
props: ImportSlicesFromLibraryModalContent,
|
|
149
|
-
) {
|
|
150
|
-
return (
|
|
151
|
-
<ReuseExistingSlicesProvider>
|
|
152
|
-
<ImportSlicesFromLibraryModalContent {...props} />
|
|
153
|
-
</ReuseExistingSlicesProvider>
|
|
154
|
-
);
|
|
155
|
-
}
|
|
@@ -26,7 +26,7 @@ export function useImportSlicesFromGithub() {
|
|
|
26
26
|
if (!owner || !repo) {
|
|
27
27
|
toast.error("Invalid GitHub URL format");
|
|
28
28
|
setIsLoadingSlices(false);
|
|
29
|
-
|
|
29
|
+
return;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const branch = await getDefaultBranch({ owner, repo });
|
|
@@ -43,14 +43,14 @@ export function useImportSlicesFromGithub() {
|
|
|
43
43
|
}`,
|
|
44
44
|
);
|
|
45
45
|
setIsLoadingSlices(false);
|
|
46
|
-
|
|
46
|
+
return;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
if (libraries.length === 0) {
|
|
50
50
|
console.warn("No libraries were found in the SM config.");
|
|
51
51
|
setIsLoadingSlices(false);
|
|
52
52
|
toast.error("No libraries were found in the SM config.");
|
|
53
|
-
|
|
53
|
+
return;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
const fetchedSlices = await fetchSlicesFromLibraries({
|
|
@@ -63,7 +63,7 @@ export function useImportSlicesFromGithub() {
|
|
|
63
63
|
if (fetchedSlices.length === 0) {
|
|
64
64
|
toast.error("Error fetching slices from the repository");
|
|
65
65
|
setIsLoadingSlices(false);
|
|
66
|
-
|
|
66
|
+
return;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
setSlices(fetchedSlices);
|
|
@@ -71,8 +71,6 @@ export function useImportSlicesFromGithub() {
|
|
|
71
71
|
toast.success(
|
|
72
72
|
`Found ${fetchedSlices.length} slice(s) from ${libraries.length} library/libraries`,
|
|
73
73
|
);
|
|
74
|
-
|
|
75
|
-
return fetchedSlices;
|
|
76
74
|
} catch (error) {
|
|
77
75
|
console.error("Error importing from GitHub:", error);
|
|
78
76
|
toast.error(
|
|
@@ -81,7 +79,6 @@ export function useImportSlicesFromGithub() {
|
|
|
81
79
|
}`,
|
|
82
80
|
);
|
|
83
81
|
setIsLoadingSlices(false);
|
|
84
|
-
return [];
|
|
85
82
|
}
|
|
86
83
|
};
|
|
87
84
|
|
|
@@ -16,6 +16,7 @@ export type SliceZoneBlankSlateProps = {
|
|
|
16
16
|
openCreateSliceModal: () => void;
|
|
17
17
|
openCreateSliceFromImageModal: () => void;
|
|
18
18
|
openSlicesTemplatesModal: () => void;
|
|
19
|
+
openImportSlicesFromLibraryModal: () => void;
|
|
19
20
|
projectHasAvailableSlices: boolean;
|
|
20
21
|
isSlicesTemplatesSupported: boolean;
|
|
21
22
|
};
|
|
@@ -24,7 +25,9 @@ export const SliceZoneBlankSlate: FC<SliceZoneBlankSlateProps> = ({
|
|
|
24
25
|
openCreateSliceModal,
|
|
25
26
|
openCreateSliceFromImageModal,
|
|
26
27
|
openUpdateSliceZoneModal,
|
|
28
|
+
openImportSlicesFromLibraryModal,
|
|
27
29
|
openSlicesTemplatesModal,
|
|
30
|
+
projectHasAvailableSlices,
|
|
28
31
|
isSlicesTemplatesSupported,
|
|
29
32
|
}) => {
|
|
30
33
|
const sliceCreationOptions = getSliceCreationOptions({
|
|
@@ -76,14 +79,25 @@ export const SliceZoneBlankSlate: FC<SliceZoneBlankSlateProps> = ({
|
|
|
76
79
|
{sliceCreationOptions.fromTemplate.title}
|
|
77
80
|
</ActionListItem>
|
|
78
81
|
)}
|
|
82
|
+
{projectHasAvailableSlices && (
|
|
83
|
+
<ActionListItem
|
|
84
|
+
renderStartIcon={() =>
|
|
85
|
+
sliceCreationOptions.fromExisting.BackgroundIcon
|
|
86
|
+
}
|
|
87
|
+
onClick={openUpdateSliceZoneModal}
|
|
88
|
+
description={sliceCreationOptions.fromExisting.description}
|
|
89
|
+
>
|
|
90
|
+
{sliceCreationOptions.fromExisting.title}
|
|
91
|
+
</ActionListItem>
|
|
92
|
+
)}
|
|
79
93
|
<ActionListItem
|
|
80
94
|
renderStartIcon={() =>
|
|
81
|
-
sliceCreationOptions.
|
|
95
|
+
sliceCreationOptions.importFromExternal.BackgroundIcon
|
|
82
96
|
}
|
|
83
|
-
onClick={
|
|
84
|
-
description={sliceCreationOptions.
|
|
97
|
+
onClick={openImportSlicesFromLibraryModal}
|
|
98
|
+
description={sliceCreationOptions.importFromExternal.description}
|
|
85
99
|
>
|
|
86
|
-
{sliceCreationOptions.
|
|
100
|
+
{sliceCreationOptions.importFromExternal.title}
|
|
87
101
|
</ActionListItem>
|
|
88
102
|
</ActionList>
|
|
89
103
|
</BlankSlateActions>
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
export const getSubmitButtonLabel = (
|
|
2
|
-
location: "custom_type" | "page_type",
|
|
3
|
-
typeName?: string,
|
|
2
|
+
location: "custom_type" | "page_type" | "slices",
|
|
4
3
|
) => {
|
|
5
4
|
switch (location) {
|
|
6
5
|
case "custom_type":
|
|
6
|
+
return "Add to type";
|
|
7
7
|
case "page_type":
|
|
8
|
-
return
|
|
8
|
+
return "Add to page";
|
|
9
|
+
case "slices":
|
|
10
|
+
return "Add to slices";
|
|
9
11
|
}
|
|
10
12
|
};
|
|
@@ -64,5 +64,19 @@ export const getSliceCreationOptions = (args: SliceCreationOptionArgs) => {
|
|
|
64
64
|
title: "Reuse an existing slice",
|
|
65
65
|
description: "Select from your created slices.",
|
|
66
66
|
},
|
|
67
|
+
importFromExternal: {
|
|
68
|
+
BackgroundIcon: (
|
|
69
|
+
<BackgroundIcon
|
|
70
|
+
name="cloudUpload"
|
|
71
|
+
size={menuType === "ActionList" ? "small" : "extraSmall"}
|
|
72
|
+
iconSize={menuType === "ActionList" ? "medium" : "small"}
|
|
73
|
+
color="white"
|
|
74
|
+
variant="solid"
|
|
75
|
+
radius={6}
|
|
76
|
+
/>
|
|
77
|
+
),
|
|
78
|
+
title: "Add from external library",
|
|
79
|
+
description: "Import slices from a github repository.",
|
|
80
|
+
},
|
|
67
81
|
};
|
|
68
82
|
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { SharedSlice } from "@prismicio/types-internal/lib/customtypes";
|
|
2
|
+
import { Text } from "theme-ui";
|
|
3
|
+
|
|
4
|
+
import ModalFormCard from "@/legacy/components/ModalFormCard";
|
|
5
|
+
import { ComponentUI } from "@/legacy/lib/models/common/ComponentUI";
|
|
6
|
+
|
|
7
|
+
import UpdateSliceZoneModalList from "./UpdateSliceZoneModalList";
|
|
8
|
+
|
|
9
|
+
interface UpdateSliceModalProps {
|
|
10
|
+
formId: string;
|
|
11
|
+
close: () => void;
|
|
12
|
+
onSubmit: (slices: SharedSlice[]) => void;
|
|
13
|
+
availableSlices: ReadonlyArray<ComponentUI>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type SliceZoneFormValues = {
|
|
17
|
+
sliceKeys: string[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const UpdateSliceZoneModal: React.FC<UpdateSliceModalProps> = ({
|
|
21
|
+
formId,
|
|
22
|
+
close,
|
|
23
|
+
onSubmit,
|
|
24
|
+
availableSlices,
|
|
25
|
+
}) => {
|
|
26
|
+
return (
|
|
27
|
+
<ModalFormCard
|
|
28
|
+
isOpen
|
|
29
|
+
buttonLabel="Add"
|
|
30
|
+
formId={formId}
|
|
31
|
+
close={close}
|
|
32
|
+
onSubmit={(values: SliceZoneFormValues) => {
|
|
33
|
+
const { sliceKeys } = values;
|
|
34
|
+
const slices = sliceKeys
|
|
35
|
+
.map(
|
|
36
|
+
(sliceKey) =>
|
|
37
|
+
availableSlices.find((s) => s.model.id === sliceKey)?.model,
|
|
38
|
+
)
|
|
39
|
+
.filter((slice) => slice !== undefined) as SharedSlice[];
|
|
40
|
+
onSubmit(slices);
|
|
41
|
+
}}
|
|
42
|
+
initialValues={{
|
|
43
|
+
sliceKeys: [],
|
|
44
|
+
}}
|
|
45
|
+
content={{
|
|
46
|
+
title: "Select existing slices",
|
|
47
|
+
}}
|
|
48
|
+
testId="update-slices-modal"
|
|
49
|
+
validate={(values) => {
|
|
50
|
+
if (values.sliceKeys.length === 0) {
|
|
51
|
+
return {
|
|
52
|
+
sliceKeys: "Select at least one slice to add",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}}
|
|
56
|
+
actionMessage={({ errors }) =>
|
|
57
|
+
errors.sliceKeys !== undefined ? (
|
|
58
|
+
<Text sx={{ color: "error" }}>{errors.sliceKeys}</Text>
|
|
59
|
+
) : undefined
|
|
60
|
+
}
|
|
61
|
+
>
|
|
62
|
+
{({ values }) => (
|
|
63
|
+
<UpdateSliceZoneModalList
|
|
64
|
+
values={values}
|
|
65
|
+
availableSlices={availableSlices}
|
|
66
|
+
/>
|
|
67
|
+
)}
|
|
68
|
+
</ModalFormCard>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export default UpdateSliceZoneModal;
|