sanity-plugin-mux-input 2.3.4 → 2.3.6

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