sanity-plugin-mux-input 2.9.1 → 2.10.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/README.md +8 -8
- package/dist/index.d.mts +13 -5
- package/dist/index.d.ts +13 -5
- package/dist/index.js +2175 -1933
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2179 -1937
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/_exports/index.ts +13 -1
- package/src/actions/assets.ts +22 -0
- package/src/components/ConfigureApi.tsx +32 -9
- package/src/components/ImportVideosFromMux.tsx +26 -2
- package/src/components/Input.tsx +3 -3
- package/src/components/ResyncMetadata.tsx +201 -0
- package/src/components/UploadConfiguration.tsx +28 -28
- package/src/components/VideosBrowser.tsx +10 -2
- package/src/hooks/useImportMuxAssets.ts +3 -3
- package/src/hooks/useMuxAssets.ts +64 -53
- package/src/hooks/useResyncMuxMetadata.ts +143 -0
- package/src/schema.ts +4 -0
- package/src/util/assetTitlePlaceholder.ts +31 -0
- package/src/util/types.ts +20 -10
package/dist/index.mjs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { useClient as useClient$1, createHookFromObservableFactory, useDocumentStore, collate, useDocumentValues, truncateString, useFormattedDuration, SanityDefaultPreview, useTimeAgo, TextWithTone, isRecord, getPreviewStateObservable, getPreviewValueWithFallback, DocumentPreviewPresence, useDocumentPreviewStore, useSchema, useDocumentPresence, PreviewCard, isReference, useProjectId, useDataset,
|
|
1
|
+
import { useClient as useClient$1, createHookFromObservableFactory, useDocumentStore, collate, useDocumentValues, truncateString, useFormattedDuration, SanityDefaultPreview, useTimeAgo, TextWithTone, isRecord, getPreviewStateObservable, getPreviewValueWithFallback, DocumentPreviewPresence, useDocumentPreviewStore, useSchema, useDocumentPresence, PreviewCard, useCurrentUser, isReference, useProjectId, useDataset, PatchEvent, unset, setIfMissing, set, LinearProgress, FormField as FormField$2, definePlugin } from "sanity";
|
|
2
2
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { ErrorOutlineIcon, RetryIcon, CheckmarkCircleIcon, RetrieveIcon, SortIcon, WarningOutlineIcon, EditIcon, PublishIcon, DocumentIcon, TrashIcon, RevertIcon, SearchIcon, ClockIcon, CropIcon, CalendarIcon, TagIcon, CheckmarkIcon, LockIcon, PlayIcon, PlugIcon, EllipsisHorizontalIcon, UploadIcon, ImageIcon, ResetIcon, TranslateIcon, WarningFilledIcon, DocumentVideoIcon } from "@sanity/icons";
|
|
4
|
-
import {
|
|
5
|
-
import React, { useState, useMemo,
|
|
3
|
+
import { ErrorOutlineIcon, InfoOutlineIcon, RetryIcon, CheckmarkCircleIcon, RetrieveIcon, SyncIcon, SortIcon, WarningOutlineIcon, EditIcon, PublishIcon, DocumentIcon, TrashIcon, RevertIcon, SearchIcon, ClockIcon, CropIcon, CalendarIcon, TagIcon, CheckmarkIcon, LockIcon, PlayIcon, PlugIcon, EllipsisHorizontalIcon, UploadIcon, ImageIcon, ResetIcon, TranslateIcon, WarningFilledIcon, DocumentVideoIcon } from "@sanity/icons";
|
|
4
|
+
import { useTheme_v2, Stack, Flex, Box, Text, Button, Dialog, Card, TextInput, Checkbox, Code, Inline, Spinner, Heading, MenuButton, Menu, MenuItem, Tooltip, useToast, TabList, Tab, TabPanel, Label as Label$1, Grid, useClickOutsideEvent, Popover, MenuDivider, Autocomplete, Radio, rem } from "@sanity/ui";
|
|
5
|
+
import React, { useState, useMemo, useCallback, useReducer, useId, memo, useRef, useEffect, createContext, useContext, isValidElement, PureComponent, createElement, forwardRef, Suspense } from "react";
|
|
6
6
|
import compact from "lodash/compact.js";
|
|
7
7
|
import toLower from "lodash/toLower.js";
|
|
8
8
|
import trim from "lodash/trim.js";
|
|
9
9
|
import uniq from "lodash/uniq.js";
|
|
10
10
|
import words from "lodash/words.js";
|
|
11
|
+
import { suspend, clear, preload } from "suspend-react";
|
|
12
|
+
import { defer, timer, of, Observable, concat, throwError, from, Subject } from "rxjs";
|
|
11
13
|
import { styled, css } from "styled-components";
|
|
12
14
|
import { uuid } from "@sanity/uuid";
|
|
13
|
-
import { defer, timer, of, Observable, concat, throwError, from, Subject } from "rxjs";
|
|
14
15
|
import { expand, concatMap, tap, switchMap, mergeMap, catchError, mergeMapTo, takeUntil } from "rxjs/operators";
|
|
15
|
-
import { suspend, clear, preload } from "suspend-react";
|
|
16
16
|
import MuxPlayer from "@mux/mux-player-react";
|
|
17
17
|
import { IntentLink } from "sanity/router";
|
|
18
18
|
import isNumber from "lodash/isNumber.js";
|
|
@@ -105,92 +105,116 @@ function useAssets() {
|
|
|
105
105
|
setSearchQuery
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
|
-
function
|
|
109
|
-
return
|
|
108
|
+
function useDialogState() {
|
|
109
|
+
return useState(!1);
|
|
110
|
+
}
|
|
111
|
+
function saveSecrets(client, token, secretKey, enableSignedUrls, signingKeyId, signingKeyPrivate) {
|
|
112
|
+
const doc = {
|
|
113
|
+
_id: "secrets.mux",
|
|
114
|
+
_type: "mux.apiKey",
|
|
115
|
+
token,
|
|
116
|
+
secretKey,
|
|
117
|
+
enableSignedUrls,
|
|
118
|
+
signingKeyId,
|
|
119
|
+
signingKeyPrivate
|
|
120
|
+
};
|
|
121
|
+
return client.createOrReplace(doc);
|
|
110
122
|
}
|
|
111
|
-
|
|
112
|
-
async function fetchMuxAssetsPage({ secretKey, token }, pageNum) {
|
|
123
|
+
async function createSigningKeys(client) {
|
|
113
124
|
try {
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
{
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
error: {
|
|
125
|
-
_tag: "MuxError",
|
|
126
|
-
error: json.error
|
|
127
|
-
}
|
|
128
|
-
} : {
|
|
129
|
-
pageNum,
|
|
130
|
-
data: json.data
|
|
131
|
-
};
|
|
132
|
-
} catch {
|
|
133
|
-
return {
|
|
134
|
-
pageNum,
|
|
135
|
-
error: { _tag: "FetchError" }
|
|
136
|
-
};
|
|
125
|
+
const { dataset } = client.config();
|
|
126
|
+
return await client.request({
|
|
127
|
+
url: `/addons/mux/signing-keys/${dataset}`,
|
|
128
|
+
withCredentials: !0,
|
|
129
|
+
method: "POST"
|
|
130
|
+
});
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error("Error creating signing keys", error);
|
|
133
|
+
const message = error.response?.statusCode === 401 ? 'Unauthorized - Failed to create the Signing Key. Please ensure that the token has "System" permissions' : error.message;
|
|
134
|
+
throw new Error(message);
|
|
137
135
|
}
|
|
138
136
|
}
|
|
139
|
-
function
|
|
140
|
-
const
|
|
141
|
-
return {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
// De-duplicate assets for safety
|
|
147
|
-
(asset) => !currentData.some((a2) => a2.id === asset.id)
|
|
148
|
-
)
|
|
149
|
-
],
|
|
150
|
-
error: "error" in pageResult ? pageResult.error : (
|
|
151
|
-
// Reset error if current page is successful
|
|
152
|
-
void 0
|
|
153
|
-
),
|
|
154
|
-
pageNum: pageResult.pageNum,
|
|
155
|
-
loading: !0
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
function hasMorePages(pageResult) {
|
|
159
|
-
return typeof pageResult == "object" && "data" in pageResult && Array.isArray(pageResult.data) && pageResult.data.length > 0;
|
|
137
|
+
function testSecrets(client) {
|
|
138
|
+
const { dataset } = client.config();
|
|
139
|
+
return client.request({
|
|
140
|
+
url: `/addons/mux/secrets/${dataset}/test`,
|
|
141
|
+
withCredentials: !0,
|
|
142
|
+
method: "GET"
|
|
143
|
+
});
|
|
160
144
|
}
|
|
161
|
-
function
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
)
|
|
171
|
-
).pipe(
|
|
172
|
-
// Here we replace "concatMap" with "expand" to recursively fetch next pages
|
|
173
|
-
expand((pageResult) => hasMorePages(pageResult) ? timer(2e3).pipe(
|
|
174
|
-
// eslint-disable-next-line max-nested-callbacks
|
|
175
|
-
concatMap(() => defer(() => fetchMuxAssetsPage(secrets, pageResult.pageNum + 1)))
|
|
176
|
-
) : of()),
|
|
177
|
-
// On each iteration, persist intermediate states to give feedback to users
|
|
178
|
-
tap(
|
|
179
|
-
(pageResult) => setState((prevState) => accumulateIntermediateState(prevState, pageResult))
|
|
180
|
-
)
|
|
181
|
-
).subscribe({
|
|
182
|
-
// Once done, let the user know we've stopped loading
|
|
183
|
-
complete: () => {
|
|
184
|
-
setState((prev) => ({
|
|
185
|
-
...prev,
|
|
186
|
-
loading: !1
|
|
187
|
-
}));
|
|
188
|
-
}
|
|
145
|
+
async function haveValidSigningKeys(client, signingKeyId, signingKeyPrivate) {
|
|
146
|
+
if (!(signingKeyId && signingKeyPrivate))
|
|
147
|
+
return !1;
|
|
148
|
+
const { dataset } = client.config();
|
|
149
|
+
try {
|
|
150
|
+
const res = await client.request({
|
|
151
|
+
url: `/addons/mux/signing-keys/${dataset}/${signingKeyId}`,
|
|
152
|
+
withCredentials: !0,
|
|
153
|
+
method: "GET"
|
|
189
154
|
});
|
|
190
|
-
return (
|
|
191
|
-
}
|
|
155
|
+
return !!(res.data && res.data.id);
|
|
156
|
+
} catch {
|
|
157
|
+
return console.error("Error fetching signingKeyId", signingKeyId, "assuming it is not valid"), !1;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function testSecretsObservable(client) {
|
|
161
|
+
const { dataset } = client.config();
|
|
162
|
+
return defer(
|
|
163
|
+
() => client.observable.request({
|
|
164
|
+
url: `/addons/mux/secrets/${dataset}/test`,
|
|
165
|
+
withCredentials: !0,
|
|
166
|
+
method: "GET"
|
|
167
|
+
})
|
|
168
|
+
);
|
|
192
169
|
}
|
|
193
|
-
const
|
|
170
|
+
const useSaveSecrets = (client, secrets) => useCallback(
|
|
171
|
+
async ({
|
|
172
|
+
token,
|
|
173
|
+
secretKey,
|
|
174
|
+
enableSignedUrls
|
|
175
|
+
}) => {
|
|
176
|
+
let { signingKeyId, signingKeyPrivate } = secrets;
|
|
177
|
+
try {
|
|
178
|
+
if (await saveSecrets(
|
|
179
|
+
client,
|
|
180
|
+
token,
|
|
181
|
+
secretKey,
|
|
182
|
+
enableSignedUrls,
|
|
183
|
+
signingKeyId,
|
|
184
|
+
signingKeyPrivate
|
|
185
|
+
), !(await testSecrets(client))?.status && token && secretKey)
|
|
186
|
+
throw new Error("Invalid secrets");
|
|
187
|
+
} catch (err) {
|
|
188
|
+
throw console.error("Error while trying to save secrets:", err), err;
|
|
189
|
+
}
|
|
190
|
+
if (enableSignedUrls && !await haveValidSigningKeys(
|
|
191
|
+
client,
|
|
192
|
+
signingKeyId,
|
|
193
|
+
signingKeyPrivate
|
|
194
|
+
))
|
|
195
|
+
try {
|
|
196
|
+
const { data } = await createSigningKeys(client);
|
|
197
|
+
signingKeyId = data.id, signingKeyPrivate = data.private_key, await saveSecrets(
|
|
198
|
+
client,
|
|
199
|
+
token,
|
|
200
|
+
secretKey,
|
|
201
|
+
enableSignedUrls,
|
|
202
|
+
signingKeyId,
|
|
203
|
+
signingKeyPrivate
|
|
204
|
+
);
|
|
205
|
+
} catch (err) {
|
|
206
|
+
throw console.log("Error while creating and saving signing key:", err?.message), err;
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
token,
|
|
210
|
+
secretKey,
|
|
211
|
+
enableSignedUrls,
|
|
212
|
+
signingKeyId,
|
|
213
|
+
signingKeyPrivate
|
|
214
|
+
};
|
|
215
|
+
},
|
|
216
|
+
[client, secrets]
|
|
217
|
+
), name = "mux-input", cacheNs = "sanity-plugin-mux-input", muxSecretsDocumentId = "secrets.mux", DIALOGS_Z_INDEX = 6e4, THUMBNAIL_ASPECT_RATIO = 1.7777777777777777, MIN_ASPECT_RATIO = 5 / 4, AUDIO_ASPECT_RATIO = 5 / 1, path$1 = ["token", "secretKey", "enableSignedUrls", "signingKeyId", "signingKeyPrivate"], useSecretsDocumentValues = () => {
|
|
194
218
|
const { error, isLoading, value } = useDocumentValues(
|
|
195
219
|
muxSecretsDocumentId,
|
|
196
220
|
path$1
|
|
@@ -210,89 +234,32 @@ const name = "mux-input", cacheNs = "sanity-plugin-mux-input", muxSecretsDocumen
|
|
|
210
234
|
}, [value]);
|
|
211
235
|
return { error, isLoading, value: cache };
|
|
212
236
|
};
|
|
213
|
-
function
|
|
214
|
-
const documentStore = useDocumentStore(), client = useClient$1({
|
|
215
|
-
apiVersion: SANITY_API_VERSION
|
|
216
|
-
}), [assetsInSanity, assetsInSanityLoading] = useAssetsInSanity(documentStore), secretDocumentValues = useSecretsDocumentValues(), hasSecrets = !!secretDocumentValues.value.secrets?.secretKey, [importError, setImportError] = useState(), [importState, setImportState] = useState("closed"), dialogOpen = importState !== "closed", muxAssets = useMuxAssets({
|
|
217
|
-
secrets: secretDocumentValues.value.secrets,
|
|
218
|
-
enabled: hasSecrets && dialogOpen
|
|
219
|
-
}), missingAssets = useMemo(() => assetsInSanity && muxAssets.data ? muxAssets.data.filter((a2) => !assetExistsInSanity(a2, assetsInSanity)) : void 0, [assetsInSanity, muxAssets.data]), [selectedAssets, setSelectedAssets] = useState([]), closeDialog = () => {
|
|
220
|
-
importState !== "importing" && setImportState("closed");
|
|
221
|
-
}, openDialog = () => {
|
|
222
|
-
importState === "closed" && setImportState("idle");
|
|
223
|
-
};
|
|
224
|
-
async function importAssets() {
|
|
225
|
-
setImportState("importing");
|
|
226
|
-
const documents = selectedAssets.flatMap((asset) => muxAssetToSanityDocument(asset) || []), tx = client.transaction();
|
|
227
|
-
documents.forEach((doc) => tx.create(doc));
|
|
228
|
-
try {
|
|
229
|
-
await tx.commit({ returnDocuments: !1 }), setSelectedAssets([]), setImportState("done");
|
|
230
|
-
} catch (error) {
|
|
231
|
-
setImportState("error"), setImportError(error);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
237
|
+
function init({ token, secretKey, enableSignedUrls }) {
|
|
234
238
|
return {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
missingAssets,
|
|
243
|
-
muxAssets,
|
|
244
|
-
openDialog,
|
|
245
|
-
selectedAssets,
|
|
246
|
-
setSelectedAssets
|
|
239
|
+
submitting: !1,
|
|
240
|
+
error: null,
|
|
241
|
+
// Form inputs don't set the state back to null when clearing a field, but uses empty strings
|
|
242
|
+
// This ensures the `dirty` check works correctly
|
|
243
|
+
token: token ?? "",
|
|
244
|
+
secretKey: secretKey ?? "",
|
|
245
|
+
enableSignedUrls: enableSignedUrls ?? !1
|
|
247
246
|
};
|
|
248
247
|
}
|
|
249
|
-
function
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
const useAssetsInSanity = createHookFromObservableFactory(
|
|
265
|
-
(documentStore) => documentStore.listenQuery(
|
|
266
|
-
/* groq */
|
|
267
|
-
`*[_type == "mux.videoAsset"] {
|
|
268
|
-
"uploadId": coalesce(uploadId, data.upload_id),
|
|
269
|
-
"assetId": coalesce(assetId, data.id),
|
|
270
|
-
}`,
|
|
271
|
-
{},
|
|
272
|
-
{
|
|
273
|
-
apiVersion: SANITY_API_VERSION
|
|
274
|
-
}
|
|
275
|
-
)
|
|
276
|
-
);
|
|
277
|
-
function assetExistsInSanity(asset, existingAssets) {
|
|
278
|
-
return asset.status !== "ready" ? !1 : existingAssets.some(
|
|
279
|
-
(existing) => existing.assetId === asset.id || existing.uploadId === asset.upload_id
|
|
280
|
-
);
|
|
281
|
-
}
|
|
282
|
-
function useInView(ref, options = {}) {
|
|
283
|
-
const [inView, setInView] = useState(!1);
|
|
284
|
-
return useEffect(() => {
|
|
285
|
-
if (!ref.current) return;
|
|
286
|
-
const observer = new IntersectionObserver(([entry], obs) => {
|
|
287
|
-
const nowInView = entry.isIntersecting && obs.thresholds.some((threshold) => entry.intersectionRatio >= threshold);
|
|
288
|
-
setInView(nowInView), options?.onChange?.(nowInView);
|
|
289
|
-
}, options), toObserve = ref.current;
|
|
290
|
-
return observer.observe(toObserve), () => {
|
|
291
|
-
toObserve && observer.unobserve(toObserve);
|
|
292
|
-
};
|
|
293
|
-
}, [options, ref]), inView;
|
|
248
|
+
function reducer(state, action) {
|
|
249
|
+
switch (action?.type) {
|
|
250
|
+
case "submit":
|
|
251
|
+
return { ...state, submitting: !0, error: null };
|
|
252
|
+
case "error":
|
|
253
|
+
return { ...state, submitting: !1, error: action.payload };
|
|
254
|
+
case "reset":
|
|
255
|
+
return init(action.payload);
|
|
256
|
+
case "change":
|
|
257
|
+
return { ...state, [action.payload.name]: action.payload.value };
|
|
258
|
+
default:
|
|
259
|
+
throw new Error(`Unknown action type: ${action?.type}`);
|
|
260
|
+
}
|
|
294
261
|
}
|
|
295
|
-
const _id = "secrets.mux";
|
|
262
|
+
const useSecretsFormState = (secrets) => useReducer(reducer, secrets, init), _id = "secrets.mux";
|
|
296
263
|
function readSecrets(client) {
|
|
297
264
|
const { projectId, dataset } = client.config();
|
|
298
265
|
return suspend(async () => {
|
|
@@ -316,1904 +283,2173 @@ function readSecrets(client) {
|
|
|
316
283
|
};
|
|
317
284
|
}, [cacheNs, _id, projectId, dataset]);
|
|
318
285
|
}
|
|
319
|
-
function
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
if (!signingKeyPrivate)
|
|
324
|
-
throw new TypeError("Missing `signingKeyPrivate`.\n Check your plugin's configuration");
|
|
325
|
-
const { default: sign } = suspend(() => import("jsonwebtoken-esm/sign"), ["jsonwebtoken-esm/sign"]);
|
|
326
|
-
return sign(
|
|
327
|
-
payload ? JSON.parse(JSON.stringify(payload, (_, v) => v ?? void 0)) : {},
|
|
328
|
-
atob(signingKeyPrivate),
|
|
329
|
-
{
|
|
330
|
-
algorithm: "RS256",
|
|
331
|
-
keyid: signingKeyId,
|
|
332
|
-
audience: aud,
|
|
333
|
-
subject: playbackId,
|
|
334
|
-
noTimestamp: !0,
|
|
335
|
-
expiresIn: "12h"
|
|
336
|
-
}
|
|
337
|
-
);
|
|
338
|
-
}
|
|
339
|
-
function getPlaybackId(asset) {
|
|
340
|
-
if (!asset?.playbackId)
|
|
341
|
-
throw console.error("Asset is missing a playbackId", { asset }), new TypeError("Missing playbackId");
|
|
342
|
-
return asset.playbackId;
|
|
343
|
-
}
|
|
344
|
-
function getPlaybackPolicy(asset) {
|
|
345
|
-
return asset.data?.playback_ids?.find((playbackId) => asset.playbackId === playbackId.id)?.policy ?? "public";
|
|
346
|
-
}
|
|
347
|
-
function createUrlParamsObject(client, asset, params, audience) {
|
|
348
|
-
const playbackId = getPlaybackId(asset);
|
|
349
|
-
let searchParams = new URLSearchParams(
|
|
350
|
-
JSON.parse(JSON.stringify(params, (_, v) => v ?? void 0))
|
|
351
|
-
);
|
|
352
|
-
if (getPlaybackPolicy(asset) === "signed") {
|
|
353
|
-
const token = generateJwt(client, playbackId, audience, params);
|
|
354
|
-
searchParams = new URLSearchParams({ token });
|
|
355
|
-
}
|
|
356
|
-
return { playbackId, searchParams };
|
|
357
|
-
}
|
|
358
|
-
function getAnimatedPosterSrc({
|
|
359
|
-
asset,
|
|
360
|
-
client,
|
|
361
|
-
height,
|
|
362
|
-
width,
|
|
363
|
-
start = asset.thumbTime ? Math.max(0, asset.thumbTime - 2.5) : 0,
|
|
364
|
-
end = start + 5,
|
|
365
|
-
fps = 15
|
|
366
|
-
}) {
|
|
367
|
-
const params = { height, width, start, end, fps }, { playbackId, searchParams } = createUrlParamsObject(client, asset, params, "g");
|
|
368
|
-
return `https://image.mux.com/${playbackId}/animated.gif?${searchParams}`;
|
|
369
|
-
}
|
|
370
|
-
function getPosterSrc({
|
|
371
|
-
asset,
|
|
372
|
-
client,
|
|
373
|
-
fit_mode,
|
|
374
|
-
height,
|
|
375
|
-
time = asset.thumbTime ?? void 0,
|
|
376
|
-
width
|
|
377
|
-
}) {
|
|
378
|
-
const params = { fit_mode, height, width };
|
|
379
|
-
time !== void 0 && (params.time = time);
|
|
380
|
-
const { playbackId, searchParams } = createUrlParamsObject(client, asset, params, "t");
|
|
381
|
-
return `https://image.mux.com/${playbackId}/thumbnail.png?${searchParams}`;
|
|
382
|
-
}
|
|
383
|
-
const Image = styled.img`
|
|
384
|
-
transition: opacity 0.175s ease-out 0s;
|
|
385
|
-
display: block;
|
|
386
|
-
width: 100%;
|
|
387
|
-
height: 100%;
|
|
388
|
-
object-fit: contain;
|
|
389
|
-
object-position: center center;
|
|
390
|
-
`, STATUS_TO_TONE = {
|
|
391
|
-
loading: "transparent",
|
|
392
|
-
error: "critical",
|
|
393
|
-
loaded: "default"
|
|
394
|
-
};
|
|
395
|
-
function VideoThumbnail({
|
|
396
|
-
asset,
|
|
397
|
-
width,
|
|
398
|
-
staticImage = !1
|
|
399
|
-
}) {
|
|
400
|
-
const ref = useRef(null), inView = useInView(ref), posterWidth = width || 250, [status, setStatus] = useState("loading"), client = useClient(), src = useMemo(() => {
|
|
401
|
-
try {
|
|
402
|
-
let thumbnail;
|
|
403
|
-
return staticImage ? thumbnail = getPosterSrc({ asset, client, width: posterWidth }) : thumbnail = getAnimatedPosterSrc({ asset, client, width: posterWidth }), thumbnail;
|
|
404
|
-
} catch {
|
|
405
|
-
status !== "error" && setStatus("error");
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
}, [asset, client, posterWidth, status, staticImage]);
|
|
409
|
-
function handleLoad() {
|
|
410
|
-
setStatus("loaded");
|
|
411
|
-
}
|
|
412
|
-
function handleError() {
|
|
413
|
-
setStatus("error");
|
|
414
|
-
}
|
|
286
|
+
function MuxLogo({ height = 26 }) {
|
|
287
|
+
const id = useId(), fillColor = useTheme_v2().color._dark ? "white" : "black", titleId = useMemo(() => `${id}-title`, [id]), pathStyle = {
|
|
288
|
+
fillRule: "nonzero"
|
|
289
|
+
};
|
|
415
290
|
return /* @__PURE__ */ jsx(
|
|
416
|
-
|
|
291
|
+
"svg",
|
|
417
292
|
{
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
ref,
|
|
428
|
-
tone: STATUS_TO_TONE[status],
|
|
429
|
-
children: inView ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
430
|
-
status === "loading" && /* @__PURE__ */ jsx(
|
|
431
|
-
Box,
|
|
293
|
+
"aria-labelledby": titleId,
|
|
294
|
+
style: { height: `${height}px` },
|
|
295
|
+
viewBox: "0 0 1600 500",
|
|
296
|
+
version: "1.1",
|
|
297
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
298
|
+
xmlSpace: "preserve",
|
|
299
|
+
children: /* @__PURE__ */ jsxs("g", { id: "Layer-1", fill: fillColor, children: [
|
|
300
|
+
/* @__PURE__ */ jsx(
|
|
301
|
+
"path",
|
|
432
302
|
{
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
left: "50%",
|
|
436
|
-
top: "50%",
|
|
437
|
-
transform: "translate(-50%, -50%)"
|
|
438
|
-
},
|
|
439
|
-
children: /* @__PURE__ */ jsx(Spinner, {})
|
|
303
|
+
d: "M994.287,93.486c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m0,-93.486c-34.509,-0 -62.484,27.976 -62.484,62.486l0,187.511c0,68.943 -56.09,125.033 -125.032,125.033c-68.942,-0 -125.03,-56.09 -125.03,-125.033l0,-187.511c0,-34.51 -27.976,-62.486 -62.485,-62.486c-34.509,-0 -62.484,27.976 -62.484,62.486l0,187.511c0,137.853 112.149,250.003 249.999,250.003c137.851,-0 250.001,-112.15 250.001,-250.003l0,-187.511c0,-34.51 -27.976,-62.486 -62.485,-62.486",
|
|
304
|
+
style: pathStyle
|
|
440
305
|
}
|
|
441
306
|
),
|
|
442
|
-
|
|
443
|
-
|
|
307
|
+
/* @__PURE__ */ jsx(
|
|
308
|
+
"path",
|
|
444
309
|
{
|
|
445
|
-
|
|
446
|
-
style:
|
|
447
|
-
position: "absolute",
|
|
448
|
-
width: "100%",
|
|
449
|
-
left: 0,
|
|
450
|
-
top: "50%",
|
|
451
|
-
transform: "translateY(-50%)",
|
|
452
|
-
justifyItems: "center"
|
|
453
|
-
},
|
|
454
|
-
children: [
|
|
455
|
-
/* @__PURE__ */ jsx(Text, { size: 4, muted: !0, children: /* @__PURE__ */ jsx(ErrorOutlineIcon, { style: { fontSize: "1.75em" } }) }),
|
|
456
|
-
/* @__PURE__ */ jsx(Text, { muted: !0, align: "center", children: "Failed loading thumbnail" })
|
|
457
|
-
]
|
|
310
|
+
d: "M1537.51,468.511c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m-275.883,-218.509l-143.33,143.329c-24.402,24.402 -24.402,63.966 0,88.368c24.402,24.402 63.967,24.402 88.369,-0l143.33,-143.329l143.328,143.329c24.402,24.4 63.967,24.402 88.369,-0c24.403,-24.402 24.403,-63.966 0.001,-88.368l-143.33,-143.329l0.001,-0.004l143.329,-143.329c24.402,-24.402 24.402,-63.965 0,-88.367c-24.402,-24.402 -63.967,-24.402 -88.369,-0l-143.329,143.328l-143.329,-143.328c-24.402,-24.401 -63.967,-24.402 -88.369,-0c-24.402,24.402 -24.402,63.965 0,88.367l143.329,143.329l0,0.004Z",
|
|
311
|
+
style: pathStyle
|
|
458
312
|
}
|
|
459
313
|
),
|
|
460
314
|
/* @__PURE__ */ jsx(
|
|
461
|
-
|
|
315
|
+
"path",
|
|
462
316
|
{
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
onLoad: handleLoad,
|
|
466
|
-
onError: handleError,
|
|
467
|
-
style: { opacity: status === "loaded" ? 1 : 0 }
|
|
317
|
+
d: "M437.511,468.521c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m23.915,-463.762c-23.348,-9.672 -50.226,-4.327 -68.096,13.544l-143.331,143.329l-143.33,-143.329c-17.871,-17.871 -44.747,-23.216 -68.096,-13.544c-23.349,9.671 -38.574,32.455 -38.574,57.729l0,375.026c0,34.51 27.977,62.486 62.487,62.486c34.51,-0 62.486,-27.976 62.486,-62.486l0,-224.173l80.843,80.844c24.404,24.402 63.965,24.402 88.369,-0l80.843,-80.844l0,224.173c0,34.51 27.976,62.486 62.486,62.486c34.51,-0 62.486,-27.976 62.486,-62.486l0,-375.026c0,-25.274 -15.224,-48.058 -38.573,-57.729",
|
|
318
|
+
style: pathStyle
|
|
468
319
|
}
|
|
469
320
|
)
|
|
470
|
-
] })
|
|
321
|
+
] })
|
|
471
322
|
}
|
|
472
323
|
);
|
|
473
324
|
}
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
})
|
|
491
|
-
|
|
492
|
-
return /* @__PURE__ */ jsx(
|
|
493
|
-
Card,
|
|
494
|
-
{
|
|
495
|
-
tone: selected ? "positive" : void 0,
|
|
496
|
-
border: !0,
|
|
497
|
-
paddingX: 2,
|
|
498
|
-
paddingY: 3,
|
|
499
|
-
style: { position: "relative" },
|
|
500
|
-
radius: 1,
|
|
501
|
-
children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
502
|
-
/* @__PURE__ */ jsx(
|
|
503
|
-
MissingAssetCheckbox,
|
|
504
|
-
{
|
|
505
|
-
checked: selected,
|
|
506
|
-
onChange: (e) => {
|
|
507
|
-
selectAsset(e.currentTarget.checked);
|
|
508
|
-
},
|
|
509
|
-
"aria-label": selected ? `Import video ${asset.id}` : `Skip import of video ${asset.id}`
|
|
510
|
-
}
|
|
511
|
-
),
|
|
512
|
-
/* @__PURE__ */ jsx(
|
|
513
|
-
VideoThumbnail,
|
|
514
|
-
{
|
|
515
|
-
asset: {
|
|
516
|
-
assetId: asset.id,
|
|
517
|
-
data: asset,
|
|
518
|
-
filename: asset.id,
|
|
519
|
-
playbackId: asset.playback_ids.find((p) => p.id)?.id
|
|
520
|
-
},
|
|
521
|
-
width: 150
|
|
522
|
-
}
|
|
523
|
-
),
|
|
524
|
-
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
525
|
-
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 1, children: [
|
|
526
|
-
/* @__PURE__ */ jsx(Code, { size: 2, children: truncateString(asset.id, 15) }),
|
|
527
|
-
" ",
|
|
528
|
-
/* @__PURE__ */ jsxs(Text, { muted: !0, size: 2, children: [
|
|
529
|
-
"(",
|
|
530
|
-
duration.formatted,
|
|
531
|
-
")"
|
|
532
|
-
] })
|
|
533
|
-
] }),
|
|
534
|
-
/* @__PURE__ */ jsxs(Text, { size: 1, children: [
|
|
535
|
-
"Uploaded at",
|
|
536
|
-
" ",
|
|
537
|
-
new Date(Number(asset.created_at) * 1e3).toLocaleDateString("en", {
|
|
538
|
-
year: "numeric",
|
|
539
|
-
day: "2-digit",
|
|
540
|
-
month: "2-digit"
|
|
541
|
-
})
|
|
542
|
-
] })
|
|
543
|
-
] })
|
|
544
|
-
] })
|
|
545
|
-
},
|
|
546
|
-
asset.id
|
|
547
|
-
);
|
|
325
|
+
const Logo = styled.span`
|
|
326
|
+
display: inline-block;
|
|
327
|
+
height: 0.8em;
|
|
328
|
+
margin-right: 1em;
|
|
329
|
+
transform: translate(0.3em, -0.2em);
|
|
330
|
+
`, Header = () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
331
|
+
/* @__PURE__ */ jsx(Logo, { children: /* @__PURE__ */ jsx(MuxLogo, { height: 13 }) }),
|
|
332
|
+
"API Credentials"
|
|
333
|
+
] });
|
|
334
|
+
function FormField(props) {
|
|
335
|
+
const { children, title, description, inputId } = props;
|
|
336
|
+
return /* @__PURE__ */ jsxs(Stack, { space: 1, children: [
|
|
337
|
+
/* @__PURE__ */ jsx(Flex, { align: "flex-end", children: /* @__PURE__ */ jsx(Box, { flex: 1, paddingY: 2, children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
338
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, weight: "semibold", size: 1, children: title || /* @__PURE__ */ jsx("em", { children: "Untitled" }) }),
|
|
339
|
+
description && /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: description })
|
|
340
|
+
] }) }) }),
|
|
341
|
+
/* @__PURE__ */ jsx("div", { children })
|
|
342
|
+
] });
|
|
548
343
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
344
|
+
var FormField$1 = memo(FormField);
|
|
345
|
+
const fieldNames = ["token", "secretKey", "enableSignedUrls"];
|
|
346
|
+
function ConfigureApiDialog({ secrets, setDialogState }) {
|
|
347
|
+
const client = useClient(), [state, dispatch] = useSecretsFormState(secrets), hasSecretsInitially = useMemo(() => secrets.token && secrets.secretKey, [secrets]), handleClose = useCallback(() => setDialogState(!1), [setDialogState]), dirty = useMemo(
|
|
348
|
+
() => secrets.token !== state.token || secrets.secretKey !== state.secretKey || secrets.enableSignedUrls !== state.enableSignedUrls,
|
|
349
|
+
[secrets, state]
|
|
350
|
+
), id = `ConfigureApi${useId()}`, [tokenId, secretKeyId, enableSignedUrlsId] = useMemo(
|
|
351
|
+
() => fieldNames.map((field) => `${id}-${field}`),
|
|
352
|
+
[id]
|
|
353
|
+
), firstField = useRef(null), handleSaveSecrets = useSaveSecrets(client, secrets), saving = useRef(!1), handleSubmit = useCallback(
|
|
354
|
+
(event) => {
|
|
355
|
+
if (event.preventDefault(), !saving.current && event.currentTarget.reportValidity()) {
|
|
356
|
+
saving.current = !0, dispatch({ type: "submit" });
|
|
357
|
+
const { token, secretKey, enableSignedUrls } = state;
|
|
358
|
+
handleSaveSecrets({ token, secretKey, enableSignedUrls }).then((savedSecrets) => {
|
|
359
|
+
const { projectId, dataset } = client.config();
|
|
360
|
+
clear([cacheNs, _id, projectId, dataset]), preload(() => Promise.resolve(savedSecrets), [cacheNs, _id, projectId, dataset]), setDialogState(!1);
|
|
361
|
+
}).catch((err) => dispatch({ type: "error", payload: err.message })).finally(() => {
|
|
362
|
+
saving.current = !1;
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
[client, dispatch, handleSaveSecrets, setDialogState, state]
|
|
367
|
+
), handleChangeToken = useCallback(
|
|
368
|
+
(event) => {
|
|
369
|
+
dispatch({
|
|
370
|
+
type: "change",
|
|
371
|
+
payload: { name: "token", value: event.currentTarget.value }
|
|
372
|
+
});
|
|
373
|
+
},
|
|
374
|
+
[dispatch]
|
|
375
|
+
), handleChangeSecretKey = useCallback(
|
|
376
|
+
(event) => {
|
|
377
|
+
dispatch({
|
|
378
|
+
type: "change",
|
|
379
|
+
payload: { name: "secretKey", value: event.currentTarget.value }
|
|
380
|
+
});
|
|
381
|
+
},
|
|
382
|
+
[dispatch]
|
|
383
|
+
), handleChangeEnableSignedUrls = useCallback(
|
|
384
|
+
(event) => {
|
|
385
|
+
dispatch({
|
|
386
|
+
type: "change",
|
|
387
|
+
payload: { name: "enableSignedUrls", value: event.currentTarget.checked }
|
|
388
|
+
});
|
|
389
|
+
},
|
|
390
|
+
[dispatch]
|
|
391
|
+
);
|
|
392
|
+
return useEffect(() => {
|
|
393
|
+
firstField.current && firstField.current.focus();
|
|
394
|
+
}, [firstField]), /* @__PURE__ */ jsx(
|
|
395
|
+
Dialog,
|
|
396
|
+
{
|
|
397
|
+
animate: !0,
|
|
398
|
+
id,
|
|
399
|
+
onClose: handleClose,
|
|
400
|
+
onClickOutside: handleClose,
|
|
401
|
+
header: /* @__PURE__ */ jsx(Header, {}),
|
|
402
|
+
zOffset: DIALOGS_Z_INDEX,
|
|
561
403
|
position: "fixed",
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
{
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
tone: "critical",
|
|
571
|
-
onClick: props.closeDialog,
|
|
572
|
-
disabled: isImporting
|
|
573
|
-
}
|
|
574
|
-
),
|
|
575
|
-
props.missingAssets && /* @__PURE__ */ jsx(
|
|
576
|
-
Button,
|
|
577
|
-
{
|
|
578
|
-
icon: RetrieveIcon,
|
|
579
|
-
fontSize: 2,
|
|
580
|
-
padding: 3,
|
|
581
|
-
mode: "ghost",
|
|
582
|
-
text: props.selectedAssets?.length > 0 ? `Import ${props.selectedAssets.length} video(s)` : "No video(s) selected",
|
|
583
|
-
tone: "positive",
|
|
584
|
-
onClick: props.importAssets,
|
|
585
|
-
iconRight: isImporting && Spinner,
|
|
586
|
-
disabled: !canTriggerImport
|
|
587
|
-
}
|
|
588
|
-
)
|
|
589
|
-
] }) }),
|
|
590
|
-
children: /* @__PURE__ */ jsxs(Box, { padding: 3, children: [
|
|
591
|
-
(props.muxAssets.loading || props.assetsInSanityLoading) && /* @__PURE__ */ jsx(Card, { tone: "primary", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 4, children: [
|
|
592
|
-
/* @__PURE__ */ jsx(Spinner, { muted: !0, size: 4 }),
|
|
593
|
-
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
594
|
-
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "Loading assets from Mux" }),
|
|
595
|
-
/* @__PURE__ */ jsxs(Text, { size: 1, children: [
|
|
596
|
-
"This may take a while.",
|
|
597
|
-
props.missingAssets && props.missingAssets.length > 0 && ` There are at least ${props.missingAssets.length} video${props.missingAssets.length > 1 ? "s" : ""} currently not in Sanity...`
|
|
598
|
-
] })
|
|
599
|
-
] })
|
|
600
|
-
] }) }),
|
|
601
|
-
props.muxAssets.error && /* @__PURE__ */ jsx(Card, { tone: "critical", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
602
|
-
/* @__PURE__ */ jsx(ErrorOutlineIcon, { fontSize: 36 }),
|
|
603
|
-
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
604
|
-
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "There was an error getting all data from Mux" }),
|
|
605
|
-
/* @__PURE__ */ jsx(Text, { size: 1, children: props.missingAssets ? `But we've found ${props.missingAssets.length} video${props.missingAssets.length > 1 ? "s" : ""} not in Sanity, which you can start importing now.` : "Please try again or contact a developer for help." })
|
|
606
|
-
] })
|
|
607
|
-
] }) }),
|
|
608
|
-
importState === "importing" && /* @__PURE__ */ jsx(Card, { tone: "primary", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 4, children: [
|
|
609
|
-
/* @__PURE__ */ jsx(Spinner, { muted: !0, size: 4 }),
|
|
610
|
-
/* @__PURE__ */ jsx(Stack, { space: 2, children: /* @__PURE__ */ jsxs(Text, { size: 2, weight: "semibold", children: [
|
|
611
|
-
"Importing ",
|
|
612
|
-
props.selectedAssets.length,
|
|
613
|
-
" video",
|
|
614
|
-
props.selectedAssets.length > 1 && "s",
|
|
615
|
-
" from Mux"
|
|
616
|
-
] }) })
|
|
617
|
-
] }) }),
|
|
618
|
-
importState === "error" && /* @__PURE__ */ jsx(Card, { tone: "critical", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
619
|
-
/* @__PURE__ */ jsx(ErrorOutlineIcon, { fontSize: 36 }),
|
|
620
|
-
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
621
|
-
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "There was an error importing videos" }),
|
|
622
|
-
/* @__PURE__ */ jsx(Text, { size: 1, children: props.importError ? `Error: ${props.importError}` : "Please try again or contact a developer for help." }),
|
|
623
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
|
|
624
|
-
Button,
|
|
404
|
+
width: 1,
|
|
405
|
+
children: /* @__PURE__ */ jsx(Box, { padding: 3, children: /* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, noValidate: !0, children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
406
|
+
!hasSecretsInitially && /* @__PURE__ */ jsx(Card, { padding: [3, 3, 3], radius: 2, shadow: 1, tone: "primary", children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
407
|
+
/* @__PURE__ */ jsxs(Text, { size: 1, children: [
|
|
408
|
+
"To set up a new access token, go to your",
|
|
409
|
+
" ",
|
|
410
|
+
/* @__PURE__ */ jsx(
|
|
411
|
+
"a",
|
|
625
412
|
{
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
413
|
+
href: "https://dashboard.mux.com/settings/access-tokens",
|
|
414
|
+
target: "_blank",
|
|
415
|
+
rel: "noreferrer noopener",
|
|
416
|
+
children: "account on mux.com"
|
|
630
417
|
}
|
|
631
|
-
)
|
|
418
|
+
),
|
|
419
|
+
"."
|
|
420
|
+
] }),
|
|
421
|
+
/* @__PURE__ */ jsxs(Text, { size: 1, children: [
|
|
422
|
+
"The access token needs permissions: ",
|
|
423
|
+
/* @__PURE__ */ jsx("strong", { children: "Mux Video " }),
|
|
424
|
+
"(Full Access) and ",
|
|
425
|
+
/* @__PURE__ */ jsx("strong", { children: "Mux Data" }),
|
|
426
|
+
" (Read)",
|
|
427
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
428
|
+
"To use Signed URLs, the token must also have System permissions.",
|
|
429
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
430
|
+
"The credentials will be stored safely in a hidden document only available to editors."
|
|
632
431
|
] })
|
|
633
432
|
] }) }),
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
433
|
+
/* @__PURE__ */ jsx(FormField$1, { title: "Access Token", inputId: tokenId, children: /* @__PURE__ */ jsx(
|
|
434
|
+
TextInput,
|
|
435
|
+
{
|
|
436
|
+
id: tokenId,
|
|
437
|
+
ref: firstField,
|
|
438
|
+
onChange: handleChangeToken,
|
|
439
|
+
type: "text",
|
|
440
|
+
value: state.token ?? "",
|
|
441
|
+
required: !!state.secretKey || state.enableSignedUrls
|
|
442
|
+
}
|
|
443
|
+
) }),
|
|
444
|
+
/* @__PURE__ */ jsx(FormField$1, { title: "Secret Key", inputId: secretKeyId, children: /* @__PURE__ */ jsx(
|
|
445
|
+
TextInput,
|
|
446
|
+
{
|
|
447
|
+
id: secretKeyId,
|
|
448
|
+
onChange: handleChangeSecretKey,
|
|
449
|
+
type: "text",
|
|
450
|
+
value: state.secretKey ?? "",
|
|
451
|
+
required: !!state.token || state.enableSignedUrls
|
|
452
|
+
}
|
|
453
|
+
) }),
|
|
454
|
+
/* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
455
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", children: [
|
|
650
456
|
/* @__PURE__ */ jsx(
|
|
651
457
|
Checkbox,
|
|
652
458
|
{
|
|
653
|
-
id:
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
},
|
|
658
|
-
checked: props.selectedAssets.length === props.missingAssets.length
|
|
459
|
+
id: enableSignedUrlsId,
|
|
460
|
+
onChange: handleChangeEnableSignedUrls,
|
|
461
|
+
checked: state.enableSignedUrls,
|
|
462
|
+
style: { display: "block" }
|
|
659
463
|
}
|
|
660
464
|
),
|
|
661
|
-
/* @__PURE__ */ jsx(Box, { flex: 1, paddingLeft: 3,
|
|
465
|
+
/* @__PURE__ */ jsx(Box, { flex: 1, paddingLeft: 3, children: /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx("label", { htmlFor: enableSignedUrlsId, children: "Enable Signed Urls" }) }) })
|
|
662
466
|
] }),
|
|
663
|
-
|
|
664
|
-
|
|
467
|
+
secrets.signingKeyId && state.enableSignedUrls ? /* @__PURE__ */ jsx(Card, { padding: [3, 3, 3], radius: 2, shadow: 1, tone: "caution", children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
468
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: "The signing key ID that Sanity will use is:" }),
|
|
469
|
+
/* @__PURE__ */ jsx(Code, { size: 1, children: secrets.signingKeyId }),
|
|
470
|
+
/* @__PURE__ */ jsxs(Text, { size: 1, children: [
|
|
471
|
+
"This key is only used for previewing content in the Sanity UI.",
|
|
472
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
473
|
+
"You should generate a different key to use in your application server."
|
|
474
|
+
] })
|
|
475
|
+
] }) }) : null
|
|
476
|
+
] }),
|
|
477
|
+
/* @__PURE__ */ jsxs(Inline, { space: 2, children: [
|
|
478
|
+
/* @__PURE__ */ jsx(
|
|
479
|
+
Button,
|
|
665
480
|
{
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
)
|
|
674
|
-
|
|
675
|
-
|
|
481
|
+
text: "Save",
|
|
482
|
+
disabled: !dirty,
|
|
483
|
+
loading: state.submitting,
|
|
484
|
+
tone: "primary",
|
|
485
|
+
mode: "default",
|
|
486
|
+
type: "submit"
|
|
487
|
+
}
|
|
488
|
+
),
|
|
489
|
+
/* @__PURE__ */ jsx(
|
|
490
|
+
Button,
|
|
491
|
+
{
|
|
492
|
+
disabled: state.submitting,
|
|
493
|
+
text: "Cancel",
|
|
494
|
+
mode: "bleed",
|
|
495
|
+
onClick: handleClose
|
|
496
|
+
}
|
|
497
|
+
)
|
|
498
|
+
] }),
|
|
499
|
+
state.error && /* @__PURE__ */ jsx(Card, { padding: [3, 3, 3], radius: 2, shadow: 1, tone: "critical", children: /* @__PURE__ */ jsx(Text, { children: state.error }) })
|
|
500
|
+
] }) }) })
|
|
676
501
|
}
|
|
677
502
|
);
|
|
678
503
|
}
|
|
679
|
-
function
|
|
680
|
-
const
|
|
681
|
-
|
|
682
|
-
|
|
504
|
+
function ConfigureApi() {
|
|
505
|
+
const [dialogOpen, setDialogOpen] = useDialogState(), secretDocumentValues = useSecretsDocumentValues(), openDialog = useCallback(() => setDialogOpen("secrets"), [setDialogOpen]);
|
|
506
|
+
return dialogOpen === "secrets" ? /* @__PURE__ */ jsx(
|
|
507
|
+
ConfigureApiDialog,
|
|
508
|
+
{
|
|
509
|
+
secrets: secretDocumentValues.value.secrets,
|
|
510
|
+
setDialogState: setDialogOpen
|
|
511
|
+
}
|
|
512
|
+
) : /* @__PURE__ */ jsx(Button, { mode: "bleed", text: "Configure plugin", onClick: openDialog });
|
|
683
513
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
placement: "bottom",
|
|
687
|
-
portal: !0,
|
|
688
|
-
width: 0
|
|
689
|
-
};
|
|
690
|
-
function SelectSortOptions(props) {
|
|
691
|
-
const id = useId();
|
|
692
|
-
return /* @__PURE__ */ jsx(
|
|
693
|
-
MenuButton,
|
|
694
|
-
{
|
|
695
|
-
button: /* @__PURE__ */ jsx(Button, { text: "Sort", icon: SortIcon, mode: "bleed", padding: 3, style: { cursor: "pointer" } }),
|
|
696
|
-
id,
|
|
697
|
-
menu: /* @__PURE__ */ jsx(Menu, { children: Object.entries(ASSET_SORT_OPTIONS).map(([type, { label }]) => /* @__PURE__ */ jsx(
|
|
698
|
-
MenuItem,
|
|
699
|
-
{
|
|
700
|
-
"data-as": "button",
|
|
701
|
-
onClick: () => props.setSort(type),
|
|
702
|
-
padding: 3,
|
|
703
|
-
tone: "default",
|
|
704
|
-
text: label,
|
|
705
|
-
pressed: type === props.sort
|
|
706
|
-
},
|
|
707
|
-
type
|
|
708
|
-
)) }),
|
|
709
|
-
popover: CONTEXT_MENU_POPOVER_PROPS
|
|
710
|
-
}
|
|
711
|
-
);
|
|
514
|
+
function generateAssetPlaceholder(assetId) {
|
|
515
|
+
return `Asset #${truncateString(assetId, 15)}`;
|
|
712
516
|
}
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
alignItems: "center",
|
|
719
|
-
justifyContent: "center",
|
|
720
|
-
minHeight: "150px"
|
|
721
|
-
},
|
|
722
|
-
children: /* @__PURE__ */ jsx(Spinner, {})
|
|
723
|
-
}
|
|
724
|
-
);
|
|
725
|
-
function FormField(props) {
|
|
726
|
-
const { children, title, description, inputId } = props;
|
|
727
|
-
return /* @__PURE__ */ jsxs(Stack, { space: 1, children: [
|
|
728
|
-
/* @__PURE__ */ jsx(Flex, { align: "flex-end", children: /* @__PURE__ */ jsx(Box, { flex: 1, paddingY: 2, children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
729
|
-
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, weight: "semibold", size: 1, children: title || /* @__PURE__ */ jsx("em", { children: "Untitled" }) }),
|
|
730
|
-
description && /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: description })
|
|
731
|
-
] }) }) }),
|
|
732
|
-
/* @__PURE__ */ jsx("div", { children })
|
|
733
|
-
] });
|
|
517
|
+
function isEmptyOrPlaceholderTitle(filename, assetId) {
|
|
518
|
+
if (!filename || filename.trim() === "")
|
|
519
|
+
return !0;
|
|
520
|
+
const placeholder = generateAssetPlaceholder(assetId);
|
|
521
|
+
return filename === placeholder;
|
|
734
522
|
}
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
const Icon = props.icon;
|
|
738
|
-
return /* @__PURE__ */ jsxs(Flex, { gap: 2, align: "center", padding: 1, children: [
|
|
739
|
-
/* @__PURE__ */ jsx(Text, { size: (props.size || 1) + 1, muted: !0, children: /* @__PURE__ */ jsx(Icon, {}) }),
|
|
740
|
-
/* @__PURE__ */ jsx(Text, { size: props.size || 1, muted: props.muted, children: props.text })
|
|
741
|
-
] });
|
|
742
|
-
};
|
|
743
|
-
function ResolutionIcon(props) {
|
|
744
|
-
return /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 24 24", ...props, children: /* @__PURE__ */ jsx(
|
|
745
|
-
"path",
|
|
746
|
-
{
|
|
747
|
-
fill: "currentColor",
|
|
748
|
-
d: "M20 9V6h-3V4h5v5h-2ZM2 9V4h5v2H4v3H2Zm15 11v-2h3v-3h2v5h-5ZM2 20v-5h2v3h3v2H2Zm4-4V8h12v8H6Zm2-2h8v-4H8v4Zm0 0v-4v4Z"
|
|
749
|
-
}
|
|
750
|
-
) });
|
|
523
|
+
function parseMuxDate(date) {
|
|
524
|
+
return new Date(Number(date) * 1e3);
|
|
751
525
|
}
|
|
752
|
-
function
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
{
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
viewBox: "0 0 512 512",
|
|
760
|
-
...props,
|
|
761
|
-
children: [
|
|
762
|
-
/* @__PURE__ */ jsx("path", { d: "M232 306.667h48V176h-48v130.667z", fill: "currentColor" }),
|
|
763
|
-
/* @__PURE__ */ jsx(
|
|
764
|
-
"path",
|
|
765
|
-
{
|
|
766
|
-
d: "M407.67 170.271l30.786-30.786-33.942-33.941-30.785 30.786C341.217 111.057 300.369 96 256 96 149.961 96 64 181.961 64 288s85.961 192 192 192 192-85.961 192-192c0-44.369-15.057-85.217-40.33-117.729zm-45.604 223.795C333.734 422.398 296.066 438 256 438s-77.735-15.602-106.066-43.934C121.602 365.735 106 328.066 106 288s15.602-77.735 43.934-106.066C178.265 153.602 215.934 138 256 138s77.734 15.602 106.066 43.934C390.398 210.265 406 247.934 406 288s-15.602 77.735-43.934 106.066z",
|
|
767
|
-
fill: "currentColor"
|
|
768
|
-
}
|
|
769
|
-
),
|
|
770
|
-
/* @__PURE__ */ jsx("path", { d: "M192 32h128v48H192z", fill: "currentColor" })
|
|
771
|
-
]
|
|
772
|
-
}
|
|
773
|
-
);
|
|
526
|
+
function deleteAssetOnMux(client, assetId) {
|
|
527
|
+
const { dataset } = client.config();
|
|
528
|
+
return client.request({
|
|
529
|
+
url: `/addons/mux/assets/${dataset}/${assetId}`,
|
|
530
|
+
withCredentials: !0,
|
|
531
|
+
method: "DELETE"
|
|
532
|
+
});
|
|
774
533
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
if (getPlaybackPolicy(asset) === "signed") {
|
|
786
|
-
const token = generateJwt(client, playbackId, "v");
|
|
787
|
-
searchParams.set("token", token);
|
|
534
|
+
async function deleteAsset({
|
|
535
|
+
client,
|
|
536
|
+
asset,
|
|
537
|
+
deleteOnMux
|
|
538
|
+
}) {
|
|
539
|
+
if (!asset?._id) return !0;
|
|
540
|
+
try {
|
|
541
|
+
await client.delete(asset._id);
|
|
542
|
+
} catch {
|
|
543
|
+
return "failed-sanity";
|
|
788
544
|
}
|
|
789
|
-
|
|
545
|
+
if (deleteOnMux && asset?.assetId)
|
|
546
|
+
try {
|
|
547
|
+
await deleteAssetOnMux(client, asset.assetId);
|
|
548
|
+
} catch {
|
|
549
|
+
return "failed-mux";
|
|
550
|
+
}
|
|
551
|
+
return !0;
|
|
790
552
|
}
|
|
791
|
-
function
|
|
792
|
-
const {
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
553
|
+
function getAsset(client, assetId) {
|
|
554
|
+
const { dataset } = client.config();
|
|
555
|
+
return client.request({
|
|
556
|
+
url: `/addons/mux/assets/${dataset}/data/${assetId}`,
|
|
557
|
+
withCredentials: !0,
|
|
558
|
+
method: "GET"
|
|
559
|
+
});
|
|
798
560
|
}
|
|
799
|
-
function
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
561
|
+
function listAssets(client, options) {
|
|
562
|
+
const { dataset } = client.config(), query = {};
|
|
563
|
+
return options.limit && (query.limit = options.limit.toString()), options.cursor && (query.cursor = options.cursor), client.request({
|
|
564
|
+
url: `/addons/mux/assets/${dataset}/data/list`,
|
|
565
|
+
withCredentials: !0,
|
|
566
|
+
method: "GET",
|
|
567
|
+
query
|
|
568
|
+
});
|
|
805
569
|
}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
570
|
+
const ASSETS_PER_PAGE = 100;
|
|
571
|
+
async function fetchMuxAssetsPage(client, cursor) {
|
|
572
|
+
try {
|
|
573
|
+
const response = await listAssets(client, {
|
|
574
|
+
limit: ASSETS_PER_PAGE,
|
|
575
|
+
cursor
|
|
576
|
+
});
|
|
577
|
+
return {
|
|
578
|
+
cursor,
|
|
579
|
+
data: response.data,
|
|
580
|
+
next_cursor: response.next_cursor || null
|
|
581
|
+
};
|
|
582
|
+
} catch {
|
|
583
|
+
return {
|
|
584
|
+
cursor,
|
|
585
|
+
error: { _tag: "FetchError" }
|
|
586
|
+
};
|
|
587
|
+
}
|
|
809
588
|
}
|
|
810
|
-
function
|
|
811
|
-
|
|
589
|
+
function accumulateIntermediateState(currentState, pageResult) {
|
|
590
|
+
const currentData = "data" in currentState && currentState.data || [], newAssets = "data" in pageResult && pageResult.data || [], { validAssets, skippedInThisPage } = newAssets.reduce(
|
|
591
|
+
(acc, asset) => {
|
|
592
|
+
const hasPlaybackIds = asset.playback_ids && asset.playback_ids.length > 0, isDuplicate = currentData.some((a2) => a2.id === asset.id);
|
|
593
|
+
return hasPlaybackIds || (acc.skippedInThisPage = !0), hasPlaybackIds && !isDuplicate && acc.validAssets.push(asset), acc;
|
|
594
|
+
},
|
|
595
|
+
{ validAssets: [], skippedInThisPage: !1 }
|
|
596
|
+
);
|
|
597
|
+
return {
|
|
598
|
+
...currentState,
|
|
599
|
+
data: [...currentData, ...validAssets],
|
|
600
|
+
error: "error" in pageResult ? pageResult.error : (
|
|
601
|
+
// Reset error if current page is successful
|
|
602
|
+
void 0
|
|
603
|
+
),
|
|
604
|
+
cursor: "next_cursor" in pageResult ? pageResult.next_cursor : pageResult.cursor,
|
|
605
|
+
loading: !0,
|
|
606
|
+
hasSkippedAssetsWithoutPlayback: currentState.hasSkippedAssetsWithoutPlayback || skippedInThisPage
|
|
607
|
+
};
|
|
812
608
|
}
|
|
813
|
-
function
|
|
814
|
-
|
|
815
|
-
return hh * 3600 + mm * 60 + ss;
|
|
609
|
+
function hasMorePages(pageResult) {
|
|
610
|
+
return typeof pageResult == "object" && "next_cursor" in pageResult && pageResult.next_cursor !== null;
|
|
816
611
|
}
|
|
817
|
-
function
|
|
818
|
-
const
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
text: "Set new thumbnail"
|
|
840
|
-
},
|
|
841
|
-
"thumbnail"
|
|
842
|
-
) }),
|
|
843
|
-
children: /* @__PURE__ */ jsxs(Stack, { space: 3, padding: 3, children: [
|
|
844
|
-
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
845
|
-
/* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "Current:" }),
|
|
846
|
-
/* @__PURE__ */ jsx(VideoThumbnail, { asset, width, staticImage: !0 })
|
|
847
|
-
] }),
|
|
848
|
-
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
849
|
-
/* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "New:" }),
|
|
850
|
-
/* @__PURE__ */ jsx(VideoThumbnail, { asset: assetWithNewThumbnail, width, staticImage: !0 })
|
|
851
|
-
] }),
|
|
852
|
-
/* @__PURE__ */ jsx(Stack, { space: 2, children: /* @__PURE__ */ jsx(Flex, { align: "center", justify: "center", children: /* @__PURE__ */ jsx(Text, { size: 5, weight: "semibold", children: "Or" }) }) }),
|
|
853
|
-
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
854
|
-
/* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "Selected time for thumbnail (hh:mm:ss):" }),
|
|
855
|
-
/* @__PURE__ */ jsx(
|
|
856
|
-
TextInput,
|
|
857
|
-
{
|
|
858
|
-
size: 1,
|
|
859
|
-
value: timeFormatted,
|
|
860
|
-
placeholder: "hh:mm:ss",
|
|
861
|
-
onChange: (event) => {
|
|
862
|
-
const value = event.currentTarget.value;
|
|
863
|
-
if (setTimeFormatted(value), isValidTimeFormat(value)) {
|
|
864
|
-
setInputError("");
|
|
865
|
-
const totalSeconds = getSecondsFromTimeFormat(value);
|
|
866
|
-
setNextTime(totalSeconds);
|
|
867
|
-
} else
|
|
868
|
-
setInputError("Invalid time format");
|
|
869
|
-
},
|
|
870
|
-
customValidity: inputError
|
|
871
|
-
}
|
|
612
|
+
function useMuxAssets({ client, enabled }) {
|
|
613
|
+
const [state, setState] = useState({ loading: !0, cursor: null });
|
|
614
|
+
return useEffect(() => {
|
|
615
|
+
if (!enabled) return;
|
|
616
|
+
const subscription = defer(
|
|
617
|
+
() => fetchMuxAssetsPage(
|
|
618
|
+
client,
|
|
619
|
+
// When we've already successfully loaded before (fully or partially), we start from the next cursor to avoid re-fetching
|
|
620
|
+
"data" in state && state.data && state.data.length > 0 && !state.error ? state.cursor : null
|
|
621
|
+
)
|
|
622
|
+
).pipe(
|
|
623
|
+
// Here we use "expand" to recursively fetch next pages
|
|
624
|
+
expand((pageResult) => hasMorePages(pageResult) ? timer(2e3).pipe(
|
|
625
|
+
concatMap(
|
|
626
|
+
() => (
|
|
627
|
+
// eslint-disable-next-line max-nested-callbacks
|
|
628
|
+
defer(
|
|
629
|
+
() => fetchMuxAssetsPage(
|
|
630
|
+
client,
|
|
631
|
+
"next_cursor" in pageResult ? pageResult.next_cursor : null
|
|
632
|
+
)
|
|
633
|
+
)
|
|
872
634
|
)
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
}
|
|
891
|
-
}, [asset, client]), signedToken = useMemo(() => {
|
|
892
|
-
try {
|
|
893
|
-
return new URL(videoSrc).searchParams.get("token");
|
|
894
|
-
} catch {
|
|
895
|
-
return !1;
|
|
896
|
-
}
|
|
897
|
-
}, [videoSrc]), [width, height] = (asset?.data?.aspect_ratio ?? "16:9").split(":").map(Number), targetAspectRatio = props.forceAspectRatio || (Number.isNaN(width) ? 16 / 9 : width / height);
|
|
898
|
-
let aspectRatio = Math.max(MIN_ASPECT_RATIO, targetAspectRatio);
|
|
899
|
-
return isAudio && (aspectRatio = props.forceAspectRatio ? (
|
|
900
|
-
// Make it wider when forcing aspect ratio to balance with videos' rendering height (audio players overflow a bit)
|
|
901
|
-
props.forceAspectRatio * 1.2
|
|
902
|
-
) : AUDIO_ASPECT_RATIO), /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
903
|
-
/* @__PURE__ */ jsxs(Card, { tone: "transparent", style: { aspectRatio, position: "relative" }, children: [
|
|
904
|
-
videoSrc && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
905
|
-
/* @__PURE__ */ jsx(
|
|
906
|
-
MuxPlayer,
|
|
907
|
-
{
|
|
908
|
-
poster: thumbnail,
|
|
909
|
-
ref: muxPlayer,
|
|
910
|
-
...props,
|
|
911
|
-
playsInline: !0,
|
|
912
|
-
playbackId: asset.playbackId,
|
|
913
|
-
tokens: signedToken ? { playback: signedToken, thumbnail: signedToken, storyboard: signedToken } : void 0,
|
|
914
|
-
preload: "metadata",
|
|
915
|
-
crossOrigin: "anonymous",
|
|
916
|
-
metadata: {
|
|
917
|
-
player_name: "Sanity Admin Dashboard",
|
|
918
|
-
player_version: "2.9.1",
|
|
919
|
-
page_type: "Preview Player"
|
|
920
|
-
},
|
|
921
|
-
audio: isAudio,
|
|
922
|
-
style: {
|
|
923
|
-
height: "100%",
|
|
924
|
-
width: "100%",
|
|
925
|
-
display: "block",
|
|
926
|
-
objectFit: "contain"
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
),
|
|
930
|
-
children
|
|
931
|
-
] }),
|
|
932
|
-
error ? /* @__PURE__ */ jsx(
|
|
933
|
-
"div",
|
|
934
|
-
{
|
|
935
|
-
style: {
|
|
936
|
-
position: "absolute",
|
|
937
|
-
top: "50%",
|
|
938
|
-
left: "50%",
|
|
939
|
-
transform: "translate(-50%, -50%)"
|
|
940
|
-
},
|
|
941
|
-
children: /* @__PURE__ */ jsxs(Text, { muted: !0, children: [
|
|
942
|
-
/* @__PURE__ */ jsx(ErrorOutlineIcon, { style: { marginRight: "0.15em" } }),
|
|
943
|
-
typeof error == "object" && "message" in error && typeof error.message == "string" ? error.message : "Error loading video"
|
|
944
|
-
] })
|
|
945
|
-
}
|
|
946
|
-
) : null,
|
|
947
|
-
children
|
|
948
|
-
] }),
|
|
949
|
-
dialogState === "edit-thumbnail" && /* @__PURE__ */ jsx(EditThumbnailDialog, { asset, currentTime: muxPlayer?.current?.currentTime })
|
|
950
|
-
] });
|
|
951
|
-
}
|
|
952
|
-
function assetIsAudio(asset) {
|
|
953
|
-
return asset.data?.max_stored_resolution === "Audio only";
|
|
954
|
-
}
|
|
955
|
-
function deleteAssetOnMux(client, assetId) {
|
|
956
|
-
const { dataset } = client.config();
|
|
957
|
-
return client.request({
|
|
958
|
-
url: `/addons/mux/assets/${dataset}/${assetId}`,
|
|
959
|
-
withCredentials: !0,
|
|
960
|
-
method: "DELETE"
|
|
961
|
-
});
|
|
635
|
+
)
|
|
636
|
+
) : of()),
|
|
637
|
+
// On each iteration, persist intermediate states to give feedback to users
|
|
638
|
+
tap(
|
|
639
|
+
(pageResult) => setState((prevState) => accumulateIntermediateState(prevState, pageResult))
|
|
640
|
+
)
|
|
641
|
+
).subscribe({
|
|
642
|
+
// Once done, let the user know we've stopped loading
|
|
643
|
+
complete: () => {
|
|
644
|
+
setState((prev) => ({
|
|
645
|
+
...prev,
|
|
646
|
+
loading: !1
|
|
647
|
+
}));
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
return () => subscription.unsubscribe();
|
|
651
|
+
}, [enabled]), state;
|
|
962
652
|
}
|
|
963
|
-
|
|
964
|
-
client
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
}
|
|
974
|
-
|
|
653
|
+
function useImportMuxAssets() {
|
|
654
|
+
const documentStore = useDocumentStore(), client = useClient$1({
|
|
655
|
+
apiVersion: SANITY_API_VERSION
|
|
656
|
+
}), [assetsInSanity, assetsInSanityLoading] = useAssetsInSanity(documentStore), hasSecrets = !!useSecretsDocumentValues().value.secrets?.secretKey, [importError, setImportError] = useState(), [importState, setImportState] = useState("closed"), dialogOpen = importState !== "closed", muxAssets = useMuxAssets({
|
|
657
|
+
client,
|
|
658
|
+
enabled: hasSecrets && dialogOpen
|
|
659
|
+
}), missingAssets = useMemo(() => assetsInSanity && muxAssets.data ? muxAssets.data.filter((a2) => !assetExistsInSanity(a2, assetsInSanity)) : void 0, [assetsInSanity, muxAssets.data]), [selectedAssets, setSelectedAssets] = useState([]), closeDialog = () => {
|
|
660
|
+
importState !== "importing" && setImportState("closed");
|
|
661
|
+
}, openDialog = () => {
|
|
662
|
+
importState === "closed" && setImportState("idle");
|
|
663
|
+
};
|
|
664
|
+
async function importAssets() {
|
|
665
|
+
setImportState("importing");
|
|
666
|
+
const documents = selectedAssets.flatMap((asset) => muxAssetToSanityDocument(asset) || []), tx = client.transaction();
|
|
667
|
+
documents.forEach((doc) => tx.create(doc));
|
|
975
668
|
try {
|
|
976
|
-
await
|
|
977
|
-
} catch {
|
|
978
|
-
|
|
669
|
+
await tx.commit({ returnDocuments: !1 }), setSelectedAssets([]), setImportState("done");
|
|
670
|
+
} catch (error) {
|
|
671
|
+
setImportState("error"), setImportError(error);
|
|
979
672
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
subtitle: /* @__PURE__ */ jsxs("em", { children: [
|
|
996
|
-
"Document: ",
|
|
997
|
-
/* @__PURE__ */ jsx("code", { children: id })
|
|
998
|
-
] }),
|
|
999
|
-
media: () => /* @__PURE__ */ jsx(WarningOutlineIcon, {})
|
|
1000
|
-
});
|
|
1001
|
-
function MissingSchemaType(props) {
|
|
1002
|
-
const { layout, value } = props;
|
|
1003
|
-
return /* @__PURE__ */ jsx(SanityDefaultPreview, { ...getUnknownTypeFallback(value._id, value._type), layout });
|
|
673
|
+
}
|
|
674
|
+
return {
|
|
675
|
+
assetsInSanityLoading,
|
|
676
|
+
closeDialog,
|
|
677
|
+
dialogOpen,
|
|
678
|
+
importState,
|
|
679
|
+
importError,
|
|
680
|
+
hasSecrets,
|
|
681
|
+
importAssets,
|
|
682
|
+
missingAssets,
|
|
683
|
+
muxAssets,
|
|
684
|
+
openDialog,
|
|
685
|
+
selectedAssets,
|
|
686
|
+
setSelectedAssets
|
|
687
|
+
};
|
|
1004
688
|
}
|
|
1005
|
-
function
|
|
1006
|
-
const
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
689
|
+
function muxAssetToSanityDocument(asset) {
|
|
690
|
+
const playbackId = (asset.playback_ids || []).find((p) => p.id)?.id;
|
|
691
|
+
if (playbackId)
|
|
692
|
+
return {
|
|
693
|
+
_id: uuid(),
|
|
694
|
+
_type: "mux.videoAsset",
|
|
695
|
+
_updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
696
|
+
_createdAt: parseMuxDate(asset.created_at).toISOString(),
|
|
697
|
+
assetId: asset.id,
|
|
698
|
+
playbackId,
|
|
699
|
+
filename: asset.meta?.title ?? generateAssetPlaceholder(asset.id),
|
|
700
|
+
status: asset.status,
|
|
701
|
+
data: asset
|
|
702
|
+
};
|
|
1011
703
|
}
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
704
|
+
const useAssetsInSanity = createHookFromObservableFactory(
|
|
705
|
+
(documentStore) => documentStore.listenQuery(
|
|
706
|
+
/* groq */
|
|
707
|
+
`*[_type == "mux.videoAsset"] {
|
|
708
|
+
"uploadId": coalesce(uploadId, data.upload_id),
|
|
709
|
+
"assetId": coalesce(assetId, data.id),
|
|
710
|
+
}`,
|
|
711
|
+
{},
|
|
1016
712
|
{
|
|
1017
|
-
|
|
1018
|
-
portal: !0,
|
|
1019
|
-
content: /* @__PURE__ */ jsx(Box, { padding: 2, children: /* @__PURE__ */ jsx(Text, { size: 1, children: document2 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1020
|
-
"Edited ",
|
|
1021
|
-
updatedAt && /* @__PURE__ */ jsx(TimeAgo, { time: updatedAt })
|
|
1022
|
-
] }) : /* @__PURE__ */ jsx(Fragment, { children: "No unpublished edits" }) }) }),
|
|
1023
|
-
children: /* @__PURE__ */ jsx(TextWithTone, { tone: "caution", dimmed: !document2, muted: !document2, size: 1, children: /* @__PURE__ */ jsx(EditIcon, {}) })
|
|
713
|
+
apiVersion: SANITY_API_VERSION
|
|
1024
714
|
}
|
|
715
|
+
)
|
|
716
|
+
);
|
|
717
|
+
function assetExistsInSanity(asset, existingAssets) {
|
|
718
|
+
return asset.status !== "ready" ? !1 : existingAssets.some(
|
|
719
|
+
(existing) => existing.assetId === asset.id || existing.uploadId === asset.upload_id
|
|
1025
720
|
);
|
|
1026
721
|
}
|
|
1027
|
-
function
|
|
1028
|
-
const
|
|
1029
|
-
return
|
|
1030
|
-
|
|
722
|
+
function useInView(ref, options = {}) {
|
|
723
|
+
const [inView, setInView] = useState(!1);
|
|
724
|
+
return useEffect(() => {
|
|
725
|
+
if (!ref.current) return;
|
|
726
|
+
const observer = new IntersectionObserver(([entry], obs) => {
|
|
727
|
+
const nowInView = entry.isIntersecting && obs.thresholds.some((threshold) => entry.intersectionRatio >= threshold);
|
|
728
|
+
setInView(nowInView), options?.onChange?.(nowInView);
|
|
729
|
+
}, options), toObserve = ref.current;
|
|
730
|
+
return observer.observe(toObserve), () => {
|
|
731
|
+
toObserve && observer.unobserve(toObserve);
|
|
732
|
+
};
|
|
733
|
+
}, [options, ref]), inView;
|
|
734
|
+
}
|
|
735
|
+
function generateJwt(client, playbackId, aud, payload) {
|
|
736
|
+
const { signingKeyId, signingKeyPrivate } = readSecrets(client);
|
|
737
|
+
if (!signingKeyId)
|
|
738
|
+
throw new TypeError("Missing `signingKeyId`.\n Check your plugin's configuration");
|
|
739
|
+
if (!signingKeyPrivate)
|
|
740
|
+
throw new TypeError("Missing `signingKeyPrivate`.\n Check your plugin's configuration");
|
|
741
|
+
const { default: sign } = suspend(() => import("jsonwebtoken-esm/sign"), ["jsonwebtoken-esm/sign"]);
|
|
742
|
+
return sign(
|
|
743
|
+
payload ? JSON.parse(JSON.stringify(payload, (_, v) => v ?? void 0)) : {},
|
|
744
|
+
atob(signingKeyPrivate),
|
|
1031
745
|
{
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
children: /* @__PURE__ */ jsx(TextWithTone, { tone: "positive", dimmed: !document2, muted: !document2, size: 1, children: /* @__PURE__ */ jsx(PublishIcon, {}) })
|
|
746
|
+
algorithm: "RS256",
|
|
747
|
+
keyid: signingKeyId,
|
|
748
|
+
audience: aud,
|
|
749
|
+
subject: playbackId,
|
|
750
|
+
noTimestamp: !0,
|
|
751
|
+
expiresIn: "12h"
|
|
1039
752
|
}
|
|
1040
753
|
);
|
|
1041
754
|
}
|
|
1042
|
-
function
|
|
1043
|
-
|
|
1044
|
-
(
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
] });
|
|
1055
|
-
return /* @__PURE__ */ jsx(
|
|
1056
|
-
SanityDefaultPreview,
|
|
1057
|
-
{
|
|
1058
|
-
...getPreviewValueWithFallback({ value, draft, published }),
|
|
1059
|
-
isPlaceholder: isLoading,
|
|
1060
|
-
icon,
|
|
1061
|
-
layout,
|
|
1062
|
-
status
|
|
1063
|
-
}
|
|
755
|
+
function getPlaybackId(asset) {
|
|
756
|
+
if (!asset?.playbackId)
|
|
757
|
+
throw console.error("Asset is missing a playbackId", { asset }), new TypeError("Missing playbackId");
|
|
758
|
+
return asset.playbackId;
|
|
759
|
+
}
|
|
760
|
+
function getPlaybackPolicy(asset) {
|
|
761
|
+
return asset.data?.playback_ids?.find((playbackId) => asset.playbackId === playbackId.id)?.policy ?? "public";
|
|
762
|
+
}
|
|
763
|
+
function createUrlParamsObject(client, asset, params, audience) {
|
|
764
|
+
const playbackId = getPlaybackId(asset);
|
|
765
|
+
let searchParams = new URLSearchParams(
|
|
766
|
+
JSON.parse(JSON.stringify(params, (_, v) => v ?? void 0))
|
|
1064
767
|
);
|
|
768
|
+
if (getPlaybackPolicy(asset) === "signed") {
|
|
769
|
+
const token = generateJwt(client, playbackId, audience, params);
|
|
770
|
+
searchParams = new URLSearchParams({ token });
|
|
771
|
+
}
|
|
772
|
+
return { playbackId, searchParams };
|
|
1065
773
|
}
|
|
1066
|
-
function
|
|
1067
|
-
|
|
774
|
+
function getAnimatedPosterSrc({
|
|
775
|
+
asset,
|
|
776
|
+
client,
|
|
777
|
+
height,
|
|
778
|
+
width,
|
|
779
|
+
start = asset.thumbTime ? Math.max(0, asset.thumbTime - 2.5) : 0,
|
|
780
|
+
end = start + 5,
|
|
781
|
+
fps = 15
|
|
782
|
+
}) {
|
|
783
|
+
const params = { height, width, start, end, fps }, { playbackId, searchParams } = createUrlParamsObject(client, asset, params, "g");
|
|
784
|
+
return `https://image.mux.com/${playbackId}/animated.gif?${searchParams}`;
|
|
1068
785
|
}
|
|
1069
|
-
function
|
|
1070
|
-
|
|
786
|
+
function getPosterSrc({
|
|
787
|
+
asset,
|
|
788
|
+
client,
|
|
789
|
+
fit_mode,
|
|
790
|
+
height,
|
|
791
|
+
time = asset.thumbTime ?? void 0,
|
|
792
|
+
width
|
|
793
|
+
}) {
|
|
794
|
+
const params = { fit_mode, height, width };
|
|
795
|
+
time !== void 0 && (params.time = time);
|
|
796
|
+
const { playbackId, searchParams } = createUrlParamsObject(client, asset, params, "t");
|
|
797
|
+
return `https://image.mux.com/${playbackId}/thumbnail.png?${searchParams}`;
|
|
1071
798
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
799
|
+
const Image = styled.img`
|
|
800
|
+
transition: opacity 0.175s ease-out 0s;
|
|
801
|
+
display: block;
|
|
802
|
+
width: 100%;
|
|
803
|
+
height: 100%;
|
|
804
|
+
object-fit: contain;
|
|
805
|
+
object-position: center center;
|
|
806
|
+
`, STATUS_TO_TONE = {
|
|
807
|
+
loading: "transparent",
|
|
808
|
+
error: "critical",
|
|
809
|
+
loaded: "default"
|
|
810
|
+
};
|
|
811
|
+
function VideoThumbnail({
|
|
812
|
+
asset,
|
|
813
|
+
width,
|
|
814
|
+
staticImage = !1
|
|
815
|
+
}) {
|
|
816
|
+
const ref = useRef(null), inView = useInView(ref), posterWidth = width || 250, [status, setStatus] = useState("loading"), client = useClient(), src = useMemo(() => {
|
|
817
|
+
try {
|
|
818
|
+
let thumbnail;
|
|
819
|
+
return staticImage ? thumbnail = getPosterSrc({ asset, client, width: posterWidth }) : thumbnail = getAnimatedPosterSrc({ asset, client, width: posterWidth }), thumbnail;
|
|
820
|
+
} catch {
|
|
821
|
+
status !== "error" && setStatus("error");
|
|
822
|
+
return;
|
|
1082
823
|
}
|
|
1083
|
-
|
|
824
|
+
}, [asset, client, posterWidth, status, staticImage]);
|
|
825
|
+
function handleLoad() {
|
|
826
|
+
setStatus("loaded");
|
|
827
|
+
}
|
|
828
|
+
function handleError() {
|
|
829
|
+
setStatus("error");
|
|
830
|
+
}
|
|
1084
831
|
return /* @__PURE__ */ jsx(
|
|
1085
|
-
|
|
832
|
+
Card,
|
|
1086
833
|
{
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
834
|
+
style: {
|
|
835
|
+
aspectRatio: THUMBNAIL_ASPECT_RATIO,
|
|
836
|
+
position: "relative",
|
|
837
|
+
maxWidth: width ? `${width}px` : void 0,
|
|
838
|
+
width: "100%",
|
|
839
|
+
flex: 1
|
|
840
|
+
},
|
|
841
|
+
border: !0,
|
|
1092
842
|
radius: 2,
|
|
1093
|
-
|
|
1094
|
-
|
|
843
|
+
ref,
|
|
844
|
+
tone: STATUS_TO_TONE[status],
|
|
845
|
+
children: inView ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
846
|
+
status === "loading" && /* @__PURE__ */ jsx(
|
|
847
|
+
Box,
|
|
848
|
+
{
|
|
849
|
+
style: {
|
|
850
|
+
position: "absolute",
|
|
851
|
+
left: "50%",
|
|
852
|
+
top: "50%",
|
|
853
|
+
transform: "translate(-50%, -50%)"
|
|
854
|
+
},
|
|
855
|
+
children: /* @__PURE__ */ jsx(Spinner, {})
|
|
856
|
+
}
|
|
857
|
+
),
|
|
858
|
+
status === "error" && /* @__PURE__ */ jsxs(
|
|
859
|
+
Stack,
|
|
860
|
+
{
|
|
861
|
+
space: 4,
|
|
862
|
+
style: {
|
|
863
|
+
position: "absolute",
|
|
864
|
+
width: "100%",
|
|
865
|
+
left: 0,
|
|
866
|
+
top: "50%",
|
|
867
|
+
transform: "translateY(-50%)",
|
|
868
|
+
justifyItems: "center"
|
|
869
|
+
},
|
|
870
|
+
children: [
|
|
871
|
+
/* @__PURE__ */ jsx(Text, { size: 4, muted: !0, children: /* @__PURE__ */ jsx(ErrorOutlineIcon, { style: { fontSize: "1.75em" } }) }),
|
|
872
|
+
/* @__PURE__ */ jsx(Text, { muted: !0, align: "center", children: "Failed loading thumbnail" })
|
|
873
|
+
]
|
|
874
|
+
}
|
|
875
|
+
),
|
|
876
|
+
/* @__PURE__ */ jsx(
|
|
877
|
+
Image,
|
|
878
|
+
{
|
|
879
|
+
src,
|
|
880
|
+
alt: `Preview for ${staticImage ? "image" : "video"} ${asset.filename || asset.assetId}`,
|
|
881
|
+
onLoad: handleLoad,
|
|
882
|
+
onError: handleError,
|
|
883
|
+
style: { opacity: status === "loaded" ? 1 : 0 }
|
|
884
|
+
}
|
|
885
|
+
)
|
|
886
|
+
] }) : null
|
|
1095
887
|
}
|
|
1096
888
|
);
|
|
1097
889
|
}
|
|
1098
|
-
const
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
890
|
+
const MissingAssetCheckbox = styled(Checkbox)`
|
|
891
|
+
position: static !important;
|
|
892
|
+
|
|
893
|
+
input::after {
|
|
894
|
+
content: '';
|
|
895
|
+
position: absolute;
|
|
896
|
+
inset: 0;
|
|
897
|
+
display: block;
|
|
898
|
+
cursor: pointer;
|
|
899
|
+
z-index: 1000;
|
|
1107
900
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
if (!props.isLoaded)
|
|
1111
|
-
return /* @__PURE__ */ jsx(SpinnerBox, {});
|
|
1112
|
-
if (!props.references?.length)
|
|
1113
|
-
return /* @__PURE__ */ jsx(Card, { border: !0, radius: 3, padding: 3, children: /* @__PURE__ */ jsx(Text, { size: 2, children: "No documents are using this video" }) });
|
|
1114
|
-
const documentPairs = collate(props.references || []);
|
|
1115
|
-
return /* @__PURE__ */ jsx(Container, { children: documentPairs?.map((documentPair) => {
|
|
1116
|
-
const schemaType = schema.get(documentPair.type);
|
|
1117
|
-
return /* @__PURE__ */ jsx(
|
|
1118
|
-
Card,
|
|
1119
|
-
{
|
|
1120
|
-
marginBottom: 2,
|
|
1121
|
-
padding: 2,
|
|
1122
|
-
radius: 2,
|
|
1123
|
-
shadow: 1,
|
|
1124
|
-
style: { overflow: "hidden" },
|
|
1125
|
-
children: /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(DocumentPreview, { documentPair, schemaType }) })
|
|
1126
|
-
},
|
|
1127
|
-
documentPair.id
|
|
1128
|
-
);
|
|
1129
|
-
}) });
|
|
1130
|
-
};
|
|
1131
|
-
function DeleteDialog({
|
|
901
|
+
`;
|
|
902
|
+
function MissingAsset({
|
|
1132
903
|
asset,
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
cancelDelete,
|
|
1136
|
-
succeededDeleting
|
|
904
|
+
selectAsset,
|
|
905
|
+
selected
|
|
1137
906
|
}) {
|
|
1138
|
-
const
|
|
1139
|
-
useEffect(() => {
|
|
1140
|
-
state !== "checkingReferences" || referencesLoading || setState(references?.length ? "cantDelete" : "confirm");
|
|
1141
|
-
}, [state, references, referencesLoading]);
|
|
1142
|
-
async function confirmDelete() {
|
|
1143
|
-
if (state !== "confirm") return;
|
|
1144
|
-
setState("processing_deletion");
|
|
1145
|
-
const worked = await deleteAsset({ client, asset, deleteOnMux });
|
|
1146
|
-
worked === !0 ? (toast.push({ title: "Successfully deleted video", status: "success" }), succeededDeleting()) : worked === "failed-mux" ? (toast.push({
|
|
1147
|
-
title: "Deleted video in Sanity",
|
|
1148
|
-
description: "But it wasn't deleted in Mux",
|
|
1149
|
-
status: "warning"
|
|
1150
|
-
}), succeededDeleting()) : (toast.push({ title: "Failed deleting video", status: "error" }), setState("error_deleting"));
|
|
1151
|
-
}
|
|
907
|
+
const duration = useFormattedDuration(asset.duration * 1e3);
|
|
1152
908
|
return /* @__PURE__ */ jsx(
|
|
1153
|
-
|
|
909
|
+
Card,
|
|
1154
910
|
{
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
/* @__PURE__ */ jsx(Text, { size: 2, children: "This action is irreversible" }),
|
|
1193
|
-
/* @__PURE__ */ jsxs(Stack, { space: 4, marginY: 4, children: [
|
|
1194
|
-
/* @__PURE__ */ jsxs(Flex, { align: "center", as: "label", children: [
|
|
1195
|
-
/* @__PURE__ */ jsx(
|
|
1196
|
-
Checkbox,
|
|
1197
|
-
{
|
|
1198
|
-
checked: deleteOnMux,
|
|
1199
|
-
onChange: () => setDeleteOnMux((prev) => !prev)
|
|
1200
|
-
}
|
|
1201
|
-
),
|
|
1202
|
-
/* @__PURE__ */ jsx(Text, { style: { margin: "0 10px" }, children: "Delete asset on Mux" })
|
|
1203
|
-
] }),
|
|
1204
|
-
/* @__PURE__ */ jsxs(Flex, { align: "center", as: "label", children: [
|
|
1205
|
-
/* @__PURE__ */ jsx(Checkbox, { disabled: !0, checked: !0 }),
|
|
1206
|
-
/* @__PURE__ */ jsx(Text, { style: { margin: "0 10px" }, children: "Delete video from dataset" })
|
|
1207
|
-
] }),
|
|
1208
|
-
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
|
|
1209
|
-
Button,
|
|
1210
|
-
{
|
|
1211
|
-
icon: TrashIcon,
|
|
1212
|
-
fontSize: 2,
|
|
1213
|
-
padding: 3,
|
|
1214
|
-
text: "Delete video",
|
|
1215
|
-
tone: "critical",
|
|
1216
|
-
onClick: confirmDelete,
|
|
1217
|
-
disabled: ["processing_deletion", "checkingReferences", "cantDelete"].some(
|
|
1218
|
-
(s) => s === state
|
|
1219
|
-
)
|
|
1220
|
-
}
|
|
1221
|
-
) })
|
|
1222
|
-
] })
|
|
1223
|
-
] }),
|
|
1224
|
-
state === "processing_deletion" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1225
|
-
/* @__PURE__ */ jsx(Heading, { size: 2, children: "Deleting video..." }),
|
|
1226
|
-
/* @__PURE__ */ jsx(SpinnerBox, {})
|
|
1227
|
-
] }),
|
|
1228
|
-
state === "error_deleting" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1229
|
-
/* @__PURE__ */ jsx(Heading, { size: 2, children: "Something went wrong!" }),
|
|
1230
|
-
/* @__PURE__ */ jsx(Text, { size: 2, children: "Try deleting the video again by clicking the button below" })
|
|
911
|
+
tone: selected ? "positive" : void 0,
|
|
912
|
+
border: !0,
|
|
913
|
+
paddingX: 2,
|
|
914
|
+
paddingY: 3,
|
|
915
|
+
style: { position: "relative" },
|
|
916
|
+
radius: 1,
|
|
917
|
+
children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
918
|
+
/* @__PURE__ */ jsx(
|
|
919
|
+
MissingAssetCheckbox,
|
|
920
|
+
{
|
|
921
|
+
checked: selected,
|
|
922
|
+
onChange: (e) => {
|
|
923
|
+
selectAsset(e.currentTarget.checked);
|
|
924
|
+
},
|
|
925
|
+
"aria-label": selected ? `Import video ${asset.id}` : `Skip import of video ${asset.id}`
|
|
926
|
+
}
|
|
927
|
+
),
|
|
928
|
+
/* @__PURE__ */ jsx(
|
|
929
|
+
VideoThumbnail,
|
|
930
|
+
{
|
|
931
|
+
asset: {
|
|
932
|
+
assetId: asset.id,
|
|
933
|
+
data: asset,
|
|
934
|
+
filename: asset.id,
|
|
935
|
+
playbackId: asset.playback_ids.find((p) => p.id)?.id
|
|
936
|
+
},
|
|
937
|
+
width: 150
|
|
938
|
+
}
|
|
939
|
+
),
|
|
940
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
941
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 1, children: [
|
|
942
|
+
/* @__PURE__ */ jsx(Code, { size: 2, children: truncateString(asset.id, 15) }),
|
|
943
|
+
" ",
|
|
944
|
+
/* @__PURE__ */ jsxs(Text, { muted: !0, size: 2, children: [
|
|
945
|
+
"(",
|
|
946
|
+
duration.formatted,
|
|
947
|
+
")"
|
|
1231
948
|
] })
|
|
949
|
+
] }),
|
|
950
|
+
/* @__PURE__ */ jsxs(Text, { size: 1, children: [
|
|
951
|
+
"Uploaded at",
|
|
952
|
+
" ",
|
|
953
|
+
new Date(Number(asset.created_at) * 1e3).toLocaleDateString("en", {
|
|
954
|
+
year: "numeric",
|
|
955
|
+
day: "2-digit",
|
|
956
|
+
month: "2-digit"
|
|
957
|
+
})
|
|
1232
958
|
] })
|
|
1233
|
-
}
|
|
1234
|
-
)
|
|
1235
|
-
}
|
|
959
|
+
] })
|
|
960
|
+
] })
|
|
961
|
+
},
|
|
962
|
+
asset.id
|
|
1236
963
|
);
|
|
1237
964
|
}
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
{ id },
|
|
1242
|
-
{
|
|
1243
|
-
apiVersion: SANITY_API_VERSION
|
|
1244
|
-
}
|
|
1245
|
-
));
|
|
1246
|
-
function getVideoMetadata(doc) {
|
|
1247
|
-
const id = doc.assetId || doc._id || "", date = doc.data?.created_at ? new Date(Number(doc.data.created_at) * 1e3) : new Date(doc._createdAt || doc._updatedAt || Date.now());
|
|
1248
|
-
return {
|
|
1249
|
-
title: doc.filename || id.slice(0, 12),
|
|
1250
|
-
id,
|
|
1251
|
-
playbackId: doc.playbackId,
|
|
1252
|
-
createdAt: date,
|
|
1253
|
-
duration: doc.data?.duration ? formatSeconds(doc.data?.duration) : void 0,
|
|
1254
|
-
aspect_ratio: doc.data?.aspect_ratio,
|
|
1255
|
-
max_stored_resolution: doc.data?.max_stored_resolution,
|
|
1256
|
-
max_stored_frame_rate: doc.data?.max_stored_frame_rate
|
|
1257
|
-
};
|
|
1258
|
-
}
|
|
1259
|
-
function useVideoDetails(props) {
|
|
1260
|
-
const documentStore = useDocumentStore(), toast = useToast(), client = useClient(), [references, referencesLoading] = useDocReferences(
|
|
1261
|
-
useMemo(() => ({ documentStore, id: props.asset._id }), [documentStore, props.asset._id])
|
|
1262
|
-
), [originalAsset, setOriginalAsset] = useState(() => props.asset), [filename, setFilename] = useState(props.asset.filename), modified = filename !== originalAsset.filename, displayInfo = getVideoMetadata({ ...props.asset, filename }), [state, setState] = useState("idle");
|
|
1263
|
-
function handleClose() {
|
|
1264
|
-
if (state === "idle") {
|
|
1265
|
-
if (modified) {
|
|
1266
|
-
setState("closing");
|
|
1267
|
-
return;
|
|
1268
|
-
}
|
|
1269
|
-
props.closeDialog();
|
|
1270
|
-
}
|
|
1271
|
-
}
|
|
1272
|
-
function confirmClose(shouldClose) {
|
|
1273
|
-
state === "closing" && (shouldClose && props.closeDialog(), setState("idle"));
|
|
1274
|
-
}
|
|
1275
|
-
async function saveChanges() {
|
|
1276
|
-
if (state === "idle") {
|
|
1277
|
-
setState("saving");
|
|
1278
|
-
try {
|
|
1279
|
-
await client.patch(props.asset._id).set({ filename }).commit(), setOriginalAsset((prev) => ({ ...prev, filename })), toast.push({
|
|
1280
|
-
title: "Video title updated",
|
|
1281
|
-
description: `New title: ${filename}`,
|
|
1282
|
-
status: "success"
|
|
1283
|
-
}), props.closeDialog();
|
|
1284
|
-
} catch (error) {
|
|
1285
|
-
toast.push({
|
|
1286
|
-
title: "Failed updating file name",
|
|
1287
|
-
status: "error",
|
|
1288
|
-
description: typeof error == "string" ? error : "Please try again"
|
|
1289
|
-
}), setFilename(originalAsset.filename);
|
|
1290
|
-
}
|
|
1291
|
-
setState("idle");
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
return {
|
|
1295
|
-
references,
|
|
1296
|
-
referencesLoading,
|
|
1297
|
-
modified,
|
|
1298
|
-
filename,
|
|
1299
|
-
setFilename,
|
|
1300
|
-
displayInfo,
|
|
1301
|
-
state,
|
|
1302
|
-
setState,
|
|
1303
|
-
handleClose,
|
|
1304
|
-
confirmClose,
|
|
1305
|
-
saveChanges
|
|
1306
|
-
};
|
|
1307
|
-
}
|
|
1308
|
-
const AssetInput = (props) => /* @__PURE__ */ jsx(FormField$1, { title: props.label, description: props.description, inputId: props.label, children: /* @__PURE__ */ jsx(
|
|
1309
|
-
TextInput,
|
|
1310
|
-
{
|
|
1311
|
-
id: props.label,
|
|
1312
|
-
value: props.value,
|
|
1313
|
-
placeholder: props.placeholder,
|
|
1314
|
-
onInput: props.onInput,
|
|
1315
|
-
disabled: props.disabled
|
|
1316
|
-
}
|
|
1317
|
-
) }), VideoDetails = (props) => {
|
|
1318
|
-
const [tab, setTab] = useState("details"), {
|
|
1319
|
-
displayInfo,
|
|
1320
|
-
filename,
|
|
1321
|
-
modified,
|
|
1322
|
-
references,
|
|
1323
|
-
referencesLoading,
|
|
1324
|
-
setFilename,
|
|
1325
|
-
state,
|
|
1326
|
-
setState,
|
|
1327
|
-
handleClose,
|
|
1328
|
-
confirmClose,
|
|
1329
|
-
saveChanges
|
|
1330
|
-
} = useVideoDetails(props), isSaving = state === "saving", [containerHeight, setContainerHeight] = useState(null), contentsRef = React.useRef(null);
|
|
1331
|
-
return useEffect(() => {
|
|
1332
|
-
!contentsRef.current || !("getBoundingClientRect" in contentsRef.current) || setContainerHeight(contentsRef.current.getBoundingClientRect().height);
|
|
1333
|
-
}, []), /* @__PURE__ */ jsxs(
|
|
965
|
+
function ImportVideosDialog(props) {
|
|
966
|
+
const { importState } = props, canTriggerImport = (importState === "idle" || importState === "error") && props.selectedAssets.length > 0, isImporting = importState === "importing", noAssetsToImport = props.missingAssets?.length === 0 && !props.muxAssets.loading && !props.assetsInSanityLoading;
|
|
967
|
+
return /* @__PURE__ */ jsx(
|
|
1334
968
|
Dialog,
|
|
1335
969
|
{
|
|
1336
970
|
animate: !0,
|
|
1337
|
-
header:
|
|
971
|
+
header: "Import videos from Mux",
|
|
1338
972
|
zOffset: DIALOGS_Z_INDEX,
|
|
1339
973
|
id: "video-details-dialog",
|
|
1340
|
-
onClose:
|
|
1341
|
-
onClickOutside:
|
|
1342
|
-
width:
|
|
974
|
+
onClose: props.closeDialog,
|
|
975
|
+
onClickOutside: props.closeDialog,
|
|
976
|
+
width: 1,
|
|
1343
977
|
position: "fixed",
|
|
1344
|
-
footer: /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
|
|
978
|
+
footer: importState !== "done" && !noAssetsToImport && /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
|
|
1345
979
|
/* @__PURE__ */ jsx(
|
|
1346
980
|
Button,
|
|
1347
981
|
{
|
|
1348
|
-
icon: TrashIcon,
|
|
1349
982
|
fontSize: 2,
|
|
1350
983
|
padding: 3,
|
|
1351
|
-
mode: "
|
|
1352
|
-
text: "
|
|
984
|
+
mode: "ghost",
|
|
985
|
+
text: "Cancel",
|
|
1353
986
|
tone: "critical",
|
|
1354
|
-
onClick:
|
|
1355
|
-
disabled:
|
|
987
|
+
onClick: props.closeDialog,
|
|
988
|
+
disabled: isImporting
|
|
1356
989
|
}
|
|
1357
990
|
),
|
|
1358
|
-
|
|
991
|
+
props.missingAssets && /* @__PURE__ */ jsx(
|
|
1359
992
|
Button,
|
|
1360
993
|
{
|
|
1361
|
-
icon:
|
|
994
|
+
icon: RetrieveIcon,
|
|
1362
995
|
fontSize: 2,
|
|
1363
996
|
padding: 3,
|
|
1364
997
|
mode: "ghost",
|
|
1365
|
-
text: "
|
|
998
|
+
text: props.selectedAssets?.length > 0 ? `Import ${props.selectedAssets.length} video(s)` : "No video(s) selected",
|
|
1366
999
|
tone: "positive",
|
|
1367
|
-
onClick:
|
|
1368
|
-
iconRight:
|
|
1369
|
-
disabled:
|
|
1000
|
+
onClick: props.importAssets,
|
|
1001
|
+
iconRight: isImporting && Spinner,
|
|
1002
|
+
disabled: !canTriggerImport
|
|
1370
1003
|
}
|
|
1371
1004
|
)
|
|
1372
1005
|
] }) }),
|
|
1373
|
-
children: [
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
{
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1006
|
+
children: /* @__PURE__ */ jsxs(Box, { padding: 3, children: [
|
|
1007
|
+
props.muxAssets.hasSkippedAssetsWithoutPlayback && /* @__PURE__ */ jsx(Card, { tone: "caution", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
1008
|
+
/* @__PURE__ */ jsx(InfoOutlineIcon, { fontSize: 36 }),
|
|
1009
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1010
|
+
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "Some videos were skipped" }),
|
|
1011
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: "Videos without playback IDs cannot be imported and have been excluded from the list." })
|
|
1012
|
+
] })
|
|
1013
|
+
] }) }),
|
|
1014
|
+
(props.muxAssets.loading || props.assetsInSanityLoading) && /* @__PURE__ */ jsx(Card, { tone: "primary", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 4, children: [
|
|
1015
|
+
/* @__PURE__ */ jsx(Spinner, { muted: !0, size: 4 }),
|
|
1016
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1017
|
+
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "Loading assets from Mux" }),
|
|
1018
|
+
/* @__PURE__ */ jsxs(Text, { size: 1, children: [
|
|
1019
|
+
"This may take a while.",
|
|
1020
|
+
props.missingAssets && props.missingAssets.length > 0 && ` There are at least ${props.missingAssets.length} video${props.missingAssets.length > 1 ? "s" : ""} currently not in Sanity...`
|
|
1021
|
+
] })
|
|
1022
|
+
] })
|
|
1023
|
+
] }) }),
|
|
1024
|
+
props.muxAssets.error && /* @__PURE__ */ jsx(Card, { tone: "critical", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
1025
|
+
/* @__PURE__ */ jsx(ErrorOutlineIcon, { fontSize: 36 }),
|
|
1026
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1027
|
+
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "There was an error getting all data from Mux" }),
|
|
1028
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: props.missingAssets ? `But we've found ${props.missingAssets.length} video${props.missingAssets.length > 1 ? "s" : ""} not in Sanity, which you can start importing now.` : "Please try again or contact a developer for help." })
|
|
1029
|
+
] })
|
|
1030
|
+
] }) }),
|
|
1031
|
+
importState === "importing" && /* @__PURE__ */ jsx(Card, { tone: "primary", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 4, children: [
|
|
1032
|
+
/* @__PURE__ */ jsx(Spinner, { muted: !0, size: 4 }),
|
|
1033
|
+
/* @__PURE__ */ jsx(Stack, { space: 2, children: /* @__PURE__ */ jsxs(Text, { size: 2, weight: "semibold", children: [
|
|
1034
|
+
"Importing ",
|
|
1035
|
+
props.selectedAssets.length,
|
|
1036
|
+
" video",
|
|
1037
|
+
props.selectedAssets.length > 1 && "s",
|
|
1038
|
+
" from Mux"
|
|
1039
|
+
] }) })
|
|
1040
|
+
] }) }),
|
|
1041
|
+
importState === "error" && /* @__PURE__ */ jsx(Card, { tone: "critical", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
1042
|
+
/* @__PURE__ */ jsx(ErrorOutlineIcon, { fontSize: 36 }),
|
|
1043
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1044
|
+
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "There was an error importing videos" }),
|
|
1045
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: props.importError ? `Error: ${props.importError}` : "Please try again or contact a developer for help." }),
|
|
1046
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
|
|
1047
|
+
Button,
|
|
1048
|
+
{
|
|
1049
|
+
icon: RetryIcon,
|
|
1050
|
+
text: "Retry",
|
|
1051
|
+
tone: "primary",
|
|
1052
|
+
onClick: props.importAssets
|
|
1053
|
+
}
|
|
1054
|
+
) })
|
|
1055
|
+
] })
|
|
1056
|
+
] }) }),
|
|
1057
|
+
(noAssetsToImport || importState === "done") && /* @__PURE__ */ jsxs(Stack, { paddingY: 5, marginBottom: 4, space: 3, style: { textAlign: "center" }, children: [
|
|
1058
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(CheckmarkCircleIcon, { fontSize: 48 }) }),
|
|
1059
|
+
/* @__PURE__ */ jsx(Heading, { size: 2, children: importState === "done" ? "Videos imported successfully" : "There are no Mux videos to import" }),
|
|
1060
|
+
/* @__PURE__ */ jsx(Text, { size: 2, children: importState === "done" ? "You can now use them in your Sanity content." : "They're all in Sanity and ready to be used in your content." })
|
|
1061
|
+
] }),
|
|
1062
|
+
props.missingAssets && props.missingAssets.length > 0 && (importState === "idle" || importState === "error") && /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
1063
|
+
/* @__PURE__ */ jsxs(Heading, { size: 1, children: [
|
|
1064
|
+
"There are ",
|
|
1065
|
+
props.missingAssets.length,
|
|
1066
|
+
props.muxAssets.loading && "+",
|
|
1067
|
+
" Mux video",
|
|
1068
|
+
props.missingAssets.length > 1 && "s",
|
|
1069
|
+
" ",
|
|
1070
|
+
"not in Sanity"
|
|
1071
|
+
] }),
|
|
1072
|
+
!props.muxAssets.loading && /* @__PURE__ */ jsxs(Flex, { align: "center", paddingX: 2, children: [
|
|
1073
|
+
/* @__PURE__ */ jsx(
|
|
1074
|
+
Checkbox,
|
|
1075
|
+
{
|
|
1076
|
+
id: "import-all",
|
|
1077
|
+
style: { display: "block" },
|
|
1078
|
+
onClick: (e) => {
|
|
1079
|
+
e.currentTarget.checked ? props.missingAssets && props.setSelectedAssets(props.missingAssets) : props.setSelectedAssets([]);
|
|
1080
|
+
},
|
|
1081
|
+
checked: props.selectedAssets.length === props.missingAssets.length
|
|
1082
|
+
}
|
|
1083
|
+
),
|
|
1084
|
+
/* @__PURE__ */ jsx(Box, { flex: 1, paddingLeft: 3, as: "label", htmlFor: "import-all", children: /* @__PURE__ */ jsx(Text, { children: "Import all" }) })
|
|
1085
|
+
] }),
|
|
1086
|
+
props.missingAssets.map((asset) => /* @__PURE__ */ jsx(
|
|
1087
|
+
MissingAsset,
|
|
1088
|
+
{
|
|
1089
|
+
asset,
|
|
1090
|
+
selectAsset: (selected) => {
|
|
1091
|
+
selected ? props.setSelectedAssets([...props.selectedAssets, asset]) : props.setSelectedAssets(props.selectedAssets.filter((a2) => a2.id !== asset.id));
|
|
1092
|
+
},
|
|
1093
|
+
selected: props.selectedAssets.some((a2) => a2.id === asset.id)
|
|
1094
|
+
},
|
|
1095
|
+
asset.id
|
|
1096
|
+
))
|
|
1097
|
+
] })
|
|
1098
|
+
] })
|
|
1099
|
+
}
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
1102
|
+
function ImportVideosFromMux() {
|
|
1103
|
+
const importAssets = useImportMuxAssets();
|
|
1104
|
+
if (importAssets.hasSecrets)
|
|
1105
|
+
return importAssets.dialogOpen ? /* @__PURE__ */ jsx(ImportVideosDialog, { ...importAssets }) : /* @__PURE__ */ jsx(Button, { mode: "bleed", text: "Import from Mux", onClick: importAssets.openDialog });
|
|
1106
|
+
}
|
|
1107
|
+
function useResyncMuxMetadata() {
|
|
1108
|
+
const documentStore = useDocumentStore(), client = useClient$1({
|
|
1109
|
+
apiVersion: SANITY_API_VERSION
|
|
1110
|
+
}), [sanityAssets, sanityAssetsLoading] = useSanityAssets(documentStore), hasSecrets = !!useSecretsDocumentValues().value.secrets?.secretKey, [resyncError, setResyncError] = useState(), [resyncState, setResyncState] = useState("closed"), dialogOpen = resyncState !== "closed", muxAssets = useMuxAssets({
|
|
1111
|
+
client,
|
|
1112
|
+
enabled: hasSecrets && dialogOpen
|
|
1113
|
+
}), matchedAssets = useMemo(() => sanityAssets && muxAssets.data ? sanityAssets.map((sanityDoc) => {
|
|
1114
|
+
const muxAsset = muxAssets.data?.find(
|
|
1115
|
+
(m) => m.id === sanityDoc.assetId || m.id === sanityDoc.data?.id
|
|
1116
|
+
);
|
|
1117
|
+
return {
|
|
1118
|
+
sanityDoc,
|
|
1119
|
+
muxAsset,
|
|
1120
|
+
muxTitle: muxAsset?.meta?.title,
|
|
1121
|
+
currentTitle: sanityDoc.filename
|
|
1122
|
+
};
|
|
1123
|
+
}) : void 0, [sanityAssets, muxAssets.data]), closeDialog = () => {
|
|
1124
|
+
resyncState !== "syncing" && setResyncState("closed");
|
|
1125
|
+
}, openDialog = () => {
|
|
1126
|
+
resyncState === "closed" && setResyncState("idle");
|
|
1127
|
+
};
|
|
1128
|
+
async function syncAllVideos() {
|
|
1129
|
+
if (matchedAssets) {
|
|
1130
|
+
setResyncState("syncing");
|
|
1131
|
+
try {
|
|
1132
|
+
const tx = client.transaction();
|
|
1133
|
+
matchedAssets.forEach((matched) => {
|
|
1134
|
+
const newTitle = matched.muxTitle || "";
|
|
1135
|
+
tx.patch(matched.sanityDoc._id, { set: { filename: newTitle } });
|
|
1136
|
+
}), await tx.commit({ returnDocuments: !1 }), setResyncState("done");
|
|
1137
|
+
} catch (error) {
|
|
1138
|
+
setResyncState("error"), setResyncError(error);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
async function syncOnlyEmpty() {
|
|
1143
|
+
if (matchedAssets) {
|
|
1144
|
+
setResyncState("syncing");
|
|
1145
|
+
try {
|
|
1146
|
+
const tx = client.transaction();
|
|
1147
|
+
matchedAssets.forEach((matched) => {
|
|
1148
|
+
matched.muxAsset && matched.muxTitle && isEmptyOrPlaceholderTitle(matched.currentTitle, matched.muxAsset.id) && tx.patch(matched.sanityDoc._id, { set: { filename: matched.muxTitle } });
|
|
1149
|
+
}), await tx.commit({ returnDocuments: !1 }), setResyncState("done");
|
|
1150
|
+
} catch (error) {
|
|
1151
|
+
setResyncState("error"), setResyncError(error);
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
return {
|
|
1156
|
+
sanityAssetsLoading,
|
|
1157
|
+
closeDialog,
|
|
1158
|
+
dialogOpen,
|
|
1159
|
+
resyncState,
|
|
1160
|
+
resyncError,
|
|
1161
|
+
hasSecrets,
|
|
1162
|
+
syncAllVideos,
|
|
1163
|
+
syncOnlyEmpty,
|
|
1164
|
+
matchedAssets,
|
|
1165
|
+
muxAssets,
|
|
1166
|
+
openDialog
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
const useSanityAssets = createHookFromObservableFactory(
|
|
1170
|
+
(documentStore) => documentStore.listenQuery(
|
|
1171
|
+
/* groq */
|
|
1172
|
+
'*[_type == "mux.videoAsset"]',
|
|
1173
|
+
{},
|
|
1174
|
+
{
|
|
1175
|
+
apiVersion: SANITY_API_VERSION
|
|
1176
|
+
}
|
|
1177
|
+
)
|
|
1178
|
+
);
|
|
1179
|
+
function ResyncMetadataDialog(props) {
|
|
1180
|
+
const { resyncState } = props, canTriggerResync = resyncState === "idle" || resyncState === "error", isResyncing = resyncState === "syncing", isDone = resyncState === "done", videosToUpdate = props.matchedAssets?.filter((m) => m.muxAsset).length || 0, videosWithEmptyOrPlaceholder = props.matchedAssets?.filter(
|
|
1181
|
+
(m) => m.muxAsset && m.muxTitle && isEmptyOrPlaceholderTitle(m.currentTitle, m.muxAsset.id)
|
|
1182
|
+
).length || 0;
|
|
1183
|
+
return /* @__PURE__ */ jsx(
|
|
1184
|
+
Dialog,
|
|
1185
|
+
{
|
|
1186
|
+
animate: !0,
|
|
1187
|
+
header: "Resync Metadata from Mux",
|
|
1188
|
+
zOffset: DIALOGS_Z_INDEX,
|
|
1189
|
+
id: "resync-metadata-dialog",
|
|
1190
|
+
onClose: props.closeDialog,
|
|
1191
|
+
onClickOutside: props.closeDialog,
|
|
1192
|
+
width: 1,
|
|
1193
|
+
position: "fixed",
|
|
1194
|
+
footer: !isDone && /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
|
|
1428
1195
|
/* @__PURE__ */ jsx(
|
|
1429
|
-
|
|
1196
|
+
Button,
|
|
1430
1197
|
{
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1198
|
+
fontSize: 2,
|
|
1199
|
+
padding: 3,
|
|
1200
|
+
mode: "ghost",
|
|
1201
|
+
text: "Cancel",
|
|
1202
|
+
tone: "critical",
|
|
1203
|
+
onClick: props.closeDialog,
|
|
1204
|
+
disabled: isResyncing
|
|
1205
|
+
}
|
|
1206
|
+
),
|
|
1207
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
|
1208
|
+
videosWithEmptyOrPlaceholder > 0 && /* @__PURE__ */ jsx(
|
|
1209
|
+
Button,
|
|
1210
|
+
{
|
|
1211
|
+
fontSize: 2,
|
|
1212
|
+
padding: 3,
|
|
1213
|
+
mode: "ghost",
|
|
1214
|
+
text: `Update empty (${videosWithEmptyOrPlaceholder})`,
|
|
1215
|
+
tone: "caution",
|
|
1216
|
+
onClick: props.syncOnlyEmpty,
|
|
1217
|
+
disabled: isResyncing || !canTriggerResync
|
|
1218
|
+
}
|
|
1219
|
+
),
|
|
1220
|
+
/* @__PURE__ */ jsx(
|
|
1221
|
+
Button,
|
|
1222
|
+
{
|
|
1223
|
+
icon: SyncIcon,
|
|
1224
|
+
fontSize: 2,
|
|
1225
|
+
padding: 3,
|
|
1226
|
+
mode: "ghost",
|
|
1227
|
+
text: `Update all (${videosToUpdate})`,
|
|
1228
|
+
tone: "positive",
|
|
1229
|
+
onClick: props.syncAllVideos,
|
|
1230
|
+
iconRight: isResyncing && Spinner,
|
|
1231
|
+
disabled: !canTriggerResync
|
|
1232
|
+
}
|
|
1233
|
+
)
|
|
1234
|
+
] })
|
|
1235
|
+
] }) }),
|
|
1236
|
+
children: /* @__PURE__ */ jsxs(Box, { padding: 4, children: [
|
|
1237
|
+
(props.muxAssets.loading || props.sanityAssetsLoading) && /* @__PURE__ */ jsx(Card, { tone: "primary", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 4, children: [
|
|
1238
|
+
/* @__PURE__ */ jsx(Spinner, { muted: !0, size: 4 }),
|
|
1239
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1240
|
+
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "Loading assets from Mux" }),
|
|
1241
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: "This may take a while." })
|
|
1242
|
+
] })
|
|
1243
|
+
] }) }),
|
|
1244
|
+
props.muxAssets.error && /* @__PURE__ */ jsx(Card, { tone: "critical", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
1245
|
+
/* @__PURE__ */ jsx(ErrorOutlineIcon, { fontSize: 36 }),
|
|
1246
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1247
|
+
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "There was an error getting data from Mux" }),
|
|
1248
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: "Please try again or contact a developer for help." })
|
|
1249
|
+
] })
|
|
1250
|
+
] }) }),
|
|
1251
|
+
resyncState === "syncing" && /* @__PURE__ */ jsx(Card, { tone: "primary", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 4, children: [
|
|
1252
|
+
/* @__PURE__ */ jsx(Spinner, { muted: !0, size: 4 }),
|
|
1253
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1254
|
+
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "Updating video metadata" }),
|
|
1255
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: "Syncing titles from Mux..." })
|
|
1256
|
+
] })
|
|
1257
|
+
] }) }),
|
|
1258
|
+
resyncState === "error" && /* @__PURE__ */ jsx(Card, { tone: "critical", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
1259
|
+
/* @__PURE__ */ jsx(ErrorOutlineIcon, { fontSize: 36 }),
|
|
1260
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1261
|
+
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "There was an error syncing metadata" }),
|
|
1262
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: props.resyncError ? `Error: ${props.resyncError}` : "Please try again or contact a developer for help." })
|
|
1263
|
+
] })
|
|
1264
|
+
] }) }),
|
|
1265
|
+
resyncState === "done" && /* @__PURE__ */ jsxs(Stack, { paddingY: 5, marginBottom: 4, space: 3, style: { textAlign: "center" }, children: [
|
|
1266
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(CheckmarkCircleIcon, { fontSize: 48 }) }),
|
|
1267
|
+
/* @__PURE__ */ jsx(Heading, { size: 2, children: "Metadata synced successfully" }),
|
|
1268
|
+
/* @__PURE__ */ jsx(Text, { size: 2, children: "All video titles have been updated from Mux." })
|
|
1269
|
+
] }),
|
|
1270
|
+
resyncState === "idle" && !props.muxAssets.loading && !props.sanityAssetsLoading && /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
1271
|
+
/* @__PURE__ */ jsxs(Heading, { size: 1, children: [
|
|
1272
|
+
"There ",
|
|
1273
|
+
videosToUpdate === 1 ? "is" : "are",
|
|
1274
|
+
" ",
|
|
1275
|
+
videosToUpdate,
|
|
1276
|
+
" video",
|
|
1277
|
+
videosToUpdate === 1 ? "" : "s",
|
|
1278
|
+
" with Mux metadata"
|
|
1279
|
+
] }),
|
|
1280
|
+
/* @__PURE__ */ jsx(Text, { size: 2, children: "This will update video titles in Sanity to match those in Mux. No new videos will be created." }),
|
|
1281
|
+
videosWithEmptyOrPlaceholder > 0 && /* @__PURE__ */ jsx(Card, { padding: 3, tone: "caution", border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "flex-start", gap: 2, children: [
|
|
1282
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(ErrorOutlineIcon, {}) }),
|
|
1283
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1284
|
+
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "Videos with empty or placeholder titles" }),
|
|
1285
|
+
/* @__PURE__ */ jsxs(Text, { size: 1, muted: !0, children: [
|
|
1286
|
+
videosWithEmptyOrPlaceholder,
|
|
1287
|
+
" video",
|
|
1288
|
+
videosWithEmptyOrPlaceholder === 1 ? "" : "s",
|
|
1289
|
+
' without titles or with placeholder titles (e.g., "Asset #123") can be updated selectively.'
|
|
1290
|
+
] })
|
|
1291
|
+
] })
|
|
1292
|
+
] }) })
|
|
1293
|
+
] })
|
|
1294
|
+
] })
|
|
1295
|
+
}
|
|
1296
|
+
);
|
|
1297
|
+
}
|
|
1298
|
+
function ResyncMetadata() {
|
|
1299
|
+
const resyncMetadata = useResyncMuxMetadata();
|
|
1300
|
+
if (resyncMetadata.hasSecrets)
|
|
1301
|
+
return resyncMetadata.dialogOpen ? /* @__PURE__ */ jsx(ResyncMetadataDialog, { ...resyncMetadata }) : /* @__PURE__ */ jsx(Button, { mode: "bleed", text: "Resync Metadata", onClick: resyncMetadata.openDialog });
|
|
1302
|
+
}
|
|
1303
|
+
const CONTEXT_MENU_POPOVER_PROPS = {
|
|
1304
|
+
constrainSize: !0,
|
|
1305
|
+
placement: "bottom",
|
|
1306
|
+
portal: !0,
|
|
1307
|
+
width: 0
|
|
1308
|
+
};
|
|
1309
|
+
function SelectSortOptions(props) {
|
|
1310
|
+
const id = useId();
|
|
1311
|
+
return /* @__PURE__ */ jsx(
|
|
1312
|
+
MenuButton,
|
|
1313
|
+
{
|
|
1314
|
+
button: /* @__PURE__ */ jsx(Button, { text: "Sort", icon: SortIcon, mode: "bleed", padding: 3, style: { cursor: "pointer" } }),
|
|
1315
|
+
id,
|
|
1316
|
+
menu: /* @__PURE__ */ jsx(Menu, { children: Object.entries(ASSET_SORT_OPTIONS).map(([type, { label }]) => /* @__PURE__ */ jsx(
|
|
1317
|
+
MenuItem,
|
|
1318
|
+
{
|
|
1319
|
+
"data-as": "button",
|
|
1320
|
+
onClick: () => props.setSort(type),
|
|
1321
|
+
padding: 3,
|
|
1322
|
+
tone: "default",
|
|
1323
|
+
text: label,
|
|
1324
|
+
pressed: type === props.sort
|
|
1325
|
+
},
|
|
1326
|
+
type
|
|
1327
|
+
)) }),
|
|
1328
|
+
popover: CONTEXT_MENU_POPOVER_PROPS
|
|
1329
|
+
}
|
|
1330
|
+
);
|
|
1331
|
+
}
|
|
1332
|
+
const SpinnerBox = () => /* @__PURE__ */ jsx(
|
|
1333
|
+
Box,
|
|
1334
|
+
{
|
|
1335
|
+
style: {
|
|
1336
|
+
display: "flex",
|
|
1337
|
+
alignItems: "center",
|
|
1338
|
+
justifyContent: "center",
|
|
1339
|
+
minHeight: "150px"
|
|
1340
|
+
},
|
|
1341
|
+
children: /* @__PURE__ */ jsx(Spinner, {})
|
|
1342
|
+
}
|
|
1343
|
+
), IconInfo = (props) => {
|
|
1344
|
+
const Icon = props.icon;
|
|
1345
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, align: "center", padding: 1, children: [
|
|
1346
|
+
/* @__PURE__ */ jsx(Text, { size: (props.size || 1) + 1, muted: !0, children: /* @__PURE__ */ jsx(Icon, {}) }),
|
|
1347
|
+
/* @__PURE__ */ jsx(Text, { size: props.size || 1, muted: props.muted, children: props.text })
|
|
1348
|
+
] });
|
|
1349
|
+
};
|
|
1350
|
+
function ResolutionIcon(props) {
|
|
1351
|
+
return /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 24 24", ...props, children: /* @__PURE__ */ jsx(
|
|
1352
|
+
"path",
|
|
1353
|
+
{
|
|
1354
|
+
fill: "currentColor",
|
|
1355
|
+
d: "M20 9V6h-3V4h5v5h-2ZM2 9V4h5v2H4v3H2Zm15 11v-2h3v-3h2v5h-5ZM2 20v-5h2v3h3v2H2Zm4-4V8h12v8H6Zm2-2h8v-4H8v4Zm0 0v-4v4Z"
|
|
1356
|
+
}
|
|
1357
|
+
) });
|
|
1358
|
+
}
|
|
1359
|
+
function StopWatchIcon(props) {
|
|
1360
|
+
return /* @__PURE__ */ jsxs(
|
|
1361
|
+
"svg",
|
|
1362
|
+
{
|
|
1363
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1364
|
+
width: "1em",
|
|
1365
|
+
height: "1em",
|
|
1366
|
+
viewBox: "0 0 512 512",
|
|
1367
|
+
...props,
|
|
1368
|
+
children: [
|
|
1369
|
+
/* @__PURE__ */ jsx("path", { d: "M232 306.667h48V176h-48v130.667z", fill: "currentColor" }),
|
|
1370
|
+
/* @__PURE__ */ jsx(
|
|
1371
|
+
"path",
|
|
1372
|
+
{
|
|
1373
|
+
d: "M407.67 170.271l30.786-30.786-33.942-33.941-30.785 30.786C341.217 111.057 300.369 96 256 96 149.961 96 64 181.961 64 288s85.961 192 192 192 192-85.961 192-192c0-44.369-15.057-85.217-40.33-117.729zm-45.604 223.795C333.734 422.398 296.066 438 256 438s-77.735-15.602-106.066-43.934C121.602 365.735 106 328.066 106 288s15.602-77.735 43.934-106.066C178.265 153.602 215.934 138 256 138s77.734 15.602 106.066 43.934C390.398 210.265 406 247.934 406 288s-15.602 77.735-43.934 106.066z",
|
|
1374
|
+
fill: "currentColor"
|
|
1375
|
+
}
|
|
1376
|
+
),
|
|
1377
|
+
/* @__PURE__ */ jsx("path", { d: "M192 32h128v48H192z", fill: "currentColor" })
|
|
1378
|
+
]
|
|
1379
|
+
}
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
const DialogStateContext = createContext({
|
|
1383
|
+
dialogState: !1,
|
|
1384
|
+
setDialogState: () => null
|
|
1385
|
+
}), DialogStateProvider = ({
|
|
1386
|
+
dialogState,
|
|
1387
|
+
setDialogState,
|
|
1388
|
+
children
|
|
1389
|
+
}) => /* @__PURE__ */ jsx(DialogStateContext.Provider, { value: { dialogState, setDialogState }, children }), useDialogStateContext = () => useContext(DialogStateContext);
|
|
1390
|
+
function getVideoSrc({ asset, client }) {
|
|
1391
|
+
const playbackId = getPlaybackId(asset), searchParams = new URLSearchParams();
|
|
1392
|
+
if (getPlaybackPolicy(asset) === "signed") {
|
|
1393
|
+
const token = generateJwt(client, playbackId, "v");
|
|
1394
|
+
searchParams.set("token", token);
|
|
1395
|
+
}
|
|
1396
|
+
return `https://stream.mux.com/${playbackId}.m3u8?${searchParams}`;
|
|
1397
|
+
}
|
|
1398
|
+
function getDevicePixelRatio(options) {
|
|
1399
|
+
const {
|
|
1400
|
+
defaultDpr = 1,
|
|
1401
|
+
maxDpr = 3,
|
|
1402
|
+
round = !0
|
|
1403
|
+
} = options || {}, dpr = typeof window < "u" && typeof window.devicePixelRatio == "number" ? window.devicePixelRatio : defaultDpr;
|
|
1404
|
+
return Math.min(Math.max(1, round ? Math.floor(dpr) : dpr), maxDpr);
|
|
1405
|
+
}
|
|
1406
|
+
function formatSeconds(seconds) {
|
|
1407
|
+
if (typeof seconds != "number" || Number.isNaN(seconds))
|
|
1408
|
+
return "";
|
|
1409
|
+
const hrs = ~~(seconds / 3600), mins = ~~(seconds % 3600 / 60), secs = ~~seconds % 60;
|
|
1410
|
+
let ret = "";
|
|
1411
|
+
return hrs > 0 && (ret += "" + hrs + ":" + (mins < 10 ? "0" : "")), ret += "" + mins + ":" + (secs < 10 ? "0" : ""), ret += "" + secs, ret;
|
|
1412
|
+
}
|
|
1413
|
+
function formatSecondsToHHMMSS(seconds) {
|
|
1414
|
+
const hrs = Math.floor(seconds / 3600).toString().padStart(2, "0"), mins = Math.floor(seconds % 3600 / 60).toString().padStart(2, "0"), secs = Math.floor(seconds % 60).toString().padStart(2, "0");
|
|
1415
|
+
return `${hrs}:${mins}:${secs}`;
|
|
1416
|
+
}
|
|
1417
|
+
function isValidTimeFormat(time) {
|
|
1418
|
+
return /^([0-1]?[0-9]|2[0-3]):([0-5]?[0-9]):([0-5]?[0-9])$/.test(time) || time === "";
|
|
1419
|
+
}
|
|
1420
|
+
function getSecondsFromTimeFormat(time) {
|
|
1421
|
+
const [hh = 0, mm = 0, ss = 0] = time.split(":").map(Number);
|
|
1422
|
+
return hh * 3600 + mm * 60 + ss;
|
|
1423
|
+
}
|
|
1424
|
+
function EditThumbnailDialog({ asset, currentTime = 0 }) {
|
|
1425
|
+
const client = useClient(), { setDialogState } = useDialogStateContext(), dialogId = `EditThumbnailDialog${useId()}`, [timeFormatted, setTimeFormatted] = useState(
|
|
1426
|
+
() => formatSecondsToHHMMSS(currentTime)
|
|
1427
|
+
), [nextTime, setNextTime] = useState(currentTime), [inputError, setInputError] = useState(""), assetWithNewThumbnail = useMemo(() => ({ ...asset, thumbTime: nextTime }), [asset, nextTime]), [saving, setSaving] = useState(!1), [saveThumbnailError, setSaveThumbnailError] = useState(null), handleSave = () => {
|
|
1428
|
+
setSaving(!0), client.patch(asset._id).set({ thumbTime: nextTime }).commit({ returnDocuments: !1 }).then(() => void setDialogState(!1)).catch(setSaveThumbnailError).finally(() => void setSaving(!1));
|
|
1429
|
+
}, width = 300 * getDevicePixelRatio({ maxDpr: 2 });
|
|
1430
|
+
if (saveThumbnailError)
|
|
1431
|
+
throw saveThumbnailError;
|
|
1432
|
+
return /* @__PURE__ */ jsx(
|
|
1433
|
+
Dialog,
|
|
1434
|
+
{
|
|
1435
|
+
id: dialogId,
|
|
1436
|
+
header: "Edit thumbnail",
|
|
1437
|
+
onClose: () => setDialogState(!1),
|
|
1438
|
+
footer: /* @__PURE__ */ jsx(Stack, { padding: 3, children: /* @__PURE__ */ jsx(
|
|
1439
|
+
Button,
|
|
1440
|
+
{
|
|
1441
|
+
disabled: inputError !== "",
|
|
1442
|
+
mode: "ghost",
|
|
1443
|
+
tone: "primary",
|
|
1444
|
+
loading: saving,
|
|
1445
|
+
onClick: handleSave,
|
|
1446
|
+
text: "Set new thumbnail"
|
|
1447
|
+
},
|
|
1448
|
+
"thumbnail"
|
|
1449
|
+
) }),
|
|
1450
|
+
children: /* @__PURE__ */ jsxs(Stack, { space: 3, padding: 3, children: [
|
|
1451
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1452
|
+
/* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "Current:" }),
|
|
1453
|
+
/* @__PURE__ */ jsx(VideoThumbnail, { asset, width, staticImage: !0 })
|
|
1454
|
+
] }),
|
|
1455
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1456
|
+
/* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "New:" }),
|
|
1457
|
+
/* @__PURE__ */ jsx(VideoThumbnail, { asset: assetWithNewThumbnail, width, staticImage: !0 })
|
|
1458
|
+
] }),
|
|
1459
|
+
/* @__PURE__ */ jsx(Stack, { space: 2, children: /* @__PURE__ */ jsx(Flex, { align: "center", justify: "center", children: /* @__PURE__ */ jsx(Text, { size: 5, weight: "semibold", children: "Or" }) }) }),
|
|
1460
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1461
|
+
/* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "Selected time for thumbnail (hh:mm:ss):" }),
|
|
1462
|
+
/* @__PURE__ */ jsx(
|
|
1463
|
+
TextInput,
|
|
1464
|
+
{
|
|
1465
|
+
size: 1,
|
|
1466
|
+
value: timeFormatted,
|
|
1467
|
+
placeholder: "hh:mm:ss",
|
|
1468
|
+
onChange: (event) => {
|
|
1469
|
+
const value = event.currentTarget.value;
|
|
1470
|
+
if (setTimeFormatted(value), isValidTimeFormat(value)) {
|
|
1471
|
+
setInputError("");
|
|
1472
|
+
const totalSeconds = getSecondsFromTimeFormat(value);
|
|
1473
|
+
setNextTime(totalSeconds);
|
|
1474
|
+
} else
|
|
1475
|
+
setInputError("Invalid time format");
|
|
1476
|
+
},
|
|
1477
|
+
customValidity: inputError
|
|
1478
|
+
}
|
|
1479
|
+
)
|
|
1480
|
+
] })
|
|
1481
|
+
] })
|
|
1482
|
+
}
|
|
1483
|
+
);
|
|
1484
|
+
}
|
|
1485
|
+
function VideoPlayer({
|
|
1486
|
+
asset,
|
|
1487
|
+
thumbnailWidth = 250,
|
|
1488
|
+
children,
|
|
1489
|
+
...props
|
|
1490
|
+
}) {
|
|
1491
|
+
const client = useClient(), { dialogState } = useDialogStateContext(), isAudio = assetIsAudio(asset), muxPlayer = useRef(null), thumbnail = getPosterSrc({ asset, client, width: thumbnailWidth }), { src: videoSrc, error } = useMemo(() => {
|
|
1492
|
+
try {
|
|
1493
|
+
const src = asset?.playbackId && getVideoSrc({ client, asset });
|
|
1494
|
+
return src ? { src } : { error: new TypeError("Asset has no playback ID") };
|
|
1495
|
+
} catch (error2) {
|
|
1496
|
+
return { error: error2 };
|
|
1497
|
+
}
|
|
1498
|
+
}, [asset, client]), signedToken = useMemo(() => {
|
|
1499
|
+
try {
|
|
1500
|
+
return new URL(videoSrc).searchParams.get("token");
|
|
1501
|
+
} catch {
|
|
1502
|
+
return !1;
|
|
1503
|
+
}
|
|
1504
|
+
}, [videoSrc]), [width, height] = (asset?.data?.aspect_ratio ?? "16:9").split(":").map(Number), targetAspectRatio = props.forceAspectRatio || (Number.isNaN(width) ? 16 / 9 : width / height);
|
|
1505
|
+
let aspectRatio = Math.max(MIN_ASPECT_RATIO, targetAspectRatio);
|
|
1506
|
+
return isAudio && (aspectRatio = props.forceAspectRatio ? (
|
|
1507
|
+
// Make it wider when forcing aspect ratio to balance with videos' rendering height (audio players overflow a bit)
|
|
1508
|
+
props.forceAspectRatio * 1.2
|
|
1509
|
+
) : AUDIO_ASPECT_RATIO), /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1510
|
+
/* @__PURE__ */ jsxs(Card, { tone: "transparent", style: { aspectRatio, position: "relative" }, children: [
|
|
1511
|
+
videoSrc && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1512
|
+
/* @__PURE__ */ jsx(
|
|
1513
|
+
MuxPlayer,
|
|
1514
|
+
{
|
|
1515
|
+
poster: thumbnail,
|
|
1516
|
+
ref: muxPlayer,
|
|
1517
|
+
...props,
|
|
1518
|
+
playsInline: !0,
|
|
1519
|
+
playbackId: asset.playbackId,
|
|
1520
|
+
tokens: signedToken ? { playback: signedToken, thumbnail: signedToken, storyboard: signedToken } : void 0,
|
|
1521
|
+
preload: "metadata",
|
|
1522
|
+
crossOrigin: "anonymous",
|
|
1523
|
+
metadata: {
|
|
1524
|
+
player_name: "Sanity Admin Dashboard",
|
|
1525
|
+
player_version: "2.10.1",
|
|
1526
|
+
page_type: "Preview Player"
|
|
1527
|
+
},
|
|
1528
|
+
audio: isAudio,
|
|
1529
|
+
style: {
|
|
1530
|
+
height: "100%",
|
|
1531
|
+
width: "100%",
|
|
1532
|
+
display: "block",
|
|
1533
|
+
objectFit: "contain"
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
),
|
|
1537
|
+
children
|
|
1538
|
+
] }),
|
|
1539
|
+
error ? /* @__PURE__ */ jsx(
|
|
1540
|
+
"div",
|
|
1541
|
+
{
|
|
1542
|
+
style: {
|
|
1543
|
+
position: "absolute",
|
|
1544
|
+
top: "50%",
|
|
1545
|
+
left: "50%",
|
|
1546
|
+
transform: "translate(-50%, -50%)"
|
|
1547
|
+
},
|
|
1548
|
+
children: /* @__PURE__ */ jsxs(Text, { muted: !0, children: [
|
|
1549
|
+
/* @__PURE__ */ jsx(ErrorOutlineIcon, { style: { marginRight: "0.15em" } }),
|
|
1550
|
+
typeof error == "object" && "message" in error && typeof error.message == "string" ? error.message : "Error loading video"
|
|
1551
|
+
] })
|
|
1552
|
+
}
|
|
1553
|
+
) : null,
|
|
1554
|
+
children
|
|
1555
|
+
] }),
|
|
1556
|
+
dialogState === "edit-thumbnail" && /* @__PURE__ */ jsx(EditThumbnailDialog, { asset, currentTime: muxPlayer?.current?.currentTime })
|
|
1557
|
+
] });
|
|
1558
|
+
}
|
|
1559
|
+
function assetIsAudio(asset) {
|
|
1560
|
+
return asset.data?.max_stored_resolution === "Audio only";
|
|
1561
|
+
}
|
|
1562
|
+
const getUnknownTypeFallback = (id, typeName) => ({
|
|
1563
|
+
title: /* @__PURE__ */ jsxs("em", { children: [
|
|
1564
|
+
"No schema found for type ",
|
|
1565
|
+
/* @__PURE__ */ jsx("code", { children: typeName })
|
|
1566
|
+
] }),
|
|
1567
|
+
subtitle: /* @__PURE__ */ jsxs("em", { children: [
|
|
1568
|
+
"Document: ",
|
|
1569
|
+
/* @__PURE__ */ jsx("code", { children: id })
|
|
1570
|
+
] }),
|
|
1571
|
+
media: () => /* @__PURE__ */ jsx(WarningOutlineIcon, {})
|
|
1572
|
+
});
|
|
1573
|
+
function MissingSchemaType(props) {
|
|
1574
|
+
const { layout, value } = props;
|
|
1575
|
+
return /* @__PURE__ */ jsx(SanityDefaultPreview, { ...getUnknownTypeFallback(value._id, value._type), layout });
|
|
1576
|
+
}
|
|
1577
|
+
function TimeAgo({ time }) {
|
|
1578
|
+
const timeAgo = useTimeAgo(time);
|
|
1579
|
+
return /* @__PURE__ */ jsxs("span", { title: timeAgo, children: [
|
|
1580
|
+
timeAgo,
|
|
1581
|
+
" ago"
|
|
1582
|
+
] });
|
|
1583
|
+
}
|
|
1584
|
+
function DraftStatus(props) {
|
|
1585
|
+
const { document: document2 } = props, updatedAt = document2 && "_updatedAt" in document2 && document2._updatedAt;
|
|
1586
|
+
return /* @__PURE__ */ jsx(
|
|
1587
|
+
Tooltip,
|
|
1588
|
+
{
|
|
1589
|
+
animate: !0,
|
|
1590
|
+
portal: !0,
|
|
1591
|
+
content: /* @__PURE__ */ jsx(Box, { padding: 2, children: /* @__PURE__ */ jsx(Text, { size: 1, children: document2 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1592
|
+
"Edited ",
|
|
1593
|
+
updatedAt && /* @__PURE__ */ jsx(TimeAgo, { time: updatedAt })
|
|
1594
|
+
] }) : /* @__PURE__ */ jsx(Fragment, { children: "No unpublished edits" }) }) }),
|
|
1595
|
+
children: /* @__PURE__ */ jsx(TextWithTone, { tone: "caution", dimmed: !document2, muted: !document2, size: 1, children: /* @__PURE__ */ jsx(EditIcon, {}) })
|
|
1596
|
+
}
|
|
1597
|
+
);
|
|
1598
|
+
}
|
|
1599
|
+
function PublishedStatus(props) {
|
|
1600
|
+
const { document: document2 } = props, updatedAt = document2 && "_updatedAt" in document2 && document2._updatedAt;
|
|
1601
|
+
return /* @__PURE__ */ jsx(
|
|
1602
|
+
Tooltip,
|
|
1603
|
+
{
|
|
1604
|
+
animate: !0,
|
|
1605
|
+
portal: !0,
|
|
1606
|
+
content: /* @__PURE__ */ jsx(Box, { padding: 2, children: /* @__PURE__ */ jsx(Text, { size: 1, children: document2 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1607
|
+
"Published ",
|
|
1608
|
+
updatedAt && /* @__PURE__ */ jsx(TimeAgo, { time: updatedAt })
|
|
1609
|
+
] }) : /* @__PURE__ */ jsx(Fragment, { children: "Not published" }) }) }),
|
|
1610
|
+
children: /* @__PURE__ */ jsx(TextWithTone, { tone: "positive", dimmed: !document2, muted: !document2, size: 1, children: /* @__PURE__ */ jsx(PublishIcon, {}) })
|
|
1611
|
+
}
|
|
1612
|
+
);
|
|
1613
|
+
}
|
|
1614
|
+
function PaneItemPreview(props) {
|
|
1615
|
+
const { icon, layout, presence, schemaType, value } = props, title = isRecord(value.title) && isValidElement(value.title) || isString(value.title) || isNumber(value.title) ? value.title : null, observable = useMemo(
|
|
1616
|
+
() => getPreviewStateObservable(props.documentPreviewStore, schemaType, value._id, title),
|
|
1617
|
+
[props.documentPreviewStore, schemaType, title, value._id]
|
|
1618
|
+
), { draft, published, isLoading } = useObservable(observable, {
|
|
1619
|
+
draft: null,
|
|
1620
|
+
published: null,
|
|
1621
|
+
isLoading: !0
|
|
1622
|
+
}), status = isLoading ? null : /* @__PURE__ */ jsxs(Inline, { space: 4, children: [
|
|
1623
|
+
presence && presence.length > 0 && /* @__PURE__ */ jsx(DocumentPreviewPresence, { presence }),
|
|
1624
|
+
/* @__PURE__ */ jsx(PublishedStatus, { document: published }),
|
|
1625
|
+
/* @__PURE__ */ jsx(DraftStatus, { document: draft })
|
|
1626
|
+
] });
|
|
1627
|
+
return /* @__PURE__ */ jsx(
|
|
1628
|
+
SanityDefaultPreview,
|
|
1629
|
+
{
|
|
1630
|
+
...getPreviewValueWithFallback({ value, draft, published }),
|
|
1631
|
+
isPlaceholder: isLoading,
|
|
1632
|
+
icon,
|
|
1633
|
+
layout,
|
|
1634
|
+
status
|
|
1635
|
+
}
|
|
1636
|
+
);
|
|
1637
|
+
}
|
|
1638
|
+
function getIconWithFallback(icon, schemaType, defaultIcon) {
|
|
1639
|
+
return icon === !1 ? !1 : icon || schemaType && schemaType.icon || defaultIcon || !1;
|
|
1640
|
+
}
|
|
1641
|
+
function DocumentPreviewLink(props) {
|
|
1642
|
+
return (linkProps) => /* @__PURE__ */ jsx(IntentLink, { intent: "edit", params: { id: props.documentPair.id }, children: linkProps.children });
|
|
1643
|
+
}
|
|
1644
|
+
function DocumentPreview(props) {
|
|
1645
|
+
const { schemaType, documentPair } = props, doc = documentPair?.draft || documentPair?.published, id = documentPair.id || "", documentPreviewStore = useDocumentPreviewStore(), schema = useSchema(), documentPresence = useDocumentPresence(id), hasSchemaType = !!(schemaType && schemaType.name && schema.get(schemaType.name)), PreviewComponent = useMemo(() => doc ? !schemaType || !hasSchemaType ? /* @__PURE__ */ jsx(MissingSchemaType, { value: doc }) : /* @__PURE__ */ jsx(
|
|
1646
|
+
PaneItemPreview,
|
|
1647
|
+
{
|
|
1648
|
+
documentPreviewStore,
|
|
1649
|
+
icon: getIconWithFallback(void 0, schemaType, DocumentIcon),
|
|
1650
|
+
schemaType,
|
|
1651
|
+
layout: "default",
|
|
1652
|
+
value: doc,
|
|
1653
|
+
presence: documentPresence
|
|
1654
|
+
}
|
|
1655
|
+
) : null, [hasSchemaType, schemaType, documentPresence, doc, documentPreviewStore]);
|
|
1656
|
+
return /* @__PURE__ */ jsx(
|
|
1657
|
+
PreviewCard,
|
|
1658
|
+
{
|
|
1659
|
+
__unstable_focusRing: !0,
|
|
1660
|
+
as: DocumentPreviewLink(props),
|
|
1661
|
+
"data-as": "a",
|
|
1662
|
+
"data-ui": "PaneItem",
|
|
1663
|
+
padding: 2,
|
|
1664
|
+
radius: 2,
|
|
1665
|
+
tone: "inherit",
|
|
1666
|
+
children: PreviewComponent
|
|
1667
|
+
}
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1670
|
+
const Container = styled(Box)`
|
|
1671
|
+
* {
|
|
1672
|
+
color: ${(props) => props.theme.sanity.color.base.fg};
|
|
1673
|
+
}
|
|
1674
|
+
a {
|
|
1675
|
+
text-decoration: none;
|
|
1676
|
+
}
|
|
1677
|
+
h2 {
|
|
1678
|
+
font-size: ${(props) => props.theme.sanity.fonts.text.sizes[1]};
|
|
1679
|
+
}
|
|
1680
|
+
`, VideoReferences = (props) => {
|
|
1681
|
+
const schema = useSchema();
|
|
1682
|
+
if (!props.isLoaded)
|
|
1683
|
+
return /* @__PURE__ */ jsx(SpinnerBox, {});
|
|
1684
|
+
if (!props.references?.length)
|
|
1685
|
+
return /* @__PURE__ */ jsx(Card, { border: !0, radius: 3, padding: 3, children: /* @__PURE__ */ jsx(Text, { size: 2, children: "No documents are using this video" }) });
|
|
1686
|
+
const documentPairs = collate(props.references || []);
|
|
1687
|
+
return /* @__PURE__ */ jsx(Container, { children: documentPairs?.map((documentPair) => {
|
|
1688
|
+
const schemaType = schema.get(documentPair.type);
|
|
1689
|
+
return /* @__PURE__ */ jsx(
|
|
1690
|
+
Card,
|
|
1691
|
+
{
|
|
1692
|
+
marginBottom: 2,
|
|
1693
|
+
padding: 2,
|
|
1694
|
+
radius: 2,
|
|
1695
|
+
shadow: 1,
|
|
1696
|
+
style: { overflow: "hidden" },
|
|
1697
|
+
children: /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(DocumentPreview, { documentPair, schemaType }) })
|
|
1698
|
+
},
|
|
1699
|
+
documentPair.id
|
|
1700
|
+
);
|
|
1701
|
+
}) });
|
|
1702
|
+
};
|
|
1703
|
+
function DeleteDialog({
|
|
1704
|
+
asset,
|
|
1705
|
+
references,
|
|
1706
|
+
referencesLoading,
|
|
1707
|
+
cancelDelete,
|
|
1708
|
+
succeededDeleting
|
|
1709
|
+
}) {
|
|
1710
|
+
const client = useClient(), [state, setState] = useState("checkingReferences"), [deleteOnMux, setDeleteOnMux] = useState(!0), toast = useToast();
|
|
1711
|
+
useEffect(() => {
|
|
1712
|
+
state !== "checkingReferences" || referencesLoading || setState(references?.length ? "cantDelete" : "confirm");
|
|
1713
|
+
}, [state, references, referencesLoading]);
|
|
1714
|
+
async function confirmDelete() {
|
|
1715
|
+
if (state !== "confirm") return;
|
|
1716
|
+
setState("processing_deletion");
|
|
1717
|
+
const worked = await deleteAsset({ client, asset, deleteOnMux });
|
|
1718
|
+
worked === !0 ? (toast.push({ title: "Successfully deleted video", status: "success" }), succeededDeleting()) : worked === "failed-mux" ? (toast.push({
|
|
1719
|
+
title: "Deleted video in Sanity",
|
|
1720
|
+
description: "But it wasn't deleted in Mux",
|
|
1721
|
+
status: "warning"
|
|
1722
|
+
}), succeededDeleting()) : (toast.push({ title: "Failed deleting video", status: "error" }), setState("error_deleting"));
|
|
1723
|
+
}
|
|
1724
|
+
return /* @__PURE__ */ jsx(
|
|
1725
|
+
Dialog,
|
|
1726
|
+
{
|
|
1727
|
+
animate: !0,
|
|
1728
|
+
header: "Delete video",
|
|
1729
|
+
zOffset: DIALOGS_Z_INDEX,
|
|
1730
|
+
id: "deleting-video-details-dialog",
|
|
1731
|
+
onClose: cancelDelete,
|
|
1732
|
+
onClickOutside: cancelDelete,
|
|
1733
|
+
width: 1,
|
|
1734
|
+
position: "fixed",
|
|
1735
|
+
children: /* @__PURE__ */ jsx(
|
|
1736
|
+
Card,
|
|
1737
|
+
{
|
|
1738
|
+
padding: 3,
|
|
1739
|
+
style: {
|
|
1740
|
+
minHeight: "150px",
|
|
1741
|
+
display: "flex",
|
|
1742
|
+
alignItems: "center",
|
|
1743
|
+
justifyContent: "center"
|
|
1744
|
+
},
|
|
1745
|
+
children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
1746
|
+
state === "checkingReferences" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1747
|
+
/* @__PURE__ */ jsx(Heading, { size: 2, children: "Checking if video can be deleted" }),
|
|
1748
|
+
/* @__PURE__ */ jsx(SpinnerBox, {})
|
|
1749
|
+
] }),
|
|
1750
|
+
state === "cantDelete" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1751
|
+
/* @__PURE__ */ jsx(Heading, { size: 2, children: "Video can't be deleted" }),
|
|
1752
|
+
/* @__PURE__ */ jsxs(Text, { size: 2, style: { marginBottom: "2rem" }, children: [
|
|
1753
|
+
"There are ",
|
|
1754
|
+
references?.length,
|
|
1755
|
+
" document",
|
|
1756
|
+
references && references.length > 0 && "s",
|
|
1757
|
+
" ",
|
|
1758
|
+
"pointing to this video. Remove their references to this file or delete them before proceeding."
|
|
1759
|
+
] }),
|
|
1760
|
+
/* @__PURE__ */ jsx(VideoReferences, { references, isLoaded: !referencesLoading })
|
|
1761
|
+
] }),
|
|
1762
|
+
state === "confirm" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1763
|
+
/* @__PURE__ */ jsx(Heading, { size: 2, children: "Are you sure you want to delete this video?" }),
|
|
1764
|
+
/* @__PURE__ */ jsx(Text, { size: 2, children: "This action is irreversible" }),
|
|
1765
|
+
/* @__PURE__ */ jsxs(Stack, { space: 4, marginY: 4, children: [
|
|
1766
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", as: "label", children: [
|
|
1767
|
+
/* @__PURE__ */ jsx(
|
|
1768
|
+
Checkbox,
|
|
1769
|
+
{
|
|
1770
|
+
checked: deleteOnMux,
|
|
1771
|
+
onChange: () => setDeleteOnMux((prev) => !prev)
|
|
1772
|
+
}
|
|
1773
|
+
),
|
|
1774
|
+
/* @__PURE__ */ jsx(Text, { style: { margin: "0 10px" }, children: "Delete asset on Mux" })
|
|
1775
|
+
] }),
|
|
1776
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", as: "label", children: [
|
|
1777
|
+
/* @__PURE__ */ jsx(Checkbox, { disabled: !0, checked: !0 }),
|
|
1778
|
+
/* @__PURE__ */ jsx(Text, { style: { margin: "0 10px" }, children: "Delete video from dataset" })
|
|
1779
|
+
] }),
|
|
1780
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
|
|
1781
|
+
Button,
|
|
1782
|
+
{
|
|
1783
|
+
icon: TrashIcon,
|
|
1784
|
+
fontSize: 2,
|
|
1785
|
+
padding: 3,
|
|
1786
|
+
text: "Delete video",
|
|
1787
|
+
tone: "critical",
|
|
1788
|
+
onClick: confirmDelete,
|
|
1789
|
+
disabled: ["processing_deletion", "checkingReferences", "cantDelete"].some(
|
|
1790
|
+
(s) => s === state
|
|
1562
1791
|
)
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
}
|
|
1566
|
-
)
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1792
|
+
}
|
|
1793
|
+
) })
|
|
1794
|
+
] })
|
|
1795
|
+
] }),
|
|
1796
|
+
state === "processing_deletion" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1797
|
+
/* @__PURE__ */ jsx(Heading, { size: 2, children: "Deleting video..." }),
|
|
1798
|
+
/* @__PURE__ */ jsx(SpinnerBox, {})
|
|
1799
|
+
] }),
|
|
1800
|
+
state === "error_deleting" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1801
|
+
/* @__PURE__ */ jsx(Heading, { size: 2, children: "Something went wrong!" }),
|
|
1802
|
+
/* @__PURE__ */ jsx(Text, { size: 2, children: "Try deleting the video again by clicking the button below" })
|
|
1803
|
+
] })
|
|
1804
|
+
] })
|
|
1805
|
+
}
|
|
1806
|
+
)
|
|
1570
1807
|
}
|
|
1571
1808
|
);
|
|
1572
|
-
}
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
{
|
|
1580
|
-
size: 1,
|
|
1581
|
-
weight: "semibold",
|
|
1582
|
-
style: {
|
|
1583
|
-
wordWrap: "break-word"
|
|
1584
|
-
},
|
|
1585
|
-
children: displayInfo.title
|
|
1586
|
-
}
|
|
1587
|
-
),
|
|
1588
|
-
/* @__PURE__ */ jsxs(Inline, { space: 3, children: [
|
|
1589
|
-
displayInfo?.duration && /* @__PURE__ */ jsx(IconInfo, { text: displayInfo.duration, icon: ClockIcon, size: 1, muted: !0 }),
|
|
1590
|
-
/* @__PURE__ */ jsx(
|
|
1591
|
-
IconInfo,
|
|
1592
|
-
{
|
|
1593
|
-
text: displayInfo.createdAt.toISOString().split("T")[0],
|
|
1594
|
-
icon: CalendarIcon,
|
|
1595
|
-
size: 1,
|
|
1596
|
-
muted: !0
|
|
1597
|
-
}
|
|
1598
|
-
),
|
|
1599
|
-
displayInfo.title != displayInfo.id.slice(0, 12) && /* @__PURE__ */ jsx(IconInfo, { text: displayInfo.id.slice(0, 12), icon: TagIcon, size: 1, muted: !0 })
|
|
1600
|
-
] })
|
|
1601
|
-
] });
|
|
1602
|
-
}, PlayButton = styled.button`
|
|
1603
|
-
display: block;
|
|
1604
|
-
padding: 0;
|
|
1605
|
-
margin: 0;
|
|
1606
|
-
border: none;
|
|
1607
|
-
border-radius: 0.1875rem;
|
|
1608
|
-
position: relative;
|
|
1609
|
-
cursor: pointer;
|
|
1610
|
-
|
|
1611
|
-
&::after {
|
|
1612
|
-
content: '';
|
|
1613
|
-
background: var(--card-fg-color);
|
|
1614
|
-
opacity: 0;
|
|
1615
|
-
display: block;
|
|
1616
|
-
position: absolute;
|
|
1617
|
-
inset: 0;
|
|
1618
|
-
z-index: 10;
|
|
1619
|
-
transition: 0.15s ease-out;
|
|
1620
|
-
border-radius: inherit;
|
|
1809
|
+
}
|
|
1810
|
+
const useDocReferences = createHookFromObservableFactory(({ documentStore, id }) => documentStore.listenQuery(
|
|
1811
|
+
/* groq */
|
|
1812
|
+
"*[references($id)]{_id, _type, _rev, _updatedAt, _createdAt}",
|
|
1813
|
+
{ id },
|
|
1814
|
+
{
|
|
1815
|
+
apiVersion: SANITY_API_VERSION
|
|
1621
1816
|
}
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1817
|
+
));
|
|
1818
|
+
function getVideoMetadata(doc) {
|
|
1819
|
+
const id = doc.assetId || doc._id || "", date = doc.data?.created_at ? new Date(Number(doc.data.created_at) * 1e3) : new Date(doc._createdAt || doc._updatedAt || Date.now());
|
|
1820
|
+
return {
|
|
1821
|
+
title: doc.filename || id.slice(0, 12),
|
|
1822
|
+
id,
|
|
1823
|
+
playbackId: doc.playbackId,
|
|
1824
|
+
createdAt: date,
|
|
1825
|
+
duration: doc.data?.duration ? formatSeconds(doc.data?.duration) : void 0,
|
|
1826
|
+
aspect_ratio: doc.data?.aspect_ratio,
|
|
1827
|
+
max_stored_resolution: doc.data?.max_stored_resolution,
|
|
1828
|
+
max_stored_frame_rate: doc.data?.max_stored_frame_rate
|
|
1829
|
+
};
|
|
1830
|
+
}
|
|
1831
|
+
function useVideoDetails(props) {
|
|
1832
|
+
const documentStore = useDocumentStore(), toast = useToast(), client = useClient(), [references, referencesLoading] = useDocReferences(
|
|
1833
|
+
useMemo(() => ({ documentStore, id: props.asset._id }), [documentStore, props.asset._id])
|
|
1834
|
+
), [originalAsset, setOriginalAsset] = useState(() => props.asset), [filename, setFilename] = useState(props.asset.filename), modified = filename !== originalAsset.filename, displayInfo = getVideoMetadata({ ...props.asset, filename }), [state, setState] = useState("idle");
|
|
1835
|
+
function handleClose() {
|
|
1836
|
+
if (state === "idle") {
|
|
1837
|
+
if (modified) {
|
|
1838
|
+
setState("closing");
|
|
1839
|
+
return;
|
|
1840
|
+
}
|
|
1841
|
+
props.closeDialog();
|
|
1647
1842
|
}
|
|
1648
1843
|
}
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1844
|
+
function confirmClose(shouldClose) {
|
|
1845
|
+
state === "closing" && (shouldClose && props.closeDialog(), setState("idle"));
|
|
1846
|
+
}
|
|
1847
|
+
async function saveChanges() {
|
|
1848
|
+
if (state === "idle") {
|
|
1849
|
+
setState("saving");
|
|
1850
|
+
try {
|
|
1851
|
+
await client.patch(props.asset._id).set({ filename }).commit(), setOriginalAsset((prev) => ({ ...prev, filename })), toast.push({
|
|
1852
|
+
title: "Video title updated",
|
|
1853
|
+
description: `New title: ${filename}`,
|
|
1854
|
+
status: "success"
|
|
1855
|
+
}), props.closeDialog();
|
|
1856
|
+
} catch (error) {
|
|
1857
|
+
toast.push({
|
|
1858
|
+
title: "Failed updating file name",
|
|
1859
|
+
status: "error",
|
|
1860
|
+
description: typeof error == "string" ? error : "Please try again"
|
|
1861
|
+
}), setFilename(originalAsset.filename);
|
|
1862
|
+
}
|
|
1863
|
+
setState("idle");
|
|
1657
1864
|
}
|
|
1658
1865
|
}
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1866
|
+
return {
|
|
1867
|
+
references,
|
|
1868
|
+
referencesLoading,
|
|
1869
|
+
modified,
|
|
1870
|
+
filename,
|
|
1871
|
+
setFilename,
|
|
1872
|
+
displayInfo,
|
|
1873
|
+
state,
|
|
1874
|
+
setState,
|
|
1875
|
+
handleClose,
|
|
1876
|
+
confirmClose,
|
|
1877
|
+
saveChanges
|
|
1878
|
+
};
|
|
1879
|
+
}
|
|
1880
|
+
const AssetInput = (props) => /* @__PURE__ */ jsx(FormField$1, { title: props.label, description: props.description, inputId: props.label, children: /* @__PURE__ */ jsx(
|
|
1881
|
+
TextInput,
|
|
1882
|
+
{
|
|
1883
|
+
id: props.label,
|
|
1884
|
+
value: props.value,
|
|
1885
|
+
placeholder: props.placeholder,
|
|
1886
|
+
onInput: props.onInput,
|
|
1887
|
+
disabled: props.disabled
|
|
1888
|
+
}
|
|
1889
|
+
) }), VideoDetails = (props) => {
|
|
1890
|
+
const [tab, setTab] = useState("details"), {
|
|
1891
|
+
displayInfo,
|
|
1892
|
+
filename,
|
|
1893
|
+
modified,
|
|
1894
|
+
references,
|
|
1895
|
+
referencesLoading,
|
|
1896
|
+
setFilename,
|
|
1897
|
+
state,
|
|
1898
|
+
setState,
|
|
1899
|
+
handleClose,
|
|
1900
|
+
confirmClose,
|
|
1901
|
+
saveChanges
|
|
1902
|
+
} = useVideoDetails(props), isSaving = state === "saving", [containerHeight, setContainerHeight] = useState(null), contentsRef = React.useRef(null);
|
|
1903
|
+
return useEffect(() => {
|
|
1904
|
+
!contentsRef.current || !("getBoundingClientRect" in contentsRef.current) || setContainerHeight(contentsRef.current.getBoundingClientRect().height);
|
|
1905
|
+
}, []), /* @__PURE__ */ jsxs(
|
|
1906
|
+
Dialog,
|
|
1671
1907
|
{
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1908
|
+
animate: !0,
|
|
1909
|
+
header: displayInfo.title,
|
|
1910
|
+
zOffset: DIALOGS_Z_INDEX,
|
|
1911
|
+
id: "video-details-dialog",
|
|
1912
|
+
onClose: handleClose,
|
|
1913
|
+
onClickOutside: handleClose,
|
|
1914
|
+
width: 2,
|
|
1915
|
+
position: "fixed",
|
|
1916
|
+
footer: /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
|
|
1917
|
+
/* @__PURE__ */ jsx(
|
|
1918
|
+
Button,
|
|
1919
|
+
{
|
|
1920
|
+
icon: TrashIcon,
|
|
1921
|
+
fontSize: 2,
|
|
1922
|
+
padding: 3,
|
|
1923
|
+
mode: "bleed",
|
|
1924
|
+
text: "Delete",
|
|
1925
|
+
tone: "critical",
|
|
1926
|
+
onClick: () => setState("deleting"),
|
|
1927
|
+
disabled: isSaving
|
|
1928
|
+
}
|
|
1929
|
+
),
|
|
1930
|
+
modified && /* @__PURE__ */ jsx(
|
|
1931
|
+
Button,
|
|
1932
|
+
{
|
|
1933
|
+
icon: CheckmarkIcon,
|
|
1934
|
+
fontSize: 2,
|
|
1935
|
+
padding: 3,
|
|
1936
|
+
mode: "ghost",
|
|
1937
|
+
text: "Save and close",
|
|
1938
|
+
tone: "positive",
|
|
1939
|
+
onClick: saveChanges,
|
|
1940
|
+
iconRight: isSaving && Spinner,
|
|
1941
|
+
disabled: isSaving
|
|
1942
|
+
}
|
|
1943
|
+
)
|
|
1944
|
+
] }) }),
|
|
1679
1945
|
children: [
|
|
1680
|
-
|
|
1681
|
-
|
|
1946
|
+
state === "deleting" && /* @__PURE__ */ jsx(
|
|
1947
|
+
DeleteDialog,
|
|
1948
|
+
{
|
|
1949
|
+
asset: props.asset,
|
|
1950
|
+
cancelDelete: () => setState("idle"),
|
|
1951
|
+
referencesLoading,
|
|
1952
|
+
references,
|
|
1953
|
+
succeededDeleting: () => {
|
|
1954
|
+
props.closeDialog();
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
),
|
|
1958
|
+
state === "closing" && /* @__PURE__ */ jsx(
|
|
1959
|
+
Dialog,
|
|
1682
1960
|
{
|
|
1683
1961
|
animate: !0,
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1962
|
+
header: "You have unsaved changes",
|
|
1963
|
+
zOffset: DIALOGS_Z_INDEX,
|
|
1964
|
+
id: "closing-video-details-dialog",
|
|
1965
|
+
onClose: () => confirmClose(!1),
|
|
1966
|
+
onClickOutside: () => confirmClose(!1),
|
|
1967
|
+
width: 1,
|
|
1968
|
+
position: "fixed",
|
|
1969
|
+
footer: /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
|
|
1970
|
+
/* @__PURE__ */ jsx(
|
|
1971
|
+
Button,
|
|
1972
|
+
{
|
|
1973
|
+
icon: ErrorOutlineIcon,
|
|
1974
|
+
fontSize: 2,
|
|
1975
|
+
padding: 3,
|
|
1976
|
+
text: "Discard changes",
|
|
1977
|
+
tone: "critical",
|
|
1978
|
+
onClick: () => confirmClose(!0)
|
|
1979
|
+
}
|
|
1980
|
+
),
|
|
1981
|
+
modified && /* @__PURE__ */ jsx(
|
|
1982
|
+
Button,
|
|
1983
|
+
{
|
|
1984
|
+
icon: RevertIcon,
|
|
1985
|
+
fontSize: 2,
|
|
1986
|
+
padding: 3,
|
|
1987
|
+
mode: "ghost",
|
|
1988
|
+
text: "Keep editing",
|
|
1989
|
+
tone: "primary",
|
|
1990
|
+
onClick: () => confirmClose(!1)
|
|
1991
|
+
}
|
|
1992
|
+
)
|
|
1993
|
+
] }) }),
|
|
1994
|
+
children: /* @__PURE__ */ jsx(Card, { padding: 5, children: /* @__PURE__ */ jsxs(Stack, { style: { textAlign: "center" }, space: 3, children: [
|
|
1995
|
+
/* @__PURE__ */ jsx(Heading, { size: 2, children: "Unsaved changes will be lost" }),
|
|
1996
|
+
/* @__PURE__ */ jsx(Text, { size: 2, children: "Are you sure you want to discard them?" })
|
|
1997
|
+
] }) })
|
|
1704
1998
|
}
|
|
1705
1999
|
),
|
|
1706
|
-
/* @__PURE__ */
|
|
1707
|
-
|
|
2000
|
+
/* @__PURE__ */ jsx(
|
|
2001
|
+
Card,
|
|
1708
2002
|
{
|
|
1709
|
-
|
|
1710
|
-
|
|
2003
|
+
padding: 4,
|
|
2004
|
+
sizing: "border",
|
|
1711
2005
|
style: {
|
|
1712
|
-
|
|
2006
|
+
containerType: "inline-size"
|
|
1713
2007
|
},
|
|
1714
|
-
children:
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
2008
|
+
children: /* @__PURE__ */ jsxs(
|
|
2009
|
+
Flex,
|
|
2010
|
+
{
|
|
2011
|
+
sizing: "border",
|
|
2012
|
+
gap: 4,
|
|
2013
|
+
direction: ["column", "column", "row"],
|
|
2014
|
+
align: "flex-start",
|
|
2015
|
+
ref: contentsRef,
|
|
2016
|
+
style: typeof containerHeight == "number" ? {
|
|
2017
|
+
minHeight: containerHeight
|
|
2018
|
+
} : void 0,
|
|
2019
|
+
children: [
|
|
2020
|
+
/* @__PURE__ */ jsx(Stack, { space: 4, flex: 1, sizing: "border", children: /* @__PURE__ */ jsx(VideoPlayer, { asset: props.asset, autoPlay: props.asset.autoPlay || !1 }) }),
|
|
2021
|
+
/* @__PURE__ */ jsxs(Stack, { space: 4, flex: 1, sizing: "border", children: [
|
|
2022
|
+
/* @__PURE__ */ jsxs(TabList, { space: 2, children: [
|
|
2023
|
+
/* @__PURE__ */ jsx(
|
|
2024
|
+
Tab,
|
|
2025
|
+
{
|
|
2026
|
+
"aria-controls": "details-panel",
|
|
2027
|
+
icon: EditIcon,
|
|
2028
|
+
id: "details-tab",
|
|
2029
|
+
label: "Details",
|
|
2030
|
+
onClick: () => setTab("details"),
|
|
2031
|
+
selected: tab === "details"
|
|
2032
|
+
}
|
|
2033
|
+
),
|
|
2034
|
+
/* @__PURE__ */ jsx(
|
|
2035
|
+
Tab,
|
|
2036
|
+
{
|
|
2037
|
+
"aria-controls": "references-panel",
|
|
2038
|
+
icon: SearchIcon,
|
|
2039
|
+
id: "references-tab",
|
|
2040
|
+
label: `Used by ${references ? `(${references.length})` : ""}`,
|
|
2041
|
+
onClick: () => setTab("references"),
|
|
2042
|
+
selected: tab === "references"
|
|
2043
|
+
}
|
|
2044
|
+
)
|
|
2045
|
+
] }),
|
|
2046
|
+
/* @__PURE__ */ jsx(
|
|
2047
|
+
TabPanel,
|
|
1751
2048
|
{
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
2049
|
+
"aria-labelledby": "details-tab",
|
|
2050
|
+
id: "details-panel",
|
|
2051
|
+
hidden: tab !== "details",
|
|
2052
|
+
style: { wordBreak: "break-word" },
|
|
2053
|
+
children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
2054
|
+
/* @__PURE__ */ jsx(
|
|
2055
|
+
AssetInput,
|
|
2056
|
+
{
|
|
2057
|
+
label: "Video title or file name",
|
|
2058
|
+
description: "Not visible to users. Useful for finding videos later.",
|
|
2059
|
+
value: filename || "",
|
|
2060
|
+
onInput: (e) => setFilename(e.currentTarget.value),
|
|
2061
|
+
disabled: state !== "idle"
|
|
2062
|
+
}
|
|
2063
|
+
),
|
|
2064
|
+
/* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
2065
|
+
displayInfo?.duration && /* @__PURE__ */ jsx(
|
|
2066
|
+
IconInfo,
|
|
2067
|
+
{
|
|
2068
|
+
text: `Duration: ${displayInfo.duration}`,
|
|
2069
|
+
icon: ClockIcon,
|
|
2070
|
+
size: 2
|
|
2071
|
+
}
|
|
2072
|
+
),
|
|
2073
|
+
displayInfo?.max_stored_resolution && /* @__PURE__ */ jsx(
|
|
2074
|
+
IconInfo,
|
|
2075
|
+
{
|
|
2076
|
+
text: `Max Resolution: ${displayInfo.max_stored_resolution}`,
|
|
2077
|
+
icon: ResolutionIcon,
|
|
2078
|
+
size: 2
|
|
2079
|
+
}
|
|
2080
|
+
),
|
|
2081
|
+
displayInfo?.max_stored_frame_rate && /* @__PURE__ */ jsx(
|
|
2082
|
+
IconInfo,
|
|
2083
|
+
{
|
|
2084
|
+
text: `Frame rate: ${displayInfo.max_stored_frame_rate}`,
|
|
2085
|
+
icon: StopWatchIcon,
|
|
2086
|
+
size: 2
|
|
2087
|
+
}
|
|
2088
|
+
),
|
|
2089
|
+
displayInfo?.aspect_ratio && /* @__PURE__ */ jsx(
|
|
2090
|
+
IconInfo,
|
|
2091
|
+
{
|
|
2092
|
+
text: `Aspect Ratio: ${displayInfo.aspect_ratio}`,
|
|
2093
|
+
icon: CropIcon,
|
|
2094
|
+
size: 2
|
|
2095
|
+
}
|
|
2096
|
+
),
|
|
2097
|
+
/* @__PURE__ */ jsx(
|
|
2098
|
+
IconInfo,
|
|
2099
|
+
{
|
|
2100
|
+
text: `Uploaded on: ${displayInfo.createdAt.toLocaleDateString("en", {
|
|
2101
|
+
year: "numeric",
|
|
2102
|
+
month: "2-digit",
|
|
2103
|
+
day: "2-digit",
|
|
2104
|
+
hour: "2-digit",
|
|
2105
|
+
minute: "2-digit",
|
|
2106
|
+
hour12: !0
|
|
2107
|
+
})}`,
|
|
2108
|
+
icon: CalendarIcon,
|
|
2109
|
+
size: 2
|
|
2110
|
+
}
|
|
2111
|
+
),
|
|
2112
|
+
/* @__PURE__ */ jsx(IconInfo, { text: `Mux ID:
|
|
2113
|
+
${displayInfo.id}`, icon: TagIcon, size: 2 }),
|
|
2114
|
+
displayInfo?.playbackId && /* @__PURE__ */ jsx(
|
|
2115
|
+
IconInfo,
|
|
2116
|
+
{
|
|
2117
|
+
text: `Playback ID: ${displayInfo.playbackId}`,
|
|
2118
|
+
icon: TagIcon,
|
|
2119
|
+
size: 2
|
|
2120
|
+
}
|
|
2121
|
+
)
|
|
2122
|
+
] })
|
|
2123
|
+
] })
|
|
1760
2124
|
}
|
|
1761
2125
|
),
|
|
1762
2126
|
/* @__PURE__ */ jsx(
|
|
1763
|
-
|
|
2127
|
+
TabPanel,
|
|
1764
2128
|
{
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
text: "Details",
|
|
1770
|
-
style: { flex: 1 },
|
|
1771
|
-
onClick: edit
|
|
2129
|
+
"aria-labelledby": "references-tab",
|
|
2130
|
+
id: "references-panel",
|
|
2131
|
+
hidden: tab !== "references",
|
|
2132
|
+
children: /* @__PURE__ */ jsx(VideoReferences, { references, isLoaded: !referencesLoading })
|
|
1772
2133
|
}
|
|
1773
2134
|
)
|
|
1774
|
-
]
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
2135
|
+
] })
|
|
2136
|
+
]
|
|
2137
|
+
}
|
|
2138
|
+
)
|
|
1778
2139
|
}
|
|
1779
2140
|
)
|
|
1780
2141
|
]
|
|
1781
2142
|
}
|
|
1782
2143
|
);
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
searchQuery ? `matching "${searchQuery}"` : "found"
|
|
1813
|
-
] }),
|
|
1814
|
-
/* @__PURE__ */ jsx(
|
|
1815
|
-
Grid,
|
|
1816
|
-
{
|
|
1817
|
-
gap: 2,
|
|
1818
|
-
style: {
|
|
1819
|
-
gridTemplateColumns: "repeat(auto-fill, minmax(250px, 1fr))"
|
|
1820
|
-
},
|
|
1821
|
-
children: assets.map((asset) => /* @__PURE__ */ jsx(
|
|
1822
|
-
VideoInBrowser,
|
|
1823
|
-
{
|
|
1824
|
-
asset,
|
|
1825
|
-
onEdit: setEditedAsset,
|
|
1826
|
-
onSelect
|
|
1827
|
-
},
|
|
1828
|
-
asset._id
|
|
1829
|
-
))
|
|
1830
|
-
}
|
|
1831
|
-
)
|
|
1832
|
-
] }),
|
|
1833
|
-
isLoading && /* @__PURE__ */ jsx(SpinnerBox, {}),
|
|
1834
|
-
!isLoading && assets.length === 0 && /* @__PURE__ */ jsx(Card, { marginY: 4, paddingX: 4, paddingY: 6, border: !0, radius: 2, tone: "transparent", children: /* @__PURE__ */ jsx(Text, { align: "center", muted: !0, size: 3, children: searchQuery ? `No videos found for "${searchQuery}"` : "No videos in this dataset" }) })
|
|
1835
|
-
] }),
|
|
1836
|
-
freshEditedAsset && /* @__PURE__ */ jsx(VideoDetails, { closeDialog: () => setEditedAsset(null), asset: freshEditedAsset })
|
|
2144
|
+
}, VideoMetadata = (props) => {
|
|
2145
|
+
if (!props.asset)
|
|
2146
|
+
return null;
|
|
2147
|
+
const displayInfo = getVideoMetadata(props.asset);
|
|
2148
|
+
return /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
2149
|
+
displayInfo.title && /* @__PURE__ */ jsx(
|
|
2150
|
+
Text,
|
|
2151
|
+
{
|
|
2152
|
+
size: 1,
|
|
2153
|
+
weight: "semibold",
|
|
2154
|
+
style: {
|
|
2155
|
+
wordWrap: "break-word"
|
|
2156
|
+
},
|
|
2157
|
+
children: displayInfo.title
|
|
2158
|
+
}
|
|
2159
|
+
),
|
|
2160
|
+
/* @__PURE__ */ jsxs(Inline, { space: 3, children: [
|
|
2161
|
+
displayInfo?.duration && /* @__PURE__ */ jsx(IconInfo, { text: displayInfo.duration, icon: ClockIcon, size: 1, muted: !0 }),
|
|
2162
|
+
/* @__PURE__ */ jsx(
|
|
2163
|
+
IconInfo,
|
|
2164
|
+
{
|
|
2165
|
+
text: displayInfo.createdAt.toISOString().split("T")[0],
|
|
2166
|
+
icon: CalendarIcon,
|
|
2167
|
+
size: 1,
|
|
2168
|
+
muted: !0
|
|
2169
|
+
}
|
|
2170
|
+
),
|
|
2171
|
+
displayInfo.title != displayInfo.id.slice(0, 12) && /* @__PURE__ */ jsx(IconInfo, { text: displayInfo.id.slice(0, 12), icon: TagIcon, size: 1, muted: !0 })
|
|
2172
|
+
] })
|
|
1837
2173
|
] });
|
|
1838
|
-
}
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
return useState(!1);
|
|
1858
|
-
}
|
|
1859
|
-
const useMuxPolling = (asset) => {
|
|
1860
|
-
const client = useClient(), projectId = useProjectId(), dataset = useDataset(), shouldFetch = useMemo(
|
|
1861
|
-
() => !!asset?.assetId && (asset?.status === "preparing" || asset?.data?.static_renditions?.status === "preparing"),
|
|
1862
|
-
[asset?.assetId, asset?.data?.static_renditions?.status, asset?.status]
|
|
1863
|
-
);
|
|
1864
|
-
return useSWR(
|
|
1865
|
-
shouldFetch ? `/${projectId}/addons/mux/assets/${dataset}/data/${asset?.assetId}` : null,
|
|
1866
|
-
async () => {
|
|
1867
|
-
const { data } = await client.request({
|
|
1868
|
-
url: `/addons/mux/assets/${dataset}/data/${asset.assetId}`,
|
|
1869
|
-
withCredentials: !0,
|
|
1870
|
-
method: "GET"
|
|
1871
|
-
});
|
|
1872
|
-
client.patch(asset._id).set({ status: data.status, data }).commit({ returnDocuments: !1 });
|
|
1873
|
-
},
|
|
1874
|
-
{ refreshInterval: 2e3, refreshWhenHidden: !0, dedupingInterval: 1e3 }
|
|
1875
|
-
);
|
|
1876
|
-
};
|
|
1877
|
-
function saveSecrets(client, token, secretKey, enableSignedUrls, signingKeyId, signingKeyPrivate) {
|
|
1878
|
-
const doc = {
|
|
1879
|
-
_id: "secrets.mux",
|
|
1880
|
-
_type: "mux.apiKey",
|
|
1881
|
-
token,
|
|
1882
|
-
secretKey,
|
|
1883
|
-
enableSignedUrls,
|
|
1884
|
-
signingKeyId,
|
|
1885
|
-
signingKeyPrivate
|
|
1886
|
-
};
|
|
1887
|
-
return client.createOrReplace(doc);
|
|
1888
|
-
}
|
|
1889
|
-
async function createSigningKeys(client) {
|
|
1890
|
-
try {
|
|
1891
|
-
const { dataset } = client.config();
|
|
1892
|
-
return await client.request({
|
|
1893
|
-
url: `/addons/mux/signing-keys/${dataset}`,
|
|
1894
|
-
withCredentials: !0,
|
|
1895
|
-
method: "POST"
|
|
1896
|
-
});
|
|
1897
|
-
} catch (error) {
|
|
1898
|
-
console.error("Error creating signing keys", error);
|
|
1899
|
-
const message = error.response?.statusCode === 401 ? 'Unauthorized - Failed to create the Signing Key. Please ensure that the token has "System" permissions' : error.message;
|
|
1900
|
-
throw new Error(message);
|
|
1901
|
-
}
|
|
1902
|
-
}
|
|
1903
|
-
function testSecrets(client) {
|
|
1904
|
-
const { dataset } = client.config();
|
|
1905
|
-
return client.request({
|
|
1906
|
-
url: `/addons/mux/secrets/${dataset}/test`,
|
|
1907
|
-
withCredentials: !0,
|
|
1908
|
-
method: "GET"
|
|
1909
|
-
});
|
|
1910
|
-
}
|
|
1911
|
-
async function haveValidSigningKeys(client, signingKeyId, signingKeyPrivate) {
|
|
1912
|
-
if (!(signingKeyId && signingKeyPrivate))
|
|
1913
|
-
return !1;
|
|
1914
|
-
const { dataset } = client.config();
|
|
1915
|
-
try {
|
|
1916
|
-
const res = await client.request({
|
|
1917
|
-
url: `/addons/mux/signing-keys/${dataset}/${signingKeyId}`,
|
|
1918
|
-
withCredentials: !0,
|
|
1919
|
-
method: "GET"
|
|
1920
|
-
});
|
|
1921
|
-
return !!(res.data && res.data.id);
|
|
1922
|
-
} catch {
|
|
1923
|
-
return console.error("Error fetching signingKeyId", signingKeyId, "assuming it is not valid"), !1;
|
|
2174
|
+
}, PlayButton = styled.button`
|
|
2175
|
+
display: block;
|
|
2176
|
+
padding: 0;
|
|
2177
|
+
margin: 0;
|
|
2178
|
+
border: none;
|
|
2179
|
+
border-radius: 0.1875rem;
|
|
2180
|
+
position: relative;
|
|
2181
|
+
cursor: pointer;
|
|
2182
|
+
|
|
2183
|
+
&::after {
|
|
2184
|
+
content: '';
|
|
2185
|
+
background: var(--card-fg-color);
|
|
2186
|
+
opacity: 0;
|
|
2187
|
+
display: block;
|
|
2188
|
+
position: absolute;
|
|
2189
|
+
inset: 0;
|
|
2190
|
+
z-index: 10;
|
|
2191
|
+
transition: 0.15s ease-out;
|
|
2192
|
+
border-radius: inherit;
|
|
1924
2193
|
}
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
signingKeyPrivate
|
|
1951
|
-
), !(await testSecrets(client))?.status && token && secretKey)
|
|
1952
|
-
throw new Error("Invalid secrets");
|
|
1953
|
-
} catch (err) {
|
|
1954
|
-
throw console.error("Error while trying to save secrets:", err), err;
|
|
2194
|
+
|
|
2195
|
+
> div[data-play] {
|
|
2196
|
+
z-index: 11;
|
|
2197
|
+
opacity: 0;
|
|
2198
|
+
transition: 0.15s 0.05s ease-out;
|
|
2199
|
+
position: absolute;
|
|
2200
|
+
left: 50%;
|
|
2201
|
+
top: 50%;
|
|
2202
|
+
transform: translate(-50%, -50%);
|
|
2203
|
+
color: var(--card-fg-color);
|
|
2204
|
+
background: var(--card-bg-color);
|
|
2205
|
+
width: auto;
|
|
2206
|
+
height: 30%;
|
|
2207
|
+
aspect-ratio: 1;
|
|
2208
|
+
border-radius: 100%;
|
|
2209
|
+
display: flex;
|
|
2210
|
+
justify-content: center;
|
|
2211
|
+
align-items: center;
|
|
2212
|
+
box-sizing: border-box;
|
|
2213
|
+
> svg {
|
|
2214
|
+
display: block;
|
|
2215
|
+
width: 70%;
|
|
2216
|
+
height: auto;
|
|
2217
|
+
// Visual balance to center-align the icon
|
|
2218
|
+
transform: translateX(5%);
|
|
1955
2219
|
}
|
|
1956
|
-
if (enableSignedUrls && !await haveValidSigningKeys(
|
|
1957
|
-
client,
|
|
1958
|
-
signingKeyId,
|
|
1959
|
-
signingKeyPrivate
|
|
1960
|
-
))
|
|
1961
|
-
try {
|
|
1962
|
-
const { data } = await createSigningKeys(client);
|
|
1963
|
-
signingKeyId = data.id, signingKeyPrivate = data.private_key, await saveSecrets(
|
|
1964
|
-
client,
|
|
1965
|
-
token,
|
|
1966
|
-
secretKey,
|
|
1967
|
-
enableSignedUrls,
|
|
1968
|
-
signingKeyId,
|
|
1969
|
-
signingKeyPrivate
|
|
1970
|
-
);
|
|
1971
|
-
} catch (err) {
|
|
1972
|
-
throw console.log("Error while creating and saving signing key:", err?.message), err;
|
|
1973
|
-
}
|
|
1974
|
-
return {
|
|
1975
|
-
token,
|
|
1976
|
-
secretKey,
|
|
1977
|
-
enableSignedUrls,
|
|
1978
|
-
signingKeyId,
|
|
1979
|
-
signingKeyPrivate
|
|
1980
|
-
};
|
|
1981
|
-
},
|
|
1982
|
-
[client, secrets]
|
|
1983
|
-
);
|
|
1984
|
-
function init({ token, secretKey, enableSignedUrls }) {
|
|
1985
|
-
return {
|
|
1986
|
-
submitting: !1,
|
|
1987
|
-
error: null,
|
|
1988
|
-
// Form inputs don't set the state back to null when clearing a field, but uses empty strings
|
|
1989
|
-
// This ensures the `dirty` check works correctly
|
|
1990
|
-
token: token ?? "",
|
|
1991
|
-
secretKey: secretKey ?? "",
|
|
1992
|
-
enableSignedUrls: enableSignedUrls ?? !1
|
|
1993
|
-
};
|
|
1994
|
-
}
|
|
1995
|
-
function reducer(state, action) {
|
|
1996
|
-
switch (action?.type) {
|
|
1997
|
-
case "submit":
|
|
1998
|
-
return { ...state, submitting: !0, error: null };
|
|
1999
|
-
case "error":
|
|
2000
|
-
return { ...state, submitting: !1, error: action.payload };
|
|
2001
|
-
case "reset":
|
|
2002
|
-
return init(action.payload);
|
|
2003
|
-
case "change":
|
|
2004
|
-
return { ...state, [action.payload.name]: action.payload.value };
|
|
2005
|
-
default:
|
|
2006
|
-
throw new Error(`Unknown action type: ${action?.type}`);
|
|
2007
2220
|
}
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2221
|
+
|
|
2222
|
+
&:hover,
|
|
2223
|
+
&:focus {
|
|
2224
|
+
&::after {
|
|
2225
|
+
opacity: 0.3;
|
|
2226
|
+
}
|
|
2227
|
+
> div[data-play] {
|
|
2228
|
+
opacity: 1;
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
`;
|
|
2232
|
+
function VideoInBrowser({
|
|
2233
|
+
onSelect,
|
|
2234
|
+
onEdit,
|
|
2235
|
+
asset
|
|
2236
|
+
}) {
|
|
2237
|
+
const [renderVideo, setRenderVideo] = useState(!1), select = React.useCallback(() => onSelect?.(asset), [onSelect, asset]), edit = React.useCallback(() => onEdit?.(asset), [onEdit, asset]);
|
|
2238
|
+
if (!asset)
|
|
2239
|
+
return null;
|
|
2240
|
+
const playbackPolicy = getPlaybackPolicy(asset);
|
|
2241
|
+
return /* @__PURE__ */ jsxs(
|
|
2242
|
+
Card,
|
|
2016
2243
|
{
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
d: "M994.287,93.486c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m0,-93.486c-34.509,-0 -62.484,27.976 -62.484,62.486l0,187.511c0,68.943 -56.09,125.033 -125.032,125.033c-68.942,-0 -125.03,-56.09 -125.03,-125.033l0,-187.511c0,-34.51 -27.976,-62.486 -62.485,-62.486c-34.509,-0 -62.484,27.976 -62.484,62.486l0,187.511c0,137.853 112.149,250.003 249.999,250.003c137.851,-0 250.001,-112.15 250.001,-250.003l0,-187.511c0,-34.51 -27.976,-62.486 -62.485,-62.486",
|
|
2028
|
-
style: pathStyle
|
|
2029
|
-
}
|
|
2030
|
-
),
|
|
2031
|
-
/* @__PURE__ */ jsx(
|
|
2032
|
-
"path",
|
|
2244
|
+
border: !0,
|
|
2245
|
+
padding: 2,
|
|
2246
|
+
sizing: "border",
|
|
2247
|
+
radius: 2,
|
|
2248
|
+
style: {
|
|
2249
|
+
position: "relative"
|
|
2250
|
+
},
|
|
2251
|
+
children: [
|
|
2252
|
+
playbackPolicy === "signed" && /* @__PURE__ */ jsx(
|
|
2253
|
+
Tooltip,
|
|
2033
2254
|
{
|
|
2034
|
-
|
|
2035
|
-
|
|
2255
|
+
animate: !0,
|
|
2256
|
+
content: /* @__PURE__ */ jsx(Card, { padding: 2, radius: 2, children: /* @__PURE__ */ jsx(IconInfo, { icon: LockIcon, text: "Signed playback policy", size: 2 }) }),
|
|
2257
|
+
placement: "right",
|
|
2258
|
+
fallbackPlacements: ["top", "bottom"],
|
|
2259
|
+
portal: !0,
|
|
2260
|
+
children: /* @__PURE__ */ jsx(
|
|
2261
|
+
Card,
|
|
2262
|
+
{
|
|
2263
|
+
tone: "caution",
|
|
2264
|
+
style: {
|
|
2265
|
+
borderRadius: "100%",
|
|
2266
|
+
position: "absolute",
|
|
2267
|
+
left: "1em",
|
|
2268
|
+
top: "1em",
|
|
2269
|
+
zIndex: 10
|
|
2270
|
+
},
|
|
2271
|
+
padding: 2,
|
|
2272
|
+
border: !0,
|
|
2273
|
+
children: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: /* @__PURE__ */ jsx(LockIcon, {}) })
|
|
2274
|
+
}
|
|
2275
|
+
)
|
|
2036
2276
|
}
|
|
2037
2277
|
),
|
|
2038
|
-
/* @__PURE__ */
|
|
2039
|
-
|
|
2278
|
+
/* @__PURE__ */ jsxs(
|
|
2279
|
+
Stack,
|
|
2040
2280
|
{
|
|
2041
|
-
|
|
2042
|
-
|
|
2281
|
+
space: 3,
|
|
2282
|
+
height: "fill",
|
|
2283
|
+
style: {
|
|
2284
|
+
gridTemplateRows: "min-content min-content 1fr"
|
|
2285
|
+
},
|
|
2286
|
+
children: [
|
|
2287
|
+
renderVideo ? /* @__PURE__ */ jsx(VideoPlayer, { asset, autoPlay: !0, forceAspectRatio: THUMBNAIL_ASPECT_RATIO }) : /* @__PURE__ */ jsxs(PlayButton, { onClick: () => setRenderVideo(!0), children: [
|
|
2288
|
+
/* @__PURE__ */ jsx("div", { "data-play": !0, children: /* @__PURE__ */ jsx(PlayIcon, {}) }),
|
|
2289
|
+
assetIsAudio(asset) ? /* @__PURE__ */ jsx(
|
|
2290
|
+
"div",
|
|
2291
|
+
{
|
|
2292
|
+
style: {
|
|
2293
|
+
aspectRatio: THUMBNAIL_ASPECT_RATIO,
|
|
2294
|
+
display: "flex",
|
|
2295
|
+
alignItems: "center",
|
|
2296
|
+
justifyContent: "center"
|
|
2297
|
+
},
|
|
2298
|
+
children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "3em", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx(
|
|
2299
|
+
"path",
|
|
2300
|
+
{
|
|
2301
|
+
fill: "currentColor",
|
|
2302
|
+
style: { opacity: "0.65" },
|
|
2303
|
+
d: "M10.75 19q.95 0 1.6-.65t.65-1.6V13h3v-2h-4v3.875q-.275-.2-.587-.288t-.663-.087q-.95 0-1.6.65t-.65 1.6t.65 1.6t1.6.65M6 22q-.825 0-1.412-.587T4 20V4q0-.825.588-1.412T6 2h8l6 6v12q0 .825-.587 1.413T18 22zm7-13V4H6v16h12V9zM6 4v5zv16z"
|
|
2304
|
+
}
|
|
2305
|
+
) })
|
|
2306
|
+
}
|
|
2307
|
+
) : /* @__PURE__ */ jsx(VideoThumbnail, { asset })
|
|
2308
|
+
] }),
|
|
2309
|
+
/* @__PURE__ */ jsx(VideoMetadata, { asset }),
|
|
2310
|
+
/* @__PURE__ */ jsxs(
|
|
2311
|
+
"div",
|
|
2312
|
+
{
|
|
2313
|
+
style: {
|
|
2314
|
+
display: "flex",
|
|
2315
|
+
width: "100%",
|
|
2316
|
+
alignItems: "flex-end",
|
|
2317
|
+
justifyContent: "flex-start",
|
|
2318
|
+
gap: ".35rem"
|
|
2319
|
+
},
|
|
2320
|
+
children: [
|
|
2321
|
+
onSelect && /* @__PURE__ */ jsx(
|
|
2322
|
+
Button,
|
|
2323
|
+
{
|
|
2324
|
+
icon: CheckmarkIcon,
|
|
2325
|
+
fontSize: 2,
|
|
2326
|
+
padding: 2,
|
|
2327
|
+
mode: "ghost",
|
|
2328
|
+
text: "Select",
|
|
2329
|
+
style: { flex: 1 },
|
|
2330
|
+
tone: "positive",
|
|
2331
|
+
onClick: select
|
|
2332
|
+
}
|
|
2333
|
+
),
|
|
2334
|
+
/* @__PURE__ */ jsx(
|
|
2335
|
+
Button,
|
|
2336
|
+
{
|
|
2337
|
+
icon: EditIcon,
|
|
2338
|
+
fontSize: 2,
|
|
2339
|
+
padding: 2,
|
|
2340
|
+
mode: "ghost",
|
|
2341
|
+
text: "Details",
|
|
2342
|
+
style: { flex: 1 },
|
|
2343
|
+
onClick: edit
|
|
2344
|
+
}
|
|
2345
|
+
)
|
|
2346
|
+
]
|
|
2347
|
+
}
|
|
2348
|
+
)
|
|
2349
|
+
]
|
|
2043
2350
|
}
|
|
2044
2351
|
)
|
|
2045
|
-
]
|
|
2352
|
+
]
|
|
2046
2353
|
}
|
|
2047
2354
|
);
|
|
2048
2355
|
}
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
transform: translate(0.3em, -0.2em);
|
|
2054
|
-
`, Header = () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2055
|
-
/* @__PURE__ */ jsx(Logo, { children: /* @__PURE__ */ jsx(MuxLogo, { height: 13 }) }),
|
|
2056
|
-
"API Credentials"
|
|
2057
|
-
] }), fieldNames = ["token", "secretKey", "enableSignedUrls"];
|
|
2058
|
-
function ConfigureApi({ secrets, setDialogState }) {
|
|
2059
|
-
const client = useClient(), [state, dispatch] = useSecretsFormState(secrets), hasSecretsInitially = useMemo(() => secrets.token && secrets.secretKey, [secrets]), handleClose = useCallback(() => setDialogState(!1), [setDialogState]), dirty = useMemo(
|
|
2060
|
-
() => secrets.token !== state.token || secrets.secretKey !== state.secretKey || secrets.enableSignedUrls !== state.enableSignedUrls,
|
|
2061
|
-
[secrets, state]
|
|
2062
|
-
), id = `ConfigureApi${useId()}`, [tokenId, secretKeyId, enableSignedUrlsId] = useMemo(
|
|
2063
|
-
() => fieldNames.map((field) => `${id}-${field}`),
|
|
2064
|
-
[id]
|
|
2065
|
-
), firstField = useRef(null), handleSaveSecrets = useSaveSecrets(client, secrets), saving = useRef(!1), handleSubmit = useCallback(
|
|
2066
|
-
(event) => {
|
|
2067
|
-
if (event.preventDefault(), !saving.current && event.currentTarget.reportValidity()) {
|
|
2068
|
-
saving.current = !0, dispatch({ type: "submit" });
|
|
2069
|
-
const { token, secretKey, enableSignedUrls } = state;
|
|
2070
|
-
handleSaveSecrets({ token, secretKey, enableSignedUrls }).then((savedSecrets) => {
|
|
2071
|
-
const { projectId, dataset } = client.config();
|
|
2072
|
-
clear([cacheNs, _id, projectId, dataset]), preload(() => Promise.resolve(savedSecrets), [cacheNs, _id, projectId, dataset]), setDialogState(!1);
|
|
2073
|
-
}).catch((err) => dispatch({ type: "error", payload: err.message })).finally(() => {
|
|
2074
|
-
saving.current = !1;
|
|
2075
|
-
});
|
|
2076
|
-
}
|
|
2077
|
-
},
|
|
2078
|
-
[client, dispatch, handleSaveSecrets, setDialogState, state]
|
|
2079
|
-
), handleChangeToken = useCallback(
|
|
2080
|
-
(event) => {
|
|
2081
|
-
dispatch({
|
|
2082
|
-
type: "change",
|
|
2083
|
-
payload: { name: "token", value: event.currentTarget.value }
|
|
2084
|
-
});
|
|
2085
|
-
},
|
|
2086
|
-
[dispatch]
|
|
2087
|
-
), handleChangeSecretKey = useCallback(
|
|
2088
|
-
(event) => {
|
|
2089
|
-
dispatch({
|
|
2090
|
-
type: "change",
|
|
2091
|
-
payload: { name: "secretKey", value: event.currentTarget.value }
|
|
2092
|
-
});
|
|
2093
|
-
},
|
|
2094
|
-
[dispatch]
|
|
2095
|
-
), handleChangeEnableSignedUrls = useCallback(
|
|
2096
|
-
(event) => {
|
|
2097
|
-
dispatch({
|
|
2098
|
-
type: "change",
|
|
2099
|
-
payload: { name: "enableSignedUrls", value: event.currentTarget.checked }
|
|
2100
|
-
});
|
|
2101
|
-
},
|
|
2102
|
-
[dispatch]
|
|
2356
|
+
function VideosBrowser({ onSelect }) {
|
|
2357
|
+
const { assets, isLoading, searchQuery, setSearchQuery, setSort, sort } = useAssets(), [editedAsset, setEditedAsset] = useState(null), freshEditedAsset = useMemo(
|
|
2358
|
+
() => assets.find((a2) => a2._id === editedAsset?._id) || editedAsset,
|
|
2359
|
+
[editedAsset, assets]
|
|
2103
2360
|
);
|
|
2104
|
-
return
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
{
|
|
2109
|
-
animate: !0,
|
|
2110
|
-
id,
|
|
2111
|
-
onClose: handleClose,
|
|
2112
|
-
header: /* @__PURE__ */ jsx(Header, {}),
|
|
2113
|
-
width: 1,
|
|
2114
|
-
style: {
|
|
2115
|
-
maxWidth: "550px"
|
|
2116
|
-
},
|
|
2117
|
-
children: /* @__PURE__ */ jsx(Box, { padding: 4, style: { position: "relative" }, children: /* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, noValidate: !0, children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
2118
|
-
!hasSecretsInitially && /* @__PURE__ */ jsx(Card, { padding: [3, 3, 3], radius: 2, shadow: 1, tone: "primary", children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
2119
|
-
/* @__PURE__ */ jsxs(Text, { size: 1, children: [
|
|
2120
|
-
"To set up a new access token, go to your",
|
|
2121
|
-
" ",
|
|
2122
|
-
/* @__PURE__ */ jsx(
|
|
2123
|
-
"a",
|
|
2124
|
-
{
|
|
2125
|
-
href: "https://dashboard.mux.com/settings/access-tokens",
|
|
2126
|
-
target: "_blank",
|
|
2127
|
-
rel: "noreferrer noopener",
|
|
2128
|
-
children: "account on mux.com"
|
|
2129
|
-
}
|
|
2130
|
-
),
|
|
2131
|
-
"."
|
|
2132
|
-
] }),
|
|
2133
|
-
/* @__PURE__ */ jsxs(Text, { size: 1, children: [
|
|
2134
|
-
"The access token needs permissions: ",
|
|
2135
|
-
/* @__PURE__ */ jsx("strong", { children: "Mux Video " }),
|
|
2136
|
-
"(Full Access) and ",
|
|
2137
|
-
/* @__PURE__ */ jsx("strong", { children: "Mux Data" }),
|
|
2138
|
-
" (Read)",
|
|
2139
|
-
/* @__PURE__ */ jsx("br", {}),
|
|
2140
|
-
"To use Signed URLs, the token must also have System permissions.",
|
|
2141
|
-
/* @__PURE__ */ jsx("br", {}),
|
|
2142
|
-
"The credentials will be stored safely in a hidden document only available to editors."
|
|
2143
|
-
] })
|
|
2144
|
-
] }) }),
|
|
2145
|
-
/* @__PURE__ */ jsx(FormField$1, { title: "Access Token", inputId: tokenId, children: /* @__PURE__ */ jsx(
|
|
2146
|
-
TextInput,
|
|
2147
|
-
{
|
|
2148
|
-
id: tokenId,
|
|
2149
|
-
ref: firstField,
|
|
2150
|
-
onChange: handleChangeToken,
|
|
2151
|
-
type: "text",
|
|
2152
|
-
value: state.token ?? "",
|
|
2153
|
-
required: !!state.secretKey || state.enableSignedUrls
|
|
2154
|
-
}
|
|
2155
|
-
) }),
|
|
2156
|
-
/* @__PURE__ */ jsx(FormField$1, { title: "Secret Key", inputId: secretKeyId, children: /* @__PURE__ */ jsx(
|
|
2157
|
-
TextInput,
|
|
2158
|
-
{
|
|
2159
|
-
id: secretKeyId,
|
|
2160
|
-
onChange: handleChangeSecretKey,
|
|
2161
|
-
type: "text",
|
|
2162
|
-
value: state.secretKey ?? "",
|
|
2163
|
-
required: !!state.token || state.enableSignedUrls
|
|
2164
|
-
}
|
|
2165
|
-
) }),
|
|
2166
|
-
/* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
2167
|
-
/* @__PURE__ */ jsxs(Flex, { align: "center", children: [
|
|
2168
|
-
/* @__PURE__ */ jsx(
|
|
2169
|
-
Checkbox,
|
|
2170
|
-
{
|
|
2171
|
-
id: enableSignedUrlsId,
|
|
2172
|
-
onChange: handleChangeEnableSignedUrls,
|
|
2173
|
-
checked: state.enableSignedUrls,
|
|
2174
|
-
style: { display: "block" }
|
|
2175
|
-
}
|
|
2176
|
-
),
|
|
2177
|
-
/* @__PURE__ */ jsx(Box, { flex: 1, paddingLeft: 3, children: /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx("label", { htmlFor: enableSignedUrlsId, children: "Enable Signed Urls" }) }) })
|
|
2178
|
-
] }),
|
|
2179
|
-
secrets.signingKeyId && state.enableSignedUrls ? /* @__PURE__ */ jsx(Card, { padding: [3, 3, 3], radius: 2, shadow: 1, tone: "caution", children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
2180
|
-
/* @__PURE__ */ jsx(Text, { size: 1, children: "The signing key ID that Sanity will use is:" }),
|
|
2181
|
-
/* @__PURE__ */ jsx(Code, { size: 1, children: secrets.signingKeyId }),
|
|
2182
|
-
/* @__PURE__ */ jsxs(Text, { size: 1, children: [
|
|
2183
|
-
"This key is only used for previewing content in the Sanity UI.",
|
|
2184
|
-
/* @__PURE__ */ jsx("br", {}),
|
|
2185
|
-
"You should generate a different key to use in your application server."
|
|
2186
|
-
] })
|
|
2187
|
-
] }) }) : null
|
|
2188
|
-
] }),
|
|
2189
|
-
/* @__PURE__ */ jsxs(Inline, { space: 2, children: [
|
|
2361
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2362
|
+
/* @__PURE__ */ jsxs(Stack, { padding: 4, space: 4, style: { minHeight: "50vh" }, children: [
|
|
2363
|
+
/* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
|
|
2364
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 3, children: [
|
|
2190
2365
|
/* @__PURE__ */ jsx(
|
|
2191
|
-
|
|
2366
|
+
TextInput,
|
|
2192
2367
|
{
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
mode: "default",
|
|
2198
|
-
type: "submit"
|
|
2368
|
+
value: searchQuery,
|
|
2369
|
+
icon: SearchIcon,
|
|
2370
|
+
onInput: (e) => setSearchQuery(e.currentTarget.value),
|
|
2371
|
+
placeholder: "Search videos"
|
|
2199
2372
|
}
|
|
2200
2373
|
),
|
|
2201
|
-
/* @__PURE__ */ jsx(
|
|
2202
|
-
Button,
|
|
2203
|
-
{
|
|
2204
|
-
disabled: state.submitting,
|
|
2205
|
-
text: "Cancel",
|
|
2206
|
-
mode: "bleed",
|
|
2207
|
-
onClick: handleClose
|
|
2208
|
-
}
|
|
2209
|
-
)
|
|
2374
|
+
/* @__PURE__ */ jsx(SelectSortOptions, { setSort, sort })
|
|
2210
2375
|
] }),
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2376
|
+
(onSelect ? "input" : "tool") == "tool" && /* @__PURE__ */ jsxs(Inline, { space: 2, children: [
|
|
2377
|
+
/* @__PURE__ */ jsx(ImportVideosFromMux, {}),
|
|
2378
|
+
/* @__PURE__ */ jsx(ResyncMetadata, {}),
|
|
2379
|
+
/* @__PURE__ */ jsx(ConfigureApi, {})
|
|
2380
|
+
] })
|
|
2381
|
+
] }),
|
|
2382
|
+
/* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
2383
|
+
assets?.length > 0 && /* @__PURE__ */ jsxs(Label$1, { muted: !0, children: [
|
|
2384
|
+
assets.length,
|
|
2385
|
+
" video",
|
|
2386
|
+
assets.length > 1 ? "s" : null,
|
|
2387
|
+
" ",
|
|
2388
|
+
searchQuery ? `matching "${searchQuery}"` : "found"
|
|
2389
|
+
] }),
|
|
2390
|
+
/* @__PURE__ */ jsx(
|
|
2391
|
+
Grid,
|
|
2392
|
+
{
|
|
2393
|
+
gap: 2,
|
|
2394
|
+
style: {
|
|
2395
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(250px, 1fr))"
|
|
2396
|
+
},
|
|
2397
|
+
children: assets.map((asset) => /* @__PURE__ */ jsx(
|
|
2398
|
+
VideoInBrowser,
|
|
2399
|
+
{
|
|
2400
|
+
asset,
|
|
2401
|
+
onEdit: setEditedAsset,
|
|
2402
|
+
onSelect
|
|
2403
|
+
},
|
|
2404
|
+
asset._id
|
|
2405
|
+
))
|
|
2406
|
+
}
|
|
2407
|
+
)
|
|
2408
|
+
] }),
|
|
2409
|
+
isLoading && /* @__PURE__ */ jsx(SpinnerBox, {}),
|
|
2410
|
+
!isLoading && assets.length === 0 && /* @__PURE__ */ jsx(Card, { marginY: 4, paddingX: 4, paddingY: 6, border: !0, radius: 2, tone: "transparent", children: /* @__PURE__ */ jsx(Text, { align: "center", muted: !0, size: 3, children: searchQuery ? `No videos found for "${searchQuery}"` : "No videos in this dataset" }) })
|
|
2411
|
+
] }),
|
|
2412
|
+
freshEditedAsset && /* @__PURE__ */ jsx(VideoDetails, { closeDialog: () => setEditedAsset(null), asset: freshEditedAsset })
|
|
2413
|
+
] });
|
|
2414
|
+
}
|
|
2415
|
+
const StudioTool = () => /* @__PURE__ */ jsx(VideosBrowser, {}), DEFAULT_TOOL_CONFIG = {
|
|
2416
|
+
icon: ToolIcon,
|
|
2417
|
+
title: "Videos"
|
|
2418
|
+
};
|
|
2419
|
+
function createStudioTool(config) {
|
|
2420
|
+
const toolConfig = typeof config.tool == "object" ? config.tool : DEFAULT_TOOL_CONFIG;
|
|
2421
|
+
return {
|
|
2422
|
+
name: "mux",
|
|
2423
|
+
icon: toolConfig.icon || DEFAULT_TOOL_CONFIG.icon,
|
|
2424
|
+
title: toolConfig.title || DEFAULT_TOOL_CONFIG.title,
|
|
2425
|
+
component: (props) => /* @__PURE__ */ jsx(StudioTool, { ...config, ...props })
|
|
2426
|
+
};
|
|
2215
2427
|
}
|
|
2216
|
-
|
|
2428
|
+
const useAccessControl = (config) => {
|
|
2429
|
+
const user = useCurrentUser();
|
|
2430
|
+
return { hasConfigAccess: !config?.allowedRolesForConfiguration?.length || user?.roles?.some((role) => config.allowedRolesForConfiguration.includes(role.name)) };
|
|
2431
|
+
}, path = ["assetId", "data", "playbackId", "status", "thumbTime", "filename"], useAssetDocumentValues = (asset) => useDocumentValues(
|
|
2432
|
+
isReference(asset) ? asset._ref : "",
|
|
2433
|
+
path
|
|
2434
|
+
), useMuxPolling = (asset) => {
|
|
2435
|
+
const client = useClient(), projectId = useProjectId(), dataset = useDataset(), shouldFetch = useMemo(
|
|
2436
|
+
() => !!asset?.assetId && (asset?.status === "preparing" || asset?.data?.static_renditions?.status === "preparing"),
|
|
2437
|
+
[asset?.assetId, asset?.data?.static_renditions?.status, asset?.status]
|
|
2438
|
+
);
|
|
2439
|
+
return useSWR(
|
|
2440
|
+
shouldFetch ? `/${projectId}/addons/mux/assets/${dataset}/data/${asset?.assetId}` : null,
|
|
2441
|
+
async () => {
|
|
2442
|
+
const { data } = await client.request({
|
|
2443
|
+
url: `/addons/mux/assets/${dataset}/data/${asset.assetId}`,
|
|
2444
|
+
withCredentials: !0,
|
|
2445
|
+
method: "GET"
|
|
2446
|
+
});
|
|
2447
|
+
client.patch(asset._id).set({ status: data.status, data }).commit({ returnDocuments: !1 });
|
|
2448
|
+
},
|
|
2449
|
+
{ refreshInterval: 2e3, refreshWhenHidden: !0, dedupingInterval: 1e3 }
|
|
2450
|
+
);
|
|
2451
|
+
};
|
|
2452
|
+
var c = function(r) {
|
|
2217
2453
|
var t, e;
|
|
2218
2454
|
function n(t2) {
|
|
2219
2455
|
var e2;
|
|
@@ -2307,10 +2543,7 @@ const InputFallback = () => /* @__PURE__ */ jsx("div", { style: { padding: 1 },
|
|
|
2307
2543
|
/* @__PURE__ */ jsx(Box, { marginTop: 3, children: /* @__PURE__ */ jsx(Text, { align: "center", muted: !0, size: 1, children: "Loading\u2026" }) })
|
|
2308
2544
|
] })
|
|
2309
2545
|
}
|
|
2310
|
-
) })
|
|
2311
|
-
const user = useCurrentUser();
|
|
2312
|
-
return { hasConfigAccess: !config?.allowedRolesForConfiguration?.length || user?.roles?.some((role) => config.allowedRolesForConfiguration.includes(role.name)) };
|
|
2313
|
-
};
|
|
2546
|
+
) });
|
|
2314
2547
|
function Onboard(props) {
|
|
2315
2548
|
const { setDialogState } = props, handleOpen = useCallback(() => setDialogState("secrets"), [setDialogState]), { hasConfigAccess } = useAccessControl(props.config);
|
|
2316
2549
|
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("div", { style: { padding: 2 }, children: /* @__PURE__ */ jsx(
|
|
@@ -3098,9 +3331,10 @@ function PlaybackPolicy({
|
|
|
3098
3331
|
noPolicySelected && /* @__PURE__ */ jsx(PlaybackPolicyWarning, {})
|
|
3099
3332
|
] });
|
|
3100
3333
|
}
|
|
3101
|
-
const
|
|
3102
|
-
{ value: "
|
|
3103
|
-
{ value: "
|
|
3334
|
+
const VIDEO_QUALITY_LEVELS = [
|
|
3335
|
+
{ value: "basic", label: "Basic" },
|
|
3336
|
+
{ value: "plus", label: "Plus" },
|
|
3337
|
+
{ value: "premium", label: "Premium" }
|
|
3104
3338
|
], RESOLUTION_TIERS = [
|
|
3105
3339
|
{ value: "1080p", label: "1080p" },
|
|
3106
3340
|
{ value: "1440p", label: "1440p (2k)" },
|
|
@@ -3114,7 +3348,7 @@ function UploadConfiguration({
|
|
|
3114
3348
|
onClose
|
|
3115
3349
|
}) {
|
|
3116
3350
|
const id = useId(), autoTextTracks = useRef(
|
|
3117
|
-
pluginConfig.
|
|
3351
|
+
pluginConfig.video_quality === "plus" && pluginConfig.defaultAutogeneratedSubtitleLang ? [
|
|
3118
3352
|
{
|
|
3119
3353
|
_id: uuid(),
|
|
3120
3354
|
type: "autogenerated",
|
|
@@ -3125,16 +3359,16 @@ function UploadConfiguration({
|
|
|
3125
3359
|
).current, [config, dispatch] = useReducer(
|
|
3126
3360
|
(prev, action) => {
|
|
3127
3361
|
switch (action.action) {
|
|
3128
|
-
case "
|
|
3129
|
-
return action.value === "
|
|
3130
|
-
|
|
3362
|
+
case "video_quality":
|
|
3363
|
+
return action.value === "basic" ? Object.assign({}, prev, {
|
|
3364
|
+
video_quality: action.value,
|
|
3131
3365
|
mp4_support: "none",
|
|
3132
3366
|
max_resolution_tier: "1080p",
|
|
3133
3367
|
text_tracks: prev.text_tracks?.filter(({ type }) => type !== "autogenerated"),
|
|
3134
3368
|
public_policy: !0,
|
|
3135
3369
|
signed_policy: !1
|
|
3136
3370
|
}) : Object.assign({}, prev, {
|
|
3137
|
-
|
|
3371
|
+
video_quality: action.value,
|
|
3138
3372
|
mp4_support: pluginConfig.mp4_support,
|
|
3139
3373
|
max_resolution_tier: pluginConfig.max_resolution_tier,
|
|
3140
3374
|
text_tracks: [...autoTextTracks, ...prev.text_tracks || []]
|
|
@@ -3176,7 +3410,7 @@ function UploadConfiguration({
|
|
|
3176
3410
|
}
|
|
3177
3411
|
},
|
|
3178
3412
|
{
|
|
3179
|
-
|
|
3413
|
+
video_quality: pluginConfig.video_quality,
|
|
3180
3414
|
max_resolution_tier: pluginConfig.max_resolution_tier,
|
|
3181
3415
|
mp4_support: pluginConfig.mp4_support,
|
|
3182
3416
|
signed_policy: secrets.enableSignedUrls && pluginConfig.defaultSigned,
|
|
@@ -3188,7 +3422,7 @@ function UploadConfiguration({
|
|
|
3188
3422
|
if (useEffect(() => {
|
|
3189
3423
|
skipConfig && startUpload(formatUploadConfig(config));
|
|
3190
3424
|
}, []), skipConfig) return null;
|
|
3191
|
-
const maxSupportedResolution = RESOLUTION_TIERS.findIndex(
|
|
3425
|
+
const basicConfig = config.video_quality !== "plus" && config.video_quality !== "premium", maxSupportedResolution = RESOLUTION_TIERS.findIndex(
|
|
3192
3426
|
(rt) => rt.value === pluginConfig.max_resolution_tier
|
|
3193
3427
|
);
|
|
3194
3428
|
return /* @__PURE__ */ jsx(
|
|
@@ -3224,9 +3458,9 @@ function UploadConfiguration({
|
|
|
3224
3458
|
/* @__PURE__ */ jsx(
|
|
3225
3459
|
FormField$2,
|
|
3226
3460
|
{
|
|
3227
|
-
title: "
|
|
3461
|
+
title: "Video Quality Level",
|
|
3228
3462
|
description: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3229
|
-
"The
|
|
3463
|
+
"The video quality level informs the cost, quality, and available platform features for the asset.",
|
|
3230
3464
|
" ",
|
|
3231
3465
|
/* @__PURE__ */ jsx(
|
|
3232
3466
|
"a",
|
|
@@ -3238,16 +3472,16 @@ function UploadConfiguration({
|
|
|
3238
3472
|
}
|
|
3239
3473
|
)
|
|
3240
3474
|
] }),
|
|
3241
|
-
children: /* @__PURE__ */ jsx(Flex, { gap: 3, children:
|
|
3475
|
+
children: /* @__PURE__ */ jsx(Flex, { gap: 3, children: VIDEO_QUALITY_LEVELS.map(({ value, label }) => {
|
|
3242
3476
|
const inputId = `${id}--encodingtier-${value}`;
|
|
3243
3477
|
return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
3244
3478
|
/* @__PURE__ */ jsx(
|
|
3245
3479
|
Radio,
|
|
3246
3480
|
{
|
|
3247
|
-
checked: config.
|
|
3481
|
+
checked: config.video_quality === value,
|
|
3248
3482
|
name: "asset-encodingtier",
|
|
3249
3483
|
onChange: (e) => dispatch({
|
|
3250
|
-
action: "
|
|
3484
|
+
action: "video_quality",
|
|
3251
3485
|
value: e.currentTarget.value
|
|
3252
3486
|
}),
|
|
3253
3487
|
value,
|
|
@@ -3259,7 +3493,7 @@ function UploadConfiguration({
|
|
|
3259
3493
|
}) })
|
|
3260
3494
|
}
|
|
3261
3495
|
),
|
|
3262
|
-
|
|
3496
|
+
!basicConfig && maxSupportedResolution > 0 && /* @__PURE__ */ jsx(
|
|
3263
3497
|
FormField$2,
|
|
3264
3498
|
{
|
|
3265
3499
|
title: "Resolution Tier",
|
|
@@ -3299,9 +3533,9 @@ function UploadConfiguration({
|
|
|
3299
3533
|
}) })
|
|
3300
3534
|
}
|
|
3301
3535
|
),
|
|
3302
|
-
|
|
3536
|
+
!basicConfig && /* @__PURE__ */ jsx(FormField$2, { title: "Additional Configuration", children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
3303
3537
|
/* @__PURE__ */ jsx(PlaybackPolicy, { id, config, secrets, dispatch }),
|
|
3304
|
-
|
|
3538
|
+
!basicConfig && /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, padding: [0, 2], children: [
|
|
3305
3539
|
/* @__PURE__ */ jsx(
|
|
3306
3540
|
Checkbox,
|
|
3307
3541
|
{
|
|
@@ -3320,7 +3554,7 @@ function UploadConfiguration({
|
|
|
3320
3554
|
] })
|
|
3321
3555
|
] }) })
|
|
3322
3556
|
] }),
|
|
3323
|
-
!disableTextTrackConfig &&
|
|
3557
|
+
!disableTextTrackConfig && !basicConfig && /* @__PURE__ */ jsx(
|
|
3324
3558
|
TextTracksEditor,
|
|
3325
3559
|
{
|
|
3326
3560
|
tracks: config.text_tracks,
|
|
@@ -3331,7 +3565,7 @@ function UploadConfiguration({
|
|
|
3331
3565
|
/* @__PURE__ */ jsx(Box, { marginTop: 4, children: /* @__PURE__ */ jsx(
|
|
3332
3566
|
Button,
|
|
3333
3567
|
{
|
|
3334
|
-
disabled:
|
|
3568
|
+
disabled: !basicConfig && !config.public_policy && !config.signed_policy,
|
|
3335
3569
|
icon: UploadIcon,
|
|
3336
3570
|
text: "Upload",
|
|
3337
3571
|
tone: "positive",
|
|
@@ -3372,7 +3606,7 @@ function formatUploadConfig(config) {
|
|
|
3372
3606
|
mp4_support: config.mp4_support,
|
|
3373
3607
|
playback_policy: setPlaybackPolicy(config),
|
|
3374
3608
|
max_resolution_tier: config.max_resolution_tier,
|
|
3375
|
-
|
|
3609
|
+
video_quality: config.video_quality,
|
|
3376
3610
|
normalize_audio: config.normalize_audio
|
|
3377
3611
|
};
|
|
3378
3612
|
}
|
|
@@ -3789,7 +4023,7 @@ const Input = (props) => {
|
|
|
3789
4023
|
}
|
|
3790
4024
|
),
|
|
3791
4025
|
dialogState === "secrets" && hasConfigAccess && /* @__PURE__ */ jsx(
|
|
3792
|
-
|
|
4026
|
+
ConfigureApiDialog,
|
|
3793
4027
|
{
|
|
3794
4028
|
setDialogState,
|
|
3795
4029
|
secrets: secretDocumentValues.value.secrets
|
|
@@ -3913,6 +4147,10 @@ const muxVideoSchema = {
|
|
|
3913
4147
|
type: "string",
|
|
3914
4148
|
name: "encoding_tier"
|
|
3915
4149
|
},
|
|
4150
|
+
{
|
|
4151
|
+
type: "string",
|
|
4152
|
+
name: "video_quality"
|
|
4153
|
+
},
|
|
3916
4154
|
{
|
|
3917
4155
|
type: "string",
|
|
3918
4156
|
name: "master_access"
|
|
@@ -3991,13 +4229,17 @@ const muxVideoSchema = {
|
|
|
3991
4229
|
muxVideoAsset
|
|
3992
4230
|
], defaultConfig = {
|
|
3993
4231
|
mp4_support: "none",
|
|
3994
|
-
|
|
4232
|
+
video_quality: "plus",
|
|
3995
4233
|
max_resolution_tier: "1080p",
|
|
3996
4234
|
normalize_audio: !1,
|
|
3997
4235
|
defaultSigned: !1,
|
|
3998
4236
|
tool: DEFAULT_TOOL_CONFIG,
|
|
3999
4237
|
allowedRolesForConfiguration: []
|
|
4000
4238
|
}, muxInput = definePlugin((userConfig) => {
|
|
4239
|
+
if (typeof userConfig == "object" && "encoding_tier" in userConfig) {
|
|
4240
|
+
const deprecated_encoding_tier = userConfig.encoding_tier;
|
|
4241
|
+
userConfig.video_quality || (deprecated_encoding_tier === "baseline" && (userConfig.video_quality = "basic"), deprecated_encoding_tier === "smart" && (userConfig.video_quality = "plus"));
|
|
4242
|
+
}
|
|
4001
4243
|
const config = { ...defaultConfig, ...userConfig || {} };
|
|
4002
4244
|
return {
|
|
4003
4245
|
name: "mux-input",
|