slice-machine-ui 1.15.1-dev-next-release.5 → 1.16.1-dev-upgrade-legacy-2.2
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/components/Forms/ConvertLegacySliceModal/ConvertLegacySliceModal.css.ts +35 -0
- package/components/Forms/ConvertLegacySliceModal/ConvertLegacySliceModal.tsx +295 -0
- package/components/Forms/ConvertLegacySliceModal/FormAsNewSlice.tsx +153 -0
- package/components/Forms/ConvertLegacySliceModal/FormAsNewVariation.tsx +234 -0
- package/components/Forms/ConvertLegacySliceModal/FormMergeWithIdentical.tsx +104 -0
- package/components/Forms/ConvertLegacySliceModal/index.tsx +1 -0
- package/components/Forms/ConvertLegacySliceModal/types.ts +48 -0
- package/lib/builders/CustomTypeBuilder/SliceZone/List.tsx +12 -7
- package/lib/builders/CustomTypeBuilder/SliceZone/index.tsx +10 -1
- package/out/404.html +1 -1
- package/out/[lib]/[sliceName]/[variation]/screenshot.html +1 -1
- package/out/[lib]/[sliceName]/[variation]/simulator.html +1 -1
- package/out/[lib]/[sliceName]/[variation].html +1 -1
- package/out/_next/static/{_4bA7O4YBUUWzYZC33uVh → ERajXsW0rmM1eiFC9OrRN}/_buildManifest.js +1 -1
- package/out/_next/static/chunks/{125-84464edfe25651eb.js → 521-7d6a8c036ebc8ed7.js} +2 -2
- package/out/_next/static/chunks/792-642ab5cdb981cc31.js +1 -0
- package/out/_next/static/chunks/pages/{_app-20ab241fc120112d.js → _app-da0f1b0fa49ba1ba.js} +4 -4
- package/out/_next/static/chunks/pages/custom-types/{[customTypeId]-1baa6af0ddf0ab6b.js → [customTypeId]-9d0629783340bfd7.js} +1 -1
- package/out/_next/static/chunks/pages/page-types/{[pageTypeId]-708b782db680b804.js → [pageTypeId]-48d0d43500b8cc5d.js} +1 -1
- 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/page-types/[pageTypeId].html +1 -1
- package/out/slices.html +1 -1
- package/package.json +4 -4
- package/src/features/slices/sliceCards/NonSharedSliceViewCard.tsx +16 -4
- package/out/_next/static/chunks/14-9205b47277b0e0f4.js +0 -1
- /package/out/_next/static/{_4bA7O4YBUUWzYZC33uVh → ERajXsW0rmM1eiFC9OrRN}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { sprinkles } from "@prismicio/editor-ui";
|
|
2
|
+
import { style } from "@vanilla-extract/css";
|
|
3
|
+
|
|
4
|
+
export const form = style([
|
|
5
|
+
sprinkles({
|
|
6
|
+
display: "flex",
|
|
7
|
+
flexDirection: "column",
|
|
8
|
+
}),
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
export const scrollArea = style([
|
|
12
|
+
sprinkles({
|
|
13
|
+
height: "100%",
|
|
14
|
+
display: "flex",
|
|
15
|
+
gap: 8,
|
|
16
|
+
paddingInline: 16,
|
|
17
|
+
paddingBlock: 16,
|
|
18
|
+
}),
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
export const field = style([
|
|
22
|
+
sprinkles({
|
|
23
|
+
display: "flex",
|
|
24
|
+
flexDirection: "column",
|
|
25
|
+
gap: 4,
|
|
26
|
+
}),
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
export const label = style([
|
|
30
|
+
sprinkles({
|
|
31
|
+
display: "inline-flex",
|
|
32
|
+
alignItems: "center",
|
|
33
|
+
gap: 4,
|
|
34
|
+
}),
|
|
35
|
+
]);
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { useMemo, useState } from "react";
|
|
2
|
+
import { useSelector } from "react-redux";
|
|
3
|
+
import {
|
|
4
|
+
DropdownMenu,
|
|
5
|
+
DropdownMenuContent,
|
|
6
|
+
DropdownMenuItem,
|
|
7
|
+
DropdownMenuTrigger,
|
|
8
|
+
Icon,
|
|
9
|
+
Button,
|
|
10
|
+
} from "@prismicio/editor-ui";
|
|
11
|
+
import {
|
|
12
|
+
LegacySlice,
|
|
13
|
+
CompositeSlice,
|
|
14
|
+
} from "@prismicio/types-internal/lib/customtypes";
|
|
15
|
+
|
|
16
|
+
import { VariationSM } from "@models/common/Slice";
|
|
17
|
+
import { CustomTypes } from "@models/common/CustomType";
|
|
18
|
+
import { getLibraries } from "@src/modules/slices";
|
|
19
|
+
import { SliceMachineStoreType } from "@src/redux/type";
|
|
20
|
+
import { managerClient } from "@src/managerClient";
|
|
21
|
+
import { getState, telemetry } from "@src/apiClient";
|
|
22
|
+
import useSliceMachineActions from "@src/modules/useSliceMachineActions";
|
|
23
|
+
import { ToasterType } from "@src/modules/toaster";
|
|
24
|
+
|
|
25
|
+
import { FormAsNewSlice } from "./FormAsNewSlice";
|
|
26
|
+
import { FormAsNewVariation } from "./FormAsNewVariation";
|
|
27
|
+
import { FormMergeWithIdentical } from "./FormMergeWithIdentical";
|
|
28
|
+
import {
|
|
29
|
+
ConvertLegacySliceModalProps,
|
|
30
|
+
ConvertLegacySliceAndTrackArgs,
|
|
31
|
+
IdenticalSlice,
|
|
32
|
+
Type,
|
|
33
|
+
} from "./types";
|
|
34
|
+
|
|
35
|
+
const getFieldMappingFingerprint = (
|
|
36
|
+
slice: LegacySlice | CompositeSlice | VariationSM,
|
|
37
|
+
sliceName: string
|
|
38
|
+
): {
|
|
39
|
+
primary: string;
|
|
40
|
+
items: string;
|
|
41
|
+
} => {
|
|
42
|
+
const primary: Record<string, string> = {};
|
|
43
|
+
const items: Record<string, string> = {};
|
|
44
|
+
|
|
45
|
+
if ("type" in slice) {
|
|
46
|
+
if (slice.type === "Slice") {
|
|
47
|
+
for (const key in slice["non-repeat"]) {
|
|
48
|
+
primary[key] = slice["non-repeat"][key].type;
|
|
49
|
+
}
|
|
50
|
+
for (const key in slice.repeat) {
|
|
51
|
+
items[key] = slice.repeat[key].type;
|
|
52
|
+
}
|
|
53
|
+
} else if (slice.type === "Group") {
|
|
54
|
+
for (const key in slice.config?.fields) {
|
|
55
|
+
items[key] = slice.config?.fields[key].type ?? "";
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
primary[sliceName] = slice.type;
|
|
59
|
+
}
|
|
60
|
+
} else if ("id" in slice) {
|
|
61
|
+
for (const { key, value } of slice.primary ?? []) {
|
|
62
|
+
primary[key] = value.type;
|
|
63
|
+
}
|
|
64
|
+
for (const { key, value } of slice.items ?? []) {
|
|
65
|
+
items[key] = value.type;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
primary: JSON.stringify(
|
|
71
|
+
Object.keys(primary)
|
|
72
|
+
.sort()
|
|
73
|
+
.map((key) => [key, primary[key]])
|
|
74
|
+
),
|
|
75
|
+
items: JSON.stringify(
|
|
76
|
+
Object.keys(items)
|
|
77
|
+
.sort()
|
|
78
|
+
.map((key) => [key, items[key]])
|
|
79
|
+
),
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const ConvertLegacySliceModal: React.FC<
|
|
84
|
+
ConvertLegacySliceModalProps
|
|
85
|
+
> = ({ slice, path }) => {
|
|
86
|
+
const {
|
|
87
|
+
refreshState,
|
|
88
|
+
openToaster,
|
|
89
|
+
initCustomTypeStore,
|
|
90
|
+
saveCustomTypeSuccess,
|
|
91
|
+
} = useSliceMachineActions();
|
|
92
|
+
|
|
93
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
94
|
+
const [isModalOpen, setIsModalOpen] = useState<false | Type>(false);
|
|
95
|
+
|
|
96
|
+
const { libraries: allLibraries } = useSelector(
|
|
97
|
+
(store: SliceMachineStoreType) => ({
|
|
98
|
+
libraries: getLibraries(store),
|
|
99
|
+
})
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const {} = useSliceMachineActions();
|
|
103
|
+
|
|
104
|
+
const sliceName = useMemo(() => {
|
|
105
|
+
return slice.value.type === "Slice"
|
|
106
|
+
? slice.value.fieldset ?? slice.key
|
|
107
|
+
: slice.key;
|
|
108
|
+
}, [slice]);
|
|
109
|
+
const libraries = useMemo(() => {
|
|
110
|
+
return allLibraries.filter((library) => library.isLocal);
|
|
111
|
+
}, [allLibraries]);
|
|
112
|
+
const localSharedSlices = useMemo(() => {
|
|
113
|
+
return libraries.map((library) => library.components).flat();
|
|
114
|
+
}, [libraries]);
|
|
115
|
+
const identicalSlices = useMemo<IdenticalSlice[]>(() => {
|
|
116
|
+
const results: IdenticalSlice[] = [];
|
|
117
|
+
|
|
118
|
+
const sliceFields = getFieldMappingFingerprint(slice.value, sliceName);
|
|
119
|
+
|
|
120
|
+
for (const sharedSlice of localSharedSlices) {
|
|
121
|
+
for (const variation of sharedSlice.model.variations) {
|
|
122
|
+
const variationFields = getFieldMappingFingerprint(
|
|
123
|
+
variation,
|
|
124
|
+
sharedSlice.model.name
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
if (
|
|
128
|
+
sliceFields.primary === variationFields.primary &&
|
|
129
|
+
sliceFields.items === variationFields.items
|
|
130
|
+
) {
|
|
131
|
+
results.push({
|
|
132
|
+
libraryID: sharedSlice.from,
|
|
133
|
+
sliceID: sharedSlice.model.id,
|
|
134
|
+
variationID: variation.id,
|
|
135
|
+
path: `${sharedSlice.from}::${sharedSlice.model.id}::${variation.id}`,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return results;
|
|
142
|
+
}, [slice, sliceName, localSharedSlices]);
|
|
143
|
+
|
|
144
|
+
const convertLegacySliceAndTrack = (args: ConvertLegacySliceAndTrackArgs) => {
|
|
145
|
+
if (isModalOpen === false) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
setIsLoading(true);
|
|
150
|
+
void (async () => {
|
|
151
|
+
void telemetry.track({
|
|
152
|
+
event: "legacy-slice:converted",
|
|
153
|
+
id: args.sliceID,
|
|
154
|
+
variation: args.variationID ?? "default",
|
|
155
|
+
library: args.libraryID,
|
|
156
|
+
conversionType: isModalOpen,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const { errors } =
|
|
160
|
+
await managerClient.slices.convertLegacySliceToSharedSlice({
|
|
161
|
+
model: slice.value,
|
|
162
|
+
src: {
|
|
163
|
+
...path,
|
|
164
|
+
sliceID: slice.key,
|
|
165
|
+
},
|
|
166
|
+
dest: {
|
|
167
|
+
libraryID: args.libraryID,
|
|
168
|
+
sliceID: args.sliceID,
|
|
169
|
+
variationName: args.variationName ?? "Default",
|
|
170
|
+
variationID: args.variationID ?? "default",
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
if (errors.length) {
|
|
175
|
+
console.error(
|
|
176
|
+
`Errors happened when converting slice \`${sliceName}\``,
|
|
177
|
+
errors
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const { model: customType, errors: customTypeReadErrors } =
|
|
182
|
+
await managerClient.customTypes.readCustomType({
|
|
183
|
+
id: path.customTypeID,
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
if (customTypeReadErrors.length || !customType) {
|
|
187
|
+
console.error(
|
|
188
|
+
`Errors happened when converting slice \`${sliceName}\``,
|
|
189
|
+
customTypeReadErrors
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
throw customTypeReadErrors;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// TODO(DT-1453): Remove the need of the global getState
|
|
196
|
+
const serverState = await getState();
|
|
197
|
+
// Update Redux store
|
|
198
|
+
refreshState(serverState);
|
|
199
|
+
|
|
200
|
+
setIsLoading(false);
|
|
201
|
+
setIsModalOpen(false);
|
|
202
|
+
switch (isModalOpen) {
|
|
203
|
+
case "as_new_slice":
|
|
204
|
+
openToaster(
|
|
205
|
+
`${sliceName} has been upgraded to a new slice ${args.libraryID} > ${args.sliceID}`,
|
|
206
|
+
ToasterType.SUCCESS
|
|
207
|
+
);
|
|
208
|
+
break;
|
|
209
|
+
|
|
210
|
+
case "as_new_variation":
|
|
211
|
+
openToaster(
|
|
212
|
+
`${sliceName} has been converted as a variation of ${args.libraryID} > ${args.sliceID}`,
|
|
213
|
+
ToasterType.SUCCESS
|
|
214
|
+
);
|
|
215
|
+
break;
|
|
216
|
+
|
|
217
|
+
case "merge_with_identical":
|
|
218
|
+
default:
|
|
219
|
+
openToaster(
|
|
220
|
+
`${sliceName} has been merged with ${args.libraryID} > ${args.sliceID}`,
|
|
221
|
+
ToasterType.SUCCESS
|
|
222
|
+
);
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const customTypeSM = CustomTypes.toSM(customType);
|
|
227
|
+
initCustomTypeStore(customTypeSM, customTypeSM);
|
|
228
|
+
saveCustomTypeSuccess(customType);
|
|
229
|
+
})();
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const formProps = {
|
|
233
|
+
path,
|
|
234
|
+
slice,
|
|
235
|
+
sliceName,
|
|
236
|
+
libraries,
|
|
237
|
+
localSharedSlices,
|
|
238
|
+
identicalSlices,
|
|
239
|
+
close: () => setIsModalOpen(false),
|
|
240
|
+
onSubmit: convertLegacySliceAndTrack,
|
|
241
|
+
isLoading,
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
return (
|
|
245
|
+
<>
|
|
246
|
+
<DropdownMenu>
|
|
247
|
+
<DropdownMenuTrigger>
|
|
248
|
+
<Button
|
|
249
|
+
data-cy="convert-legacy-slice"
|
|
250
|
+
startIcon="refresh"
|
|
251
|
+
endIcon="arrowDropDown"
|
|
252
|
+
size="medium"
|
|
253
|
+
variant="secondary"
|
|
254
|
+
>
|
|
255
|
+
Migrate legacy slice
|
|
256
|
+
</Button>
|
|
257
|
+
</DropdownMenuTrigger>
|
|
258
|
+
<DropdownMenuContent align="start">
|
|
259
|
+
<DropdownMenuItem
|
|
260
|
+
startIcon={<Icon name="folder" size="large" />}
|
|
261
|
+
description="Use it with new types"
|
|
262
|
+
onSelect={() => setIsModalOpen("as_new_slice")}
|
|
263
|
+
>
|
|
264
|
+
Upgrade slice
|
|
265
|
+
</DropdownMenuItem>
|
|
266
|
+
<DropdownMenuItem
|
|
267
|
+
startIcon={<Icon name="viewDay" size="large" />}
|
|
268
|
+
description="Add it to another slice"
|
|
269
|
+
onSelect={() => setIsModalOpen("as_new_variation")}
|
|
270
|
+
disabled={!localSharedSlices.length}
|
|
271
|
+
>
|
|
272
|
+
Convert to slice variation
|
|
273
|
+
</DropdownMenuItem>
|
|
274
|
+
<DropdownMenuItem
|
|
275
|
+
startIcon={<Icon name="driveFileMove" size="large" />}
|
|
276
|
+
description="Combine identical slices"
|
|
277
|
+
onSelect={() => setIsModalOpen("merge_with_identical")}
|
|
278
|
+
disabled={!identicalSlices.length}
|
|
279
|
+
>
|
|
280
|
+
Merge with another slice
|
|
281
|
+
</DropdownMenuItem>
|
|
282
|
+
</DropdownMenuContent>
|
|
283
|
+
</DropdownMenu>
|
|
284
|
+
<FormAsNewSlice {...formProps} isOpen={isModalOpen === "as_new_slice"} />
|
|
285
|
+
<FormAsNewVariation
|
|
286
|
+
{...formProps}
|
|
287
|
+
isOpen={isModalOpen === "as_new_variation"}
|
|
288
|
+
/>
|
|
289
|
+
<FormMergeWithIdentical
|
|
290
|
+
{...formProps}
|
|
291
|
+
isOpen={isModalOpen === "merge_with_identical"}
|
|
292
|
+
/>
|
|
293
|
+
</>
|
|
294
|
+
);
|
|
295
|
+
};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { useSelector } from "react-redux";
|
|
2
|
+
import { Formik } from "formik";
|
|
3
|
+
import {
|
|
4
|
+
Dialog,
|
|
5
|
+
DialogActions,
|
|
6
|
+
DialogContent,
|
|
7
|
+
DialogHeader,
|
|
8
|
+
ScrollArea,
|
|
9
|
+
FormInput,
|
|
10
|
+
Text,
|
|
11
|
+
Select,
|
|
12
|
+
SelectItem,
|
|
13
|
+
} from "@prismicio/editor-ui";
|
|
14
|
+
|
|
15
|
+
import { SliceMachineStoreType } from "@src/redux/type";
|
|
16
|
+
import { getRemoteSlices } from "@src/modules/slices";
|
|
17
|
+
import { pascalize } from "@lib/utils/str";
|
|
18
|
+
|
|
19
|
+
import { validateSliceModalValues as validateAsNewSliceValues } from "../formsValidator";
|
|
20
|
+
import * as styles from "./ConvertLegacySliceModal.css";
|
|
21
|
+
import { FormProps } from "./types";
|
|
22
|
+
|
|
23
|
+
export const FormAsNewSlice: React.FC<FormProps> = ({
|
|
24
|
+
isOpen,
|
|
25
|
+
close,
|
|
26
|
+
onSubmit,
|
|
27
|
+
isLoading,
|
|
28
|
+
slice,
|
|
29
|
+
libraries,
|
|
30
|
+
}) => {
|
|
31
|
+
const { remoteSlices } = useSelector((store: SliceMachineStoreType) => ({
|
|
32
|
+
remoteSlices: getRemoteSlices(store),
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Dialog
|
|
37
|
+
open={isOpen}
|
|
38
|
+
onOpenChange={(open) => !open && close()}
|
|
39
|
+
size={{ width: 448, height: "auto" }}
|
|
40
|
+
>
|
|
41
|
+
<DialogHeader title="Upgrade slice" />
|
|
42
|
+
<DialogContent>
|
|
43
|
+
<Formik
|
|
44
|
+
validateOnChange
|
|
45
|
+
initialValues={{
|
|
46
|
+
_init: false,
|
|
47
|
+
from: libraries[0]?.name,
|
|
48
|
+
sliceName: pascalize(slice.key),
|
|
49
|
+
}}
|
|
50
|
+
validate={(values) => {
|
|
51
|
+
return validateAsNewSliceValues(values, libraries, remoteSlices);
|
|
52
|
+
}}
|
|
53
|
+
onSubmit={(values) => {
|
|
54
|
+
onSubmit({ libraryID: values.from, sliceID: values.sliceName });
|
|
55
|
+
}}
|
|
56
|
+
>
|
|
57
|
+
{(formik) => {
|
|
58
|
+
// Just a hack to trigger validation on init for better UX
|
|
59
|
+
if (!formik.values._init) {
|
|
60
|
+
void formik.setFieldValue("_init", true);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<form
|
|
65
|
+
id="convert-legacy-slice-modal-as-new-slice"
|
|
66
|
+
data-cy="convert-legacy-slice-modal-as-new-slice"
|
|
67
|
+
className={styles.form}
|
|
68
|
+
>
|
|
69
|
+
<ScrollArea className={styles.scrollArea}>
|
|
70
|
+
<Text variant="normal" color="grey11">
|
|
71
|
+
This will create a new slice with the same fields. The new
|
|
72
|
+
slice will replace the legacy slice in all of your types,
|
|
73
|
+
and the existing slice content will be re-mapped to the new
|
|
74
|
+
slice.
|
|
75
|
+
</Text>
|
|
76
|
+
<Text variant="normal" color="grey11">
|
|
77
|
+
This will not migrate your component. You will need to do
|
|
78
|
+
that manually.
|
|
79
|
+
</Text>
|
|
80
|
+
<div className={styles.field}>
|
|
81
|
+
<label className={styles.label}>
|
|
82
|
+
<Text variant="bold">Display name*</Text>
|
|
83
|
+
{typeof formik.errors.sliceName === "string" ? (
|
|
84
|
+
<Text variant="small" color="tomato10">
|
|
85
|
+
{formik.errors.sliceName}
|
|
86
|
+
</Text>
|
|
87
|
+
) : null}
|
|
88
|
+
</label>
|
|
89
|
+
<FormInput
|
|
90
|
+
placeholder={`Pascalised Slice API ID (e.g. ${pascalize(
|
|
91
|
+
slice.key
|
|
92
|
+
)})`}
|
|
93
|
+
error={typeof formik.errors.sliceName === "string"}
|
|
94
|
+
value={formik.values.sliceName}
|
|
95
|
+
onValueChange={(value) =>
|
|
96
|
+
void formik.setFieldValue(
|
|
97
|
+
"sliceName",
|
|
98
|
+
value.slice(0, 30)
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
data-cy="slice-name-input"
|
|
102
|
+
/>
|
|
103
|
+
<Text variant="normal" color="grey11">
|
|
104
|
+
A display name for the slice
|
|
105
|
+
</Text>
|
|
106
|
+
</div>
|
|
107
|
+
<div className={styles.field}>
|
|
108
|
+
<label className={styles.label}>
|
|
109
|
+
<Text variant="bold">Slice library*</Text>
|
|
110
|
+
{typeof formik.errors.from === "string" ? (
|
|
111
|
+
<Text variant="small" color="tomato10">
|
|
112
|
+
{formik.errors.from}
|
|
113
|
+
</Text>
|
|
114
|
+
) : null}
|
|
115
|
+
</label>
|
|
116
|
+
<Select
|
|
117
|
+
size="medium"
|
|
118
|
+
variant="secondary"
|
|
119
|
+
startIcon="folder"
|
|
120
|
+
flexContent={true}
|
|
121
|
+
value={formik.values.from}
|
|
122
|
+
onValueChange={(value) =>
|
|
123
|
+
value ? void formik.setFieldValue("from", value) : null
|
|
124
|
+
}
|
|
125
|
+
>
|
|
126
|
+
{libraries.map((library) => (
|
|
127
|
+
<SelectItem key={library.name} value={library.name}>
|
|
128
|
+
{library.name}
|
|
129
|
+
</SelectItem>
|
|
130
|
+
))}
|
|
131
|
+
</Select>
|
|
132
|
+
<Text variant="normal" color="grey11">
|
|
133
|
+
The library where we'll store your slice
|
|
134
|
+
</Text>
|
|
135
|
+
</div>
|
|
136
|
+
</ScrollArea>
|
|
137
|
+
<DialogActions
|
|
138
|
+
ok={{
|
|
139
|
+
text: "Upgrade",
|
|
140
|
+
onClick: () => void formik.submitForm(),
|
|
141
|
+
loading: isLoading,
|
|
142
|
+
disabled: !formik.isValid,
|
|
143
|
+
}}
|
|
144
|
+
cancel={{ text: "Cancel" }}
|
|
145
|
+
/>
|
|
146
|
+
</form>
|
|
147
|
+
);
|
|
148
|
+
}}
|
|
149
|
+
</Formik>
|
|
150
|
+
</DialogContent>
|
|
151
|
+
</Dialog>
|
|
152
|
+
);
|
|
153
|
+
};
|