sanity-plugin-mux-input 2.3.3 → 2.3.5

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/lib/index.esm.js DELETED
@@ -1,4275 +0,0 @@
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, PatchEvent, unset, setIfMissing, set, LinearProgress, FormField as FormField$2, definePlugin } from "sanity";
2
- import { jsx, jsxs, Fragment } from "react/jsx-runtime";
3
- import { ErrorOutlineIcon, RetrieveIcon, RetryIcon, CheckmarkCircleIcon, SortIcon, WarningOutlineIcon, EditIcon, PublishIcon, DocumentIcon, TrashIcon, CheckmarkIcon, RevertIcon, SearchIcon, ClockIcon, CropIcon, CalendarIcon, TagIcon, LockIcon, PlayIcon, PlugIcon, UploadIcon, ResetIcon, EllipsisHorizontalIcon, AddIcon, TranslateIcon, DocumentVideoIcon } from "@sanity/icons";
4
- import { Card, Box, Spinner, Stack, Text, Checkbox, Button, Dialog, Flex, Heading, Code, MenuButton, Menu, MenuItem, Tooltip, Inline, useToast, TabList, Tab, TabPanel, TextInput, Label as Label$1, Grid, useClickOutside, Popover, MenuDivider, Radio, Autocomplete, rem } from "@sanity/ui";
5
- import React, { useState, useMemo, useEffect, useRef, useId, memo, isValidElement, useCallback, useReducer, createElement, forwardRef, Suspense } from "react";
6
- import compact from "lodash/compact.js";
7
- import toLower from "lodash/toLower.js";
8
- import trim from "lodash/trim.js";
9
- import uniq from "lodash/uniq.js";
10
- import words from "lodash/words.js";
11
- import { styled, css } from "styled-components";
12
- import { uuid } from "@sanity/uuid";
13
- import { defer, timer, of, Observable, concat, throwError, from, Subject } from "rxjs";
14
- import { expand, concatMap, tap, switchMap, mergeMap, catchError, mergeMapTo, takeUntil } from "rxjs/operators";
15
- import { suspend, clear, preload } from "suspend-react";
16
- import MuxPlayer from "@mux/mux-player-react";
17
- import { usePaneRouter } from "sanity/desk";
18
- import { IntentLink } from "sanity/router";
19
- import isNumber from "lodash/isNumber.js";
20
- import isString from "lodash/isString.js";
21
- import { useMemoObservable } from "react-rx";
22
- import useSWR from "swr";
23
- import scrollIntoView from "scroll-into-view-if-needed";
24
- import { useErrorBoundary } from "use-error-boundary";
25
- import { UpChunk } from "@mux/upchunk";
26
- import { isValidElementType } from "react-is";
27
- import LanguagesList from "iso-639-1";
28
- const ToolIcon = () => /* @__PURE__ */ jsx(
29
- "svg",
30
- {
31
- stroke: "currentColor",
32
- fill: "currentColor",
33
- strokeWidth: "0",
34
- viewBox: "0 0 24 24",
35
- height: "1em",
36
- width: "1em",
37
- xmlns: "http://www.w3.org/2000/svg",
38
- children: /* @__PURE__ */ jsx("path", { d: "M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12zm-5-6l-7 4V7z" })
39
- }
40
- ), SANITY_API_VERSION = "2024-03-05";
41
- function useClient() {
42
- return useClient$1({ apiVersion: SANITY_API_VERSION });
43
- }
44
- const SPECIAL_CHARS = /([^!@#$%^&*(),\\/?";:{}|[\]+<>\s-])+/g, STRIP_EDGE_CHARS = /(^[.]+)|([.]+$)/;
45
- function tokenize(string) {
46
- return (string.match(SPECIAL_CHARS) || []).map((token) => token.replace(STRIP_EDGE_CHARS, ""));
47
- }
48
- function toGroqParams(terms) {
49
- const params = {};
50
- return terms.reduce((acc, term, i) => (acc[`t${i}`] = `*${term}*`, acc), params);
51
- }
52
- function extractTermsFromQuery(query) {
53
- const quotedQueries = [], unquotedQuery = query.replace(/("[^"]*")/g, (match) => words(match).length > 1 ? (quotedQueries.push(match), "") : match), quotedTerms = quotedQueries.map((str) => trim(toLower(str))), remainingTerms = uniq(compact(tokenize(toLower(unquotedQuery))));
54
- return [...quotedTerms, ...remainingTerms];
55
- }
56
- function createConstraints(terms, includeAssetId) {
57
- const searchPaths = includeAssetId ? ["filename", "assetId"] : ["filename"];
58
- return terms.map((_term, i) => searchPaths.map((joinedPath) => `${joinedPath} match $t${i}`)).filter((constraint) => constraint.length > 0).map((constraint) => `(${constraint.join(" || ")})`);
59
- }
60
- function createSearchFilter(query) {
61
- const terms = extractTermsFromQuery(query);
62
- return {
63
- filter: createConstraints(terms, query.length >= 8),
64
- // if the search is big enough, include the assetId (mux id) in the results
65
- params: {
66
- ...toGroqParams(terms)
67
- }
68
- };
69
- }
70
- const ASSET_SORT_OPTIONS = {
71
- createdDesc: { groq: "_createdAt desc", label: "Newest first" },
72
- createdAsc: { groq: "_createdAt asc", label: "First created (oldest)" },
73
- filenameAsc: { groq: "filename asc", label: "By filename (A-Z)" },
74
- filenameDesc: { groq: "filename desc", label: "By filename (Z-A)" }
75
- }, useAssetDocuments = createHookFromObservableFactory(({ documentStore, sort, searchQuery }) => {
76
- const search = createSearchFilter(searchQuery), filter = ['_type == "mux.videoAsset"', ...search.filter].filter(Boolean).join(" && "), sortFragment = ASSET_SORT_OPTIONS[sort].groq;
77
- return documentStore.listenQuery(
78
- /* groq */
79
- `*[${filter}] | order(${sortFragment})`,
80
- search.params,
81
- {
82
- apiVersion: SANITY_API_VERSION
83
- }
84
- );
85
- });
86
- function useAssets() {
87
- const documentStore = useDocumentStore(), [sort, setSort] = useState("createdDesc"), [searchQuery, setSearchQuery] = useState(""), [assetDocuments = [], isLoading] = useAssetDocuments({ documentStore, sort, searchQuery });
88
- return {
89
- assets: useMemo(
90
- () => (
91
- // Avoid displaying both drafts & published assets by collating them together and giving preference to drafts
92
- collate(assetDocuments).map(
93
- (collated) => ({
94
- ...collated.draft || collated.published || {},
95
- _id: collated.id
96
- })
97
- )
98
- ),
99
- [assetDocuments]
100
- ),
101
- isLoading,
102
- sort,
103
- searchQuery,
104
- setSort,
105
- setSearchQuery
106
- };
107
- }
108
- function parseMuxDate(date) {
109
- return new Date(Number(date) * 1e3);
110
- }
111
- const FIRST_PAGE = 1, ASSETS_PER_PAGE = 100;
112
- async function fetchMuxAssetsPage({ secretKey, token }, pageNum) {
113
- try {
114
- const json = await (await fetch(
115
- `https://api.mux.com/video/v1/assets?limit=${ASSETS_PER_PAGE}&page=${pageNum}`,
116
- {
117
- headers: {
118
- Authorization: `Basic ${btoa(`${token}:${secretKey}`)}`
119
- }
120
- }
121
- )).json();
122
- return json.error ? {
123
- pageNum,
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
- };
137
- }
138
- }
139
- function accumulateIntermediateState(currentState, pageResult) {
140
- const currentData = "data" in currentState && currentState.data || [];
141
- return {
142
- ...currentState,
143
- data: [
144
- ...currentData,
145
- ...("data" in pageResult && pageResult.data || []).filter(
146
- // De-duplicate assets for safety
147
- (asset) => !currentData.some((a) => a.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;
160
- }
161
- function useMuxAssets({ secrets, enabled }) {
162
- const [state, setState] = useState({ loading: !0, pageNum: FIRST_PAGE });
163
- return useEffect(() => {
164
- if (!enabled)
165
- return;
166
- const subscription = defer(
167
- () => fetchMuxAssetsPage(
168
- secrets,
169
- // When we've already successfully loaded before (fully or partially), we start from the following page to avoid re-fetching
170
- "data" in state && state.data && state.data.length > 0 && !state.error ? state.pageNum + 1 : state.pageNum
171
- )
172
- ).pipe(
173
- // Here we replace "concatMap" with "expand" to recursively fetch next pages
174
- expand((pageResult) => hasMorePages(pageResult) ? timer(2e3).pipe(
175
- // eslint-disable-next-line max-nested-callbacks
176
- concatMap(() => defer(() => fetchMuxAssetsPage(secrets, pageResult.pageNum + 1)))
177
- ) : of()),
178
- // On each iteration, persist intermediate states to give feedback to users
179
- tap(
180
- (pageResult) => setState((prevState) => accumulateIntermediateState(prevState, pageResult))
181
- )
182
- ).subscribe({
183
- // Once done, let the user know we've stopped loading
184
- complete: () => {
185
- setState((prev) => ({
186
- ...prev,
187
- loading: !1
188
- }));
189
- }
190
- });
191
- return () => subscription.unsubscribe();
192
- }, [enabled]), state;
193
- }
194
- const 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, path$1 = ["token", "secretKey", "enableSignedUrls", "signingKeyId", "signingKeyPrivate"], useSecretsDocumentValues = () => {
195
- const { error, isLoading, value } = useDocumentValues(
196
- muxSecretsDocumentId,
197
- path$1
198
- ), cache = useMemo(() => {
199
- const exists = !!value, secrets = {
200
- token: (value == null ? void 0 : value.token) || null,
201
- secretKey: (value == null ? void 0 : value.secretKey) || null,
202
- enableSignedUrls: (value == null ? void 0 : value.enableSignedUrls) || !1,
203
- signingKeyId: (value == null ? void 0 : value.signingKeyId) || null,
204
- signingKeyPrivate: (value == null ? void 0 : value.signingKeyPrivate) || null
205
- };
206
- return {
207
- isInitialSetup: !exists,
208
- needsSetup: !(secrets != null && secrets.token) || !(secrets != null && secrets.secretKey),
209
- secrets
210
- };
211
- }, [value]);
212
- return { error, isLoading, value: cache };
213
- };
214
- function useImportMuxAssets() {
215
- var _a;
216
- const documentStore = useDocumentStore(), client = useClient$1({
217
- apiVersion: SANITY_API_VERSION
218
- }), [assetsInSanity, assetsInSanityLoading] = useAssetsInSanity(documentStore), secretDocumentValues = useSecretsDocumentValues(), hasSecrets = !!((_a = secretDocumentValues.value.secrets) != null && _a.secretKey), [importError, setImportError] = useState(), [importState, setImportState] = useState("closed"), dialogOpen = importState !== "closed", muxAssets = useMuxAssets({
219
- secrets: secretDocumentValues.value.secrets,
220
- enabled: hasSecrets && dialogOpen
221
- }), missingAssets = useMemo(() => assetsInSanity && muxAssets.data ? muxAssets.data.filter((a) => !assetExistsInSanity(a, assetsInSanity)) : void 0, [assetsInSanity, muxAssets.data]), [selectedAssets, setSelectedAssets] = useState([]), closeDialog = () => {
222
- importState !== "importing" && setImportState("closed");
223
- }, openDialog = () => {
224
- importState === "closed" && setImportState("idle");
225
- };
226
- async function importAssets() {
227
- setImportState("importing");
228
- const documents = selectedAssets.map(muxAssetToSanityDocument), tx = client.transaction();
229
- documents.forEach((doc) => tx.create(doc));
230
- try {
231
- await tx.commit({ returnDocuments: !1 }), setSelectedAssets([]), setImportState("done");
232
- } catch (error) {
233
- setImportState("error"), setImportError(error);
234
- }
235
- }
236
- return {
237
- assetsInSanityLoading,
238
- closeDialog,
239
- dialogOpen,
240
- importState,
241
- importError,
242
- hasSecrets,
243
- importAssets,
244
- missingAssets,
245
- muxAssets,
246
- openDialog,
247
- selectedAssets,
248
- setSelectedAssets
249
- };
250
- }
251
- function muxAssetToSanityDocument(asset) {
252
- var _a;
253
- return {
254
- _id: uuid(),
255
- _type: "mux.videoAsset",
256
- _updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
257
- _createdAt: parseMuxDate(asset.created_at).toISOString(),
258
- assetId: asset.id,
259
- playbackId: (_a = asset.playback_ids.find((p) => p.id)) == null ? void 0 : _a.id,
260
- filename: `Asset #${truncateString(asset.id, 15)}`,
261
- status: asset.status,
262
- data: asset
263
- };
264
- }
265
- const useAssetsInSanity = createHookFromObservableFactory(
266
- (documentStore) => documentStore.listenQuery(
267
- /* groq */
268
- `*[_type == "mux.videoAsset"] {
269
- "uploadId": coalesce(uploadId, data.upload_id),
270
- "assetId": coalesce(assetId, data.id),
271
- }`,
272
- {},
273
- {
274
- apiVersion: SANITY_API_VERSION
275
- }
276
- )
277
- );
278
- function assetExistsInSanity(asset, existingAssets) {
279
- return asset.status !== "ready" ? !1 : existingAssets.some(
280
- (existing) => existing.assetId === asset.id || existing.uploadId === asset.upload_id
281
- );
282
- }
283
- function useInView(options = {}) {
284
- const [inView, setInView] = useState(!1), ref = useRef(null);
285
- return useEffect(() => {
286
- if (!ref.current)
287
- return;
288
- const observer = new IntersectionObserver(([entry], obs) => {
289
- var _a;
290
- const nowInView = entry.isIntersecting && obs.thresholds.some((threshold) => entry.intersectionRatio >= threshold);
291
- setInView(nowInView), (_a = options == null ? void 0 : options.onChange) == null || _a.call(options, nowInView);
292
- }, options), toObserve = ref.current;
293
- return observer.observe(toObserve), () => {
294
- toObserve && observer.unobserve(toObserve);
295
- };
296
- }, [options]), { inView, ref };
297
- }
298
- const _id = "secrets.mux";
299
- function readSecrets(client) {
300
- const { projectId, dataset } = client.config();
301
- return suspend(async () => {
302
- const data = await client.fetch(
303
- /* groq */
304
- `*[_id == $_id][0]{
305
- token,
306
- secretKey,
307
- enableSignedUrls,
308
- signingKeyId,
309
- signingKeyPrivate
310
- }`,
311
- { _id }
312
- );
313
- return {
314
- token: (data == null ? void 0 : data.token) || null,
315
- secretKey: (data == null ? void 0 : data.secretKey) || null,
316
- enableSignedUrls: !!(data != null && data.enableSignedUrls) || !1,
317
- signingKeyId: (data == null ? void 0 : data.signingKeyId) || null,
318
- signingKeyPrivate: (data == null ? void 0 : data.signingKeyPrivate) || null
319
- };
320
- }, [cacheNs, _id, projectId, dataset]);
321
- }
322
- function generateJwt(client, playbackId, aud, payload) {
323
- const { signingKeyId, signingKeyPrivate } = readSecrets(client);
324
- if (!signingKeyId)
325
- throw new TypeError("Missing signingKeyId");
326
- if (!signingKeyPrivate)
327
- throw new TypeError("Missing signingKeyPrivate");
328
- const { default: sign } = suspend(() => import("jsonwebtoken-esm/sign"), ["jsonwebtoken-esm/sign"]);
329
- return sign(
330
- payload ? JSON.parse(JSON.stringify(payload, (_, v) => v != null ? v : void 0)) : {},
331
- atob(signingKeyPrivate),
332
- {
333
- algorithm: "RS256",
334
- keyid: signingKeyId,
335
- audience: aud,
336
- subject: playbackId,
337
- noTimestamp: !0,
338
- expiresIn: "12h"
339
- }
340
- );
341
- }
342
- function getPlaybackId(asset) {
343
- if (!(asset != null && asset.playbackId))
344
- throw console.error("Asset is missing a playbackId", { asset }), new TypeError("Missing playbackId");
345
- return asset.playbackId;
346
- }
347
- function getPlaybackPolicy(asset) {
348
- var _a, _b, _c, _d;
349
- return (_d = (_c = (_b = (_a = asset.data) == null ? void 0 : _a.playback_ids) == null ? void 0 : _b[0]) == null ? void 0 : _c.policy) != null ? _d : "public";
350
- }
351
- function getAnimatedPosterSrc({
352
- asset,
353
- client,
354
- height,
355
- width,
356
- start = asset.thumbTime ? Math.max(0, asset.thumbTime - 2.5) : 0,
357
- end = start + 5,
358
- fps = 15
359
- }) {
360
- const params = { height, width, start, end, fps }, playbackId = getPlaybackId(asset);
361
- let searchParams = new URLSearchParams(
362
- JSON.parse(JSON.stringify(params, (_, v) => v != null ? v : void 0))
363
- );
364
- if (getPlaybackPolicy(asset) === "signed") {
365
- const token = generateJwt(client, playbackId, "g", params);
366
- searchParams = new URLSearchParams({ token });
367
- }
368
- return `https://image.mux.com/${playbackId}/animated.gif?${searchParams}`;
369
- }
370
- const Image = styled.img`
371
- transition: opacity 0.175s ease-out 0s;
372
- display: block;
373
- width: 100%;
374
- height: 100%;
375
- object-fit: contain;
376
- object-position: center center;
377
- `, STATUS_TO_TONE = {
378
- loading: "transparent",
379
- error: "critical",
380
- loaded: "default"
381
- };
382
- function VideoThumbnail({
383
- asset,
384
- width
385
- }) {
386
- const { inView, ref } = useInView(), posterWidth = width || 250, [status, setStatus] = useState("loading"), client = useClient(), animatedSrc = useMemo(() => {
387
- try {
388
- return getAnimatedPosterSrc({ asset, client, width: posterWidth });
389
- } catch {
390
- status !== "error" && setStatus("error");
391
- return;
392
- }
393
- }, [asset, client, width, status, setStatus]);
394
- function handleLoad() {
395
- setStatus("loaded");
396
- }
397
- function handleError() {
398
- setStatus("error");
399
- }
400
- return /* @__PURE__ */ jsx(
401
- Card,
402
- {
403
- style: {
404
- aspectRatio: THUMBNAIL_ASPECT_RATIO,
405
- position: "relative",
406
- maxWidth: width ? `${width}px` : void 0,
407
- width: "100%",
408
- flex: 1
409
- },
410
- border: !0,
411
- radius: 2,
412
- ref,
413
- tone: STATUS_TO_TONE[status],
414
- children: inView ? /* @__PURE__ */ jsxs(Fragment, { children: [
415
- status === "loading" && /* @__PURE__ */ jsx(
416
- Box,
417
- {
418
- style: {
419
- position: "absolute",
420
- left: "50%",
421
- top: "50%",
422
- transform: "translate(-50%, -50%)"
423
- },
424
- children: /* @__PURE__ */ jsx(Spinner, {})
425
- }
426
- ),
427
- status === "error" && /* @__PURE__ */ jsxs(
428
- Stack,
429
- {
430
- space: 4,
431
- style: {
432
- position: "absolute",
433
- width: "100%",
434
- left: 0,
435
- top: "50%",
436
- transform: "translateY(-50%)",
437
- justifyItems: "center"
438
- },
439
- children: [
440
- /* @__PURE__ */ jsx(Text, { size: 4, muted: !0, children: /* @__PURE__ */ jsx(ErrorOutlineIcon, { style: { fontSize: "1.75em" } }) }),
441
- /* @__PURE__ */ jsx(Text, { muted: !0, align: "center", children: "Failed loading thumbnail" })
442
- ]
443
- }
444
- ),
445
- /* @__PURE__ */ jsx(
446
- Image,
447
- {
448
- src: animatedSrc,
449
- alt: `Preview for video ${asset.filename || asset.assetId}`,
450
- onLoad: handleLoad,
451
- onError: handleError,
452
- style: {
453
- opacity: status === "loaded" ? 1 : 0
454
- }
455
- }
456
- )
457
- ] }) : null
458
- }
459
- );
460
- }
461
- const MissingAssetCheckbox = styled(Checkbox)`
462
- position: static !important;
463
-
464
- input::after {
465
- content: '';
466
- position: absolute;
467
- inset: 0;
468
- display: block;
469
- cursor: pointer;
470
- z-index: 1000;
471
- }
472
- `;
473
- function MissingAsset({
474
- asset,
475
- selectAsset,
476
- selected
477
- }) {
478
- var _a;
479
- const duration = useFormattedDuration(asset.duration * 1e3);
480
- return /* @__PURE__ */ jsx(
481
- Card,
482
- {
483
- tone: selected ? "positive" : void 0,
484
- border: !0,
485
- paddingX: 2,
486
- paddingY: 3,
487
- style: { position: "relative" },
488
- radius: 1,
489
- children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
490
- /* @__PURE__ */ jsx(
491
- MissingAssetCheckbox,
492
- {
493
- checked: selected,
494
- onChange: (e) => {
495
- selectAsset(e.currentTarget.checked);
496
- },
497
- "aria-label": selected ? `Import video ${asset.id}` : `Skip import of video ${asset.id}`
498
- }
499
- ),
500
- /* @__PURE__ */ jsx(
501
- VideoThumbnail,
502
- {
503
- asset: {
504
- assetId: asset.id,
505
- data: asset,
506
- filename: asset.id,
507
- playbackId: (_a = asset.playback_ids.find((p) => p.id)) == null ? void 0 : _a.id
508
- },
509
- width: 150
510
- }
511
- ),
512
- /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
513
- /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 1, children: [
514
- /* @__PURE__ */ jsx(Code, { size: 2, children: truncateString(asset.id, 15) }),
515
- " ",
516
- /* @__PURE__ */ jsxs(Text, { muted: !0, size: 2, children: [
517
- "(",
518
- duration.formatted,
519
- ")"
520
- ] })
521
- ] }),
522
- /* @__PURE__ */ jsxs(Text, { size: 1, children: [
523
- "Uploaded at",
524
- " ",
525
- new Date(Number(asset.created_at) * 1e3).toLocaleDateString("en", {
526
- year: "numeric",
527
- day: "2-digit",
528
- month: "2-digit"
529
- })
530
- ] })
531
- ] })
532
- ] })
533
- },
534
- asset.id
535
- );
536
- }
537
- function ImportVideosDialog(props) {
538
- var _a, _b;
539
- const { importState } = props, canTriggerImport = (importState === "idle" || importState === "error") && props.selectedAssets.length > 0, isImporting = importState === "importing", noAssetsToImport = ((_a = props.missingAssets) == null ? void 0 : _a.length) === 0 && !props.muxAssets.loading && !props.assetsInSanityLoading;
540
- return /* @__PURE__ */ jsx(
541
- Dialog,
542
- {
543
- animate: !0,
544
- header: "Import videos from Mux",
545
- zOffset: DIALOGS_Z_INDEX,
546
- id: "video-details-dialog",
547
- onClose: props.closeDialog,
548
- onClickOutside: props.closeDialog,
549
- width: 1,
550
- position: "fixed",
551
- footer: importState !== "done" && !noAssetsToImport && /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
552
- /* @__PURE__ */ jsx(
553
- Button,
554
- {
555
- fontSize: 2,
556
- padding: 3,
557
- mode: "bleed",
558
- text: "Cancel",
559
- tone: "critical",
560
- onClick: props.closeDialog,
561
- disabled: isImporting
562
- }
563
- ),
564
- props.missingAssets && /* @__PURE__ */ jsx(
565
- Button,
566
- {
567
- icon: RetrieveIcon,
568
- fontSize: 2,
569
- padding: 3,
570
- mode: "ghost",
571
- text: ((_b = props.selectedAssets) == null ? void 0 : _b.length) > 0 ? `Import ${props.selectedAssets.length} video(s)` : "No video(s) selected",
572
- tone: "positive",
573
- onClick: props.importAssets,
574
- iconRight: isImporting && Spinner,
575
- disabled: !canTriggerImport
576
- }
577
- )
578
- ] }) }),
579
- children: /* @__PURE__ */ jsxs(Box, { padding: 3, children: [
580
- (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: [
581
- /* @__PURE__ */ jsx(Spinner, { muted: !0, size: 4 }),
582
- /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
583
- /* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "Loading assets from Mux" }),
584
- /* @__PURE__ */ jsxs(Text, { size: 1, children: [
585
- "This may take a while.",
586
- props.missingAssets && props.missingAssets.length > 0 && ` There are at least ${props.missingAssets.length} video${props.missingAssets.length > 1 ? "s" : ""} currently not in Sanity...`
587
- ] })
588
- ] })
589
- ] }) }),
590
- props.muxAssets.error && /* @__PURE__ */ jsx(Card, { tone: "critical", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
591
- /* @__PURE__ */ jsx(ErrorOutlineIcon, { fontSize: 36 }),
592
- /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
593
- /* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "There was an error getting all data from Mux" }),
594
- /* @__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." })
595
- ] })
596
- ] }) }),
597
- importState === "importing" && /* @__PURE__ */ jsx(Card, { tone: "primary", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 4, children: [
598
- /* @__PURE__ */ jsx(Spinner, { muted: !0, size: 4 }),
599
- /* @__PURE__ */ jsx(Stack, { space: 2, children: /* @__PURE__ */ jsxs(Text, { size: 2, weight: "semibold", children: [
600
- "Importing ",
601
- props.selectedAssets.length,
602
- " video",
603
- props.selectedAssets.length > 1 && "s",
604
- " from Mux"
605
- ] }) })
606
- ] }) }),
607
- importState === "error" && /* @__PURE__ */ jsx(Card, { tone: "critical", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
608
- /* @__PURE__ */ jsx(ErrorOutlineIcon, { fontSize: 36 }),
609
- /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
610
- /* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "There was an error importing videos" }),
611
- /* @__PURE__ */ jsx(Text, { size: 1, children: props.importError ? `Error: ${props.importError}` : "Please try again or contact a developer for help." }),
612
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
613
- Button,
614
- {
615
- icon: RetryIcon,
616
- text: "Retry",
617
- tone: "primary",
618
- onClick: props.importAssets
619
- }
620
- ) })
621
- ] })
622
- ] }) }),
623
- (noAssetsToImport || importState === "done") && /* @__PURE__ */ jsxs(Stack, { paddingY: 5, marginBottom: 4, space: 3, style: { textAlign: "center" }, children: [
624
- /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(CheckmarkCircleIcon, { fontSize: 48 }) }),
625
- /* @__PURE__ */ jsx(Heading, { size: 2, children: importState === "done" ? "Videos imported successfully" : "There are no Mux videos to import" }),
626
- /* @__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." })
627
- ] }),
628
- props.missingAssets && props.missingAssets.length > 0 && (importState === "idle" || importState === "error") && /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
629
- /* @__PURE__ */ jsxs(Heading, { size: 1, children: [
630
- "There are ",
631
- props.missingAssets.length,
632
- props.muxAssets.loading && "+",
633
- " Mux video",
634
- props.missingAssets.length > 1 && "s",
635
- " ",
636
- "not in Sanity"
637
- ] }),
638
- !props.muxAssets.loading && /* @__PURE__ */ jsxs(Flex, { align: "center", paddingX: 2, children: [
639
- /* @__PURE__ */ jsx(
640
- Checkbox,
641
- {
642
- id: "import-all",
643
- style: { display: "block" },
644
- onClick: (e) => {
645
- e.currentTarget.checked ? props.missingAssets && props.setSelectedAssets(props.missingAssets) : props.setSelectedAssets([]);
646
- },
647
- checked: props.selectedAssets.length === props.missingAssets.length
648
- }
649
- ),
650
- /* @__PURE__ */ jsx(Box, { flex: 1, paddingLeft: 3, as: "label", htmlFor: "import-all", children: /* @__PURE__ */ jsx(Text, { children: "Import all" }) })
651
- ] }),
652
- props.missingAssets.map((asset) => /* @__PURE__ */ jsx(
653
- MissingAsset,
654
- {
655
- asset,
656
- selectAsset: (selected) => {
657
- selected ? props.setSelectedAssets([...props.selectedAssets, asset]) : props.setSelectedAssets(props.selectedAssets.filter((a) => a.id !== asset.id));
658
- },
659
- selected: props.selectedAssets.some((a) => a.id === asset.id)
660
- },
661
- asset.id
662
- ))
663
- ] })
664
- ] })
665
- }
666
- );
667
- }
668
- function ImportVideosFromMux() {
669
- const importAssets = useImportMuxAssets();
670
- if (importAssets.hasSecrets)
671
- return importAssets.dialogOpen ? /* @__PURE__ */ jsx(ImportVideosDialog, { ...importAssets }) : /* @__PURE__ */ jsx(Button, { mode: "bleed", text: "Import from Mux", onClick: importAssets.openDialog });
672
- }
673
- const CONTEXT_MENU_POPOVER_PROPS = {
674
- constrainSize: !0,
675
- placement: "bottom",
676
- portal: !0,
677
- width: 0
678
- };
679
- function SelectSortOptions(props) {
680
- const id = useId();
681
- return /* @__PURE__ */ jsx(
682
- MenuButton,
683
- {
684
- button: /* @__PURE__ */ jsx(Button, { text: "Sort", icon: SortIcon, mode: "bleed", padding: 3, style: { cursor: "pointer" } }),
685
- id,
686
- menu: /* @__PURE__ */ jsx(Menu, { children: Object.entries(ASSET_SORT_OPTIONS).map(([type, { label }]) => /* @__PURE__ */ jsx(
687
- MenuItem,
688
- {
689
- "data-as": "button",
690
- onClick: () => props.setSort(type),
691
- padding: 3,
692
- tone: "default",
693
- text: label,
694
- pressed: type === props.sort
695
- },
696
- type
697
- )) }),
698
- popover: CONTEXT_MENU_POPOVER_PROPS
699
- }
700
- );
701
- }
702
- const SpinnerBox = () => /* @__PURE__ */ jsx(
703
- Box,
704
- {
705
- style: {
706
- display: "flex",
707
- alignItems: "center",
708
- justifyContent: "center",
709
- minHeight: "150px"
710
- },
711
- children: /* @__PURE__ */ jsx(Spinner, {})
712
- }
713
- );
714
- function FormField(props) {
715
- const { children, title, description, inputId } = props;
716
- return /* @__PURE__ */ jsxs(Stack, { space: 1, children: [
717
- /* @__PURE__ */ jsx(Flex, { align: "flex-end", children: /* @__PURE__ */ jsx(Box, { flex: 1, paddingY: 2, children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
718
- /* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, weight: "semibold", size: 1, children: title || /* @__PURE__ */ jsx("em", { children: "Untitled" }) }),
719
- description && /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: description })
720
- ] }) }) }),
721
- /* @__PURE__ */ jsx("div", { children })
722
- ] });
723
- }
724
- var FormField$1 = memo(FormField);
725
- const IconInfo = (props) => {
726
- const Icon = props.icon;
727
- return /* @__PURE__ */ jsxs(Flex, { gap: 2, align: "center", padding: 1, children: [
728
- /* @__PURE__ */ jsx(Text, { size: (props.size || 1) + 1, muted: !0, children: /* @__PURE__ */ jsx(Icon, {}) }),
729
- /* @__PURE__ */ jsx(Text, { size: props.size || 1, muted: props.muted, children: props.text })
730
- ] });
731
- };
732
- function ResolutionIcon(props) {
733
- return /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 24 24", ...props, children: /* @__PURE__ */ jsx(
734
- "path",
735
- {
736
- fill: "currentColor",
737
- d: "M20 9V6h-3V4h5v5h-2ZM2 9V4h5v2H4v3H2Zm15 11v-2h3v-3h2v5h-5ZM2 20v-5h2v3h3v2H2Zm4-4V8h12v8H6Zm2-2h8v-4H8v4Zm0 0v-4v4Z"
738
- }
739
- ) });
740
- }
741
- function StopWatchIcon(props) {
742
- return /* @__PURE__ */ jsxs(
743
- "svg",
744
- {
745
- xmlns: "http://www.w3.org/2000/svg",
746
- width: "1em",
747
- height: "1em",
748
- viewBox: "0 0 512 512",
749
- ...props,
750
- children: [
751
- /* @__PURE__ */ jsx("path", { d: "M232 306.667h48V176h-48v130.667z", fill: "currentColor" }),
752
- /* @__PURE__ */ jsx(
753
- "path",
754
- {
755
- 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",
756
- fill: "currentColor"
757
- }
758
- ),
759
- /* @__PURE__ */ jsx("path", { d: "M192 32h128v48H192z", fill: "currentColor" })
760
- ]
761
- }
762
- );
763
- }
764
- function getVideoSrc({ asset, client }) {
765
- const playbackId = getPlaybackId(asset), searchParams = new URLSearchParams();
766
- if (getPlaybackPolicy(asset) === "signed") {
767
- const token = generateJwt(client, playbackId, "v");
768
- searchParams.set("token", token);
769
- }
770
- return `https://stream.mux.com/${playbackId}.m3u8?${searchParams}`;
771
- }
772
- function VideoPlayer({
773
- asset,
774
- children,
775
- ...props
776
- }) {
777
- var _a, _b;
778
- const client = useClient(), { src: videoSrc, error } = useMemo(() => {
779
- try {
780
- const src = (asset == null ? void 0 : asset.playbackId) && getVideoSrc({ client, asset });
781
- return src ? { src } : { error: new TypeError("Asset has no playback ID") };
782
- } catch (error2) {
783
- return { error: error2 };
784
- }
785
- }, [asset, client]), signedToken = useMemo(() => {
786
- try {
787
- return new URL(videoSrc).searchParams.get("token");
788
- } catch {
789
- return !1;
790
- }
791
- }, [videoSrc]), [width, height] = ((_b = (_a = asset == null ? void 0 : asset.data) == null ? void 0 : _a.aspect_ratio) != null ? _b : "16:9").split(":").map(Number), targetAspectRatio = props.forceAspectRatio || (Number.isNaN(width) ? 16 / 9 : width / height), aspectRatio = Math.max(MIN_ASPECT_RATIO, targetAspectRatio);
792
- return /* @__PURE__ */ jsxs(Card, { tone: "transparent", style: { aspectRatio, position: "relative" }, children: [
793
- videoSrc && /* @__PURE__ */ jsxs(Fragment, { children: [
794
- /* @__PURE__ */ jsx(
795
- MuxPlayer,
796
- {
797
- ...props,
798
- playsInline: !0,
799
- playbackId: asset.playbackId,
800
- tokens: signedToken ? { playback: signedToken, thumbnail: signedToken, storyboard: signedToken } : void 0,
801
- preload: "metadata",
802
- crossOrigin: "anonymous",
803
- metadata: {
804
- player_name: "Sanity Admin Dashboard",
805
- player_version: "2.3.3",
806
- page_type: "Preview Player"
807
- },
808
- style: {
809
- height: "100%",
810
- width: "100%",
811
- display: "block",
812
- objectFit: "contain"
813
- }
814
- }
815
- ),
816
- children
817
- ] }),
818
- error ? /* @__PURE__ */ jsx(
819
- "div",
820
- {
821
- style: {
822
- position: "absolute",
823
- top: "50%",
824
- left: "50%",
825
- transform: "translate(-50%, -50%)"
826
- },
827
- children: /* @__PURE__ */ jsxs(Text, { muted: !0, children: [
828
- /* @__PURE__ */ jsx(ErrorOutlineIcon, { style: { marginRight: "0.15em" } }),
829
- typeof error == "object" && "message" in error && typeof error.message == "string" ? error.message : "Error loading video"
830
- ] })
831
- }
832
- ) : null,
833
- children
834
- ] });
835
- }
836
- function deleteAssetOnMux(client, assetId) {
837
- const { dataset } = client.config();
838
- return client.request({
839
- url: `/addons/mux/assets/${dataset}/${assetId}`,
840
- withCredentials: !0,
841
- method: "DELETE"
842
- });
843
- }
844
- async function deleteAsset({
845
- client,
846
- asset,
847
- deleteOnMux
848
- }) {
849
- if (!(asset != null && asset._id))
850
- return !0;
851
- try {
852
- await client.delete(asset._id);
853
- } catch {
854
- return "failed-sanity";
855
- }
856
- if (deleteOnMux && asset != null && asset.assetId)
857
- try {
858
- await deleteAssetOnMux(client, asset.assetId);
859
- } catch {
860
- return "failed-mux";
861
- }
862
- return !0;
863
- }
864
- function getAsset(client, assetId) {
865
- const { dataset } = client.config();
866
- return client.request({
867
- url: `/addons/mux/assets/${dataset}/data/${assetId}`,
868
- withCredentials: !0,
869
- method: "GET"
870
- });
871
- }
872
- const getUnknownTypeFallback = (id, typeName) => ({
873
- title: /* @__PURE__ */ jsxs("em", { children: [
874
- "No schema found for type ",
875
- /* @__PURE__ */ jsx("code", { children: typeName })
876
- ] }),
877
- subtitle: /* @__PURE__ */ jsxs("em", { children: [
878
- "Document: ",
879
- /* @__PURE__ */ jsx("code", { children: id })
880
- ] }),
881
- media: () => /* @__PURE__ */ jsx(WarningOutlineIcon, {})
882
- });
883
- function MissingSchemaType(props) {
884
- const { layout, value } = props;
885
- return /* @__PURE__ */ jsx(SanityDefaultPreview, { ...getUnknownTypeFallback(value._id, value._type), layout });
886
- }
887
- function TimeAgo({ time }) {
888
- const timeAgo = useTimeAgo(time);
889
- return /* @__PURE__ */ jsxs("span", { title: timeAgo, children: [
890
- timeAgo,
891
- " ago"
892
- ] });
893
- }
894
- function DraftStatus(props) {
895
- const { document: document2 } = props, updatedAt = document2 && "_updatedAt" in document2 && document2._updatedAt;
896
- return /* @__PURE__ */ jsx(
897
- Tooltip,
898
- {
899
- animate: !0,
900
- portal: !0,
901
- content: /* @__PURE__ */ jsx(Box, { padding: 2, children: /* @__PURE__ */ jsx(Text, { size: 1, children: document2 ? /* @__PURE__ */ jsxs(Fragment, { children: [
902
- "Edited ",
903
- updatedAt && /* @__PURE__ */ jsx(TimeAgo, { time: updatedAt })
904
- ] }) : /* @__PURE__ */ jsx(Fragment, { children: "No unpublished edits" }) }) }),
905
- children: /* @__PURE__ */ jsx(TextWithTone, { tone: "caution", dimmed: !document2, muted: !document2, size: 1, children: /* @__PURE__ */ jsx(EditIcon, {}) })
906
- }
907
- );
908
- }
909
- function PublishedStatus(props) {
910
- const { document: document2 } = props, updatedAt = document2 && "_updatedAt" in document2 && document2._updatedAt;
911
- return /* @__PURE__ */ jsx(
912
- Tooltip,
913
- {
914
- animate: !0,
915
- portal: !0,
916
- content: /* @__PURE__ */ jsx(Box, { padding: 2, children: /* @__PURE__ */ jsx(Text, { size: 1, children: document2 ? /* @__PURE__ */ jsxs(Fragment, { children: [
917
- "Published ",
918
- updatedAt && /* @__PURE__ */ jsx(TimeAgo, { time: updatedAt })
919
- ] }) : /* @__PURE__ */ jsx(Fragment, { children: "Not published" }) }) }),
920
- children: /* @__PURE__ */ jsx(TextWithTone, { tone: "positive", dimmed: !document2, muted: !document2, size: 1, children: /* @__PURE__ */ jsx(PublishIcon, {}) })
921
- }
922
- );
923
- }
924
- function PaneItemPreview(props) {
925
- const { icon, layout, presence, schemaType, value } = props, title = isRecord(value.title) && isValidElement(value.title) || isString(value.title) || isNumber(value.title) ? value.title : null, { draft, published, isLoading } = useMemoObservable(
926
- () => getPreviewStateObservable(props.documentPreviewStore, schemaType, value._id, title),
927
- [props.documentPreviewStore, schemaType, value._id, title]
928
- ), status = isLoading ? null : /* @__PURE__ */ jsxs(Inline, { space: 4, children: [
929
- presence && presence.length > 0 && /* @__PURE__ */ jsx(DocumentPreviewPresence, { presence }),
930
- /* @__PURE__ */ jsx(PublishedStatus, { document: published }),
931
- /* @__PURE__ */ jsx(DraftStatus, { document: draft })
932
- ] });
933
- return /* @__PURE__ */ jsx(
934
- SanityDefaultPreview,
935
- {
936
- ...getPreviewValueWithFallback({ value, draft, published }),
937
- isPlaceholder: isLoading,
938
- icon,
939
- layout,
940
- status
941
- }
942
- );
943
- }
944
- function getIconWithFallback(icon, schemaType, defaultIcon) {
945
- return icon === !1 ? !1 : icon || schemaType && schemaType.icon || defaultIcon || !1;
946
- }
947
- function DocumentPreviewInInput(props) {
948
- const { ChildLink } = usePaneRouter();
949
- return (linkProps) => /* @__PURE__ */ jsx(
950
- ChildLink,
951
- {
952
- childId: props.documentPair.id,
953
- childParameters: { type: props.documentPair.type },
954
- children: linkProps.children
955
- }
956
- );
957
- }
958
- function DocumentPreviewInRool(props) {
959
- return (linkProps) => /* @__PURE__ */ jsx(IntentLink, { intent: "edit", params: { id: props.documentPair.id }, children: linkProps.children });
960
- }
961
- function DocumentPreview(props) {
962
- const { schemaType, documentPair } = props, doc = (documentPair == null ? void 0 : documentPair.draft) || (documentPair == null ? void 0 : 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(
963
- PaneItemPreview,
964
- {
965
- documentPreviewStore,
966
- icon: getIconWithFallback(void 0, schemaType, DocumentIcon),
967
- schemaType,
968
- layout: "default",
969
- value: doc,
970
- presence: documentPresence
971
- }
972
- ) : null, [hasSchemaType, schemaType, documentPresence, doc, documentPreviewStore]);
973
- return /* @__PURE__ */ jsx(
974
- PreviewCard,
975
- {
976
- __unstable_focusRing: !0,
977
- as: props.placement === "input" ? DocumentPreviewInInput(props) : DocumentPreviewInRool(props),
978
- "data-as": "a",
979
- "data-ui": "PaneItem",
980
- padding: 2,
981
- radius: 2,
982
- tone: "inherit",
983
- children: PreviewComponent
984
- }
985
- );
986
- }
987
- const Container = styled(Box)`
988
- * {
989
- color: ${(props) => props.theme.sanity.color.base.fg};
990
- }
991
- a {
992
- text-decoration: none;
993
- }
994
- h2 {
995
- font-size: ${(props) => props.theme.sanity.fonts.text.sizes[1]};
996
- }
997
- `, VideoReferences = (props) => {
998
- var _a;
999
- const schema = useSchema();
1000
- if (!props.isLoaded)
1001
- return /* @__PURE__ */ jsx(SpinnerBox, {});
1002
- if (!((_a = props.references) != null && _a.length))
1003
- return /* @__PURE__ */ jsx(Card, { border: !0, radius: 3, padding: 3, children: /* @__PURE__ */ jsx(Text, { size: 2, children: "No documents are using this video" }) });
1004
- const documentPairs = collate(props.references || []);
1005
- return /* @__PURE__ */ jsx(Container, { children: documentPairs == null ? void 0 : documentPairs.map((documentPair) => {
1006
- const schemaType = schema.get(documentPair.type);
1007
- return /* @__PURE__ */ jsx(
1008
- Card,
1009
- {
1010
- marginBottom: 2,
1011
- padding: 2,
1012
- radius: 2,
1013
- shadow: 1,
1014
- style: { overflow: "hidden" },
1015
- children: /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
1016
- DocumentPreview,
1017
- {
1018
- documentPair,
1019
- schemaType,
1020
- placement: props.placement
1021
- }
1022
- ) })
1023
- },
1024
- documentPair.id
1025
- );
1026
- }) });
1027
- };
1028
- function DeleteDialog({
1029
- asset,
1030
- references,
1031
- referencesLoading,
1032
- cancelDelete,
1033
- placement,
1034
- succeededDeleting
1035
- }) {
1036
- const client = useClient(), [state, setState] = useState("checkingReferences"), [deleteOnMux, setDeleteOnMux] = useState(!0), toast = useToast();
1037
- useEffect(() => {
1038
- state !== "checkingReferences" || referencesLoading || setState(references != null && references.length ? "cantDelete" : "confirm");
1039
- }, [state, references, referencesLoading]);
1040
- async function confirmDelete() {
1041
- if (state !== "confirm")
1042
- return;
1043
- setState("processing_deletion");
1044
- const worked = await deleteAsset({ client, asset, deleteOnMux });
1045
- worked === !0 ? (toast.push({ title: "Successfully deleted video", status: "success" }), succeededDeleting()) : worked === "failed-mux" ? (toast.push({
1046
- title: "Deleted video in Sanity",
1047
- description: "But it wasn't deleted in Mux",
1048
- status: "warning"
1049
- }), succeededDeleting()) : (toast.push({ title: "Failed deleting video", status: "error" }), setState("error_deleting"));
1050
- }
1051
- return /* @__PURE__ */ jsx(
1052
- Dialog,
1053
- {
1054
- animate: !0,
1055
- header: "Delete video",
1056
- zOffset: DIALOGS_Z_INDEX,
1057
- id: "deleting-video-details-dialog",
1058
- onClose: cancelDelete,
1059
- onClickOutside: cancelDelete,
1060
- width: 1,
1061
- position: "fixed",
1062
- children: /* @__PURE__ */ jsx(
1063
- Card,
1064
- {
1065
- padding: 3,
1066
- style: {
1067
- minHeight: "150px",
1068
- display: "flex",
1069
- alignItems: "center",
1070
- justifyContent: "center"
1071
- },
1072
- children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
1073
- state === "checkingReferences" && /* @__PURE__ */ jsxs(Fragment, { children: [
1074
- /* @__PURE__ */ jsx(Heading, { size: 2, children: "Checking if video can be deleted" }),
1075
- /* @__PURE__ */ jsx(SpinnerBox, {})
1076
- ] }),
1077
- state === "cantDelete" && /* @__PURE__ */ jsxs(Fragment, { children: [
1078
- /* @__PURE__ */ jsx(Heading, { size: 2, children: "Video can't be deleted" }),
1079
- /* @__PURE__ */ jsxs(Text, { size: 2, style: { marginBottom: "2rem" }, children: [
1080
- "There are ",
1081
- references == null ? void 0 : references.length,
1082
- " document",
1083
- references && references.length > 0 && "s",
1084
- " ",
1085
- "pointing to this video. Remove their references to this file or delete them before proceeding."
1086
- ] }),
1087
- /* @__PURE__ */ jsx(
1088
- VideoReferences,
1089
- {
1090
- references,
1091
- isLoaded: !referencesLoading,
1092
- placement
1093
- }
1094
- )
1095
- ] }),
1096
- state === "confirm" && /* @__PURE__ */ jsxs(Fragment, { children: [
1097
- /* @__PURE__ */ jsx(Heading, { size: 2, children: "Are you sure you want to delete this video?" }),
1098
- /* @__PURE__ */ jsx(Text, { size: 2, children: "This action is irreversible" }),
1099
- /* @__PURE__ */ jsxs(Stack, { space: 4, marginY: 4, children: [
1100
- /* @__PURE__ */ jsxs(Flex, { align: "center", as: "label", children: [
1101
- /* @__PURE__ */ jsx(
1102
- Checkbox,
1103
- {
1104
- checked: deleteOnMux,
1105
- onChange: () => setDeleteOnMux((prev) => !prev)
1106
- }
1107
- ),
1108
- /* @__PURE__ */ jsx(Text, { style: { margin: "0 10px" }, children: "Delete asset on Mux" })
1109
- ] }),
1110
- /* @__PURE__ */ jsxs(Flex, { align: "center", as: "label", children: [
1111
- /* @__PURE__ */ jsx(Checkbox, { disabled: !0, checked: !0 }),
1112
- /* @__PURE__ */ jsx(Text, { style: { margin: "0 10px" }, children: "Delete video from dataset" })
1113
- ] }),
1114
- /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
1115
- Button,
1116
- {
1117
- icon: TrashIcon,
1118
- fontSize: 2,
1119
- padding: 3,
1120
- text: "Delete video",
1121
- tone: "critical",
1122
- onClick: confirmDelete,
1123
- disabled: ["processing_deletion", "checkingReferences", "cantDelete"].some(
1124
- (s) => s === state
1125
- )
1126
- }
1127
- ) })
1128
- ] })
1129
- ] }),
1130
- state === "processing_deletion" && /* @__PURE__ */ jsxs(Fragment, { children: [
1131
- /* @__PURE__ */ jsx(Heading, { size: 2, children: "Deleting video..." }),
1132
- /* @__PURE__ */ jsx(SpinnerBox, {})
1133
- ] }),
1134
- state === "error_deleting" && /* @__PURE__ */ jsxs(Fragment, { children: [
1135
- /* @__PURE__ */ jsx(Heading, { size: 2, children: "Something went wrong!" }),
1136
- /* @__PURE__ */ jsx(Text, { size: 2, children: "Try deleting the video again by clicking the button below" })
1137
- ] })
1138
- ] })
1139
- }
1140
- )
1141
- }
1142
- );
1143
- }
1144
- const useDocReferences = createHookFromObservableFactory(({ documentStore, id }) => documentStore.listenQuery(
1145
- /* groq */
1146
- "*[references($id)]{_id, _type, _rev, _updatedAt, _createdAt}",
1147
- { id },
1148
- {
1149
- apiVersion: SANITY_API_VERSION
1150
- }
1151
- ));
1152
- function formatSeconds(seconds) {
1153
- if (typeof seconds != "number" || Number.isNaN(seconds))
1154
- return "";
1155
- const hrs = ~~(seconds / 3600), mins = ~~(seconds % 3600 / 60), secs = ~~seconds % 60;
1156
- let ret = "";
1157
- return hrs > 0 && (ret += "" + hrs + ":" + (mins < 10 ? "0" : "")), ret += "" + mins + ":" + (secs < 10 ? "0" : ""), ret += "" + secs, ret;
1158
- }
1159
- function getVideoMetadata(doc) {
1160
- var _a, _b, _c, _d, _e, _f;
1161
- const id = doc.assetId || doc._id || "", date = (_a = doc.data) != null && _a.created_at ? new Date(Number(doc.data.created_at) * 1e3) : new Date(doc._createdAt || doc._updatedAt || Date.now());
1162
- return {
1163
- title: doc.filename || id.slice(0, 12),
1164
- id,
1165
- createdAt: date,
1166
- duration: (_b = doc.data) != null && _b.duration ? formatSeconds((_c = doc.data) == null ? void 0 : _c.duration) : void 0,
1167
- aspect_ratio: (_d = doc.data) == null ? void 0 : _d.aspect_ratio,
1168
- max_stored_resolution: (_e = doc.data) == null ? void 0 : _e.max_stored_resolution,
1169
- max_stored_frame_rate: (_f = doc.data) == null ? void 0 : _f.max_stored_frame_rate
1170
- };
1171
- }
1172
- function useVideoDetails(props) {
1173
- const documentStore = useDocumentStore(), toast = useToast(), client = useClient(), [references, referencesLoading] = useDocReferences({
1174
- documentStore,
1175
- id: props.asset._id
1176
- }), [originalAsset, setOriginalAsset] = useState(() => props.asset), [filename, setFilename] = useState(props.asset.filename), modified = filename !== originalAsset.filename, displayInfo = getVideoMetadata({ ...props.asset, filename }), [state, setState] = useState("idle");
1177
- function handleClose() {
1178
- if (state === "idle") {
1179
- if (modified) {
1180
- setState("closing");
1181
- return;
1182
- }
1183
- props.closeDialog();
1184
- }
1185
- }
1186
- function confirmClose(shouldClose) {
1187
- state === "closing" && (shouldClose && props.closeDialog(), setState("idle"));
1188
- }
1189
- async function saveChanges() {
1190
- if (state === "idle") {
1191
- setState("saving");
1192
- try {
1193
- await client.patch(props.asset._id).set({ filename }).commit(), setOriginalAsset((prev) => ({ ...prev, filename })), toast.push({
1194
- title: "Video title updated",
1195
- description: `New title: ${filename}`,
1196
- status: "success"
1197
- }), props.closeDialog();
1198
- } catch (error) {
1199
- toast.push({
1200
- title: "Failed updating file name",
1201
- status: "error",
1202
- description: typeof error == "string" ? error : "Please try again"
1203
- }), setFilename(originalAsset.filename);
1204
- }
1205
- setState("idle");
1206
- }
1207
- }
1208
- return {
1209
- references,
1210
- referencesLoading,
1211
- modified,
1212
- filename,
1213
- setFilename,
1214
- displayInfo,
1215
- state,
1216
- setState,
1217
- handleClose,
1218
- confirmClose,
1219
- saveChanges
1220
- };
1221
- }
1222
- const AssetInput = (props) => /* @__PURE__ */ jsx(FormField$1, { title: props.label, description: props.description, inputId: props.label, children: /* @__PURE__ */ jsx(
1223
- TextInput,
1224
- {
1225
- id: props.label,
1226
- value: props.value,
1227
- placeholder: props.placeholder,
1228
- onInput: props.onInput,
1229
- disabled: props.disabled
1230
- }
1231
- ) }), VideoDetails = (props) => {
1232
- const [tab, setTab] = useState("details"), {
1233
- displayInfo,
1234
- filename,
1235
- modified,
1236
- references,
1237
- referencesLoading,
1238
- setFilename,
1239
- state,
1240
- setState,
1241
- handleClose,
1242
- confirmClose,
1243
- saveChanges
1244
- } = useVideoDetails(props), isSaving = state === "saving", [containerHeight, setContainerHeight] = useState(null), contentsRef = React.useRef(null);
1245
- return useEffect(() => {
1246
- !contentsRef.current || !("getBoundingClientRect" in contentsRef.current) || setContainerHeight(contentsRef.current.getBoundingClientRect().height);
1247
- }, []), /* @__PURE__ */ jsxs(
1248
- Dialog,
1249
- {
1250
- animate: !0,
1251
- header: displayInfo.title,
1252
- zOffset: DIALOGS_Z_INDEX,
1253
- id: "video-details-dialog",
1254
- onClose: handleClose,
1255
- onClickOutside: handleClose,
1256
- width: 2,
1257
- position: "fixed",
1258
- footer: /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
1259
- /* @__PURE__ */ jsx(
1260
- Button,
1261
- {
1262
- icon: TrashIcon,
1263
- fontSize: 2,
1264
- padding: 3,
1265
- mode: "bleed",
1266
- text: "Delete",
1267
- tone: "critical",
1268
- onClick: () => setState("deleting"),
1269
- disabled: isSaving
1270
- }
1271
- ),
1272
- modified && /* @__PURE__ */ jsx(
1273
- Button,
1274
- {
1275
- icon: CheckmarkIcon,
1276
- fontSize: 2,
1277
- padding: 3,
1278
- mode: "ghost",
1279
- text: "Save and close",
1280
- tone: "positive",
1281
- onClick: saveChanges,
1282
- iconRight: isSaving && Spinner,
1283
- disabled: isSaving
1284
- }
1285
- )
1286
- ] }) }),
1287
- children: [
1288
- state === "deleting" && /* @__PURE__ */ jsx(
1289
- DeleteDialog,
1290
- {
1291
- asset: props.asset,
1292
- cancelDelete: () => setState("idle"),
1293
- placement: props.placement,
1294
- referencesLoading,
1295
- references,
1296
- succeededDeleting: () => {
1297
- props.closeDialog();
1298
- }
1299
- }
1300
- ),
1301
- state === "closing" && /* @__PURE__ */ jsx(
1302
- Dialog,
1303
- {
1304
- animate: !0,
1305
- header: "You have unsaved changes",
1306
- zOffset: DIALOGS_Z_INDEX,
1307
- id: "closing-video-details-dialog",
1308
- onClose: () => confirmClose(!1),
1309
- onClickOutside: () => confirmClose(!1),
1310
- width: 1,
1311
- position: "fixed",
1312
- footer: /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
1313
- /* @__PURE__ */ jsx(
1314
- Button,
1315
- {
1316
- icon: ErrorOutlineIcon,
1317
- fontSize: 2,
1318
- padding: 3,
1319
- text: "Discard changes",
1320
- tone: "critical",
1321
- onClick: () => confirmClose(!0)
1322
- }
1323
- ),
1324
- modified && /* @__PURE__ */ jsx(
1325
- Button,
1326
- {
1327
- icon: RevertIcon,
1328
- fontSize: 2,
1329
- padding: 3,
1330
- mode: "ghost",
1331
- text: "Keep editing",
1332
- tone: "primary",
1333
- onClick: () => confirmClose(!1)
1334
- }
1335
- )
1336
- ] }) }),
1337
- children: /* @__PURE__ */ jsx(Card, { padding: 5, children: /* @__PURE__ */ jsxs(Stack, { style: { textAlign: "center" }, space: 3, children: [
1338
- /* @__PURE__ */ jsx(Heading, { size: 2, children: "Unsaved changes will be lost" }),
1339
- /* @__PURE__ */ jsx(Text, { size: 2, children: "Are you sure you want to discard them?" })
1340
- ] }) })
1341
- }
1342
- ),
1343
- /* @__PURE__ */ jsx(
1344
- Card,
1345
- {
1346
- padding: 4,
1347
- sizing: "border",
1348
- style: {
1349
- containerType: "inline-size"
1350
- },
1351
- children: /* @__PURE__ */ jsxs(
1352
- Flex,
1353
- {
1354
- sizing: "border",
1355
- gap: 4,
1356
- direction: ["column", "column", "row"],
1357
- align: "flex-start",
1358
- ref: contentsRef,
1359
- style: typeof containerHeight == "number" ? {
1360
- minHeight: containerHeight
1361
- } : void 0,
1362
- children: [
1363
- /* @__PURE__ */ jsx(Stack, { space: 4, flex: 1, sizing: "border", children: /* @__PURE__ */ jsx(VideoPlayer, { asset: props.asset, autoPlay: props.asset.autoPlay || !1 }) }),
1364
- /* @__PURE__ */ jsxs(Stack, { space: 4, flex: 1, sizing: "border", children: [
1365
- /* @__PURE__ */ jsxs(TabList, { space: 2, children: [
1366
- /* @__PURE__ */ jsx(
1367
- Tab,
1368
- {
1369
- "aria-controls": "details-panel",
1370
- icon: EditIcon,
1371
- id: "details-tab",
1372
- label: "Details",
1373
- onClick: () => setTab("details"),
1374
- selected: tab === "details"
1375
- }
1376
- ),
1377
- /* @__PURE__ */ jsx(
1378
- Tab,
1379
- {
1380
- "aria-controls": "references-panel",
1381
- icon: SearchIcon,
1382
- id: "references-tab",
1383
- label: `Used by ${references ? `(${references.length})` : ""}`,
1384
- onClick: () => setTab("references"),
1385
- selected: tab === "references"
1386
- }
1387
- )
1388
- ] }),
1389
- /* @__PURE__ */ jsx(
1390
- TabPanel,
1391
- {
1392
- "aria-labelledby": "details-tab",
1393
- id: "details-panel",
1394
- hidden: tab !== "details",
1395
- style: { wordBreak: "break-word" },
1396
- children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
1397
- /* @__PURE__ */ jsx(
1398
- AssetInput,
1399
- {
1400
- label: "Video title or file name",
1401
- description: "Not visible to users. Useful for finding videos later.",
1402
- value: filename || "",
1403
- onInput: (e) => setFilename(e.currentTarget.value),
1404
- disabled: state !== "idle"
1405
- }
1406
- ),
1407
- /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
1408
- (displayInfo == null ? void 0 : displayInfo.duration) && /* @__PURE__ */ jsx(
1409
- IconInfo,
1410
- {
1411
- text: `Duration: ${displayInfo.duration}`,
1412
- icon: ClockIcon,
1413
- size: 2
1414
- }
1415
- ),
1416
- (displayInfo == null ? void 0 : displayInfo.max_stored_resolution) && /* @__PURE__ */ jsx(
1417
- IconInfo,
1418
- {
1419
- text: `Max Resolution: ${displayInfo.max_stored_resolution}`,
1420
- icon: ResolutionIcon,
1421
- size: 2
1422
- }
1423
- ),
1424
- (displayInfo == null ? void 0 : displayInfo.max_stored_frame_rate) && /* @__PURE__ */ jsx(
1425
- IconInfo,
1426
- {
1427
- text: `Frame rate: ${displayInfo.max_stored_frame_rate}`,
1428
- icon: StopWatchIcon,
1429
- size: 2
1430
- }
1431
- ),
1432
- (displayInfo == null ? void 0 : displayInfo.aspect_ratio) && /* @__PURE__ */ jsx(
1433
- IconInfo,
1434
- {
1435
- text: `Aspect Ratio: ${displayInfo.aspect_ratio}`,
1436
- icon: CropIcon,
1437
- size: 2
1438
- }
1439
- ),
1440
- /* @__PURE__ */ jsx(
1441
- IconInfo,
1442
- {
1443
- text: `Uploaded on: ${displayInfo.createdAt.toLocaleDateString("en", {
1444
- year: "numeric",
1445
- month: "2-digit",
1446
- day: "2-digit",
1447
- hour: "2-digit",
1448
- minute: "2-digit",
1449
- hour12: !0
1450
- })}`,
1451
- icon: CalendarIcon,
1452
- size: 2
1453
- }
1454
- ),
1455
- /* @__PURE__ */ jsx(IconInfo, { text: `Mux ID:
1456
- ${displayInfo.id}`, icon: TagIcon, size: 2 })
1457
- ] })
1458
- ] })
1459
- }
1460
- ),
1461
- /* @__PURE__ */ jsx(
1462
- TabPanel,
1463
- {
1464
- "aria-labelledby": "references-tab",
1465
- id: "references-panel",
1466
- hidden: tab !== "references",
1467
- children: /* @__PURE__ */ jsx(
1468
- VideoReferences,
1469
- {
1470
- references,
1471
- isLoaded: !referencesLoading,
1472
- placement: props.placement
1473
- }
1474
- )
1475
- }
1476
- )
1477
- ] })
1478
- ]
1479
- }
1480
- )
1481
- }
1482
- )
1483
- ]
1484
- }
1485
- );
1486
- }, VideoMetadata = (props) => {
1487
- if (!props.asset)
1488
- return null;
1489
- const displayInfo = getVideoMetadata(props.asset);
1490
- return /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
1491
- displayInfo.title && /* @__PURE__ */ jsx(
1492
- Text,
1493
- {
1494
- size: 1,
1495
- weight: "semibold",
1496
- style: {
1497
- wordWrap: "break-word"
1498
- },
1499
- children: displayInfo.title
1500
- }
1501
- ),
1502
- /* @__PURE__ */ jsxs(Inline, { space: 3, children: [
1503
- (displayInfo == null ? void 0 : displayInfo.duration) && /* @__PURE__ */ jsx(IconInfo, { text: displayInfo.duration, icon: ClockIcon, size: 1, muted: !0 }),
1504
- /* @__PURE__ */ jsx(
1505
- IconInfo,
1506
- {
1507
- text: displayInfo.createdAt.toISOString().split("T")[0],
1508
- icon: CalendarIcon,
1509
- size: 1,
1510
- muted: !0
1511
- }
1512
- ),
1513
- displayInfo.title != displayInfo.id.slice(0, 12) && /* @__PURE__ */ jsx(IconInfo, { text: displayInfo.id.slice(0, 12), icon: TagIcon, size: 1, muted: !0 })
1514
- ] })
1515
- ] });
1516
- }, PlayButton = styled.button`
1517
- display: block;
1518
- padding: 0;
1519
- margin: 0;
1520
- border: none;
1521
- border-radius: 0.1875rem;
1522
- position: relative;
1523
- cursor: pointer;
1524
-
1525
- &::after {
1526
- content: '';
1527
- background: var(--card-fg-color);
1528
- opacity: 0;
1529
- display: block;
1530
- position: absolute;
1531
- inset: 0;
1532
- z-index: 10;
1533
- transition: 0.15s ease-out;
1534
- border-radius: inherit;
1535
- }
1536
-
1537
- > div[data-play] {
1538
- z-index: 11;
1539
- opacity: 0;
1540
- transition: 0.15s 0.05s ease-out;
1541
- position: absolute;
1542
- left: 50%;
1543
- top: 50%;
1544
- transform: translate(-50%, -50%);
1545
- color: var(--card-fg-color);
1546
- background: var(--card-bg-color);
1547
- width: auto;
1548
- height: 30%;
1549
- aspect-ratio: 1;
1550
- border-radius: 100%;
1551
- display: flex;
1552
- justify-content: center;
1553
- align-items: center;
1554
- box-sizing: border-box;
1555
- > svg {
1556
- display: block;
1557
- width: 70%;
1558
- height: auto;
1559
- // Visual balance to center-align the icon
1560
- transform: translateX(5%);
1561
- }
1562
- }
1563
-
1564
- &:hover,
1565
- &:focus {
1566
- &::after {
1567
- opacity: 0.3;
1568
- }
1569
- > div[data-play] {
1570
- opacity: 1;
1571
- }
1572
- }
1573
- `;
1574
- function VideoInBrowser({
1575
- onSelect,
1576
- onEdit,
1577
- asset
1578
- }) {
1579
- const [renderVideo, setRenderVideo] = useState(!1), select = React.useCallback(() => onSelect == null ? void 0 : onSelect(asset), [onSelect, asset]), edit = React.useCallback(() => onEdit == null ? void 0 : onEdit(asset), [onEdit, asset]);
1580
- if (!asset)
1581
- return null;
1582
- const playbackPolicy = getPlaybackPolicy(asset);
1583
- return /* @__PURE__ */ jsxs(
1584
- Card,
1585
- {
1586
- border: !0,
1587
- padding: 2,
1588
- sizing: "border",
1589
- radius: 2,
1590
- style: {
1591
- position: "relative"
1592
- },
1593
- children: [
1594
- playbackPolicy === "signed" && /* @__PURE__ */ jsx(
1595
- Tooltip,
1596
- {
1597
- animate: !0,
1598
- content: /* @__PURE__ */ jsx(Card, { padding: 2, radius: 2, children: /* @__PURE__ */ jsx(IconInfo, { icon: LockIcon, text: "Signed playback policy", size: 2 }) }),
1599
- placement: "right",
1600
- fallbackPlacements: ["top", "bottom"],
1601
- portal: !0,
1602
- children: /* @__PURE__ */ jsx(
1603
- Card,
1604
- {
1605
- tone: "caution",
1606
- style: {
1607
- borderRadius: "100%",
1608
- position: "absolute",
1609
- left: "1em",
1610
- top: "1em",
1611
- zIndex: 10
1612
- },
1613
- padding: 2,
1614
- border: !0,
1615
- children: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: /* @__PURE__ */ jsx(LockIcon, {}) })
1616
- }
1617
- )
1618
- }
1619
- ),
1620
- /* @__PURE__ */ jsxs(
1621
- Stack,
1622
- {
1623
- space: 3,
1624
- height: "fill",
1625
- style: {
1626
- gridTemplateRows: "min-content min-content 1fr"
1627
- },
1628
- children: [
1629
- renderVideo ? /* @__PURE__ */ jsx(VideoPlayer, { asset, autoPlay: !0, forceAspectRatio: THUMBNAIL_ASPECT_RATIO }) : /* @__PURE__ */ jsxs(PlayButton, { onClick: () => setRenderVideo(!0), children: [
1630
- /* @__PURE__ */ jsx("div", { "data-play": !0, children: /* @__PURE__ */ jsx(PlayIcon, {}) }),
1631
- /* @__PURE__ */ jsx(VideoThumbnail, { asset })
1632
- ] }),
1633
- /* @__PURE__ */ jsx(VideoMetadata, { asset }),
1634
- /* @__PURE__ */ jsxs(
1635
- "div",
1636
- {
1637
- style: {
1638
- display: "flex",
1639
- width: "100%",
1640
- alignItems: "flex-end",
1641
- justifyContent: "flex-start",
1642
- gap: ".35rem"
1643
- },
1644
- children: [
1645
- onSelect && /* @__PURE__ */ jsx(
1646
- Button,
1647
- {
1648
- icon: CheckmarkIcon,
1649
- fontSize: 2,
1650
- padding: 2,
1651
- mode: "ghost",
1652
- text: "Select",
1653
- style: { flex: 1 },
1654
- tone: "positive",
1655
- onClick: select
1656
- }
1657
- ),
1658
- /* @__PURE__ */ jsx(
1659
- Button,
1660
- {
1661
- icon: EditIcon,
1662
- fontSize: 2,
1663
- padding: 2,
1664
- mode: "ghost",
1665
- text: "Details",
1666
- style: { flex: 1 },
1667
- onClick: edit
1668
- }
1669
- )
1670
- ]
1671
- }
1672
- )
1673
- ]
1674
- }
1675
- )
1676
- ]
1677
- }
1678
- );
1679
- }
1680
- function VideosBrowser({ onSelect }) {
1681
- const { assets, isLoading, searchQuery, setSearchQuery, setSort, sort } = useAssets(), [editedAsset, setEditedAsset] = useState(null), freshEditedAsset = useMemo(
1682
- () => assets.find((a) => a._id === (editedAsset == null ? void 0 : editedAsset._id)) || editedAsset,
1683
- [editedAsset, assets]
1684
- ), placement = onSelect ? "input" : "tool";
1685
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1686
- /* @__PURE__ */ jsxs(Stack, { padding: 4, space: 4, style: { minHeight: "50vh" }, children: [
1687
- /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
1688
- /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 3, children: [
1689
- /* @__PURE__ */ jsx(
1690
- TextInput,
1691
- {
1692
- value: searchQuery,
1693
- icon: SearchIcon,
1694
- onInput: (e) => setSearchQuery(e.currentTarget.value),
1695
- placeholder: "Search videos"
1696
- }
1697
- ),
1698
- /* @__PURE__ */ jsx(SelectSortOptions, { setSort, sort })
1699
- ] }),
1700
- placement === "tool" && /* @__PURE__ */ jsx(ImportVideosFromMux, {})
1701
- ] }),
1702
- /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
1703
- (assets == null ? void 0 : assets.length) > 0 && /* @__PURE__ */ jsxs(Label$1, { muted: !0, children: [
1704
- assets.length,
1705
- " video",
1706
- assets.length > 1 ? "s" : null,
1707
- " ",
1708
- searchQuery ? `matching "${searchQuery}"` : "found"
1709
- ] }),
1710
- /* @__PURE__ */ jsx(
1711
- Grid,
1712
- {
1713
- gap: 2,
1714
- style: {
1715
- gridTemplateColumns: "repeat(auto-fill, minmax(250px, 1fr))"
1716
- },
1717
- children: assets.map((asset) => /* @__PURE__ */ jsx(
1718
- VideoInBrowser,
1719
- {
1720
- asset,
1721
- onEdit: setEditedAsset,
1722
- onSelect
1723
- },
1724
- asset._id
1725
- ))
1726
- }
1727
- )
1728
- ] }),
1729
- isLoading && /* @__PURE__ */ jsx(SpinnerBox, {}),
1730
- !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" }) })
1731
- ] }),
1732
- freshEditedAsset && /* @__PURE__ */ jsx(
1733
- VideoDetails,
1734
- {
1735
- closeDialog: () => setEditedAsset(null),
1736
- asset: freshEditedAsset,
1737
- placement
1738
- }
1739
- )
1740
- ] });
1741
- }
1742
- const StudioTool = () => /* @__PURE__ */ jsx(VideosBrowser, {}), DEFAULT_TOOL_CONFIG = {
1743
- icon: ToolIcon,
1744
- title: "Videos"
1745
- };
1746
- function createStudioTool(config) {
1747
- const toolConfig = typeof config.tool == "object" ? config.tool : DEFAULT_TOOL_CONFIG;
1748
- return {
1749
- name: "mux",
1750
- icon: toolConfig.icon || DEFAULT_TOOL_CONFIG.icon,
1751
- title: toolConfig.title || DEFAULT_TOOL_CONFIG.title,
1752
- component: (props) => /* @__PURE__ */ jsx(StudioTool, { ...config, ...props })
1753
- };
1754
- }
1755
- const path = ["assetId", "data", "playbackId", "status", "thumbTime", "filename"], useAssetDocumentValues = (asset) => useDocumentValues(
1756
- isReference(asset) ? asset._ref : "",
1757
- path
1758
- );
1759
- function useDialogState() {
1760
- return useState(!1);
1761
- }
1762
- const useMuxPolling = (asset) => {
1763
- var _a, _b;
1764
- const client = useClient(), projectId = useProjectId(), dataset = useDataset(), shouldFetch = useMemo(
1765
- () => {
1766
- var _a2, _b2;
1767
- return !!(asset != null && asset.assetId) && ((asset == null ? void 0 : asset.status) === "preparing" || ((_b2 = (_a2 = asset == null ? void 0 : asset.data) == null ? void 0 : _a2.static_renditions) == null ? void 0 : _b2.status) === "preparing");
1768
- },
1769
- [asset == null ? void 0 : asset.assetId, (_b = (_a = asset == null ? void 0 : asset.data) == null ? void 0 : _a.static_renditions) == null ? void 0 : _b.status, asset == null ? void 0 : asset.status]
1770
- );
1771
- return useSWR(
1772
- shouldFetch ? `/${projectId}/addons/mux/assets/${dataset}/data/${asset == null ? void 0 : asset.assetId}` : null,
1773
- async () => {
1774
- const { data } = await client.request({
1775
- url: `/addons/mux/assets/${dataset}/data/${asset.assetId}`,
1776
- withCredentials: !0,
1777
- method: "GET"
1778
- });
1779
- client.patch(asset._id).set({ status: data.status, data }).commit({ returnDocuments: !1 });
1780
- },
1781
- { refreshInterval: 2e3, refreshWhenHidden: !0, dedupingInterval: 1e3 }
1782
- );
1783
- };
1784
- function saveSecrets(client, token, secretKey, enableSignedUrls, signingKeyId, signingKeyPrivate) {
1785
- const doc = {
1786
- _id: "secrets.mux",
1787
- _type: "mux.apiKey",
1788
- token,
1789
- secretKey,
1790
- enableSignedUrls,
1791
- signingKeyId,
1792
- signingKeyPrivate
1793
- };
1794
- return client.createOrReplace(doc);
1795
- }
1796
- function createSigningKeys(client) {
1797
- const { dataset } = client.config();
1798
- return client.request({
1799
- url: `/addons/mux/signing-keys/${dataset}`,
1800
- withCredentials: !0,
1801
- method: "POST"
1802
- });
1803
- }
1804
- function testSecrets(client) {
1805
- const { dataset } = client.config();
1806
- return client.request({
1807
- url: `/addons/mux/secrets/${dataset}/test`,
1808
- withCredentials: !0,
1809
- method: "GET"
1810
- });
1811
- }
1812
- async function haveValidSigningKeys(client, signingKeyId, signingKeyPrivate) {
1813
- if (!(signingKeyId && signingKeyPrivate))
1814
- return !1;
1815
- const { dataset } = client.config();
1816
- try {
1817
- const res = await client.request({
1818
- url: `/addons/mux/signing-keys/${dataset}/${signingKeyId}`,
1819
- withCredentials: !0,
1820
- method: "GET"
1821
- });
1822
- return !!(res.data && res.data.id);
1823
- } catch {
1824
- return console.error("Error fetching signingKeyId", signingKeyId, "assuming it is not valid"), !1;
1825
- }
1826
- }
1827
- function testSecretsObservable(client) {
1828
- const { dataset } = client.config();
1829
- return defer(
1830
- () => client.observable.request({
1831
- url: `/addons/mux/secrets/${dataset}/test`,
1832
- withCredentials: !0,
1833
- method: "GET"
1834
- })
1835
- );
1836
- }
1837
- const useSaveSecrets = (client, secrets) => useCallback(
1838
- async ({
1839
- token,
1840
- secretKey,
1841
- enableSignedUrls
1842
- }) => {
1843
- let { signingKeyId, signingKeyPrivate } = secrets;
1844
- try {
1845
- await saveSecrets(
1846
- client,
1847
- token,
1848
- secretKey,
1849
- enableSignedUrls,
1850
- signingKeyId,
1851
- signingKeyPrivate
1852
- );
1853
- const valid = await testSecrets(client);
1854
- if (!(valid != null && valid.status) && token && secretKey)
1855
- throw new Error("Invalid secrets");
1856
- } catch (err) {
1857
- throw console.error("Error while trying to save secrets:", err), err;
1858
- }
1859
- if (enableSignedUrls && !await haveValidSigningKeys(
1860
- client,
1861
- signingKeyId,
1862
- signingKeyPrivate
1863
- ))
1864
- try {
1865
- const { data } = await createSigningKeys(client);
1866
- signingKeyId = data.id, signingKeyPrivate = data.private_key, await saveSecrets(
1867
- client,
1868
- token,
1869
- secretKey,
1870
- enableSignedUrls,
1871
- signingKeyId,
1872
- signingKeyPrivate
1873
- );
1874
- } catch (err) {
1875
- throw console.log("Error while creating and saving signing key:", err == null ? void 0 : err.message), err;
1876
- }
1877
- return {
1878
- token,
1879
- secretKey,
1880
- enableSignedUrls,
1881
- signingKeyId,
1882
- signingKeyPrivate
1883
- };
1884
- },
1885
- [client, secrets]
1886
- );
1887
- function init({ token, secretKey, enableSignedUrls }) {
1888
- return {
1889
- submitting: !1,
1890
- error: null,
1891
- // Form inputs don't set the state back to null when clearing a field, but uses empty strings
1892
- // This ensures the `dirty` check works correctly
1893
- token: token != null ? token : "",
1894
- secretKey: secretKey != null ? secretKey : "",
1895
- enableSignedUrls: enableSignedUrls != null ? enableSignedUrls : !1
1896
- };
1897
- }
1898
- function reducer(state, action) {
1899
- switch (action == null ? void 0 : action.type) {
1900
- case "submit":
1901
- return { ...state, submitting: !0, error: null };
1902
- case "error":
1903
- return { ...state, submitting: !1, error: action.payload };
1904
- case "reset":
1905
- return init(action.payload);
1906
- case "change":
1907
- return { ...state, [action.payload.name]: action.payload.value };
1908
- default:
1909
- throw new Error(`Unknown action type: ${action == null ? void 0 : action.type}`);
1910
- }
1911
- }
1912
- const useSecretsFormState = (secrets) => useReducer(reducer, secrets, init), ids = [
1913
- "title",
1914
- "a",
1915
- "b",
1916
- "c",
1917
- "d",
1918
- "e",
1919
- "f",
1920
- "g",
1921
- "h",
1922
- "i",
1923
- "j",
1924
- "k",
1925
- "l",
1926
- "m",
1927
- "n",
1928
- "o",
1929
- "p",
1930
- "q",
1931
- "r"
1932
- ];
1933
- function MuxLogo({ height = 26 }) {
1934
- const id = useId(), [titleId, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r] = useMemo(
1935
- () => ids.map((field) => `${id}-${field}`),
1936
- [id]
1937
- );
1938
- return /* @__PURE__ */ jsxs(
1939
- "svg",
1940
- {
1941
- "aria-labelledby": titleId,
1942
- role: "img",
1943
- xmlns: "http://www.w3.org/2000/svg",
1944
- xmlSpace: "preserve",
1945
- viewBox: "92.08878326416016 102.66712188720703 692.76123046875 219.99948120117188",
1946
- style: { height: `${height}px` },
1947
- children: [
1948
- /* @__PURE__ */ jsx("title", { id: titleId, children: "Mux Logo" }),
1949
- /* @__PURE__ */ jsxs("defs", { children: [
1950
- /* @__PURE__ */ jsxs(
1951
- "linearGradient",
1952
- {
1953
- id: c,
1954
- spreadMethod: "pad",
1955
- gradientTransform: "matrix(528.38055 0 0 -528.38055 63.801 159.5)",
1956
- gradientUnits: "userSpaceOnUse",
1957
- y2: 0,
1958
- x2: 1,
1959
- y1: 0,
1960
- x1: 0,
1961
- children: [
1962
- /* @__PURE__ */ jsx(
1963
- "stop",
1964
- {
1965
- offset: 0,
1966
- style: {
1967
- stopOpacity: 1,
1968
- stopColor: "#ff4e00"
1969
- }
1970
- }
1971
- ),
1972
- /* @__PURE__ */ jsx(
1973
- "stop",
1974
- {
1975
- offset: 1,
1976
- style: {
1977
- stopOpacity: 1,
1978
- stopColor: "#ff1791"
1979
- }
1980
- }
1981
- )
1982
- ]
1983
- }
1984
- ),
1985
- /* @__PURE__ */ jsxs(
1986
- "linearGradient",
1987
- {
1988
- id: d,
1989
- spreadMethod: "pad",
1990
- gradientTransform: "matrix(523.66766 0 0 -523.66766 67.897 159.5)",
1991
- gradientUnits: "userSpaceOnUse",
1992
- y2: 0,
1993
- x2: 1,
1994
- y1: 0,
1995
- x1: 0,
1996
- children: [
1997
- /* @__PURE__ */ jsx(
1998
- "stop",
1999
- {
2000
- offset: 0,
2001
- style: {
2002
- stopOpacity: 1,
2003
- stopColor: "#ff4e00"
2004
- }
2005
- }
2006
- ),
2007
- /* @__PURE__ */ jsx(
2008
- "stop",
2009
- {
2010
- offset: 1,
2011
- style: {
2012
- stopOpacity: 1,
2013
- stopColor: "#ff1791"
2014
- }
2015
- }
2016
- )
2017
- ]
2018
- }
2019
- ),
2020
- /* @__PURE__ */ jsxs(
2021
- "linearGradient",
2022
- {
2023
- id: g,
2024
- spreadMethod: "pad",
2025
- gradientTransform: "rotate(180 296.075 79.75) scale(524.84045)",
2026
- gradientUnits: "userSpaceOnUse",
2027
- y2: 0,
2028
- x2: 1,
2029
- y1: 0,
2030
- x1: 0,
2031
- children: [
2032
- /* @__PURE__ */ jsx(
2033
- "stop",
2034
- {
2035
- offset: 0,
2036
- style: {
2037
- stopOpacity: 1,
2038
- stopColor: "#ff4e00"
2039
- }
2040
- }
2041
- ),
2042
- /* @__PURE__ */ jsx(
2043
- "stop",
2044
- {
2045
- offset: 1,
2046
- style: {
2047
- stopOpacity: 1,
2048
- stopColor: "#ff1791"
2049
- }
2050
- }
2051
- )
2052
- ]
2053
- }
2054
- ),
2055
- /* @__PURE__ */ jsxs(
2056
- "linearGradient",
2057
- {
2058
- id: i,
2059
- spreadMethod: "pad",
2060
- gradientTransform: "matrix(524.84045 0 0 -524.84045 63.801 159.5)",
2061
- gradientUnits: "userSpaceOnUse",
2062
- y2: 0,
2063
- x2: 1,
2064
- y1: 0,
2065
- x1: 0,
2066
- children: [
2067
- /* @__PURE__ */ jsx(
2068
- "stop",
2069
- {
2070
- offset: 0,
2071
- style: {
2072
- stopOpacity: 1,
2073
- stopColor: "#ff4e00"
2074
- }
2075
- }
2076
- ),
2077
- /* @__PURE__ */ jsx(
2078
- "stop",
2079
- {
2080
- offset: 1,
2081
- style: {
2082
- stopOpacity: 1,
2083
- stopColor: "#ff1791"
2084
- }
2085
- }
2086
- )
2087
- ]
2088
- }
2089
- ),
2090
- /* @__PURE__ */ jsxs(
2091
- "linearGradient",
2092
- {
2093
- id: j,
2094
- spreadMethod: "pad",
2095
- gradientTransform: "matrix(523.08514 0 0 -523.08514 67.897 224.446)",
2096
- gradientUnits: "userSpaceOnUse",
2097
- y2: 0,
2098
- x2: 1,
2099
- y1: 0,
2100
- x1: 0,
2101
- children: [
2102
- /* @__PURE__ */ jsx(
2103
- "stop",
2104
- {
2105
- offset: 0,
2106
- style: {
2107
- stopOpacity: 1,
2108
- stopColor: "#ff4e00"
2109
- }
2110
- }
2111
- ),
2112
- /* @__PURE__ */ jsx(
2113
- "stop",
2114
- {
2115
- offset: 1,
2116
- style: {
2117
- stopOpacity: 1,
2118
- stopColor: "#ff1791"
2119
- }
2120
- }
2121
- )
2122
- ]
2123
- }
2124
- ),
2125
- /* @__PURE__ */ jsxs(
2126
- "linearGradient",
2127
- {
2128
- id: k,
2129
- spreadMethod: "pad",
2130
- gradientTransform: "matrix(524.84045 0 0 -524.84045 63.801 94.553)",
2131
- gradientUnits: "userSpaceOnUse",
2132
- y2: 0,
2133
- x2: 1,
2134
- y1: 0,
2135
- x1: 0,
2136
- children: [
2137
- /* @__PURE__ */ jsx(
2138
- "stop",
2139
- {
2140
- offset: 0,
2141
- style: {
2142
- stopOpacity: 1,
2143
- stopColor: "#ff4e00"
2144
- }
2145
- }
2146
- ),
2147
- /* @__PURE__ */ jsx(
2148
- "stop",
2149
- {
2150
- offset: 1,
2151
- style: {
2152
- stopOpacity: 1,
2153
- stopColor: "#ff1791"
2154
- }
2155
- }
2156
- )
2157
- ]
2158
- }
2159
- ),
2160
- /* @__PURE__ */ jsxs(
2161
- "linearGradient",
2162
- {
2163
- id: l,
2164
- spreadMethod: "pad",
2165
- gradientTransform: "matrix(524.84045 0 0 -524.84045 63.801 159.5)",
2166
- gradientUnits: "userSpaceOnUse",
2167
- y2: 0,
2168
- x2: 1,
2169
- y1: 0,
2170
- x1: 0,
2171
- children: [
2172
- /* @__PURE__ */ jsx(
2173
- "stop",
2174
- {
2175
- offset: 0,
2176
- style: {
2177
- stopOpacity: 1,
2178
- stopColor: "#ff4e00"
2179
- }
2180
- }
2181
- ),
2182
- /* @__PURE__ */ jsx(
2183
- "stop",
2184
- {
2185
- offset: 1,
2186
- style: {
2187
- stopOpacity: 1,
2188
- stopColor: "#ff1791"
2189
- }
2190
- }
2191
- )
2192
- ]
2193
- }
2194
- ),
2195
- /* @__PURE__ */ jsxs(
2196
- "linearGradient",
2197
- {
2198
- id: m,
2199
- spreadMethod: "pad",
2200
- gradientTransform: "matrix(524.84045 0 0 -524.84045 63.801 94.554)",
2201
- gradientUnits: "userSpaceOnUse",
2202
- y2: 0,
2203
- x2: 1,
2204
- y1: 0,
2205
- x1: 0,
2206
- children: [
2207
- /* @__PURE__ */ jsx(
2208
- "stop",
2209
- {
2210
- offset: 0,
2211
- style: {
2212
- stopOpacity: 1,
2213
- stopColor: "#ff4e00"
2214
- }
2215
- }
2216
- ),
2217
- /* @__PURE__ */ jsx(
2218
- "stop",
2219
- {
2220
- offset: 1,
2221
- style: {
2222
- stopOpacity: 1,
2223
- stopColor: "#ff1791"
2224
- }
2225
- }
2226
- )
2227
- ]
2228
- }
2229
- ),
2230
- /* @__PURE__ */ jsxs(
2231
- "linearGradient",
2232
- {
2233
- id: p,
2234
- spreadMethod: "pad",
2235
- gradientTransform: "matrix(521.97632 0 0 -521.97632 69.067 191.973)",
2236
- gradientUnits: "userSpaceOnUse",
2237
- y2: 0,
2238
- x2: 1,
2239
- y1: 0,
2240
- x1: 0,
2241
- children: [
2242
- /* @__PURE__ */ jsx(
2243
- "stop",
2244
- {
2245
- offset: 0,
2246
- style: {
2247
- stopOpacity: 1,
2248
- stopColor: "#ff4e00"
2249
- }
2250
- }
2251
- ),
2252
- /* @__PURE__ */ jsx(
2253
- "stop",
2254
- {
2255
- offset: 1,
2256
- style: {
2257
- stopOpacity: 1,
2258
- stopColor: "#ff1791"
2259
- }
2260
- }
2261
- )
2262
- ]
2263
- }
2264
- ),
2265
- /* @__PURE__ */ jsxs(
2266
- "linearGradient",
2267
- {
2268
- id: q,
2269
- spreadMethod: "pad",
2270
- gradientTransform: "matrix(523.09039 0 0 -523.09039 67.312 191.973)",
2271
- gradientUnits: "userSpaceOnUse",
2272
- y2: 0,
2273
- x2: 1,
2274
- y1: 0,
2275
- x1: 0,
2276
- children: [
2277
- /* @__PURE__ */ jsx(
2278
- "stop",
2279
- {
2280
- offset: 0,
2281
- style: {
2282
- stopOpacity: 1,
2283
- stopColor: "#ff4e00"
2284
- }
2285
- }
2286
- ),
2287
- /* @__PURE__ */ jsx(
2288
- "stop",
2289
- {
2290
- offset: 1,
2291
- style: {
2292
- stopOpacity: 1,
2293
- stopColor: "#ff1791"
2294
- }
2295
- }
2296
- )
2297
- ]
2298
- }
2299
- ),
2300
- /* @__PURE__ */ jsxs(
2301
- "linearGradient",
2302
- {
2303
- id: r,
2304
- spreadMethod: "pad",
2305
- gradientTransform: "matrix(524.84045 0 0 -524.84045 63.801 159.5)",
2306
- gradientUnits: "userSpaceOnUse",
2307
- y2: 0,
2308
- x2: 1,
2309
- y1: 0,
2310
- x1: 0,
2311
- children: [
2312
- /* @__PURE__ */ jsx(
2313
- "stop",
2314
- {
2315
- offset: 0,
2316
- style: {
2317
- stopOpacity: 1,
2318
- stopColor: "#ff4e00"
2319
- }
2320
- }
2321
- ),
2322
- /* @__PURE__ */ jsx(
2323
- "stop",
2324
- {
2325
- offset: 1,
2326
- style: {
2327
- stopOpacity: 1,
2328
- stopColor: "#ff1791"
2329
- }
2330
- }
2331
- )
2332
- ]
2333
- }
2334
- ),
2335
- /* @__PURE__ */ jsx("clipPath", { id: a, clipPathUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { d: "M0 319h657.706V0H0Z" }) }),
2336
- /* @__PURE__ */ jsx("clipPath", { id: b, clipPathUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { d: "M423.64 242h164.999V77H423.64Z" }) }),
2337
- /* @__PURE__ */ jsx("clipPath", { id: e, clipPathUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { d: "M0 319h657.706V0H0Z" }) }),
2338
- /* @__PURE__ */ jsx("clipPath", { id: f, clipPathUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { d: "M311.3 242h93.031V77H311.3Z" }) }),
2339
- /* @__PURE__ */ jsx("clipPath", { id: h, clipPathUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { d: "M198.96 242h35.106V77H198.96Z" }) }),
2340
- /* @__PURE__ */ jsx("clipPath", { id: n, clipPathUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { d: "M0 319h657.706V0H0Z" }) }),
2341
- /* @__PURE__ */ jsx("clipPath", { id: o, clipPathUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { d: "M69.067 242H169.12V141.947H69.067Z" }) })
2342
- ] }),
2343
- /* @__PURE__ */ jsx("g", { clipPath: `url(#${a})`, transform: "matrix(1.33333 0 0 -1.33333 0 425.333)", children: /* @__PURE__ */ jsx(
2344
- "g",
2345
- {
2346
- style: {
2347
- opacity: 0.69999701
2348
- },
2349
- clipPath: `url(#${b})`,
2350
- children: /* @__PURE__ */ jsx(
2351
- "path",
2352
- {
2353
- style: {
2354
- fill: `url(#${c})`,
2355
- stroke: "none"
2356
- },
2357
- d: "M558.674 82.142c6.855-6.855 17.969-6.855 24.824 0 6.854 6.855 6.854 17.969 0 24.823L453.605 236.858c-6.855 6.855-17.969 6.855-24.824 0s-6.855-17.969 0-24.823z"
2358
- }
2359
- )
2360
- }
2361
- ) }),
2362
- /* @__PURE__ */ jsx(
2363
- "path",
2364
- {
2365
- style: {
2366
- fill: `url(#${d})`,
2367
- stroke: "none"
2368
- },
2369
- d: "M558.674 236.858 428.781 106.966c-6.855-6.855-6.855-17.969 0-24.825 6.855-6.854 17.969-6.854 24.823 0l129.894 129.894c6.854 6.855 6.854 17.968 0 24.823A17.498 17.498 0 0 1 571.086 242a17.495 17.495 0 0 1-12.412-5.142",
2370
- transform: "matrix(1.33333 0 0 -1.33333 0 425.333)"
2371
- }
2372
- ),
2373
- /* @__PURE__ */ jsxs("g", { clipPath: `url(#${e})`, transform: "matrix(1.33333 0 0 -1.33333 0 425.333)", children: [
2374
- /* @__PURE__ */ jsx(
2375
- "g",
2376
- {
2377
- style: {
2378
- opacity: 0.69999701
2379
- },
2380
- clipPath: `url(#${f})`,
2381
- children: /* @__PURE__ */ jsx(
2382
- "path",
2383
- {
2384
- style: {
2385
- fill: `url(#${g})`,
2386
- stroke: "none"
2387
- },
2388
- d: "M328.853 112.107c22.297 0 40.372 18.075 40.372 40.372v71.315c0 10.054 7.505 18.206 17.554 18.206 10.048 0 17.552-8.152 17.552-18.206v-71.315c0-41.686-33.793-75.479-75.478-75.479-9.694 0-17.553 7.859-17.553 17.554 0 9.694 7.859 17.553 17.553 17.553"
2389
- }
2390
- )
2391
- }
2392
- ),
2393
- /* @__PURE__ */ jsx(
2394
- "g",
2395
- {
2396
- style: {
2397
- opacity: 0.69999701
2398
- },
2399
- clipPath: `url(#${h})`,
2400
- children: /* @__PURE__ */ jsx(
2401
- "path",
2402
- {
2403
- style: {
2404
- fill: `url(#${i})`,
2405
- stroke: "none"
2406
- },
2407
- d: "M216.513 242c-10.049 0-17.553-8.152-17.553-18.206V95.206c0-10.054 7.504-18.206 17.553-18.206 10.048 0 17.553 8.152 17.553 18.206v128.588c0 10.054-7.505 18.206-17.553 18.206"
2408
- }
2409
- )
2410
- }
2411
- )
2412
- ] }),
2413
- /* @__PURE__ */ jsx(
2414
- "path",
2415
- {
2416
- style: {
2417
- fill: `url(#${j})`,
2418
- stroke: "none"
2419
- },
2420
- d: "M369.225 224.447c0-9.694 7.859-17.553 17.553-17.553 9.695 0 17.553 7.859 17.553 17.553s-7.858 17.552-17.553 17.552c-9.694 0-17.553-7.858-17.553-17.552",
2421
- transform: "matrix(1.33333 0 0 -1.33333 0 425.333)"
2422
- }
2423
- ),
2424
- /* @__PURE__ */ jsx(
2425
- "path",
2426
- {
2427
- style: {
2428
- fill: `url(#${k})`,
2429
- stroke: "none"
2430
- },
2431
- d: "M553.532 94.554c0-9.695 7.859-17.554 17.553-17.554 9.695 0 17.554 7.859 17.554 17.554 0 9.694-7.859 17.552-17.554 17.552-9.694 0-17.553-7.858-17.553-17.552",
2432
- transform: "matrix(1.33333 0 0 -1.33333 0 425.333)"
2433
- }
2434
- ),
2435
- /* @__PURE__ */ jsx(
2436
- "path",
2437
- {
2438
- style: {
2439
- fill: `url(#${l})`,
2440
- stroke: "none"
2441
- },
2442
- d: "M69.067 223.794V95.206C69.067 85.152 76.571 77 86.62 77c10.048 0 17.553 8.152 17.553 18.206v128.588c0 10.055-7.505 18.205-17.553 18.205-10.049 0-17.553-8.15-17.553-18.205",
2443
- transform: "matrix(1.33333 0 0 -1.33333 0 425.333)"
2444
- }
2445
- ),
2446
- /* @__PURE__ */ jsx(
2447
- "path",
2448
- {
2449
- style: {
2450
- fill: `url(#${m})`,
2451
- stroke: "none"
2452
- },
2453
- d: "M198.96 94.554c0-9.695 7.859-17.554 17.553-17.554 9.695 0 17.554 7.859 17.554 17.554 0 9.694-7.859 17.553-17.554 17.553-9.694 0-17.553-7.859-17.553-17.553",
2454
- transform: "matrix(1.33333 0 0 -1.33333 0 425.333)"
2455
- }
2456
- ),
2457
- /* @__PURE__ */ jsx("g", { clipPath: `url(#${n})`, transform: "matrix(1.33333 0 0 -1.33333 0 425.333)", children: /* @__PURE__ */ jsx(
2458
- "g",
2459
- {
2460
- style: {
2461
- opacity: 0.69999701
2462
- },
2463
- clipPath: `url(#${o})`,
2464
- children: /* @__PURE__ */ jsx(
2465
- "path",
2466
- {
2467
- style: {
2468
- fill: `url(#${p})`,
2469
- stroke: "none"
2470
- },
2471
- d: "M139.155 147.088c6.855-6.855 17.969-6.855 24.824 0s6.855 17.969 0 24.824l-64.947 64.946c-6.855 6.855-17.969 6.855-24.824 0s-6.855-17.969 0-24.823z"
2472
- }
2473
- )
2474
- }
2475
- ) }),
2476
- /* @__PURE__ */ jsx(
2477
- "path",
2478
- {
2479
- style: {
2480
- fill: `url(#${q})`,
2481
- stroke: "none"
2482
- },
2483
- d: "m204.101 236.858-64.947-64.946c-6.854-6.855-6.854-17.969 0-24.824 6.856-6.855 17.97-6.855 24.824 0l64.947 64.947c6.855 6.855 6.855 17.968 0 24.823A17.495 17.495 0 0 1 216.513 242a17.498 17.498 0 0 1-12.412-5.142",
2484
- transform: "matrix(1.33333 0 0 -1.33333 0 425.333)"
2485
- }
2486
- ),
2487
- /* @__PURE__ */ jsx(
2488
- "path",
2489
- {
2490
- style: {
2491
- fill: `url(#${r})`,
2492
- stroke: "none"
2493
- },
2494
- d: "M253.374 223.794v-71.315c0-41.685 33.793-75.479 75.479-75.479 9.695 0 17.553 7.859 17.553 17.554 0 9.694-7.858 17.553-17.553 17.553-22.297 0-40.372 18.075-40.372 40.372v71.315c0 10.055-7.505 18.205-17.554 18.205s-17.553-8.15-17.553-18.205",
2495
- transform: "matrix(1.33333 0 0 -1.33333 0 425.333)"
2496
- }
2497
- )
2498
- ]
2499
- }
2500
- );
2501
- }
2502
- const Logo = styled.span`
2503
- display: inline-block;
2504
- height: 0.8em;
2505
- margin-right: 1em;
2506
- transform: translate(0.3em, -0.2em);
2507
- `, Header = () => /* @__PURE__ */ jsxs(Fragment, { children: [
2508
- /* @__PURE__ */ jsx(Logo, { children: /* @__PURE__ */ jsx(MuxLogo, { height: 13 }) }),
2509
- "API Credentials"
2510
- ] }), fieldNames = ["token", "secretKey", "enableSignedUrls"];
2511
- function ConfigureApi({ secrets, setDialogState }) {
2512
- var _a, _b;
2513
- const client = useClient(), [state, dispatch] = useSecretsFormState(secrets), hasSecretsInitially = useMemo(() => secrets.token && secrets.secretKey, [secrets]), handleClose = useCallback(() => setDialogState(!1), [setDialogState]), dirty = useMemo(
2514
- () => secrets.token !== state.token || secrets.secretKey !== state.secretKey || secrets.enableSignedUrls !== state.enableSignedUrls,
2515
- [secrets, state]
2516
- ), id = `ConfigureApi${useId()}`, [tokenId, secretKeyId, enableSignedUrlsId] = useMemo(
2517
- () => fieldNames.map((field) => `${id}-${field}`),
2518
- [id]
2519
- ), firstField = useRef(null), handleSaveSecrets = useSaveSecrets(client, secrets), saving = useRef(!1), handleSubmit = useCallback(
2520
- (event) => {
2521
- if (event.preventDefault(), !saving.current && event.currentTarget.reportValidity()) {
2522
- saving.current = !0, dispatch({ type: "submit" });
2523
- const { token, secretKey, enableSignedUrls } = state;
2524
- handleSaveSecrets({ token, secretKey, enableSignedUrls }).then((savedSecrets) => {
2525
- const { projectId, dataset } = client.config();
2526
- clear([cacheNs, _id, projectId, dataset]), preload(() => Promise.resolve(savedSecrets), [cacheNs, _id, projectId, dataset]), setDialogState(!1);
2527
- }).catch((err) => dispatch({ type: "error", payload: err.message })).finally(() => {
2528
- saving.current = !1;
2529
- });
2530
- }
2531
- },
2532
- [client, dispatch, handleSaveSecrets, setDialogState, state]
2533
- ), handleChangeToken = useCallback(
2534
- (event) => {
2535
- dispatch({
2536
- type: "change",
2537
- payload: { name: "token", value: event.currentTarget.value }
2538
- });
2539
- },
2540
- [dispatch]
2541
- ), handleChangeSecretKey = useCallback(
2542
- (event) => {
2543
- dispatch({
2544
- type: "change",
2545
- payload: { name: "secretKey", value: event.currentTarget.value }
2546
- });
2547
- },
2548
- [dispatch]
2549
- ), handleChangeEnableSignedUrls = useCallback(
2550
- (event) => {
2551
- dispatch({
2552
- type: "change",
2553
- payload: { name: "enableSignedUrls", value: event.currentTarget.checked }
2554
- });
2555
- },
2556
- [dispatch]
2557
- );
2558
- return useEffect(() => {
2559
- firstField.current && firstField.current.focus();
2560
- }, [firstField]), /* @__PURE__ */ jsx(
2561
- Dialog,
2562
- {
2563
- animate: !0,
2564
- id,
2565
- onClose: handleClose,
2566
- header: /* @__PURE__ */ jsx(Header, {}),
2567
- width: 1,
2568
- style: {
2569
- maxWidth: "550px"
2570
- },
2571
- children: /* @__PURE__ */ jsx(Box, { padding: 4, style: { position: "relative" }, children: /* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, noValidate: !0, children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
2572
- !hasSecretsInitially && /* @__PURE__ */ jsx(Card, { padding: [3, 3, 3], radius: 2, shadow: 1, tone: "primary", children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
2573
- /* @__PURE__ */ jsxs(Text, { size: 1, children: [
2574
- "To set up a new access token, go to your",
2575
- " ",
2576
- /* @__PURE__ */ jsx(
2577
- "a",
2578
- {
2579
- href: "https://dashboard.mux.com/settings/access-tokens",
2580
- target: "_blank",
2581
- rel: "noreferrer noopener",
2582
- children: "account on mux.com"
2583
- }
2584
- ),
2585
- "."
2586
- ] }),
2587
- /* @__PURE__ */ jsxs(Text, { size: 1, children: [
2588
- "The access token needs permissions: ",
2589
- /* @__PURE__ */ jsx("strong", { children: "Mux Video " }),
2590
- "(Full Access) and ",
2591
- /* @__PURE__ */ jsx("strong", { children: "Mux Data" }),
2592
- " (Read)",
2593
- /* @__PURE__ */ jsx("br", {}),
2594
- "The credentials will be stored safely in a hidden document only available to editors."
2595
- ] })
2596
- ] }) }),
2597
- /* @__PURE__ */ jsx(FormField$1, { title: "Access Token", inputId: tokenId, children: /* @__PURE__ */ jsx(
2598
- TextInput,
2599
- {
2600
- id: tokenId,
2601
- ref: firstField,
2602
- onChange: handleChangeToken,
2603
- type: "text",
2604
- value: (_a = state.token) != null ? _a : "",
2605
- required: !!state.secretKey || state.enableSignedUrls
2606
- }
2607
- ) }),
2608
- /* @__PURE__ */ jsx(FormField$1, { title: "Secret Key", inputId: secretKeyId, children: /* @__PURE__ */ jsx(
2609
- TextInput,
2610
- {
2611
- id: secretKeyId,
2612
- onChange: handleChangeSecretKey,
2613
- type: "text",
2614
- value: (_b = state.secretKey) != null ? _b : "",
2615
- required: !!state.token || state.enableSignedUrls
2616
- }
2617
- ) }),
2618
- /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
2619
- /* @__PURE__ */ jsxs(Flex, { align: "center", children: [
2620
- /* @__PURE__ */ jsx(
2621
- Checkbox,
2622
- {
2623
- id: enableSignedUrlsId,
2624
- onChange: handleChangeEnableSignedUrls,
2625
- checked: state.enableSignedUrls,
2626
- style: { display: "block" }
2627
- }
2628
- ),
2629
- /* @__PURE__ */ jsx(Box, { flex: 1, paddingLeft: 3, children: /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx("label", { htmlFor: enableSignedUrlsId, children: "Enable Signed Urls" }) }) })
2630
- ] }),
2631
- secrets.signingKeyId && state.enableSignedUrls ? /* @__PURE__ */ jsx(Card, { padding: [3, 3, 3], radius: 2, shadow: 1, tone: "caution", children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
2632
- /* @__PURE__ */ jsx(Text, { size: 1, children: "The signing key ID that Sanity will use is:" }),
2633
- /* @__PURE__ */ jsx(Code, { size: 1, children: secrets.signingKeyId }),
2634
- /* @__PURE__ */ jsxs(Text, { size: 1, children: [
2635
- "This key is only used for previewing content in the Sanity UI.",
2636
- /* @__PURE__ */ jsx("br", {}),
2637
- "You should generate a different key to use in your application server."
2638
- ] })
2639
- ] }) }) : null
2640
- ] }),
2641
- /* @__PURE__ */ jsxs(Inline, { space: 2, children: [
2642
- /* @__PURE__ */ jsx(
2643
- Button,
2644
- {
2645
- text: "Save",
2646
- disabled: !dirty,
2647
- loading: state.submitting,
2648
- tone: "primary",
2649
- mode: "default",
2650
- type: "submit"
2651
- }
2652
- ),
2653
- /* @__PURE__ */ jsx(
2654
- Button,
2655
- {
2656
- disabled: state.submitting,
2657
- text: "Cancel",
2658
- mode: "bleed",
2659
- onClick: handleClose
2660
- }
2661
- )
2662
- ] }),
2663
- state.error && /* @__PURE__ */ jsx(Card, { padding: [3, 3, 3], radius: 2, shadow: 1, tone: "critical", children: /* @__PURE__ */ jsx(Text, { children: state.error }) })
2664
- ] }) }) })
2665
- }
2666
- );
2667
- }
2668
- var ConfigureApi$1 = memo(ConfigureApi);
2669
- function ErrorBoundaryCard(props) {
2670
- const { children, schemaType } = props, { push: pushToast } = useToast(), errorRef = useRef(null), { ErrorBoundary, didCatch, error, reset } = useErrorBoundary({
2671
- onDidCatch: (err, errorInfo) => {
2672
- console.group(err.toString()), console.groupCollapsed("console.error"), console.error(err), console.groupEnd(), err.stack && (console.groupCollapsed("error.stack"), console.log(err.stack), console.groupEnd()), errorInfo != null && errorInfo.componentStack && (console.groupCollapsed("errorInfo.componentStack"), console.log(errorInfo.componentStack), console.groupEnd()), console.groupEnd(), pushToast({
2673
- status: "error",
2674
- title: "Plugin crashed",
2675
- description: /* @__PURE__ */ jsx(Flex, { align: "center", children: /* @__PURE__ */ jsxs(Inline, { space: 1, children: [
2676
- "An error happened while rendering",
2677
- /* @__PURE__ */ jsx(
2678
- Button,
2679
- {
2680
- padding: 1,
2681
- fontSize: 1,
2682
- style: { transform: "translateY(1px)" },
2683
- mode: "ghost",
2684
- text: schemaType.title,
2685
- onClick: () => {
2686
- errorRef.current && scrollIntoView(errorRef.current, {
2687
- behavior: "smooth",
2688
- scrollMode: "if-needed",
2689
- block: "center"
2690
- });
2691
- }
2692
- }
2693
- )
2694
- ] }) })
2695
- });
2696
- }
2697
- }), handleRetry = useCallback(() => {
2698
- clear([name]), reset();
2699
- }, [reset]);
2700
- return didCatch ? /* @__PURE__ */ jsx(Card, { ref: errorRef, paddingX: [2, 3, 4, 4], height: "fill", shadow: 1, overflow: "auto", children: /* @__PURE__ */ jsx(Flex, { justify: "flex-start", align: "center", height: "fill", children: /* @__PURE__ */ jsxs(Grid, { columns: 1, gap: [2, 3, 4, 4], children: [
2701
- /* @__PURE__ */ jsxs(Heading, { as: "h1", children: [
2702
- "The ",
2703
- /* @__PURE__ */ jsx("code", { children: name }),
2704
- " plugin crashed"
2705
- ] }),
2706
- (error == null ? void 0 : error.message) && /* @__PURE__ */ jsx(Card, { padding: 3, tone: "critical", shadow: 1, radius: 2, children: /* @__PURE__ */ jsx(Text, { children: error.message }) }),
2707
- /* @__PURE__ */ jsx(Inline, { children: /* @__PURE__ */ jsx(Button, { onClick: handleRetry, text: "Retry" }) })
2708
- ] }) }) }) : /* @__PURE__ */ jsx(ErrorBoundary, { children });
2709
- }
2710
- var ErrorBoundaryCard$1 = memo(ErrorBoundaryCard);
2711
- const InputFallback = () => /* @__PURE__ */ jsx("div", { style: { padding: 1 }, children: /* @__PURE__ */ jsx(
2712
- Card,
2713
- {
2714
- shadow: 1,
2715
- sizing: "border",
2716
- style: { aspectRatio: "16/9", width: "100%", borderRadius: "1px" },
2717
- children: /* @__PURE__ */ jsxs(Flex, { align: "center", direction: "column", height: "fill", justify: "center", children: [
2718
- /* @__PURE__ */ jsx(Spinner, { muted: !0 }),
2719
- /* @__PURE__ */ jsx(Box, { marginTop: 3, children: /* @__PURE__ */ jsx(Text, { align: "center", muted: !0, size: 1, children: "Loading\u2026" }) })
2720
- ] })
2721
- }
2722
- ) });
2723
- function Onboard(props) {
2724
- const { setDialogState } = props, handleOpen = useCallback(() => setDialogState("secrets"), [setDialogState]);
2725
- return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("div", { style: { padding: 2 }, children: /* @__PURE__ */ jsx(
2726
- Card,
2727
- {
2728
- display: "flex",
2729
- sizing: "border",
2730
- style: {
2731
- aspectRatio: "16/9",
2732
- width: "100%",
2733
- boxShadow: "var(--card-bg-color) 0 0 0 2px"
2734
- },
2735
- paddingX: [2, 3, 4, 4],
2736
- radius: 1,
2737
- tone: "transparent",
2738
- children: /* @__PURE__ */ jsx(Flex, { justify: "flex-start", align: "center", children: /* @__PURE__ */ jsxs(Grid, { columns: 1, gap: [2, 3, 4, 4], children: [
2739
- /* @__PURE__ */ jsx(Inline, { paddingY: 1, children: /* @__PURE__ */ jsx("div", { style: { height: "32px" }, children: /* @__PURE__ */ jsx(MuxLogo, {}) }) }),
2740
- /* @__PURE__ */ jsx(Inline, { paddingY: 1, children: /* @__PURE__ */ jsx(Heading, { size: [0, 1, 2, 2], children: "Upload and preview videos directly from your studio." }) }),
2741
- /* @__PURE__ */ jsx(Inline, { paddingY: 1, children: /* @__PURE__ */ jsx(Button, { mode: "ghost", icon: PlugIcon, text: "Configure API", onClick: handleOpen }) })
2742
- ] }) })
2743
- }
2744
- ) }) });
2745
- }
2746
- function createUpChunkObservable(uuid2, uploadUrl2, source) {
2747
- return new Observable((subscriber) => {
2748
- const upchunk = UpChunk.createUpload({
2749
- endpoint: uploadUrl2,
2750
- file: source,
2751
- dynamicChunkSize: !0
2752
- // changes the chunk size based on network speeds
2753
- }), successHandler = () => {
2754
- subscriber.next({
2755
- type: "success",
2756
- id: uuid2
2757
- }), subscriber.complete();
2758
- }, errorHandler = (data) => subscriber.error(new Error(data.detail.message)), progressHandler = (data) => subscriber.next({ type: "progress", percent: data.detail }), offlineHandler = () => {
2759
- upchunk.pause(), subscriber.next({
2760
- type: "pause",
2761
- id: uuid2
2762
- });
2763
- }, onlineHandler = () => {
2764
- upchunk.resume(), subscriber.next({
2765
- type: "resume",
2766
- id: uuid2
2767
- });
2768
- };
2769
- return upchunk.on("success", successHandler), upchunk.on("error", errorHandler), upchunk.on("progress", progressHandler), upchunk.on("offline", offlineHandler), upchunk.on("online", onlineHandler), () => upchunk.abort();
2770
- });
2771
- }
2772
- function cancelUpload(client, uuid2) {
2773
- return client.observable.request({
2774
- url: `/addons/mux/uploads/${client.config().dataset}/${uuid2}`,
2775
- withCredentials: !0,
2776
- method: "DELETE"
2777
- });
2778
- }
2779
- function uploadUrl({
2780
- url,
2781
- settings,
2782
- client
2783
- }) {
2784
- return testUrl(url).pipe(
2785
- switchMap((validUrl) => concat(
2786
- of({ type: "url", url: validUrl }),
2787
- testSecretsObservable(client).pipe(
2788
- switchMap((json) => {
2789
- if (!json || !json.status)
2790
- return throwError(new Error("Invalid credentials"));
2791
- const uuid$1 = uuid(), muxBody = settings;
2792
- muxBody.input || (muxBody.input = [{ type: "video" }]), muxBody.input[0].url = validUrl;
2793
- const query = {
2794
- muxBody: JSON.stringify(muxBody),
2795
- filename: validUrl.split("/").slice(-1)[0]
2796
- }, dataset = client.config().dataset;
2797
- return defer(
2798
- () => client.observable.request({
2799
- url: `/addons/mux/assets/${dataset}`,
2800
- withCredentials: !0,
2801
- method: "POST",
2802
- headers: {
2803
- "MUX-Proxy-UUID": uuid$1,
2804
- "Content-Type": "application/json"
2805
- },
2806
- query
2807
- })
2808
- ).pipe(
2809
- mergeMap((result) => {
2810
- const asset = result && result.results && result.results[0] && result.results[0].document || null;
2811
- return asset ? of({ type: "success", id: uuid$1, asset }) : throwError(new Error("No asset document returned"));
2812
- })
2813
- );
2814
- })
2815
- )
2816
- ))
2817
- );
2818
- }
2819
- function uploadFile({
2820
- settings,
2821
- client,
2822
- file
2823
- }) {
2824
- return testFile(file).pipe(
2825
- switchMap((fileOptions) => concat(
2826
- of({ type: "file", file: fileOptions }),
2827
- testSecretsObservable(client).pipe(
2828
- switchMap((json) => {
2829
- if (!json || !json.status)
2830
- return throwError(() => new Error("Invalid credentials"));
2831
- const uuid$1 = uuid(), body = settings;
2832
- return concat(
2833
- of({ type: "uuid", uuid: uuid$1 }),
2834
- defer(
2835
- () => client.observable.request({
2836
- url: `/addons/mux/uploads/${client.config().dataset}`,
2837
- withCredentials: !0,
2838
- method: "POST",
2839
- headers: {
2840
- "MUX-Proxy-UUID": uuid$1,
2841
- "Content-Type": "application/json"
2842
- },
2843
- body
2844
- })
2845
- ).pipe(
2846
- mergeMap((result) => createUpChunkObservable(uuid$1, result.upload.url, file).pipe(
2847
- // eslint-disable-next-line no-warning-comments
2848
- // @TODO type the observable events
2849
- // eslint-disable-next-line max-nested-callbacks
2850
- mergeMap((event) => event.type !== "success" ? of(event) : from(updateAssetDocumentFromUpload(client, uuid$1)).pipe(
2851
- // eslint-disable-next-line max-nested-callbacks
2852
- mergeMap((doc) => of({ ...event, asset: doc }))
2853
- )),
2854
- // eslint-disable-next-line max-nested-callbacks
2855
- catchError((err) => cancelUpload(client, uuid$1).pipe(mergeMapTo(throwError(err))))
2856
- ))
2857
- )
2858
- );
2859
- })
2860
- )
2861
- ))
2862
- );
2863
- }
2864
- function getUpload(client, assetId) {
2865
- const { dataset } = client.config();
2866
- return client.request({
2867
- url: `/addons/mux/uploads/${dataset}/${assetId}`,
2868
- withCredentials: !0,
2869
- method: "GET"
2870
- });
2871
- }
2872
- function pollUpload(client, uuid2) {
2873
- let pollInterval, tries = 0, assetId, upload;
2874
- return new Promise((resolve, reject) => {
2875
- pollInterval = setInterval(async () => {
2876
- try {
2877
- upload = await getUpload(client, uuid2);
2878
- } catch (err) {
2879
- reject(err);
2880
- return;
2881
- }
2882
- assetId = upload && upload.data && upload.data.asset_id, assetId && (clearInterval(pollInterval), resolve(upload)), tries > 10 && (clearInterval(pollInterval), reject(new Error("Upload did not finish"))), tries++;
2883
- }, 2e3);
2884
- });
2885
- }
2886
- async function updateAssetDocumentFromUpload(client, uuid2) {
2887
- let upload, asset;
2888
- try {
2889
- upload = await pollUpload(client, uuid2);
2890
- } catch (err) {
2891
- return Promise.reject(err);
2892
- }
2893
- try {
2894
- asset = await getAsset(client, upload.data.asset_id);
2895
- } catch (err) {
2896
- return Promise.reject(err);
2897
- }
2898
- const doc = {
2899
- _id: uuid2,
2900
- _type: "mux.videoAsset",
2901
- status: asset.data.status,
2902
- data: asset.data,
2903
- assetId: asset.data.id,
2904
- playbackId: asset.data.playback_ids[0].id,
2905
- uploadId: upload.data.id
2906
- };
2907
- return client.createOrReplace(doc).then(() => doc);
2908
- }
2909
- function testFile(file) {
2910
- if (typeof window < "u" && file instanceof window.File) {
2911
- const fileOptions = optionsFromFile({}, file);
2912
- return of(fileOptions);
2913
- }
2914
- return throwError(new Error("Invalid file"));
2915
- }
2916
- function testUrl(url) {
2917
- const error = new Error("Invalid URL");
2918
- if (typeof url != "string")
2919
- return throwError(error);
2920
- let parsed;
2921
- try {
2922
- parsed = new URL(url);
2923
- } catch {
2924
- return throwError(error);
2925
- }
2926
- return parsed && !parsed.protocol.match(/http:|https:/) ? throwError(error) : of(url);
2927
- }
2928
- function optionsFromFile(opts, file) {
2929
- if (!(typeof window > "u" || !(file instanceof window.File)))
2930
- return {
2931
- name: opts.preserveFilename === !1 ? void 0 : file.name,
2932
- type: file.type
2933
- };
2934
- }
2935
- function isValidUrl(url) {
2936
- try {
2937
- const parsed = new URL(url);
2938
- return parsed && !!parsed.protocol.match(/http:|https:/);
2939
- } catch {
2940
- return !1;
2941
- }
2942
- }
2943
- function extractDroppedFiles(dataTransfer) {
2944
- const files = Array.from(dataTransfer.files || []), items = Array.from(dataTransfer.items || []);
2945
- return files && files.length > 0 ? Promise.resolve(files) : normalizeItems(items).then((arr) => arr.flat());
2946
- }
2947
- function normalizeItems(items) {
2948
- return Promise.all(
2949
- items.map((item) => {
2950
- if (item.kind === "file" && item.webkitGetAsEntry) {
2951
- let entry;
2952
- try {
2953
- entry = item.webkitGetAsEntry();
2954
- } catch {
2955
- return [item.getAsFile()];
2956
- }
2957
- return entry ? entry.isDirectory ? walk(entry) : [item.getAsFile()] : [];
2958
- }
2959
- if (item.kind === "file") {
2960
- const file = item.getAsFile();
2961
- return Promise.resolve(file ? [file] : []);
2962
- }
2963
- return new Promise((resolve) => item.getAsString(resolve)).then(
2964
- (str) => str ? [new File([str], "unknown.txt", { type: item.type })] : []
2965
- );
2966
- })
2967
- );
2968
- }
2969
- function isFile(entry) {
2970
- return entry.isFile;
2971
- }
2972
- function isDirectory(entry) {
2973
- return entry.isDirectory;
2974
- }
2975
- function walk(entry) {
2976
- if (isFile(entry))
2977
- return new Promise((resolve) => entry.file(resolve)).then((file) => [file]);
2978
- if (isDirectory(entry)) {
2979
- const dir = entry.createReader();
2980
- return new Promise((resolve) => dir.readEntries(resolve)).then((entries) => entries.filter((entr) => !entr.name.startsWith("."))).then((entries) => Promise.all(entries.map(walk)).then((arr) => arr.flat()));
2981
- }
2982
- return Promise.resolve([]);
2983
- }
2984
- function SelectAssets({ asset: selectedAsset, onChange, setDialogState }) {
2985
- const handleSelect = useCallback(
2986
- (chosenAsset) => {
2987
- chosenAsset != null && chosenAsset._id || onChange(PatchEvent.from([unset(["asset"])])), chosenAsset._id !== (selectedAsset == null ? void 0 : selectedAsset._id) && onChange(
2988
- PatchEvent.from([
2989
- setIfMissing({ asset: {}, _type: "mux.video" }),
2990
- set({ _type: "reference", _weak: !0, _ref: chosenAsset._id }, ["asset"])
2991
- ])
2992
- ), setDialogState(!1);
2993
- },
2994
- [onChange, setDialogState, selectedAsset]
2995
- );
2996
- return /* @__PURE__ */ jsx(VideosBrowser, { onSelect: handleSelect });
2997
- }
2998
- const StyledDialog = styled(Dialog)`
2999
- > div[data-ui='DialogCard'] > div[data-ui='Card'] {
3000
- height: 100%;
3001
- }
3002
- `;
3003
- function InputBrowser({
3004
- setDialogState,
3005
- asset,
3006
- onChange
3007
- }) {
3008
- const id = `InputBrowser${useId()}`, handleClose = useCallback(() => setDialogState(!1), [setDialogState]);
3009
- return /* @__PURE__ */ jsx(
3010
- StyledDialog,
3011
- {
3012
- __unstable_autoFocus: !0,
3013
- header: "Select video",
3014
- id,
3015
- onClose: handleClose,
3016
- width: 2,
3017
- children: /* @__PURE__ */ jsx(SelectAssets, { asset, onChange, setDialogState })
3018
- }
3019
- );
3020
- }
3021
- const useCancelUpload = (asset, onChange) => {
3022
- const client = useClient();
3023
- return useCallback(() => {
3024
- asset && (onChange(PatchEvent.from(unset())), asset.assetId && deleteAssetOnMux(client, asset.assetId), asset._id && client.delete(asset._id));
3025
- }, [asset, client, onChange]);
3026
- };
3027
- styled.div`
3028
- && {
3029
- --media-background-color: transparent;
3030
- --media-button-icon-width: 100%;
3031
- --media-button-icon-height: auto;
3032
- pointer-events: none;
3033
- width: 100%;
3034
- display: flex;
3035
- flex-flow: row;
3036
- align-items: center;
3037
- justify-content: center;
3038
- media-play-button {
3039
- --media-control-background: transparent;
3040
- --media-control-hover-background: transparent;
3041
- padding: 0;
3042
- width: max(27px, min(9%, 90px));
3043
- }
3044
- }
3045
- `;
3046
- const TopControls = styled.div`
3047
- position: absolute;
3048
- top: 0;
3049
- right: 0;
3050
- justify-content: flex-end;
3051
- button {
3052
- height: auto;
3053
- }
3054
- `, CardWrapper = styled(Card)`
3055
- min-height: 82px;
3056
- box-sizing: border-box;
3057
- `, FlexWrapper = styled(Flex)`
3058
- text-overflow: ellipsis;
3059
- overflow: hidden;
3060
- `, LeftSection = styled(Stack)`
3061
- position: relative;
3062
- width: 60%;
3063
- `, CodeWrapper = styled(Code)`
3064
- position: relative;
3065
- width: 100%;
3066
-
3067
- code {
3068
- overflow: hidden;
3069
- text-overflow: ellipsis;
3070
- position: relative;
3071
- max-width: 200px;
3072
- }
3073
- `, UploadProgress = ({
3074
- progress = 100,
3075
- onCancel,
3076
- filename,
3077
- text = "Uploading"
3078
- }) => /* @__PURE__ */ jsx(CardWrapper, { tone: "primary", padding: 4, border: !0, height: "fill", children: /* @__PURE__ */ jsxs(FlexWrapper, { align: "center", justify: "space-between", height: "fill", direction: "row", gap: 2, children: [
3079
- /* @__PURE__ */ jsxs(LeftSection, { children: [
3080
- /* @__PURE__ */ jsx(Flex, { justify: "center", gap: [3, 3, 2, 2], direction: ["column", "column", "row"], children: /* @__PURE__ */ jsx(Text, { size: 1, children: /* @__PURE__ */ jsxs(Inline, { space: 2, children: [
3081
- text,
3082
- /* @__PURE__ */ jsx(CodeWrapper, { size: 1, children: filename || "..." })
3083
- ] }) }) }),
3084
- /* @__PURE__ */ jsx(Card, { marginTop: 3, radius: 5, shadow: 1, children: /* @__PURE__ */ jsx(LinearProgress, { value: progress }) })
3085
- ] }),
3086
- onCancel ? /* @__PURE__ */ jsx(
3087
- Button,
3088
- {
3089
- fontSize: 2,
3090
- text: "Cancel upload",
3091
- mode: "ghost",
3092
- tone: "critical",
3093
- onClick: onCancel
3094
- }
3095
- ) : null
3096
- ] }) }), Player = ({ asset, buttons, readOnly, onChange }) => {
3097
- var _a, _b, _c, _d;
3098
- const isLoading = useMemo(() => (asset == null ? void 0 : asset.status) === "preparing" ? "Preparing the video" : (asset == null ? void 0 : asset.status) === "waiting_for_upload" ? "Waiting for upload to start" : (asset == null ? void 0 : asset.status) === "waiting" ? "Processing upload" : !((asset == null ? void 0 : asset.status) === "ready" || typeof (asset == null ? void 0 : asset.status) > "u"), [asset]), isPreparingStaticRenditions = useMemo(() => {
3099
- var _a2, _b2;
3100
- return ((_b2 = (_a2 = asset == null ? void 0 : asset.data) == null ? void 0 : _a2.static_renditions) == null ? void 0 : _b2.status) === "preparing";
3101
- }, [(_b = (_a = asset == null ? void 0 : asset.data) == null ? void 0 : _a.static_renditions) == null ? void 0 : _b.status]), playRef = useRef(null), muteRef = useRef(null), handleCancelUpload = useCancelUpload(asset, onChange);
3102
- return useEffect(() => {
3103
- var _a2, _b2;
3104
- const style = document.createElement("style");
3105
- style.innerHTML = "button svg { vertical-align: middle; }", (_a2 = playRef.current) != null && _a2.shadowRoot && playRef.current.shadowRoot.appendChild(style), (_b2 = muteRef == null ? void 0 : muteRef.current) != null && _b2.shadowRoot && muteRef.current.shadowRoot.appendChild(style.cloneNode(!0));
3106
- }, []), useEffect(() => {
3107
- var _a2, _b2, _c2;
3108
- if ((asset == null ? void 0 : asset.status) === "errored")
3109
- throw handleCancelUpload(), new Error((_c2 = (_b2 = (_a2 = asset.data) == null ? void 0 : _a2.errors) == null ? void 0 : _b2.messages) == null ? void 0 : _c2.join(" "));
3110
- }, [(_d = (_c = asset.data) == null ? void 0 : _c.errors) == null ? void 0 : _d.messages, asset == null ? void 0 : asset.status, handleCancelUpload]), !asset || !asset.status ? null : isLoading ? /* @__PURE__ */ jsx(
3111
- UploadProgress,
3112
- {
3113
- progress: 100,
3114
- filename: asset == null ? void 0 : asset.filename,
3115
- text: isLoading !== !0 && isLoading || "Waiting for Mux to complete the upload",
3116
- onCancel: readOnly ? void 0 : () => handleCancelUpload()
3117
- }
3118
- ) : /* @__PURE__ */ jsxs(VideoPlayer, { asset, children: [
3119
- buttons && /* @__PURE__ */ jsx(TopControls, { slot: "top-chrome", children: buttons }),
3120
- isPreparingStaticRenditions && /* @__PURE__ */ jsx(
3121
- Card,
3122
- {
3123
- padding: 2,
3124
- radius: 1,
3125
- style: {
3126
- background: "var(--card-fg-color)",
3127
- position: "absolute",
3128
- top: "0.5em",
3129
- left: "0.5em"
3130
- },
3131
- children: /* @__PURE__ */ jsx(Text, { size: 1, style: { color: "var(--card-bg-color)" }, children: "MUX is preparing static renditions, please stand by" })
3132
- }
3133
- )
3134
- ] });
3135
- };
3136
- function focusRingBorderStyle(border) {
3137
- return `inset 0 0 0 ${border.width}px ${border.color}`;
3138
- }
3139
- function focusRingStyle(opts) {
3140
- const { base, border, focusRing } = opts, focusRingOutsetWidth = focusRing.offset + focusRing.width, focusRingInsetWidth = 0 - focusRing.offset, bgColor = base ? base.bg : "var(--card-bg-color)";
3141
- return [
3142
- focusRingInsetWidth > 0 && `inset 0 0 0 ${focusRingInsetWidth}px var(--card-focus-ring-color)`,
3143
- border && focusRingBorderStyle(border),
3144
- focusRingInsetWidth < 0 && `0 0 0 ${0 - focusRingInsetWidth}px ${bgColor}`,
3145
- focusRingOutsetWidth > 0 && `0 0 0 ${focusRingOutsetWidth}px var(--card-focus-ring-color)`
3146
- ].filter(Boolean).join(",");
3147
- }
3148
- const FileButton = styled(MenuItem)(({ theme }) => {
3149
- const { focusRing } = theme.sanity, base = theme.sanity.color.base;
3150
- return css`
3151
- position: relative;
3152
-
3153
- &:not([data-disabled='true']) {
3154
- &:focus-within {
3155
- box-shadow: ${focusRingStyle({ base, border: { width: 1, color: "var(--card-border-color)" }, focusRing })};
3156
- }
3157
- }
3158
-
3159
- & input {
3160
- overflow: hidden;
3161
- top: 0;
3162
- left: 0;
3163
- width: 100%;
3164
- height: 100%;
3165
- position: absolute;
3166
- min-width: 0;
3167
- display: block;
3168
- appearance: none;
3169
- padding: 0;
3170
- margin: 0;
3171
- border: 0;
3172
- opacity: 0;
3173
- }
3174
- `;
3175
- }), FileInputMenuItem = React.forwardRef(function(props, forwardedRef) {
3176
- const {
3177
- icon,
3178
- id: idProp,
3179
- accept,
3180
- capture,
3181
- fontSize,
3182
- multiple,
3183
- onSelect,
3184
- space = 3,
3185
- textAlign,
3186
- text,
3187
- disabled,
3188
- ...rest
3189
- } = props, idHook = useId(), id = idProp || idHook, handleChange = React.useCallback(
3190
- (event) => {
3191
- onSelect && event.target.files && onSelect(Array.from(event.target.files));
3192
- },
3193
- [onSelect]
3194
- ), content = /* @__PURE__ */ jsxs(Flex, { align: "center", justify: "flex-start", children: [
3195
- icon && /* @__PURE__ */ jsx(Box, { marginRight: text ? space : void 0, children: /* @__PURE__ */ jsxs(Text, { size: fontSize, children: [
3196
- isValidElement(icon) && icon,
3197
- isValidElementType(icon) && createElement(icon)
3198
- ] }) }),
3199
- text && /* @__PURE__ */ jsx(Text, { align: textAlign, size: fontSize, textOverflow: "ellipsis", children: text })
3200
- ] });
3201
- return /* @__PURE__ */ jsxs(FileButton, { ...rest, htmlFor: id, disabled, ref: forwardedRef, children: [
3202
- content,
3203
- /* @__PURE__ */ jsx(
3204
- "input",
3205
- {
3206
- "data-testid": "file-button-input",
3207
- accept,
3208
- capture,
3209
- id,
3210
- multiple,
3211
- onChange: handleChange,
3212
- type: "file",
3213
- value: "",
3214
- disabled
3215
- }
3216
- )
3217
- ] });
3218
- }), LockCard = styled(Card)`
3219
- position: absolute;
3220
- top: 0;
3221
- left: 0;
3222
- opacity: 0.6;
3223
- mix-blend-mode: screen;
3224
- background: transparent;
3225
- `, LockButton = styled(Button)`
3226
- background: transparent;
3227
- color: white;
3228
- `;
3229
- function PlayerActionsMenu(props) {
3230
- const { asset, readOnly, dialogState, setDialogState, onChange, onSelect } = props, [open, setOpen] = useState(!1), [menuElement, setMenuRef] = useState(null), isSigned = useMemo(() => getPlaybackPolicy(asset) === "signed", [asset]), onReset = useCallback(() => onChange(PatchEvent.from(unset([]))), [onChange]);
3231
- return useEffect(() => {
3232
- open && dialogState && setOpen(!1);
3233
- }, [dialogState, open]), useClickOutside(
3234
- useCallback(() => setOpen(!1), []),
3235
- [menuElement]
3236
- ), /* @__PURE__ */ jsxs(Inline, { space: 1, padding: 2, children: [
3237
- isSigned && /* @__PURE__ */ jsx(
3238
- Tooltip,
3239
- {
3240
- animate: !0,
3241
- content: /* @__PURE__ */ jsx(Box, { padding: 2, children: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: "Signed playback policy" }) }),
3242
- placement: "right",
3243
- portal: !0,
3244
- children: /* @__PURE__ */ jsx(LockCard, { radius: 2, margin: 2, scheme: "dark", tone: "positive", children: /* @__PURE__ */ jsx(LockButton, { icon: LockIcon, mode: "bleed", tone: "positive" }) })
3245
- }
3246
- ),
3247
- /* @__PURE__ */ jsx(
3248
- Popover,
3249
- {
3250
- animate: !0,
3251
- content: /* @__PURE__ */ jsxs(Menu, { ref: setMenuRef, children: [
3252
- /* @__PURE__ */ jsx(Box, { padding: 2, children: /* @__PURE__ */ jsx(Label$1, { muted: !0, size: 1, children: "Replace" }) }),
3253
- /* @__PURE__ */ jsx(
3254
- FileInputMenuItem,
3255
- {
3256
- accept: "video/*",
3257
- icon: UploadIcon,
3258
- onSelect,
3259
- text: "Upload",
3260
- disabled: readOnly,
3261
- fontSize: 1
3262
- }
3263
- ),
3264
- /* @__PURE__ */ jsx(
3265
- MenuItem,
3266
- {
3267
- icon: SearchIcon,
3268
- text: "Browse",
3269
- onClick: () => setDialogState("select-video")
3270
- }
3271
- ),
3272
- /* @__PURE__ */ jsx(MenuDivider, {}),
3273
- /* @__PURE__ */ jsx(
3274
- MenuItem,
3275
- {
3276
- icon: PlugIcon,
3277
- text: "Configure API",
3278
- onClick: () => setDialogState("secrets")
3279
- }
3280
- ),
3281
- /* @__PURE__ */ jsx(MenuDivider, {}),
3282
- /* @__PURE__ */ jsx(
3283
- MenuItem,
3284
- {
3285
- tone: "critical",
3286
- icon: ResetIcon,
3287
- text: "Clear field",
3288
- onClick: onReset,
3289
- disabled: readOnly
3290
- }
3291
- )
3292
- ] }),
3293
- portal: !0,
3294
- open,
3295
- children: /* @__PURE__ */ jsx(
3296
- Button,
3297
- {
3298
- icon: EllipsisHorizontalIcon,
3299
- mode: "ghost",
3300
- fontSize: 1,
3301
- onClick: () => {
3302
- setDialogState(!1), setOpen(!0);
3303
- }
3304
- }
3305
- )
3306
- }
3307
- )
3308
- ] });
3309
- }
3310
- var PlayerActionsMenu$1 = memo(PlayerActionsMenu);
3311
- function formatBytes(bytes, si = !1, dp = 1) {
3312
- const thresh = si ? 1e3 : 1024;
3313
- if (Math.abs(bytes) < thresh)
3314
- return bytes + " B";
3315
- const units = si ? ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] : ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
3316
- let u = -1;
3317
- const r = 10 ** dp;
3318
- do
3319
- bytes /= thresh, ++u;
3320
- while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
3321
- return bytes.toFixed(dp) + " " + units[u];
3322
- }
3323
- const SUPPORTED_MUX_LANGUAGES = [
3324
- { label: "English", code: "en", state: "Stable" },
3325
- { label: "Spanish", code: "es", state: "Stable" },
3326
- { label: "Italian", code: "it", state: "Stable" },
3327
- { label: "Portuguese", code: "pt", state: "Stable" },
3328
- { label: "German", code: "de", state: "Stable" },
3329
- { label: "French", code: "fr", state: "Stable" },
3330
- { label: "Polish", code: "pl", state: "Beta" },
3331
- { label: "Russian", code: "ru", state: "Beta" },
3332
- { label: "Dutch", code: "nl", state: "Beta" },
3333
- { label: "Catalan", code: "ca", state: "Beta" },
3334
- { label: "Turkish", code: "tr", state: "Beta" },
3335
- { label: "Swedish", code: "sv", state: "Beta" },
3336
- { label: "Ukrainian", code: "uk", state: "Beta" },
3337
- { label: "Norwegian", code: "no", state: "Beta" },
3338
- { label: "Finnish", code: "fi", state: "Beta" },
3339
- { label: "Slovak", code: "sk", state: "Beta" },
3340
- { label: "Greek", code: "el", state: "Beta" },
3341
- { label: "Czech", code: "cs", state: "Beta" },
3342
- { label: "Croatian", code: "hr", state: "Beta" },
3343
- { label: "Danish", code: "da", state: "Beta" },
3344
- { label: "Romanian", code: "ro", state: "Beta" },
3345
- { label: "Bulgarian", code: "bg", state: "Beta" }
3346
- ];
3347
- function isCustomTextTrack(track) {
3348
- return track.type !== "autogenerated";
3349
- }
3350
- function isAutogeneratedTrack(track) {
3351
- return track.type === "autogenerated";
3352
- }
3353
- const ALL_LANGUAGE_CODES = LanguagesList.getAllCodes().map((code) => ({
3354
- value: code,
3355
- label: LanguagesList.getNativeName(code)
3356
- })), SUBTITLE_LANGUAGES = {
3357
- autogenerated: SUPPORTED_MUX_LANGUAGES.map((lang) => ({
3358
- value: lang.code,
3359
- label: lang.label
3360
- })),
3361
- subtitles: ALL_LANGUAGE_CODES,
3362
- captions: ALL_LANGUAGE_CODES
3363
- }, TRACK_TYPES = [
3364
- { value: "autogenerated", label: "Auto-generated Subtitles" }
3365
- // {value: 'subtitles', label: 'Subtitles'},
3366
- // {value: 'captions', label: 'Closed Captions'},
3367
- ];
3368
- function TrackEditor({
3369
- canAutoGenerate,
3370
- track,
3371
- dispatch
3372
- }) {
3373
- const { _id: id, type } = track, dispatchTrackAction = (args) => dispatch({ action: "track", id, ...args }), trackTypes = TRACK_TYPES.filter(
3374
- ({ value }) => !(value === "autogenerated" && !canAutoGenerate)
3375
- );
3376
- return trackTypes.length === 0 ? null : /* @__PURE__ */ jsx(Card, { border: !0, padding: 3, radius: 2, style: { position: "relative" }, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
3377
- trackTypes.length > 1 && /* @__PURE__ */ jsx(FormField$2, { title: "Auto-generated subtitles", children: /* @__PURE__ */ jsx(Flex, { gap: 3, children: trackTypes.map(({ value, label }) => {
3378
- const inputId = `${id}--type-${value}`;
3379
- return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
3380
- /* @__PURE__ */ jsx(
3381
- Radio,
3382
- {
3383
- checked: type === value,
3384
- name: "track-type",
3385
- onChange: (e) => dispatchTrackAction({
3386
- subAction: "update",
3387
- value: {
3388
- type: e.currentTarget.value
3389
- }
3390
- }),
3391
- value,
3392
- id: inputId
3393
- }
3394
- ),
3395
- /* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, children: label })
3396
- ] }, value);
3397
- }) }) }),
3398
- /* @__PURE__ */ jsx(
3399
- Autocomplete,
3400
- {
3401
- id: `${id}--language`,
3402
- value: track.language_code,
3403
- onChange: (newValue) => dispatchTrackAction({
3404
- subAction: "update",
3405
- value: {
3406
- language_code: newValue,
3407
- name: LanguagesList.getNativeName(newValue)
3408
- }
3409
- }),
3410
- options: SUBTITLE_LANGUAGES[track.type],
3411
- icon: TranslateIcon,
3412
- placeholder: "Select language",
3413
- filterOption: (query, option) => option.label.toLowerCase().indexOf(query.toLowerCase()) > -1 || option.value.toLowerCase().indexOf(query.toLowerCase()) > -1,
3414
- openButton: !0,
3415
- renderValue: (value) => {
3416
- var _a;
3417
- return ((_a = SUBTITLE_LANGUAGES[track.type].find((l) => l.value === value)) == null ? void 0 : _a.label) || value;
3418
- },
3419
- renderOption: (option) => /* @__PURE__ */ jsx(Card, { "data-as": "button", padding: 3, radius: 2, tone: "inherit", children: /* @__PURE__ */ jsxs(Text, { size: 2, textOverflow: "ellipsis", children: [
3420
- option.label,
3421
- " (",
3422
- option.value,
3423
- ")"
3424
- ] }) })
3425
- }
3426
- ),
3427
- /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
3428
- Button,
3429
- {
3430
- icon: TrashIcon,
3431
- tone: "critical",
3432
- mode: "ghost",
3433
- onClick: () => dispatchTrackAction({ subAction: "delete" }),
3434
- text: "Delete"
3435
- }
3436
- ) })
3437
- ] }) });
3438
- }
3439
- function TextTracksEditor({
3440
- canAutoGenerate,
3441
- tracks,
3442
- dispatch
3443
- }) {
3444
- return TRACK_TYPES.filter(
3445
- ({ value }) => !(value === "autogenerated" && !canAutoGenerate)
3446
- ).length === 0 ? null : /* @__PURE__ */ jsx(
3447
- FormField$2,
3448
- {
3449
- title: "Captions & Subtitles",
3450
- description: "Provide text tracks for video accessibility.",
3451
- children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
3452
- tracks.map((track) => /* @__PURE__ */ jsx(
3453
- TrackEditor,
3454
- {
3455
- canAutoGenerate,
3456
- track,
3457
- dispatch
3458
- },
3459
- track._id
3460
- )),
3461
- /* @__PURE__ */ jsx(
3462
- Button,
3463
- {
3464
- icon: AddIcon,
3465
- onClick: () => dispatch({ action: "track", id: uuid(), subAction: "add" }),
3466
- text: "New caption/subtitle",
3467
- mode: "ghost"
3468
- }
3469
- )
3470
- ] })
3471
- }
3472
- );
3473
- }
3474
- const ENCODING_OPTIONS = [
3475
- { value: "smart", label: "Smart" },
3476
- { value: "baseline", label: "Baseline" }
3477
- ], RESOLUTION_TIERS = [
3478
- { value: "1080p", label: "1080p" },
3479
- { value: "1440p", label: "1440p (2k)" },
3480
- { value: "2160p", label: "2160p (4k)" }
3481
- ];
3482
- function UploadConfiguration({
3483
- stagedUpload,
3484
- secrets,
3485
- pluginConfig,
3486
- startUpload,
3487
- onClose
3488
- }) {
3489
- var _a;
3490
- const id = useId(), autoTextTracks = useRef(
3491
- pluginConfig.encoding_tier === "smart" && ((_a = pluginConfig.defaultAutogeneratedSubtitleLangs) == null ? void 0 : _a.map(
3492
- (language_code) => ({
3493
- _id: uuid(),
3494
- type: "autogenerated",
3495
- language_code,
3496
- name: LanguagesList.getNativeName(language_code)
3497
- })
3498
- )) || []
3499
- ).current, [config, dispatch] = useReducer(
3500
- (prev, action) => {
3501
- var _a2;
3502
- switch (action.action) {
3503
- case "encoding_tier":
3504
- return action.value === "baseline" ? Object.assign({}, prev, {
3505
- encoding_tier: action.value,
3506
- mp4_support: "none",
3507
- max_resolution_tier: "1080p",
3508
- text_tracks: (_a2 = prev.text_tracks) == null ? void 0 : _a2.filter(({ type }) => type !== "autogenerated")
3509
- }) : Object.assign({}, prev, {
3510
- encoding_tier: action.value,
3511
- mp4_support: pluginConfig.mp4_support,
3512
- max_resolution_tier: pluginConfig.max_resolution_tier,
3513
- text_tracks: [...autoTextTracks, ...prev.text_tracks || []]
3514
- });
3515
- case "mp4_support":
3516
- case "max_resolution_tier":
3517
- case "normalize_audio":
3518
- case "signed":
3519
- return Object.assign({}, prev, { [action.action]: action.value });
3520
- case "track": {
3521
- const text_tracks = [...prev.text_tracks], target_track_i = text_tracks.findIndex(({ _id: _id2 }) => _id2 === action.id);
3522
- switch (action.subAction) {
3523
- case "add":
3524
- if (target_track_i !== -1)
3525
- break;
3526
- text_tracks.push(
3527
- prev.encoding_tier === "smart" ? { _id: action.id, type: "autogenerated" } : { _id: action.id, type: "subtitles" }
3528
- );
3529
- break;
3530
- case "update":
3531
- if (target_track_i === -1)
3532
- break;
3533
- text_tracks[target_track_i] = {
3534
- ...text_tracks[target_track_i],
3535
- ...action.value
3536
- };
3537
- break;
3538
- case "delete":
3539
- if (target_track_i === -1)
3540
- break;
3541
- text_tracks.splice(target_track_i, 1);
3542
- break;
3543
- }
3544
- return Object.assign({}, prev, { text_tracks });
3545
- }
3546
- default:
3547
- return prev;
3548
- }
3549
- },
3550
- {
3551
- encoding_tier: pluginConfig.encoding_tier,
3552
- max_resolution_tier: pluginConfig.max_resolution_tier,
3553
- mp4_support: pluginConfig.mp4_support,
3554
- signed: secrets.enableSignedUrls && pluginConfig.defaultSigned,
3555
- normalize_audio: pluginConfig.normalize_audio,
3556
- text_tracks: autoTextTracks
3557
- }
3558
- ), { disableTextTrackConfig, disableUploadConfig } = pluginConfig, skipConfig = disableTextTrackConfig && disableUploadConfig;
3559
- if (useEffect(() => {
3560
- skipConfig && startUpload(formatUploadConfig(config));
3561
- }, []), skipConfig)
3562
- return null;
3563
- const maxSupportedResolution = RESOLUTION_TIERS.findIndex(
3564
- (rt) => rt.value === pluginConfig.max_resolution_tier
3565
- );
3566
- return /* @__PURE__ */ jsx(
3567
- Dialog,
3568
- {
3569
- animate: !0,
3570
- open: !0,
3571
- id: "upload-configuration",
3572
- zOffset: 1e3,
3573
- width: 1,
3574
- header: "Configure Mux Upload",
3575
- onClose,
3576
- children: /* @__PURE__ */ jsxs(Stack, { padding: 4, space: 2, children: [
3577
- /* @__PURE__ */ jsx(Label$1, { size: 3, children: "FILE TO UPLOAD" }),
3578
- /* @__PURE__ */ jsx(
3579
- Card,
3580
- {
3581
- tone: "transparent",
3582
- border: !0,
3583
- padding: 3,
3584
- paddingY: 4,
3585
- style: { borderRadius: "0.1865rem" },
3586
- children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3587
- /* @__PURE__ */ jsx(DocumentVideoIcon, { fontSize: "2em" }),
3588
- /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
3589
- /* @__PURE__ */ jsx(Text, { textOverflow: "ellipsis", as: "h2", size: 3, children: stagedUpload.type === "file" ? stagedUpload.files[0].name : stagedUpload.url }),
3590
- /* @__PURE__ */ jsx(Text, { as: "p", size: 1, muted: !0, children: stagedUpload.type === "file" ? `Direct File Upload (${formatBytes(stagedUpload.files[0].size)})` : "File From URL (Unknown size)" })
3591
- ] })
3592
- ] })
3593
- }
3594
- ),
3595
- !disableUploadConfig && /* @__PURE__ */ jsxs(Stack, { space: 3, paddingBottom: 2, children: [
3596
- /* @__PURE__ */ jsx(
3597
- FormField$2,
3598
- {
3599
- title: "Encoding Tier",
3600
- description: /* @__PURE__ */ jsxs(Fragment, { children: [
3601
- "The encoding tier informs the cost, quality, and available platform features for the asset.",
3602
- " ",
3603
- /* @__PURE__ */ jsx(
3604
- "a",
3605
- {
3606
- href: "https://docs.mux.com/guides/use-encoding-tiers",
3607
- target: "_blank",
3608
- rel: "noopener noreferrer",
3609
- children: "See the Mux guide for more details."
3610
- }
3611
- )
3612
- ] }),
3613
- children: /* @__PURE__ */ jsx(Flex, { gap: 3, children: ENCODING_OPTIONS.map(({ value, label }) => {
3614
- const inputId = `${id}--encodingtier-${value}`;
3615
- return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
3616
- /* @__PURE__ */ jsx(
3617
- Radio,
3618
- {
3619
- checked: config.encoding_tier === value,
3620
- name: "asset-encodingtier",
3621
- onChange: (e) => dispatch({
3622
- action: "encoding_tier",
3623
- value: e.currentTarget.value
3624
- }),
3625
- value,
3626
- id: inputId
3627
- }
3628
- ),
3629
- /* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, children: label })
3630
- ] }, value);
3631
- }) })
3632
- }
3633
- ),
3634
- config.encoding_tier === "smart" && maxSupportedResolution > 0 && /* @__PURE__ */ jsx(
3635
- FormField$2,
3636
- {
3637
- title: "Resolution Tier",
3638
- description: /* @__PURE__ */ jsxs(Fragment, { children: [
3639
- "The maximum",
3640
- " ",
3641
- /* @__PURE__ */ jsx(
3642
- "a",
3643
- {
3644
- href: "https://docs.mux.com/api-reference#video/operation/create-direct-upload",
3645
- target: "_blank",
3646
- rel: "noopener noreferrer",
3647
- children: "resolution_tier"
3648
- }
3649
- ),
3650
- " ",
3651
- "your asset is encoded, stored, and streamed at."
3652
- ] }),
3653
- children: /* @__PURE__ */ jsx(Flex, { gap: 3, wrap: "wrap", children: RESOLUTION_TIERS.map(({ value, label }, index) => {
3654
- const inputId = `${id}--type-${value}`;
3655
- return index > maxSupportedResolution ? null : /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
3656
- /* @__PURE__ */ jsx(
3657
- Radio,
3658
- {
3659
- checked: config.max_resolution_tier === value,
3660
- name: "asset-resolutiontier",
3661
- onChange: (e) => dispatch({
3662
- action: "max_resolution_tier",
3663
- value: e.currentTarget.value
3664
- }),
3665
- value,
3666
- id: inputId
3667
- }
3668
- ),
3669
- /* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, children: label })
3670
- ] }, value);
3671
- }) })
3672
- }
3673
- ),
3674
- (secrets.enableSignedUrls || config.encoding_tier === "smart") && /* @__PURE__ */ jsx(FormField$2, { title: "Additional Configuration", children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
3675
- secrets.enableSignedUrls && /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
3676
- /* @__PURE__ */ jsx(
3677
- Checkbox,
3678
- {
3679
- id: `${id}--signed`,
3680
- style: { display: "block" },
3681
- name: "signed",
3682
- required: !0,
3683
- checked: config.signed,
3684
- onChange: (e) => dispatch({
3685
- action: "signed",
3686
- value: e.currentTarget.checked
3687
- })
3688
- }
3689
- ),
3690
- /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx("label", { htmlFor: `${id}--signed`, children: "Signed playback URL" }) })
3691
- ] }),
3692
- config.encoding_tier === "smart" && /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
3693
- /* @__PURE__ */ jsx(
3694
- Checkbox,
3695
- {
3696
- id: `${id}--mp4_support`,
3697
- style: { display: "block" },
3698
- name: "mp4_support",
3699
- required: !0,
3700
- checked: config.mp4_support === "standard",
3701
- onChange: (e) => dispatch({
3702
- action: "mp4_support",
3703
- value: e.currentTarget.checked ? "standard" : "none"
3704
- })
3705
- }
3706
- ),
3707
- /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx("label", { htmlFor: `${id}--mp4_support`, children: "MP4 support (allow downloading)" }) })
3708
- ] })
3709
- ] }) })
3710
- ] }),
3711
- !disableTextTrackConfig && /* @__PURE__ */ jsx(
3712
- TextTracksEditor,
3713
- {
3714
- canAutoGenerate: config.encoding_tier === "smart",
3715
- tracks: config.text_tracks,
3716
- dispatch
3717
- }
3718
- ),
3719
- /* @__PURE__ */ jsx(
3720
- Button,
3721
- {
3722
- icon: UploadIcon,
3723
- text: "Upload",
3724
- tone: "positive",
3725
- onClick: () => startUpload(formatUploadConfig(config))
3726
- }
3727
- )
3728
- ] })
3729
- }
3730
- );
3731
- }
3732
- function formatUploadConfig(config) {
3733
- const generated_subtitles = config.text_tracks.filter(isAutogeneratedTrack).map((track) => ({
3734
- name: track.name,
3735
- language_code: track.language_code
3736
- }));
3737
- return {
3738
- input: [
3739
- {
3740
- type: "video",
3741
- generated_subtitles: generated_subtitles.length > 0 ? generated_subtitles : void 0
3742
- },
3743
- ...config.text_tracks.filter(isCustomTextTrack).reduce(
3744
- (acc, track) => (track.language_code && track.file && track.name && acc.push({
3745
- url: track.file.contents,
3746
- type: "text",
3747
- text_type: track.type === "subtitles" ? "subtitles" : void 0,
3748
- language_code: track.language_code,
3749
- name: track.name,
3750
- closed_captions: track.type === "captions"
3751
- }), acc),
3752
- []
3753
- )
3754
- ],
3755
- mp4_support: config.mp4_support,
3756
- playback_policy: config.signed ? ["public", "signed"] : ["public"],
3757
- max_resolution_tier: config.max_resolution_tier,
3758
- encoding_tier: config.encoding_tier,
3759
- normalize_audio: config.normalize_audio
3760
- };
3761
- }
3762
- function withFocusRing(component) {
3763
- return styled(component)((props) => {
3764
- const border = {
3765
- width: props.$border ? 1 : 0,
3766
- color: "var(--card-border-color)"
3767
- };
3768
- return css`
3769
- --card-focus-box-shadow: ${focusRingBorderStyle(border)};
3770
-
3771
- border-radius: ${rem(props.theme.sanity.radius[1])};
3772
- outline: none;
3773
- box-shadow: var(--card-focus-box-shadow);
3774
-
3775
- &:focus {
3776
- --card-focus-box-shadow: ${focusRingStyle({
3777
- base: props.theme.sanity.color.base,
3778
- border,
3779
- focusRing: props.theme.sanity.focusRing
3780
- })};
3781
- }
3782
- `;
3783
- });
3784
- }
3785
- const ctrlKey = 17, cmdKey = 91, UploadCardWithFocusRing = withFocusRing(Card), UploadCard = forwardRef(
3786
- ({ children, tone, onPaste, onDrop, onDragEnter, onDragLeave, onDragOver }, forwardedRef) => {
3787
- const ctrlDown = useRef(!1), inputRef = useRef(null), handleKeyDown = useCallback((event) => {
3788
- (event.keyCode == ctrlKey || event.keyCode == cmdKey) && (ctrlDown.current = !0), ctrlDown.current && event.keyCode == 86 && inputRef.current.focus();
3789
- }, []), handleKeyUp = useCallback((event) => {
3790
- (event.keyCode == ctrlKey || event.keyCode == cmdKey) && (ctrlDown.current = !1);
3791
- }, []);
3792
- return /* @__PURE__ */ jsxs(
3793
- UploadCardWithFocusRing,
3794
- {
3795
- tone,
3796
- ref: forwardedRef,
3797
- padding: 0,
3798
- radius: 2,
3799
- shadow: 0,
3800
- tabIndex: 0,
3801
- onKeyDown: handleKeyDown,
3802
- onKeyUp: handleKeyUp,
3803
- onPaste,
3804
- onDrop,
3805
- onDragEnter,
3806
- onDragLeave,
3807
- onDragOver,
3808
- children: [
3809
- /* @__PURE__ */ jsx(HiddenInput$1, { ref: inputRef, onPaste }),
3810
- children
3811
- ]
3812
- }
3813
- );
3814
- }
3815
- ), HiddenInput$1 = styled.input.attrs({ type: "text" })`
3816
- position: absolute;
3817
- border: 0;
3818
- color: white;
3819
- opacity: 0;
3820
-
3821
- &:focus {
3822
- outline: none;
3823
- }
3824
- `, HiddenInput = styled.input`
3825
- overflow: hidden;
3826
- width: 0.1px;
3827
- height: 0.1px;
3828
- opacity: 0;
3829
- position: absolute;
3830
- z-index: -1;
3831
- `, Label = styled.label`
3832
- position: relative;
3833
- `, FileInputButton = ({ onSelect, accept, ...props }) => {
3834
- const inputId = `FileSelect${useId()}`, inputRef = useRef(null), handleSelect = useCallback(
3835
- (event) => {
3836
- onSelect && onSelect(event.target.files);
3837
- },
3838
- [onSelect]
3839
- ), handleButtonClick = useCallback(() => {
3840
- var _a;
3841
- return (_a = inputRef.current) == null ? void 0 : _a.click();
3842
- }, []);
3843
- return /* @__PURE__ */ jsxs(Label, { htmlFor: inputId, children: [
3844
- /* @__PURE__ */ jsx(
3845
- HiddenInput,
3846
- {
3847
- accept: accept || "video/*",
3848
- ref: inputRef,
3849
- tabIndex: 0,
3850
- type: "file",
3851
- id: inputId,
3852
- onChange: handleSelect,
3853
- value: ""
3854
- }
3855
- ),
3856
- /* @__PURE__ */ jsx(
3857
- Button,
3858
- {
3859
- onClick: handleButtonClick,
3860
- mode: "default",
3861
- tone: "primary",
3862
- style: { width: "100%" },
3863
- ...props
3864
- }
3865
- )
3866
- ] });
3867
- };
3868
- function UploadPlaceholder(props) {
3869
- const { setDialogState, readOnly, onSelect, hovering, needsSetup } = props, handleBrowse = useCallback(() => setDialogState("select-video"), [setDialogState]), handleConfigureApi = useCallback(() => setDialogState("secrets"), [setDialogState]);
3870
- return /* @__PURE__ */ jsx(
3871
- Card,
3872
- {
3873
- sizing: "border",
3874
- tone: readOnly ? "transparent" : "inherit",
3875
- border: !0,
3876
- radius: 2,
3877
- paddingX: 3,
3878
- paddingY: 1,
3879
- style: hovering ? { borderColor: "transparent" } : void 0,
3880
- children: /* @__PURE__ */ jsxs(
3881
- Flex,
3882
- {
3883
- align: "center",
3884
- justify: "space-between",
3885
- gap: 4,
3886
- direction: ["column", "column", "row"],
3887
- paddingY: 2,
3888
- sizing: "border",
3889
- children: [
3890
- /* @__PURE__ */ jsxs(Flex, { align: "center", justify: "flex-start", gap: 2, flex: 1, children: [
3891
- /* @__PURE__ */ jsx(Flex, { justify: "center", children: /* @__PURE__ */ jsx(Text, { muted: !0, children: /* @__PURE__ */ jsx(DocumentVideoIcon, {}) }) }),
3892
- /* @__PURE__ */ jsx(Flex, { justify: "center", children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Drag video or paste URL here" }) })
3893
- ] }),
3894
- /* @__PURE__ */ jsxs(Inline, { space: 2, children: [
3895
- /* @__PURE__ */ jsx(
3896
- FileInputButton,
3897
- {
3898
- mode: "bleed",
3899
- tone: "default",
3900
- icon: UploadIcon,
3901
- text: "Upload",
3902
- onSelect
3903
- }
3904
- ),
3905
- /* @__PURE__ */ jsx(Button, { mode: "bleed", icon: SearchIcon, text: "Select", onClick: handleBrowse }),
3906
- /* @__PURE__ */ jsx(
3907
- Button,
3908
- {
3909
- padding: 3,
3910
- radius: 3,
3911
- tone: needsSetup ? "critical" : void 0,
3912
- onClick: handleConfigureApi,
3913
- icon: PlugIcon,
3914
- mode: "bleed",
3915
- title: "Configure plugin credentials"
3916
- }
3917
- )
3918
- ] })
3919
- ]
3920
- }
3921
- )
3922
- }
3923
- );
3924
- }
3925
- const INITIAL_STATE = {
3926
- stagedUpload: null,
3927
- uploadStatus: null,
3928
- error: null
3929
- };
3930
- function Uploader(props) {
3931
- var _a;
3932
- const toast = useToast(), containerRef = useRef(null), dragEnteredEls = useRef([]), [dragState, setDragState] = useState(null), cancelUploadButton = useRef(
3933
- (() => {
3934
- const events$ = new Subject();
3935
- return {
3936
- observable: events$.asObservable(),
3937
- handleClick: (event) => events$.next(event)
3938
- };
3939
- })()
3940
- ).current, uploadRef = useRef(null), [state, dispatch] = useReducer(
3941
- (prev, action) => {
3942
- var _a2, _b;
3943
- switch (action.action) {
3944
- case "stageUpload":
3945
- return Object.assign({}, INITIAL_STATE, { stagedUpload: action.input });
3946
- case "commitUpload":
3947
- return Object.assign({}, prev, { uploadStatus: { progress: 0 } });
3948
- case "progressInfo": {
3949
- const { type, action: _, ...payload } = action;
3950
- return Object.assign({}, prev, {
3951
- uploadStatus: {
3952
- ...prev.uploadStatus,
3953
- progress: prev.uploadStatus.progress,
3954
- ...payload
3955
- }
3956
- });
3957
- }
3958
- case "progress":
3959
- return Object.assign({}, prev, {
3960
- uploadStatus: {
3961
- ...prev.uploadStatus,
3962
- progress: action.percent
3963
- }
3964
- });
3965
- case "reset":
3966
- case "complete":
3967
- return (_a2 = uploadRef.current) == null || _a2.unsubscribe(), uploadRef.current = null, INITIAL_STATE;
3968
- case "error":
3969
- return (_b = uploadRef.current) == null || _b.unsubscribe(), uploadRef.current = null, Object.assign({}, INITIAL_STATE, { error: action.error });
3970
- default:
3971
- return prev;
3972
- }
3973
- },
3974
- {
3975
- stagedUpload: null,
3976
- uploadStatus: null,
3977
- error: null
3978
- }
3979
- );
3980
- useEffect(() => () => {
3981
- uploadRef.current && !uploadRef.current.closed && uploadRef.current.unsubscribe();
3982
- }, []);
3983
- const startUpload = (settings) => {
3984
- const { stagedUpload } = state;
3985
- if (!stagedUpload || uploadRef.current)
3986
- return;
3987
- dispatch({ action: "commitUpload" });
3988
- let uploadObservable;
3989
- switch (stagedUpload.type) {
3990
- case "url":
3991
- uploadObservable = uploadUrl({
3992
- client: props.client,
3993
- url: stagedUpload.url,
3994
- settings
3995
- });
3996
- break;
3997
- case "file":
3998
- uploadObservable = uploadFile({
3999
- client: props.client,
4000
- file: stagedUpload.files[0],
4001
- settings
4002
- }).pipe(
4003
- takeUntil(
4004
- cancelUploadButton.observable.pipe(
4005
- tap(() => {
4006
- var _a2;
4007
- (_a2 = state.uploadStatus) != null && _a2.uuid && props.client.delete(state.uploadStatus.uuid);
4008
- })
4009
- )
4010
- )
4011
- );
4012
- break;
4013
- }
4014
- uploadRef.current = uploadObservable.subscribe({
4015
- next: (event) => {
4016
- switch (event.type) {
4017
- case "uuid":
4018
- case "file":
4019
- case "url":
4020
- dispatch({ action: "progressInfo", ...event });
4021
- break;
4022
- case "progress":
4023
- dispatch({ action: "progress", percent: event.percent });
4024
- break;
4025
- case "success":
4026
- dispatch({ action: "progress", percent: 100 }), props.onChange(
4027
- PatchEvent.from([
4028
- setIfMissing({ asset: {} }),
4029
- set({ _type: "reference", _weak: !0, _ref: event.asset._id }, ["asset"])
4030
- ])
4031
- );
4032
- break;
4033
- }
4034
- },
4035
- complete: () => dispatch({ action: "complete" }),
4036
- error: (error) => dispatch({ action: "error", error })
4037
- });
4038
- }, handleUpload = (files) => {
4039
- dispatch({
4040
- action: "stageUpload",
4041
- input: { type: "file", files }
4042
- });
4043
- }, handlePaste = (event) => {
4044
- event.preventDefault(), event.stopPropagation();
4045
- const url = (event.clipboardData || window.clipboardData).getData("text");
4046
- if (!isValidUrl(url)) {
4047
- toast.push({ status: "error", title: "Invalid URL for Mux video input." });
4048
- return;
4049
- }
4050
- dispatch({ action: "stageUpload", input: { type: "url", url } });
4051
- }, handleDrop = (event) => {
4052
- setDragState(null), event.preventDefault(), event.stopPropagation(), extractDroppedFiles(event.nativeEvent.dataTransfer).then((files) => {
4053
- dispatch({
4054
- action: "stageUpload",
4055
- input: { type: "file", files }
4056
- });
4057
- });
4058
- }, handleDragOver = (event) => {
4059
- event.preventDefault(), event.stopPropagation();
4060
- }, handleDragEnter = (event) => {
4061
- var _a2, _b;
4062
- event.stopPropagation(), dragEnteredEls.current.push(event.target);
4063
- const type = (_b = (_a2 = event.dataTransfer.items) == null ? void 0 : _a2[0]) == null ? void 0 : _b.type;
4064
- setDragState(type != null && type.startsWith("video/") ? "valid" : "invalid");
4065
- }, handleDragLeave = (event) => {
4066
- event.stopPropagation();
4067
- const idx = dragEnteredEls.current.indexOf(event.target);
4068
- idx > -1 && dragEnteredEls.current.splice(idx, 1), dragEnteredEls.current.length === 0 && setDragState(null);
4069
- };
4070
- if (state.error !== null) {
4071
- const error = { state };
4072
- return /* @__PURE__ */ jsxs(Flex, { gap: 3, direction: "column", justify: "center", align: "center", children: [
4073
- /* @__PURE__ */ jsx(Text, { size: 5, muted: !0, children: /* @__PURE__ */ jsx(ErrorOutlineIcon, {}) }),
4074
- /* @__PURE__ */ jsx(Text, { children: "Something went wrong" }),
4075
- error instanceof Error && error.message && /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: error.message }),
4076
- /* @__PURE__ */ jsx(Button, { text: "Upload another file", onClick: () => dispatch({ action: "reset" }) })
4077
- ] });
4078
- }
4079
- if (state.uploadStatus !== null) {
4080
- const { uploadStatus } = state;
4081
- return /* @__PURE__ */ jsx(
4082
- UploadProgress,
4083
- {
4084
- onCancel: cancelUploadButton.handleClick,
4085
- progress: uploadStatus.progress,
4086
- filename: ((_a = uploadStatus.file) == null ? void 0 : _a.name) || uploadStatus.url
4087
- }
4088
- );
4089
- }
4090
- if (state.stagedUpload !== null)
4091
- return /* @__PURE__ */ jsx(
4092
- UploadConfiguration,
4093
- {
4094
- stagedUpload: state.stagedUpload,
4095
- pluginConfig: props.config,
4096
- secrets: props.secrets,
4097
- startUpload,
4098
- onClose: () => dispatch({ action: "reset" })
4099
- }
4100
- );
4101
- let tone;
4102
- return dragState && (tone = dragState === "valid" ? "positive" : "critical"), /* @__PURE__ */ jsxs(Fragment, { children: [
4103
- /* @__PURE__ */ jsx(
4104
- UploadCard,
4105
- {
4106
- tone,
4107
- onDrop: handleDrop,
4108
- onDragOver: handleDragOver,
4109
- onDragLeave: handleDragLeave,
4110
- onDragEnter: handleDragEnter,
4111
- onPaste: handlePaste,
4112
- ref: containerRef,
4113
- children: props.asset ? /* @__PURE__ */ jsx(
4114
- Player,
4115
- {
4116
- readOnly: props.readOnly,
4117
- asset: props.asset,
4118
- onChange: props.onChange,
4119
- buttons: /* @__PURE__ */ jsx(
4120
- PlayerActionsMenu$1,
4121
- {
4122
- asset: props.asset,
4123
- dialogState: props.dialogState,
4124
- setDialogState: props.setDialogState,
4125
- onChange: props.onChange,
4126
- onSelect: handleUpload,
4127
- readOnly: props.readOnly
4128
- }
4129
- )
4130
- }
4131
- ) : /* @__PURE__ */ jsx(
4132
- UploadPlaceholder,
4133
- {
4134
- hovering: dragState !== null,
4135
- onSelect: handleUpload,
4136
- readOnly: !!props.readOnly,
4137
- setDialogState: props.setDialogState,
4138
- needsSetup: props.needsSetup
4139
- }
4140
- )
4141
- }
4142
- ),
4143
- props.dialogState === "select-video" && /* @__PURE__ */ jsx(
4144
- InputBrowser,
4145
- {
4146
- asset: props.asset,
4147
- onChange: props.onChange,
4148
- setDialogState: props.setDialogState
4149
- }
4150
- )
4151
- ] });
4152
- }
4153
- const Input = (props) => {
4154
- var _a;
4155
- const client = useClient(), secretDocumentValues = useSecretsDocumentValues(), assetDocumentValues = useAssetDocumentValues((_a = props.value) == null ? void 0 : _a.asset), poll = useMuxPolling(props.readOnly ? void 0 : (assetDocumentValues == null ? void 0 : assetDocumentValues.value) || void 0), [dialogState, setDialogState] = useDialogState(), error = secretDocumentValues.error || assetDocumentValues.error || poll.error;
4156
- if (error)
4157
- throw error;
4158
- const isLoading = secretDocumentValues.isLoading || assetDocumentValues.isLoading;
4159
- return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(ErrorBoundaryCard$1, { schemaType: props.schemaType, children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(InputFallback, {}), children: isLoading ? /* @__PURE__ */ jsx(InputFallback, {}) : /* @__PURE__ */ jsxs(Fragment, { children: [
4160
- secretDocumentValues.value.needsSetup && !assetDocumentValues.value ? /* @__PURE__ */ jsx(Onboard, { setDialogState }) : /* @__PURE__ */ jsx(
4161
- Uploader,
4162
- {
4163
- ...props,
4164
- config: props.config,
4165
- onChange: props.onChange,
4166
- client,
4167
- secrets: secretDocumentValues.value.secrets,
4168
- asset: assetDocumentValues.value,
4169
- dialogState,
4170
- setDialogState,
4171
- needsSetup: secretDocumentValues.value.needsSetup
4172
- }
4173
- ),
4174
- dialogState === "secrets" && /* @__PURE__ */ jsx(
4175
- ConfigureApi$1,
4176
- {
4177
- setDialogState,
4178
- secrets: secretDocumentValues.value.secrets
4179
- }
4180
- )
4181
- ] }) }) }) });
4182
- };
4183
- var Input$1 = memo(Input);
4184
- function muxVideoCustomRendering(config) {
4185
- return {
4186
- components: {
4187
- input: (props) => /* @__PURE__ */ jsx(Input$1, { config: { ...config, ...props.schemaType.options }, ...props })
4188
- },
4189
- preview: {
4190
- select: {
4191
- filename: "asset.filename",
4192
- playbackId: "asset.playbackId",
4193
- status: "asset.status",
4194
- assetId: "asset.assetId",
4195
- thumbTime: "asset.thumbTime",
4196
- data: "asset.data"
4197
- },
4198
- prepare: (asset) => {
4199
- const { filename, playbackId, status } = asset;
4200
- return {
4201
- title: filename || playbackId || "",
4202
- subtitle: status ? `status: ${status}` : null,
4203
- media: asset.playbackId ? /* @__PURE__ */ jsx(VideoThumbnail, { asset, width: 64 }) : null
4204
- };
4205
- }
4206
- }
4207
- };
4208
- }
4209
- const muxVideo = {
4210
- name: "mux.video",
4211
- type: "object",
4212
- title: "Video asset reference",
4213
- fields: [
4214
- {
4215
- title: "Video",
4216
- name: "asset",
4217
- type: "reference",
4218
- weak: !0,
4219
- to: [{ type: "mux.videoAsset" }]
4220
- }
4221
- ]
4222
- }, muxVideoAsset = {
4223
- name: "mux.videoAsset",
4224
- type: "object",
4225
- title: "Video asset",
4226
- fields: [
4227
- {
4228
- type: "string",
4229
- name: "status"
4230
- },
4231
- {
4232
- type: "string",
4233
- name: "assetId"
4234
- },
4235
- {
4236
- type: "string",
4237
- name: "playbackId"
4238
- },
4239
- {
4240
- type: "string",
4241
- name: "filename"
4242
- },
4243
- {
4244
- type: "number",
4245
- name: "thumbTime"
4246
- }
4247
- ]
4248
- }, defaultConfig = {
4249
- mp4_support: "none",
4250
- encoding_tier: "smart",
4251
- max_resolution_tier: "1080p",
4252
- normalize_audio: !1,
4253
- defaultSigned: !1,
4254
- tool: DEFAULT_TOOL_CONFIG
4255
- }, muxInput = definePlugin((userConfig) => {
4256
- const config = { ...defaultConfig, ...userConfig || {} };
4257
- return {
4258
- name: "mux-input",
4259
- schema: {
4260
- types: [
4261
- muxVideoAsset,
4262
- {
4263
- ...muxVideo,
4264
- ...muxVideoCustomRendering(config)
4265
- }
4266
- ]
4267
- },
4268
- tools: config.tool === !1 ? void 0 : [createStudioTool(config)]
4269
- };
4270
- });
4271
- export {
4272
- defaultConfig,
4273
- muxInput
4274
- };
4275
- //# sourceMappingURL=index.esm.js.map