@sanity/cross-dataset-duplicator 1.4.2 → 1.5.0
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/README.md +1 -1
- package/dist/index.d.mts +81 -0
- package/dist/index.d.ts +0 -2
- package/dist/index.js +412 -941
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +654 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +24 -29
- package/dist/index.cjs.mjs +0 -7
- package/dist/index.esm.js +0 -1161
- package/dist/index.esm.js.map +0 -1
package/dist/index.esm.js
DELETED
|
@@ -1,1161 +0,0 @@
|
|
|
1
|
-
import { useClient, useSchema, useWorkspaces, Preview, definePlugin } from 'sanity';
|
|
2
|
-
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
-
import React, { useState, useEffect, useCallback, createContext, useContext } from 'react';
|
|
4
|
-
import { InfoOutlineIcon, ArrowRightIcon, SearchIcon, LaunchIcon } from '@sanity/icons';
|
|
5
|
-
import { useSecrets, SettingsView } from '@sanity/studio-secrets';
|
|
6
|
-
import { Card, Flex, Button, Badge, Tooltip, Box, Text, useTheme, Container, Stack, Label, Select, Checkbox, Spinner, Grid, TextInput } from '@sanity/ui';
|
|
7
|
-
import mapLimit from 'async/mapLimit';
|
|
8
|
-
import asyncify from 'async/asyncify';
|
|
9
|
-
import { extractWithPath } from '@sanity/mutator';
|
|
10
|
-
import { dset } from 'dset';
|
|
11
|
-
import { isAssetId, isSanityFileAsset } from '@sanity/asset-utils';
|
|
12
|
-
function createInitialMessage() {
|
|
13
|
-
let docCount = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
14
|
-
let refsCount = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
15
|
-
const message = [docCount === 1 ? "This Document contains" : "These ".concat(docCount, " Documents contain"), refsCount === 1 ? "1 Reference." : "".concat(refsCount, " References."), refsCount === 1 ? "That Document" : "Those Documents", "may have References too. If referenced Documents do not exist at the target Destination, this transaction will fail."];
|
|
16
|
-
return message.join(" ");
|
|
17
|
-
}
|
|
18
|
-
const stickyStyles = function () {
|
|
19
|
-
let isDarkMode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
20
|
-
return {
|
|
21
|
-
position: "sticky",
|
|
22
|
-
top: 0,
|
|
23
|
-
zIndex: 100,
|
|
24
|
-
backgroundColor: isDarkMode ? "rgba(10,10,10,0.95)" : "rgba(255,255,255,0.95)"
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
async function getDocumentsInArray(options) {
|
|
28
|
-
const {
|
|
29
|
-
fetchIds,
|
|
30
|
-
client,
|
|
31
|
-
pluginConfig,
|
|
32
|
-
currentIds,
|
|
33
|
-
projection
|
|
34
|
-
} = options;
|
|
35
|
-
const collection = [];
|
|
36
|
-
const filter = ["_id in $fetchIds", pluginConfig.filter].filter(Boolean).join(" && ");
|
|
37
|
-
const query = "*[".concat(filter, "]").concat(projection != null ? projection : "");
|
|
38
|
-
const data = await client.fetch(query, {
|
|
39
|
-
fetchIds: fetchIds != null ? fetchIds : []
|
|
40
|
-
});
|
|
41
|
-
if (!(data == null ? void 0 : data.length)) {
|
|
42
|
-
return [];
|
|
43
|
-
}
|
|
44
|
-
const localCurrentIds = currentIds != null ? currentIds : /* @__PURE__ */new Set();
|
|
45
|
-
const newDataIds = new Set(data.map(dataDoc => dataDoc._id).filter(id => (currentIds == null ? void 0 : currentIds.size) ? !localCurrentIds.has(id) : Boolean(id)));
|
|
46
|
-
if (newDataIds.size) {
|
|
47
|
-
collection.push(...data);
|
|
48
|
-
localCurrentIds.add(...newDataIds);
|
|
49
|
-
await Promise.all(data.map(async doc => {
|
|
50
|
-
const expr = ".._ref";
|
|
51
|
-
const references = extractWithPath(expr, doc).map(ref => ref.value);
|
|
52
|
-
if (references.length) {
|
|
53
|
-
const newReferenceIds = new Set(references.filter(ref => !localCurrentIds.has(ref)));
|
|
54
|
-
if (newReferenceIds.size) {
|
|
55
|
-
const referenceDocs = await getDocumentsInArray({
|
|
56
|
-
fetchIds: Array.from(newReferenceIds),
|
|
57
|
-
currentIds: localCurrentIds,
|
|
58
|
-
client,
|
|
59
|
-
pluginConfig
|
|
60
|
-
});
|
|
61
|
-
if (referenceDocs == null ? void 0 : referenceDocs.length) {
|
|
62
|
-
collection.push(...referenceDocs);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}));
|
|
67
|
-
}
|
|
68
|
-
const uniqueCollection = collection.filter(Boolean).reduce((acc, cur) => {
|
|
69
|
-
if (acc.some(doc => doc._id === cur._id)) {
|
|
70
|
-
return acc;
|
|
71
|
-
}
|
|
72
|
-
return [...acc, cur];
|
|
73
|
-
}, []);
|
|
74
|
-
return uniqueCollection;
|
|
75
|
-
}
|
|
76
|
-
const buttons = ["All", "None", null, "New", "Existing", "Older", null, "Documents", "Assets"];
|
|
77
|
-
function SelectButtons(props) {
|
|
78
|
-
const {
|
|
79
|
-
payload,
|
|
80
|
-
setPayload
|
|
81
|
-
} = props;
|
|
82
|
-
const [disabledActions, setDisabledActions] = useState([]);
|
|
83
|
-
useEffect(() => {
|
|
84
|
-
if (!(disabledActions == null ? void 0 : disabledActions.length) && payload.every(item => item.include)) {
|
|
85
|
-
setDisabledActions(["ALL"]);
|
|
86
|
-
}
|
|
87
|
-
}, [disabledActions == null ? void 0 : disabledActions.length, payload]);
|
|
88
|
-
function handleSelectButton(action) {
|
|
89
|
-
if (!action || !payload.length) return;
|
|
90
|
-
const newPayload = [...payload];
|
|
91
|
-
switch (action) {
|
|
92
|
-
case "ALL":
|
|
93
|
-
newPayload.map(item => item.include = true);
|
|
94
|
-
break;
|
|
95
|
-
case "NONE":
|
|
96
|
-
newPayload.map(item => item.include = false);
|
|
97
|
-
break;
|
|
98
|
-
case "NEW":
|
|
99
|
-
newPayload.map(item => item.include = Boolean(item.status === "CREATE"));
|
|
100
|
-
break;
|
|
101
|
-
case "EXISTING":
|
|
102
|
-
newPayload.map(item => item.include = Boolean(item.status === "EXISTS"));
|
|
103
|
-
break;
|
|
104
|
-
case "OLDER":
|
|
105
|
-
newPayload.map(item => item.include = Boolean(item.status === "OVERWRITE"));
|
|
106
|
-
break;
|
|
107
|
-
case "ASSETS":
|
|
108
|
-
newPayload.map(item => item.include = isAssetId(item.doc._id));
|
|
109
|
-
break;
|
|
110
|
-
case "DOCUMENTS":
|
|
111
|
-
newPayload.map(item => item.include = !isAssetId(item.doc._id));
|
|
112
|
-
break;
|
|
113
|
-
}
|
|
114
|
-
setDisabledActions([action]);
|
|
115
|
-
setPayload(newPayload);
|
|
116
|
-
}
|
|
117
|
-
return /* @__PURE__ */jsx(Card, {
|
|
118
|
-
padding: 1,
|
|
119
|
-
radius: 3,
|
|
120
|
-
shadow: 1,
|
|
121
|
-
children: /* @__PURE__ */jsx(Flex, {
|
|
122
|
-
gap: 2,
|
|
123
|
-
wrap: "wrap",
|
|
124
|
-
children: buttons.map((action, actionIndex) => action ? /* @__PURE__ */jsx(Button, {
|
|
125
|
-
fontSize: 1,
|
|
126
|
-
mode: "bleed",
|
|
127
|
-
padding: 2,
|
|
128
|
-
text: action,
|
|
129
|
-
disabled: disabledActions.includes(action.toUpperCase()),
|
|
130
|
-
onClick: () => handleSelectButton(action.toUpperCase())
|
|
131
|
-
}, action) :
|
|
132
|
-
// eslint-disable-next-line react/no-array-index-key
|
|
133
|
-
/* @__PURE__ */
|
|
134
|
-
jsx(Card, {
|
|
135
|
-
borderLeft: true
|
|
136
|
-
}, "divider-".concat(actionIndex)))
|
|
137
|
-
})
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
const documentTones = {
|
|
141
|
-
EXISTS: "primary",
|
|
142
|
-
OVERWRITE: "critical",
|
|
143
|
-
UPDATE: "caution",
|
|
144
|
-
CREATE: "positive",
|
|
145
|
-
UNPUBLISHED: "caution"
|
|
146
|
-
};
|
|
147
|
-
const assetTones = {
|
|
148
|
-
EXISTS: "critical",
|
|
149
|
-
OVERWRITE: "critical",
|
|
150
|
-
UPDATE: "critical",
|
|
151
|
-
CREATE: "positive",
|
|
152
|
-
UNPUBLISHED: "default"
|
|
153
|
-
};
|
|
154
|
-
const documentMessages = {
|
|
155
|
-
// Only happens once document is copied the first time, and _updatedAt is the same
|
|
156
|
-
EXISTS: "This document already exists at the Destination with the same ID with the same Updated time.",
|
|
157
|
-
// Is true immediately after transaction as _updatedAt is updated by API after mutation
|
|
158
|
-
// Is also true if the document at the destination has been manually modified
|
|
159
|
-
// Presently, the plugin doesn't actually compare the two documents
|
|
160
|
-
OVERWRITE: "A newer version of this document exists at the Destination, and it will be overwritten with this version.",
|
|
161
|
-
// Document at destination is older
|
|
162
|
-
UPDATE: "An older version of this document exists at the Destination, and it will be overwritten with this version.",
|
|
163
|
-
// Document at destination doesn't exist
|
|
164
|
-
CREATE: "This document will be created at the destination.",
|
|
165
|
-
UNPUBLISHED: "A Draft version of this Document exists in this Dataset, but only the Published version will be duplicated to the destination."
|
|
166
|
-
};
|
|
167
|
-
const assetMessages = {
|
|
168
|
-
EXISTS: "This Asset already exists at the Destination",
|
|
169
|
-
OVERWRITE: "This Asset already exists at the Destination",
|
|
170
|
-
UPDATE: "This Asset already exists at the Destination",
|
|
171
|
-
CREATE: "This Asset does not yet exist at the Destination",
|
|
172
|
-
UNPUBLISHED: ""
|
|
173
|
-
};
|
|
174
|
-
const assetStatus = {
|
|
175
|
-
EXISTS: "RE-UPLOAD",
|
|
176
|
-
OVERWRITE: "RE-UPLOAD",
|
|
177
|
-
UPDATE: "RE-UPLOAD",
|
|
178
|
-
CREATE: "UPLOAD",
|
|
179
|
-
UNPUBLISHED: ""
|
|
180
|
-
};
|
|
181
|
-
function StatusBadge(props) {
|
|
182
|
-
const {
|
|
183
|
-
status,
|
|
184
|
-
isAsset
|
|
185
|
-
} = props;
|
|
186
|
-
if (!status) {
|
|
187
|
-
return null;
|
|
188
|
-
}
|
|
189
|
-
const badgeTone = isAsset ? assetTones[status] : documentTones[status];
|
|
190
|
-
if (!badgeTone) {
|
|
191
|
-
return /* @__PURE__ */jsx(Badge, {
|
|
192
|
-
muted: true,
|
|
193
|
-
padding: 2,
|
|
194
|
-
fontSize: 1,
|
|
195
|
-
mode: "outline",
|
|
196
|
-
children: "Checking..."
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
const badgeText = isAsset ? assetMessages[status] : documentMessages[status];
|
|
200
|
-
const badgeStatus = isAsset ? assetStatus[status] : status;
|
|
201
|
-
return /* @__PURE__ */jsx(Tooltip, {
|
|
202
|
-
content: /* @__PURE__ */jsx(Box, {
|
|
203
|
-
padding: 3,
|
|
204
|
-
style: {
|
|
205
|
-
maxWidth: 200
|
|
206
|
-
},
|
|
207
|
-
children: /* @__PURE__ */jsx(Text, {
|
|
208
|
-
size: 1,
|
|
209
|
-
children: badgeText
|
|
210
|
-
})
|
|
211
|
-
}),
|
|
212
|
-
fallbackPlacements: ["right", "left"],
|
|
213
|
-
placement: "top",
|
|
214
|
-
portal: true,
|
|
215
|
-
children: /* @__PURE__ */jsxs(Badge, {
|
|
216
|
-
muted: true,
|
|
217
|
-
padding: 3,
|
|
218
|
-
fontSize: 1,
|
|
219
|
-
tone: badgeTone,
|
|
220
|
-
mode: "outline",
|
|
221
|
-
children: [badgeStatus, /* @__PURE__ */jsx(Box, {
|
|
222
|
-
marginLeft: 2,
|
|
223
|
-
display: "inline-block",
|
|
224
|
-
as: "span",
|
|
225
|
-
children: /* @__PURE__ */jsx(InfoOutlineIcon, {})
|
|
226
|
-
})]
|
|
227
|
-
})
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
function Feedback(props) {
|
|
231
|
-
const {
|
|
232
|
-
children,
|
|
233
|
-
tone = "caution"
|
|
234
|
-
} = props;
|
|
235
|
-
return /* @__PURE__ */jsx(Card, {
|
|
236
|
-
padding: 3,
|
|
237
|
-
radius: 2,
|
|
238
|
-
shadow: 1,
|
|
239
|
-
tone,
|
|
240
|
-
children: /* @__PURE__ */jsx(Text, {
|
|
241
|
-
size: 1,
|
|
242
|
-
children
|
|
243
|
-
})
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
var __defProp$1 = Object.defineProperty;
|
|
247
|
-
var __defProps$1 = Object.defineProperties;
|
|
248
|
-
var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
|
|
249
|
-
var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols;
|
|
250
|
-
var __hasOwnProp$2 = Object.prototype.hasOwnProperty;
|
|
251
|
-
var __propIsEnum$2 = Object.prototype.propertyIsEnumerable;
|
|
252
|
-
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, {
|
|
253
|
-
enumerable: true,
|
|
254
|
-
configurable: true,
|
|
255
|
-
writable: true,
|
|
256
|
-
value
|
|
257
|
-
}) : obj[key] = value;
|
|
258
|
-
var __spreadValues$1 = (a, b) => {
|
|
259
|
-
for (var prop in b || (b = {})) if (__hasOwnProp$2.call(b, prop)) __defNormalProp$1(a, prop, b[prop]);
|
|
260
|
-
if (__getOwnPropSymbols$2) for (var prop of __getOwnPropSymbols$2(b)) {
|
|
261
|
-
if (__propIsEnum$2.call(b, prop)) __defNormalProp$1(a, prop, b[prop]);
|
|
262
|
-
}
|
|
263
|
-
return a;
|
|
264
|
-
};
|
|
265
|
-
var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
|
|
266
|
-
function Duplicator(props) {
|
|
267
|
-
var _a, _b, _c;
|
|
268
|
-
const {
|
|
269
|
-
docs,
|
|
270
|
-
token,
|
|
271
|
-
pluginConfig,
|
|
272
|
-
onDuplicated
|
|
273
|
-
} = props;
|
|
274
|
-
const isDarkMode = useTheme().sanity.color.dark;
|
|
275
|
-
const originClient = useClient({
|
|
276
|
-
apiVersion: pluginConfig.apiVersion
|
|
277
|
-
});
|
|
278
|
-
const schema = useSchema();
|
|
279
|
-
const workspaces = useWorkspaces();
|
|
280
|
-
const workspacesOptions = workspaces.map(workspace => __spreadProps$1(__spreadValues$1({}, workspace), {
|
|
281
|
-
disabled: workspace.dataset === originClient.config().dataset && workspace.projectId === originClient.config().projectId
|
|
282
|
-
}));
|
|
283
|
-
const [destination, setDestination] = useState(workspaces.length ? (_a = workspacesOptions.find(space => !space.disabled)) != null ? _a : null : null);
|
|
284
|
-
const [message, setMessage] = useState(null);
|
|
285
|
-
const [payload, setPayload] = useState([]);
|
|
286
|
-
const [hasReferences, setHasReferences] = useState(false);
|
|
287
|
-
const [isDuplicating, setIsDuplicating] = useState(false);
|
|
288
|
-
const [isGathering, setIsGathering] = useState(false);
|
|
289
|
-
const [progress, setProgress] = useState([0, 0]);
|
|
290
|
-
useEffect(() => {
|
|
291
|
-
const expr = ".._ref";
|
|
292
|
-
const initialRefs = [];
|
|
293
|
-
const initialPayload = [];
|
|
294
|
-
docs.forEach(doc => {
|
|
295
|
-
const refs = extractWithPath(expr, doc).map(ref => ref.value);
|
|
296
|
-
initialRefs.push(...refs);
|
|
297
|
-
initialPayload.push({
|
|
298
|
-
include: true,
|
|
299
|
-
doc
|
|
300
|
-
});
|
|
301
|
-
});
|
|
302
|
-
updatePayloadStatuses(initialPayload);
|
|
303
|
-
const docCount = docs.length;
|
|
304
|
-
const refsCount = initialRefs.length;
|
|
305
|
-
if (initialRefs.length) {
|
|
306
|
-
setHasReferences(true);
|
|
307
|
-
setMessage({
|
|
308
|
-
tone: "caution",
|
|
309
|
-
text: createInitialMessage(docCount, refsCount)
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
}, [docs]);
|
|
313
|
-
useEffect(() => {
|
|
314
|
-
updatePayloadStatuses();
|
|
315
|
-
}, [destination]);
|
|
316
|
-
async function updatePayloadStatuses() {
|
|
317
|
-
let newPayload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
318
|
-
const payloadActual = newPayload.length ? newPayload : payload;
|
|
319
|
-
if (!payloadActual.length || !(destination == null ? void 0 : destination.name)) {
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
const payloadIds = payloadActual.map(_ref => {
|
|
323
|
-
let {
|
|
324
|
-
doc
|
|
325
|
-
} = _ref;
|
|
326
|
-
return doc._id;
|
|
327
|
-
});
|
|
328
|
-
const destinationClient = originClient.withConfig({
|
|
329
|
-
dataset: destination.dataset,
|
|
330
|
-
projectId: destination.projectId
|
|
331
|
-
});
|
|
332
|
-
const destinationData = await destinationClient.fetch("*[_id in $payloadIds]{ _id, _updatedAt }", {
|
|
333
|
-
payloadIds
|
|
334
|
-
});
|
|
335
|
-
const updatedPayload = payloadActual.map(item => {
|
|
336
|
-
var _a2;
|
|
337
|
-
const existingDoc = destinationData.find(doc => doc._id === item.doc._id);
|
|
338
|
-
if ((existingDoc == null ? void 0 : existingDoc._updatedAt) && ((_a2 = item == null ? void 0 : item.doc) == null ? void 0 : _a2._updatedAt)) {
|
|
339
|
-
if (existingDoc._updatedAt === item.doc._updatedAt) {
|
|
340
|
-
item.status = "EXISTS";
|
|
341
|
-
} else if (existingDoc._updatedAt && item.doc._updatedAt) {
|
|
342
|
-
item.status = new Date(existingDoc._updatedAt) > new Date(item.doc._updatedAt) ?
|
|
343
|
-
// Document at destination is newer
|
|
344
|
-
"OVERWRITE" :
|
|
345
|
-
// Document at destination is older
|
|
346
|
-
"UPDATE";
|
|
347
|
-
}
|
|
348
|
-
} else {
|
|
349
|
-
item.status = "CREATE";
|
|
350
|
-
}
|
|
351
|
-
return item;
|
|
352
|
-
});
|
|
353
|
-
setPayload(updatedPayload);
|
|
354
|
-
}
|
|
355
|
-
function handleCheckbox(_id) {
|
|
356
|
-
const updatedPayload = payload.map(item => {
|
|
357
|
-
if (item.doc._id === _id) {
|
|
358
|
-
item.include = !item.include;
|
|
359
|
-
}
|
|
360
|
-
return item;
|
|
361
|
-
});
|
|
362
|
-
setPayload(updatedPayload);
|
|
363
|
-
}
|
|
364
|
-
async function handleReferences() {
|
|
365
|
-
setIsGathering(true);
|
|
366
|
-
const docIds = docs.map(doc => doc._id);
|
|
367
|
-
const payloadDocs = await getDocumentsInArray({
|
|
368
|
-
fetchIds: docIds,
|
|
369
|
-
client: originClient,
|
|
370
|
-
pluginConfig
|
|
371
|
-
});
|
|
372
|
-
const draftDocs = await getDocumentsInArray({
|
|
373
|
-
fetchIds: docIds.map(id => "drafts.".concat(id)),
|
|
374
|
-
client: originClient,
|
|
375
|
-
projection: "{_id}",
|
|
376
|
-
pluginConfig
|
|
377
|
-
});
|
|
378
|
-
const draftDocsIds = new Set(draftDocs.map(_ref2 => {
|
|
379
|
-
let {
|
|
380
|
-
_id
|
|
381
|
-
} = _ref2;
|
|
382
|
-
return _id;
|
|
383
|
-
}));
|
|
384
|
-
const payloadShaped = payloadDocs.map(doc => ({
|
|
385
|
-
doc,
|
|
386
|
-
// Include this in the transaction?
|
|
387
|
-
include: true,
|
|
388
|
-
// Does it exist at the destination?
|
|
389
|
-
status: void 0,
|
|
390
|
-
// Does it have any drafts?
|
|
391
|
-
hasDraft: draftDocsIds.has("drafts.".concat(doc._id))
|
|
392
|
-
}));
|
|
393
|
-
setPayload(payloadShaped);
|
|
394
|
-
updatePayloadStatuses(payloadShaped);
|
|
395
|
-
setIsGathering(false);
|
|
396
|
-
}
|
|
397
|
-
async function handleDuplicate() {
|
|
398
|
-
if (!destination) {
|
|
399
|
-
return;
|
|
400
|
-
}
|
|
401
|
-
setIsDuplicating(true);
|
|
402
|
-
const assetsCount = payload.filter(_ref3 => {
|
|
403
|
-
let {
|
|
404
|
-
doc,
|
|
405
|
-
include
|
|
406
|
-
} = _ref3;
|
|
407
|
-
return include && isAssetId(doc._id);
|
|
408
|
-
}).length;
|
|
409
|
-
let currentProgress = 0;
|
|
410
|
-
setProgress([currentProgress, assetsCount]);
|
|
411
|
-
setMessage({
|
|
412
|
-
text: "Duplicating...",
|
|
413
|
-
tone: "transparent"
|
|
414
|
-
});
|
|
415
|
-
const destinationClient = originClient.withConfig({
|
|
416
|
-
apiVersion: pluginConfig.apiVersion,
|
|
417
|
-
dataset: destination.dataset,
|
|
418
|
-
projectId: destination.projectId
|
|
419
|
-
});
|
|
420
|
-
const transactionDocs = [];
|
|
421
|
-
const svgMaps = [];
|
|
422
|
-
async function fetchDoc(doc) {
|
|
423
|
-
if (isAssetId(doc._id)) {
|
|
424
|
-
const typeIsFile = isSanityFileAsset(doc);
|
|
425
|
-
const downloadUrl = typeIsFile ? doc.url : "".concat(doc.url, "?dlRaw=true");
|
|
426
|
-
const downloadConfig = typeIsFile ? {} : {
|
|
427
|
-
headers: {
|
|
428
|
-
Authorization: "Bearer ".concat(token)
|
|
429
|
-
}
|
|
430
|
-
};
|
|
431
|
-
await fetch(downloadUrl, downloadConfig).then(async res => {
|
|
432
|
-
const assetData = await res.blob();
|
|
433
|
-
const options = {
|
|
434
|
-
filename: doc.originalFilename
|
|
435
|
-
};
|
|
436
|
-
const assetDoc = await destinationClient.assets.upload(typeIsFile ? "file" : "image", assetData, options);
|
|
437
|
-
if ((doc == null ? void 0 : doc.extension) === "svg") {
|
|
438
|
-
svgMaps.push({
|
|
439
|
-
old: doc._id,
|
|
440
|
-
new: assetDoc._id
|
|
441
|
-
});
|
|
442
|
-
}
|
|
443
|
-
transactionDocs.push(assetDoc);
|
|
444
|
-
doc.url = assetDoc.url;
|
|
445
|
-
doc.path = assetDoc.path;
|
|
446
|
-
});
|
|
447
|
-
currentProgress += 1;
|
|
448
|
-
setMessage({
|
|
449
|
-
text: "Duplicating ".concat(currentProgress, "/").concat(assetsCount, " ").concat(assetsCount === 1 ? "Assets" : "Assets"),
|
|
450
|
-
tone: "default"
|
|
451
|
-
});
|
|
452
|
-
setProgress([currentProgress, assetsCount]);
|
|
453
|
-
}
|
|
454
|
-
return transactionDocs.push(doc);
|
|
455
|
-
}
|
|
456
|
-
const result = new Promise((resolve, reject) => {
|
|
457
|
-
const payloadIncludedDocs = payload.filter(item => item.include).map(item => item.doc);
|
|
458
|
-
mapLimit(payloadIncludedDocs, 3, asyncify(fetchDoc), err => {
|
|
459
|
-
if (err) {
|
|
460
|
-
setIsDuplicating(false);
|
|
461
|
-
setMessage({
|
|
462
|
-
tone: "critical",
|
|
463
|
-
text: "Duplication Failed"
|
|
464
|
-
});
|
|
465
|
-
console.error(err);
|
|
466
|
-
reject(new Error("Duplication Failed"));
|
|
467
|
-
}
|
|
468
|
-
resolve();
|
|
469
|
-
});
|
|
470
|
-
});
|
|
471
|
-
await result;
|
|
472
|
-
const transactionDocsMapped = transactionDocs.map(doc => {
|
|
473
|
-
const expr = ".._ref";
|
|
474
|
-
const references = extractWithPath(expr, doc);
|
|
475
|
-
if (!references.length) {
|
|
476
|
-
return doc;
|
|
477
|
-
}
|
|
478
|
-
references.forEach(ref => {
|
|
479
|
-
var _a2;
|
|
480
|
-
const newRefValue = (_a2 = svgMaps.find(asset => asset.old === ref.value)) == null ? void 0 : _a2.new;
|
|
481
|
-
if (newRefValue) {
|
|
482
|
-
const refPath = ref.path.join(".");
|
|
483
|
-
dset(doc, refPath, newRefValue);
|
|
484
|
-
}
|
|
485
|
-
});
|
|
486
|
-
return doc;
|
|
487
|
-
});
|
|
488
|
-
const transaction = destinationClient.transaction();
|
|
489
|
-
transactionDocsMapped.forEach(doc => {
|
|
490
|
-
transaction.createOrReplace(doc);
|
|
491
|
-
});
|
|
492
|
-
await transaction.commit().then(res => {
|
|
493
|
-
setMessage({
|
|
494
|
-
tone: "positive",
|
|
495
|
-
text: "Duplication complete!"
|
|
496
|
-
});
|
|
497
|
-
updatePayloadStatuses();
|
|
498
|
-
}).catch(err => {
|
|
499
|
-
setMessage({
|
|
500
|
-
tone: "critical",
|
|
501
|
-
text: err.details.description
|
|
502
|
-
});
|
|
503
|
-
});
|
|
504
|
-
setIsDuplicating(false);
|
|
505
|
-
setProgress([0, 0]);
|
|
506
|
-
if (onDuplicated) {
|
|
507
|
-
try {
|
|
508
|
-
await onDuplicated();
|
|
509
|
-
} catch (error) {
|
|
510
|
-
setMessage({
|
|
511
|
-
tone: "critical",
|
|
512
|
-
text: "Error in onDuplicated hook: ".concat(error)
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
function handleChange(e) {
|
|
518
|
-
if (!workspacesOptions.length) {
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
521
|
-
const targeted = workspacesOptions.find(space => space.name === e.currentTarget.value);
|
|
522
|
-
if (targeted) {
|
|
523
|
-
setDestination(targeted);
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
const payloadCount = payload.length;
|
|
527
|
-
const firstSvgIndex = payload.findIndex(_ref4 => {
|
|
528
|
-
let {
|
|
529
|
-
doc
|
|
530
|
-
} = _ref4;
|
|
531
|
-
return doc.extension === "svg";
|
|
532
|
-
});
|
|
533
|
-
const selectedDocumentsCount = payload.filter(item => item.include && !isAssetId(item.doc._id)).length;
|
|
534
|
-
const selectedAssetsCount = payload.filter(item => item.include && isAssetId(item.doc._id)).length;
|
|
535
|
-
const selectedTotal = selectedDocumentsCount + selectedAssetsCount;
|
|
536
|
-
const destinationTitle = (_b = destination == null ? void 0 : destination.title) != null ? _b : destination == null ? void 0 : destination.name;
|
|
537
|
-
const hasMultipleProjectIds = new Set(workspacesOptions.map(space => space == null ? void 0 : space.projectId).filter(Boolean)).size > 1;
|
|
538
|
-
const headingText = [selectedTotal, "/", payloadCount, "Documents and Assets selected"].join(" ");
|
|
539
|
-
const buttonText = React.useMemo(() => {
|
|
540
|
-
const text = ["Duplicate"];
|
|
541
|
-
if (selectedDocumentsCount > 1) {
|
|
542
|
-
text.push(String(selectedDocumentsCount), selectedDocumentsCount === 1 ? "Document" : "Documents");
|
|
543
|
-
}
|
|
544
|
-
if (selectedAssetsCount > 1) {
|
|
545
|
-
text.push("and", String(selectedAssetsCount), selectedAssetsCount === 1 ? "Asset" : "Assets");
|
|
546
|
-
}
|
|
547
|
-
if (originClient.config().projectId !== (destination == null ? void 0 : destination.projectId)) {
|
|
548
|
-
text.push("between Projects");
|
|
549
|
-
}
|
|
550
|
-
text.push("to", String(destinationTitle));
|
|
551
|
-
return text.join(" ");
|
|
552
|
-
}, [selectedDocumentsCount, selectedAssetsCount, originClient, destination == null ? void 0 : destination.projectId, destinationTitle]);
|
|
553
|
-
if (workspacesOptions.length < 2) {
|
|
554
|
-
return /* @__PURE__ */jsxs(Feedback, {
|
|
555
|
-
tone: "critical",
|
|
556
|
-
children: [/* @__PURE__ */jsx("code", {
|
|
557
|
-
children: "sanity.config.ts"
|
|
558
|
-
}), " must contain at least two Workspaces to use this plugin."]
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
return /* @__PURE__ */jsx(Container, {
|
|
562
|
-
width: 1,
|
|
563
|
-
children: /* @__PURE__ */jsx(Card, {
|
|
564
|
-
border: true,
|
|
565
|
-
children: /* @__PURE__ */jsxs(Stack, {
|
|
566
|
-
children: [/* @__PURE__ */jsx(Card, {
|
|
567
|
-
padding: 4,
|
|
568
|
-
style: stickyStyles(isDarkMode),
|
|
569
|
-
children: /* @__PURE__ */jsxs(Stack, {
|
|
570
|
-
space: 4,
|
|
571
|
-
children: [/* @__PURE__ */jsxs(Flex, {
|
|
572
|
-
gap: 3,
|
|
573
|
-
children: [/* @__PURE__ */jsxs(Stack, {
|
|
574
|
-
style: {
|
|
575
|
-
flex: 1
|
|
576
|
-
},
|
|
577
|
-
space: 3,
|
|
578
|
-
children: [/* @__PURE__ */jsx(Label, {
|
|
579
|
-
children: "Duplicate from"
|
|
580
|
-
}), /* @__PURE__ */jsx(Select, {
|
|
581
|
-
readOnly: true,
|
|
582
|
-
value: (_c = workspacesOptions.find(space => space.disabled)) == null ? void 0 : _c.name,
|
|
583
|
-
children: workspacesOptions.filter(space => space.disabled).map(space => {
|
|
584
|
-
var _a2;
|
|
585
|
-
return /* @__PURE__ */jsxs("option", {
|
|
586
|
-
value: space.name,
|
|
587
|
-
disabled: space.disabled,
|
|
588
|
-
children: [(_a2 = space.title) != null ? _a2 : space.name, hasMultipleProjectIds ? " (".concat(space.projectId, ")") : ""]
|
|
589
|
-
}, space.name);
|
|
590
|
-
})
|
|
591
|
-
})]
|
|
592
|
-
}), /* @__PURE__ */jsx(Box, {
|
|
593
|
-
padding: 4,
|
|
594
|
-
paddingTop: 5,
|
|
595
|
-
paddingBottom: 0,
|
|
596
|
-
children: /* @__PURE__ */jsx(Text, {
|
|
597
|
-
size: 3,
|
|
598
|
-
children: /* @__PURE__ */jsx(ArrowRightIcon, {})
|
|
599
|
-
})
|
|
600
|
-
}), /* @__PURE__ */jsxs(Stack, {
|
|
601
|
-
style: {
|
|
602
|
-
flex: 1
|
|
603
|
-
},
|
|
604
|
-
space: 3,
|
|
605
|
-
children: [/* @__PURE__ */jsx(Label, {
|
|
606
|
-
children: "To Destination"
|
|
607
|
-
}), /* @__PURE__ */jsx(Select, {
|
|
608
|
-
onChange: handleChange,
|
|
609
|
-
children: workspacesOptions.map(space => {
|
|
610
|
-
var _a2;
|
|
611
|
-
return /* @__PURE__ */jsxs("option", {
|
|
612
|
-
value: space.name,
|
|
613
|
-
disabled: space.disabled,
|
|
614
|
-
children: [(_a2 = space.title) != null ? _a2 : space.name, hasMultipleProjectIds ? " (".concat(space.projectId, ")") : "", space.disabled ? " (Current)" : ""]
|
|
615
|
-
}, space.name);
|
|
616
|
-
})
|
|
617
|
-
})]
|
|
618
|
-
})]
|
|
619
|
-
}), isDuplicating && /* @__PURE__ */jsx(Card, {
|
|
620
|
-
border: true,
|
|
621
|
-
radius: 2,
|
|
622
|
-
children: /* @__PURE__ */jsx(Card, {
|
|
623
|
-
style: {
|
|
624
|
-
width: "100%",
|
|
625
|
-
transform: "scaleX(".concat(progress[0] / progress[1], ")"),
|
|
626
|
-
transformOrigin: "left",
|
|
627
|
-
transition: "transform .2s ease",
|
|
628
|
-
boxSizing: "border-box"
|
|
629
|
-
},
|
|
630
|
-
padding: 1,
|
|
631
|
-
tone: "positive"
|
|
632
|
-
})
|
|
633
|
-
}), payload.length > 0 && /* @__PURE__ */jsxs(Fragment, {
|
|
634
|
-
children: [/* @__PURE__ */jsx(Label, {
|
|
635
|
-
children: headingText
|
|
636
|
-
}), /* @__PURE__ */jsx(SelectButtons, {
|
|
637
|
-
payload,
|
|
638
|
-
setPayload
|
|
639
|
-
})]
|
|
640
|
-
})]
|
|
641
|
-
})
|
|
642
|
-
}), /* @__PURE__ */jsx(Card, {
|
|
643
|
-
borderTop: true,
|
|
644
|
-
padding: 4,
|
|
645
|
-
children: /* @__PURE__ */jsxs(Stack, {
|
|
646
|
-
space: 3,
|
|
647
|
-
children: [message && /* @__PURE__ */jsx(Card, {
|
|
648
|
-
padding: 3,
|
|
649
|
-
radius: 2,
|
|
650
|
-
shadow: 1,
|
|
651
|
-
tone: message.tone,
|
|
652
|
-
children: /* @__PURE__ */jsx(Text, {
|
|
653
|
-
size: 1,
|
|
654
|
-
children: message.text
|
|
655
|
-
})
|
|
656
|
-
}), payload.length > 0 ? /* @__PURE__ */jsx(Stack, {
|
|
657
|
-
children: payload.map((_ref5, index) => {
|
|
658
|
-
let {
|
|
659
|
-
doc,
|
|
660
|
-
include,
|
|
661
|
-
status,
|
|
662
|
-
hasDraft
|
|
663
|
-
} = _ref5;
|
|
664
|
-
const schemaType = schema.get(doc._type);
|
|
665
|
-
return /* @__PURE__ */jsxs(React.Fragment, {
|
|
666
|
-
children: [/* @__PURE__ */jsxs(Flex, {
|
|
667
|
-
align: "center",
|
|
668
|
-
children: [/* @__PURE__ */jsx(Checkbox, {
|
|
669
|
-
checked: include,
|
|
670
|
-
onChange: () => handleCheckbox(doc._id)
|
|
671
|
-
}), /* @__PURE__ */jsx(Box, {
|
|
672
|
-
flex: 1,
|
|
673
|
-
paddingX: 3,
|
|
674
|
-
children: schemaType ? /* @__PURE__ */jsx(Preview, {
|
|
675
|
-
value: doc,
|
|
676
|
-
schemaType
|
|
677
|
-
}) : /* @__PURE__ */jsx(Card, {
|
|
678
|
-
tone: "caution",
|
|
679
|
-
children: "Invalid schema type"
|
|
680
|
-
})
|
|
681
|
-
}), /* @__PURE__ */jsxs(Flex, {
|
|
682
|
-
align: "center",
|
|
683
|
-
gap: 2,
|
|
684
|
-
children: [hasDraft ? /* @__PURE__ */jsx(StatusBadge, {
|
|
685
|
-
status: "UNPUBLISHED",
|
|
686
|
-
isAsset: false
|
|
687
|
-
}) : null, /* @__PURE__ */jsx(StatusBadge, {
|
|
688
|
-
status,
|
|
689
|
-
isAsset: isAssetId(doc._id)
|
|
690
|
-
})]
|
|
691
|
-
})]
|
|
692
|
-
}), (doc == null ? void 0 : doc.extension) === "svg" && index === firstSvgIndex && /* @__PURE__ */jsx(Card, {
|
|
693
|
-
padding: 3,
|
|
694
|
-
radius: 2,
|
|
695
|
-
shadow: 1,
|
|
696
|
-
tone: "caution",
|
|
697
|
-
children: /* @__PURE__ */jsxs(Text, {
|
|
698
|
-
size: 1,
|
|
699
|
-
children: ["Due to how SVGs are sanitized after first uploaded, duplicated SVG assets may have new ", /* @__PURE__ */jsx("code", {
|
|
700
|
-
children: "_id"
|
|
701
|
-
}), "'s at the destination. The newly generated ", /* @__PURE__ */jsx("code", {
|
|
702
|
-
children: "_id"
|
|
703
|
-
}), " will be the same in each duplication, but it will never be the same ", /* @__PURE__ */jsx("code", {
|
|
704
|
-
children: "_id"
|
|
705
|
-
}), " as the first time this Asset was uploaded. References to the asset will be updated to use the new ", /* @__PURE__ */jsx("code", {
|
|
706
|
-
children: "_id"
|
|
707
|
-
}), "."]
|
|
708
|
-
})
|
|
709
|
-
})]
|
|
710
|
-
}, doc._id);
|
|
711
|
-
})
|
|
712
|
-
}) : /* @__PURE__ */jsx(Flex, {
|
|
713
|
-
padding: 4,
|
|
714
|
-
align: "center",
|
|
715
|
-
justify: "center",
|
|
716
|
-
children: /* @__PURE__ */jsx(Spinner, {})
|
|
717
|
-
}), /* @__PURE__ */jsxs(Stack, {
|
|
718
|
-
space: 2,
|
|
719
|
-
children: [hasReferences && /* @__PURE__ */jsx(Button, {
|
|
720
|
-
fontSize: 2,
|
|
721
|
-
padding: 4,
|
|
722
|
-
tone: "positive",
|
|
723
|
-
mode: "ghost",
|
|
724
|
-
icon: SearchIcon,
|
|
725
|
-
onClick: handleReferences,
|
|
726
|
-
text: "Gather References",
|
|
727
|
-
disabled: isDuplicating || !selectedTotal || isGathering
|
|
728
|
-
}), /* @__PURE__ */jsx(Button, {
|
|
729
|
-
fontSize: 2,
|
|
730
|
-
padding: 4,
|
|
731
|
-
tone: "positive",
|
|
732
|
-
icon: LaunchIcon,
|
|
733
|
-
onClick: handleDuplicate,
|
|
734
|
-
text: buttonText,
|
|
735
|
-
disabled: isDuplicating || !selectedTotal || isGathering
|
|
736
|
-
})]
|
|
737
|
-
})]
|
|
738
|
-
})
|
|
739
|
-
})]
|
|
740
|
-
})
|
|
741
|
-
})
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
|
-
function DuplicatorQuery(props) {
|
|
745
|
-
var _a;
|
|
746
|
-
const {
|
|
747
|
-
token,
|
|
748
|
-
pluginConfig
|
|
749
|
-
} = props;
|
|
750
|
-
const {
|
|
751
|
-
queries: preDefinedQueries,
|
|
752
|
-
apiVersion
|
|
753
|
-
} = pluginConfig;
|
|
754
|
-
const originClient = useClient({
|
|
755
|
-
apiVersion
|
|
756
|
-
});
|
|
757
|
-
const schema = useSchema();
|
|
758
|
-
const schemaTypes = schema.getTypeNames();
|
|
759
|
-
const [value, setValue] = useState("");
|
|
760
|
-
const [fetched, setFetched] = useState(false);
|
|
761
|
-
const [initialData, setInitialData] = useState({
|
|
762
|
-
docs: []
|
|
763
|
-
});
|
|
764
|
-
function handleSubmit(e) {
|
|
765
|
-
if (e) e.preventDefault();
|
|
766
|
-
originClient.fetch(value).then(res => {
|
|
767
|
-
const registeredAndPublishedDocs = res.length ? res.filter(doc => schemaTypes.includes(doc._type)).filter(doc => !doc._id.startsWith("drafts.")) : [];
|
|
768
|
-
setInitialData({
|
|
769
|
-
docs: registeredAndPublishedDocs
|
|
770
|
-
});
|
|
771
|
-
setFetched(true);
|
|
772
|
-
}).catch(err => console.error(err));
|
|
773
|
-
}
|
|
774
|
-
useEffect(() => {
|
|
775
|
-
var _a2;
|
|
776
|
-
if (!((_a2 = initialData.docs) == null ? void 0 : _a2.length) && value) {
|
|
777
|
-
handleSubmit();
|
|
778
|
-
}
|
|
779
|
-
}, []);
|
|
780
|
-
return /* @__PURE__ */jsx(Card, {
|
|
781
|
-
padding: [0, 0, 0, 5],
|
|
782
|
-
children: /* @__PURE__ */jsx(Container, {
|
|
783
|
-
children: /* @__PURE__ */jsxs(Grid, {
|
|
784
|
-
columns: [1, 1, 1, 2],
|
|
785
|
-
gap: [1, 1, 1, 4],
|
|
786
|
-
children: [/* @__PURE__ */jsxs(Box, {
|
|
787
|
-
padding: [2, 2, 2, 0],
|
|
788
|
-
children: [/* @__PURE__ */jsx(Card, {
|
|
789
|
-
padding: 4,
|
|
790
|
-
radius: 3,
|
|
791
|
-
border: true,
|
|
792
|
-
children: /* @__PURE__ */jsxs(Stack, {
|
|
793
|
-
space: 4,
|
|
794
|
-
children: [/* @__PURE__ */jsx(Box, {
|
|
795
|
-
children: /* @__PURE__ */jsx(Label, {
|
|
796
|
-
children: "Initial Documents Query"
|
|
797
|
-
})
|
|
798
|
-
}), /* @__PURE__ */jsx(Box, {
|
|
799
|
-
children: /* @__PURE__ */jsx(Text, {
|
|
800
|
-
children: "Start with a valid GROQ query to load initial documents. The query will need to return an Array of Objects. Drafts will be removed from the results."
|
|
801
|
-
})
|
|
802
|
-
}), /* @__PURE__ */jsx("form", {
|
|
803
|
-
onSubmit: handleSubmit,
|
|
804
|
-
children: /* @__PURE__ */jsxs(Flex, {
|
|
805
|
-
children: [/* @__PURE__ */jsx(Box, {
|
|
806
|
-
flex: 1,
|
|
807
|
-
paddingRight: 2,
|
|
808
|
-
children: /* @__PURE__ */jsx(TextInput, {
|
|
809
|
-
style: {
|
|
810
|
-
fontFamily: "monospace"
|
|
811
|
-
},
|
|
812
|
-
fontSize: 2,
|
|
813
|
-
onChange: event => setValue(event.currentTarget.value),
|
|
814
|
-
padding: 4,
|
|
815
|
-
placeholder: '*[_type == "article"]',
|
|
816
|
-
value: value != null ? value : ""
|
|
817
|
-
})
|
|
818
|
-
}), /* @__PURE__ */jsx(Button, {
|
|
819
|
-
padding: 2,
|
|
820
|
-
paddingX: 4,
|
|
821
|
-
tone: "primary",
|
|
822
|
-
onClick: handleSubmit,
|
|
823
|
-
text: "Query",
|
|
824
|
-
disabled: !value
|
|
825
|
-
})]
|
|
826
|
-
})
|
|
827
|
-
})]
|
|
828
|
-
})
|
|
829
|
-
}), preDefinedQueries && (preDefinedQueries == null ? void 0 : preDefinedQueries.length) > 0 && /* @__PURE__ */jsx(Card, {
|
|
830
|
-
marginTop: 2,
|
|
831
|
-
padding: 4,
|
|
832
|
-
radius: 3,
|
|
833
|
-
border: true,
|
|
834
|
-
children: /* @__PURE__ */jsx(Box, {
|
|
835
|
-
children: /* @__PURE__ */jsxs(Stack, {
|
|
836
|
-
space: 4,
|
|
837
|
-
children: [/* @__PURE__ */jsx(Box, {
|
|
838
|
-
children: /* @__PURE__ */jsx(Label, {
|
|
839
|
-
children: "Predefined Queries"
|
|
840
|
-
})
|
|
841
|
-
}), /* @__PURE__ */jsx(Stack, {
|
|
842
|
-
space: 2,
|
|
843
|
-
children: preDefinedQueries.map(query => /* @__PURE__ */jsx(Button, {
|
|
844
|
-
padding: 2,
|
|
845
|
-
paddingX: 4,
|
|
846
|
-
tone: "primary",
|
|
847
|
-
onClick: () => setValue("*[".concat(query.query, "]")),
|
|
848
|
-
text: query.label
|
|
849
|
-
}, query.label.replace(/\s+/g, "-")))
|
|
850
|
-
})]
|
|
851
|
-
})
|
|
852
|
-
})
|
|
853
|
-
})]
|
|
854
|
-
}), fetched && initialData.docs.length < 1 && /* @__PURE__ */jsx(Container, {
|
|
855
|
-
width: 1,
|
|
856
|
-
children: /* @__PURE__ */jsx(Card, {
|
|
857
|
-
padding: 5,
|
|
858
|
-
children: value ? "No documents match this query" : "Start with a valid GROQ query"
|
|
859
|
-
})
|
|
860
|
-
}), ((_a = initialData.docs) == null ? void 0 : _a.length) > 0 && /* @__PURE__ */jsx(Duplicator, {
|
|
861
|
-
docs: initialData.docs,
|
|
862
|
-
token,
|
|
863
|
-
pluginConfig
|
|
864
|
-
})]
|
|
865
|
-
})
|
|
866
|
-
})
|
|
867
|
-
});
|
|
868
|
-
}
|
|
869
|
-
function DuplicatorWrapper(props) {
|
|
870
|
-
const {
|
|
871
|
-
docs,
|
|
872
|
-
token,
|
|
873
|
-
pluginConfig,
|
|
874
|
-
onDuplicated
|
|
875
|
-
} = props;
|
|
876
|
-
const [inbound, setInbound] = useState([]);
|
|
877
|
-
const {
|
|
878
|
-
follow = [],
|
|
879
|
-
apiVersion
|
|
880
|
-
} = pluginConfig;
|
|
881
|
-
const [mode, setMode] = useState(follow.length === 1 ? follow[0] : "outbound");
|
|
882
|
-
const client = useClient({
|
|
883
|
-
apiVersion
|
|
884
|
-
});
|
|
885
|
-
useEffect(() => {
|
|
886
|
-
(async () => {
|
|
887
|
-
if (follow.includes("inbound")) {
|
|
888
|
-
const inboundReferences = await client.fetch("*[references($id)]", {
|
|
889
|
-
id: docs[0]._id
|
|
890
|
-
});
|
|
891
|
-
setInbound([...props.docs, ...inboundReferences]);
|
|
892
|
-
}
|
|
893
|
-
})();
|
|
894
|
-
}, []);
|
|
895
|
-
return /* @__PURE__ */jsxs(Container, {
|
|
896
|
-
children: [follow.length > 1 && (follow.includes("inbound") || follow.includes("outbound")) ? /* @__PURE__ */jsx(Card, {
|
|
897
|
-
paddingX: 4,
|
|
898
|
-
paddingBottom: 4,
|
|
899
|
-
marginBottom: 4,
|
|
900
|
-
borderBottom: true,
|
|
901
|
-
children: /* @__PURE__ */jsxs(Grid, {
|
|
902
|
-
columns: 2,
|
|
903
|
-
gap: 4,
|
|
904
|
-
children: [follow.includes("outbound") ? /* @__PURE__ */jsx(Button, {
|
|
905
|
-
mode: "ghost",
|
|
906
|
-
tone: "primary",
|
|
907
|
-
selected: mode === "outbound",
|
|
908
|
-
onClick: () => setMode("outbound"),
|
|
909
|
-
text: "Outbound"
|
|
910
|
-
}) : null, follow.includes("inbound") ? /* @__PURE__ */jsx(Button, {
|
|
911
|
-
mode: "ghost",
|
|
912
|
-
tone: "primary",
|
|
913
|
-
selected: mode === "inbound",
|
|
914
|
-
onClick: () => setMode("inbound"),
|
|
915
|
-
disabled: inbound.length === 0,
|
|
916
|
-
text: inbound.length > 0 ? "Inbound (".concat(inbound.length, ")") : "No inbound references"
|
|
917
|
-
}) : null]
|
|
918
|
-
})
|
|
919
|
-
}) : null, /* @__PURE__ */jsx(Duplicator, {
|
|
920
|
-
docs: mode === "outbound" ? docs : inbound,
|
|
921
|
-
token,
|
|
922
|
-
pluginConfig,
|
|
923
|
-
onDuplicated
|
|
924
|
-
})]
|
|
925
|
-
});
|
|
926
|
-
}
|
|
927
|
-
const SECRET_NAMESPACE = "CrossDatasetDuplicator";
|
|
928
|
-
const DEFAULT_CONFIG = {
|
|
929
|
-
apiVersion: "2025-02-19",
|
|
930
|
-
tool: true,
|
|
931
|
-
types: [],
|
|
932
|
-
filter: "",
|
|
933
|
-
follow: ["outbound"],
|
|
934
|
-
queries: []
|
|
935
|
-
};
|
|
936
|
-
function ResetSecret(_ref6) {
|
|
937
|
-
let {
|
|
938
|
-
apiVersion
|
|
939
|
-
} = _ref6;
|
|
940
|
-
const client = useClient({
|
|
941
|
-
apiVersion
|
|
942
|
-
});
|
|
943
|
-
const handleClick = useCallback(() => {
|
|
944
|
-
client.delete({
|
|
945
|
-
query: '*[_id == "secrets.'.concat(SECRET_NAMESPACE, '"]')
|
|
946
|
-
});
|
|
947
|
-
}, [client]);
|
|
948
|
-
return /* @__PURE__ */jsx(Flex, {
|
|
949
|
-
align: "center",
|
|
950
|
-
justify: "flex-end",
|
|
951
|
-
paddingX: [2, 2, 2, 5],
|
|
952
|
-
paddingY: 5,
|
|
953
|
-
children: /* @__PURE__ */jsx(Button, {
|
|
954
|
-
text: "Reset Secret",
|
|
955
|
-
onClick: handleClick,
|
|
956
|
-
mode: "ghost",
|
|
957
|
-
tone: "critical",
|
|
958
|
-
fontSize: 1,
|
|
959
|
-
padding: 2
|
|
960
|
-
})
|
|
961
|
-
});
|
|
962
|
-
}
|
|
963
|
-
var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
|
|
964
|
-
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
|
|
965
|
-
var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
|
|
966
|
-
var __objRest = (source, exclude) => {
|
|
967
|
-
var target = {};
|
|
968
|
-
for (var prop in source) if (__hasOwnProp$1.call(source, prop) && exclude.indexOf(prop) < 0) target[prop] = source[prop];
|
|
969
|
-
if (source != null && __getOwnPropSymbols$1) for (var prop of __getOwnPropSymbols$1(source)) {
|
|
970
|
-
if (exclude.indexOf(prop) < 0 && __propIsEnum$1.call(source, prop)) target[prop] = source[prop];
|
|
971
|
-
}
|
|
972
|
-
return target;
|
|
973
|
-
};
|
|
974
|
-
const CrossDatasetDuplicatorContext = createContext(DEFAULT_CONFIG);
|
|
975
|
-
function useCrossDatasetDuplicatorConfig() {
|
|
976
|
-
const pluginConfig = useContext(CrossDatasetDuplicatorContext);
|
|
977
|
-
return pluginConfig;
|
|
978
|
-
}
|
|
979
|
-
function ConfigProvider(props) {
|
|
980
|
-
const _a = props,
|
|
981
|
-
{
|
|
982
|
-
pluginConfig
|
|
983
|
-
} = _a,
|
|
984
|
-
rest = __objRest(_a, ["pluginConfig"]);
|
|
985
|
-
return /* @__PURE__ */jsx(CrossDatasetDuplicatorContext.Provider, {
|
|
986
|
-
value: pluginConfig,
|
|
987
|
-
children: props.renderDefault(rest)
|
|
988
|
-
});
|
|
989
|
-
}
|
|
990
|
-
const secretConfigKeys = [{
|
|
991
|
-
key: "bearerToken",
|
|
992
|
-
title: "An API token with Viewer permissions is required to duplicate the original files of assets, and will be used for all Duplications. Create one at sanity.io/manage",
|
|
993
|
-
description: ""
|
|
994
|
-
}];
|
|
995
|
-
function CrossDatasetDuplicator(props) {
|
|
996
|
-
const {
|
|
997
|
-
mode = "tool",
|
|
998
|
-
docs = [],
|
|
999
|
-
onDuplicated
|
|
1000
|
-
} = props != null ? props : {};
|
|
1001
|
-
const pluginConfig = useCrossDatasetDuplicatorConfig();
|
|
1002
|
-
const {
|
|
1003
|
-
loading,
|
|
1004
|
-
secrets
|
|
1005
|
-
} = useSecrets(SECRET_NAMESPACE);
|
|
1006
|
-
const [showSecretsPrompt, setShowSecretsPrompt] = useState(false);
|
|
1007
|
-
useEffect(() => {
|
|
1008
|
-
if (secrets) {
|
|
1009
|
-
setShowSecretsPrompt(!(secrets == null ? void 0 : secrets.bearerToken));
|
|
1010
|
-
}
|
|
1011
|
-
}, [secrets]);
|
|
1012
|
-
if (loading) {
|
|
1013
|
-
return /* @__PURE__ */jsx(Flex, {
|
|
1014
|
-
justify: "center",
|
|
1015
|
-
align: "center",
|
|
1016
|
-
children: /* @__PURE__ */jsx(Box, {
|
|
1017
|
-
padding: 5,
|
|
1018
|
-
children: /* @__PURE__ */jsx(Spinner, {})
|
|
1019
|
-
})
|
|
1020
|
-
});
|
|
1021
|
-
}
|
|
1022
|
-
if (!loading && showSecretsPrompt || !(secrets == null ? void 0 : secrets.bearerToken)) {
|
|
1023
|
-
return /* @__PURE__ */jsx(SettingsView, {
|
|
1024
|
-
title: "Token Required",
|
|
1025
|
-
namespace: SECRET_NAMESPACE,
|
|
1026
|
-
keys: secretConfigKeys,
|
|
1027
|
-
onClose: () => setShowSecretsPrompt(false)
|
|
1028
|
-
});
|
|
1029
|
-
}
|
|
1030
|
-
if (mode === "tool" && pluginConfig) {
|
|
1031
|
-
return /* @__PURE__ */jsxs(Fragment, {
|
|
1032
|
-
children: [/* @__PURE__ */jsx(DuplicatorQuery, {
|
|
1033
|
-
token: secrets == null ? void 0 : secrets.bearerToken,
|
|
1034
|
-
pluginConfig
|
|
1035
|
-
}), /* @__PURE__ */jsx(ResetSecret, {
|
|
1036
|
-
apiVersion: pluginConfig.apiVersion
|
|
1037
|
-
})]
|
|
1038
|
-
});
|
|
1039
|
-
}
|
|
1040
|
-
if (!(docs == null ? void 0 : docs.length)) {
|
|
1041
|
-
return /* @__PURE__ */jsx(Feedback, {
|
|
1042
|
-
children: "No docs passed into Duplicator Tool"
|
|
1043
|
-
});
|
|
1044
|
-
}
|
|
1045
|
-
if (!pluginConfig) {
|
|
1046
|
-
return /* @__PURE__ */jsx(Feedback, {
|
|
1047
|
-
children: "No plugin config"
|
|
1048
|
-
});
|
|
1049
|
-
}
|
|
1050
|
-
return /* @__PURE__ */jsx(DuplicatorWrapper, {
|
|
1051
|
-
docs,
|
|
1052
|
-
token: secrets == null ? void 0 : secrets.bearerToken,
|
|
1053
|
-
pluginConfig,
|
|
1054
|
-
onDuplicated
|
|
1055
|
-
});
|
|
1056
|
-
}
|
|
1057
|
-
function CrossDatasetDuplicatorAction(props) {
|
|
1058
|
-
const {
|
|
1059
|
-
docs = [],
|
|
1060
|
-
onDuplicated
|
|
1061
|
-
} = props;
|
|
1062
|
-
return /* @__PURE__ */jsx(CrossDatasetDuplicator, {
|
|
1063
|
-
mode: "action",
|
|
1064
|
-
docs,
|
|
1065
|
-
onDuplicated
|
|
1066
|
-
});
|
|
1067
|
-
}
|
|
1068
|
-
const DuplicateToAction = props => {
|
|
1069
|
-
const {
|
|
1070
|
-
draft,
|
|
1071
|
-
published,
|
|
1072
|
-
onComplete
|
|
1073
|
-
} = props;
|
|
1074
|
-
const [dialogOpen, setDialogOpen] = useState(false);
|
|
1075
|
-
return {
|
|
1076
|
-
disabled: draft,
|
|
1077
|
-
title: draft ? "Document must be Published to begin" : null,
|
|
1078
|
-
label: "Duplicate to...",
|
|
1079
|
-
dialog: dialogOpen && published && {
|
|
1080
|
-
type: "modal",
|
|
1081
|
-
title: "Cross Dataset Duplicator",
|
|
1082
|
-
content: /* @__PURE__ */jsx(CrossDatasetDuplicatorAction, {
|
|
1083
|
-
docs: [published]
|
|
1084
|
-
}),
|
|
1085
|
-
onClose: () => {
|
|
1086
|
-
onComplete();
|
|
1087
|
-
setDialogOpen(false);
|
|
1088
|
-
}
|
|
1089
|
-
},
|
|
1090
|
-
onHandle: () => setDialogOpen(true),
|
|
1091
|
-
icon: LaunchIcon
|
|
1092
|
-
};
|
|
1093
|
-
};
|
|
1094
|
-
DuplicateToAction.action = "duplicateTo";
|
|
1095
|
-
function CrossDatasetDuplicatorTool(props) {
|
|
1096
|
-
var _a;
|
|
1097
|
-
const {
|
|
1098
|
-
docs = []
|
|
1099
|
-
} = (_a = props.tool.options) != null ? _a : {};
|
|
1100
|
-
return /* @__PURE__ */jsx(CrossDatasetDuplicator, {
|
|
1101
|
-
mode: "tool",
|
|
1102
|
-
docs
|
|
1103
|
-
});
|
|
1104
|
-
}
|
|
1105
|
-
const crossDatasetDuplicatorTool = () => ({
|
|
1106
|
-
title: "Duplicator",
|
|
1107
|
-
name: "duplicator",
|
|
1108
|
-
icon: LaunchIcon,
|
|
1109
|
-
component: CrossDatasetDuplicatorTool,
|
|
1110
|
-
options: {
|
|
1111
|
-
docs: []
|
|
1112
|
-
}
|
|
1113
|
-
});
|
|
1114
|
-
var __defProp = Object.defineProperty;
|
|
1115
|
-
var __defProps = Object.defineProperties;
|
|
1116
|
-
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
1117
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
1118
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
1119
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
1120
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {
|
|
1121
|
-
enumerable: true,
|
|
1122
|
-
configurable: true,
|
|
1123
|
-
writable: true,
|
|
1124
|
-
value
|
|
1125
|
-
}) : obj[key] = value;
|
|
1126
|
-
var __spreadValues = (a, b) => {
|
|
1127
|
-
for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]);
|
|
1128
|
-
if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) {
|
|
1129
|
-
if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]);
|
|
1130
|
-
}
|
|
1131
|
-
return a;
|
|
1132
|
-
};
|
|
1133
|
-
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
1134
|
-
const crossDatasetDuplicator = definePlugin(function () {
|
|
1135
|
-
let config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
1136
|
-
const pluginConfig = __spreadValues(__spreadValues({}, DEFAULT_CONFIG), config);
|
|
1137
|
-
const {
|
|
1138
|
-
types
|
|
1139
|
-
} = pluginConfig;
|
|
1140
|
-
return {
|
|
1141
|
-
name: "@sanity/cross-dataset-duplicator",
|
|
1142
|
-
tools: prev => pluginConfig.tool ? [...prev, crossDatasetDuplicatorTool()] : prev,
|
|
1143
|
-
studio: {
|
|
1144
|
-
components: {
|
|
1145
|
-
layout: props => ConfigProvider(__spreadProps(__spreadValues({}, props), {
|
|
1146
|
-
pluginConfig
|
|
1147
|
-
}))
|
|
1148
|
-
}
|
|
1149
|
-
},
|
|
1150
|
-
document: {
|
|
1151
|
-
actions: (prev, _ref7) => {
|
|
1152
|
-
let {
|
|
1153
|
-
schemaType
|
|
1154
|
-
} = _ref7;
|
|
1155
|
-
return types && types.includes(schemaType) ? [...prev, DuplicateToAction] : prev;
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
};
|
|
1159
|
-
});
|
|
1160
|
-
export { CrossDatasetDuplicatorAction, DuplicateToAction, crossDatasetDuplicator, useCrossDatasetDuplicatorConfig };
|
|
1161
|
-
//# sourceMappingURL=index.esm.js.map
|