@strapi/upload 5.0.3 → 5.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/_chunks/{index-Cze6kL5_.mjs → index-BJfZXhbz.mjs} +5 -2
  2. package/dist/_chunks/index-BJfZXhbz.mjs.map +1 -0
  3. package/dist/_chunks/{index-BwMdH-eI.js → index-C7Nj9ETW.js} +356 -290
  4. package/dist/_chunks/index-C7Nj9ETW.js.map +1 -0
  5. package/dist/_chunks/{index-DzHgwpS9.mjs → index-CuzWuOXx.mjs} +357 -291
  6. package/dist/_chunks/index-CuzWuOXx.mjs.map +1 -0
  7. package/dist/_chunks/{index-DK1he91f.js → index-DIjfjBzf.js} +5 -2
  8. package/dist/_chunks/index-DIjfjBzf.js.map +1 -0
  9. package/dist/_chunks/{index-C5E7jC83.js → index-Dztfplsk.js} +8 -8
  10. package/dist/_chunks/index-Dztfplsk.js.map +1 -0
  11. package/dist/_chunks/{index-ox-PAURv.js → index-boOjOtd3.js} +2 -2
  12. package/dist/_chunks/{index-ox-PAURv.js.map → index-boOjOtd3.js.map} +1 -1
  13. package/dist/_chunks/{index-Cw3NiaYP.mjs → index-moi5JZRr.mjs} +2 -2
  14. package/dist/_chunks/{index-Cw3NiaYP.mjs.map → index-moi5JZRr.mjs.map} +1 -1
  15. package/dist/_chunks/{index-CCEHGHWW.mjs → index-uOSk9F1z.mjs} +8 -8
  16. package/dist/_chunks/index-uOSk9F1z.mjs.map +1 -0
  17. package/dist/admin/index.js +4 -1
  18. package/dist/admin/index.js.map +1 -1
  19. package/dist/admin/index.mjs +4 -1
  20. package/dist/admin/index.mjs.map +1 -1
  21. package/dist/admin/src/components/SelectTree/utils/flattenTree.d.ts +14 -0
  22. package/dist/admin/src/hooks/useAssets.d.ts +14 -0
  23. package/dist/admin/src/hooks/useBulkMove.d.ts +78 -0
  24. package/dist/admin/src/hooks/useBulkRemove.d.ts +73 -0
  25. package/dist/admin/src/hooks/useConfig.d.ts +5 -0
  26. package/dist/admin/src/hooks/useCropImg.d.ts +9 -0
  27. package/dist/admin/src/hooks/useEditAsset.d.ts +119 -0
  28. package/dist/admin/src/hooks/useEditFolder.d.ts +71 -0
  29. package/dist/admin/src/hooks/useFolder.d.ts +7 -0
  30. package/dist/admin/src/hooks/useFolderStructure.d.ts +12 -0
  31. package/dist/admin/src/hooks/useFolders.d.ts +11 -0
  32. package/dist/admin/src/hooks/useMediaLibraryPermissions.d.ts +3 -0
  33. package/dist/admin/src/hooks/useModalQueryParams.d.ts +21 -0
  34. package/dist/admin/src/hooks/usePersistentState.d.ts +1 -0
  35. package/dist/admin/src/hooks/useRemoveAsset.d.ts +66 -0
  36. package/dist/admin/src/hooks/useUpload.d.ts +12 -0
  37. package/dist/admin/src/hooks/utils/rename-keys.d.ts +6 -0
  38. package/dist/admin/src/newConstants.d.ts +45 -0
  39. package/dist/admin/src/pluginId.d.ts +2 -0
  40. package/dist/admin/src/utils/appendSearchParamsToUrl.d.ts +6 -0
  41. package/dist/admin/src/utils/containsAssetFilter.d.ts +2 -0
  42. package/dist/admin/src/utils/createAssetUrl.d.ts +2 -0
  43. package/dist/admin/src/utils/displayedFilters.d.ts +22 -0
  44. package/dist/admin/src/utils/downloadFile.d.ts +1 -0
  45. package/dist/admin/src/utils/findRecursiveFolderByValue.d.ts +10 -0
  46. package/dist/admin/src/utils/formatBytes.d.ts +1 -0
  47. package/dist/admin/src/utils/formatDuration.d.ts +1 -0
  48. package/dist/admin/src/utils/getAPIInnerErrors.d.ts +14 -0
  49. package/dist/admin/src/utils/getAllowedFiles.d.ts +15 -0
  50. package/dist/admin/src/utils/getBreadcrumbDataCM.d.ts +19 -0
  51. package/dist/admin/src/utils/getBreadcrumbDataML.d.ts +18 -0
  52. package/dist/admin/src/utils/getFileExtension.d.ts +1 -0
  53. package/dist/admin/src/utils/getFolderParents.d.ts +10 -0
  54. package/dist/admin/src/utils/getFolderURL.d.ts +5 -0
  55. package/dist/admin/src/utils/getTrad.d.ts +1 -0
  56. package/dist/admin/src/utils/index.d.ts +25 -0
  57. package/dist/admin/src/utils/moveElement.d.ts +1 -0
  58. package/dist/admin/src/utils/normalizeAPIError.d.ts +22 -0
  59. package/dist/admin/src/utils/prefixFileUrlWithBackendUrl.d.ts +1 -0
  60. package/dist/admin/src/utils/prefixPluginTranslations.d.ts +5 -0
  61. package/dist/admin/src/utils/rawFileToAsset.d.ts +14 -0
  62. package/dist/admin/src/utils/toSingularTypes.d.ts +2 -0
  63. package/dist/admin/src/utils/typeFromMime.d.ts +2 -0
  64. package/dist/admin/src/utils/urlYupSchema.d.ts +8 -0
  65. package/dist/admin/src/utils/urlsToAssets.d.ts +10 -0
  66. package/dist/shared/contracts/files.d.ts +46 -6
  67. package/dist/shared/contracts/folders.d.ts +5 -6
  68. package/package.json +8 -7
  69. package/dist/_chunks/index-BwMdH-eI.js.map +0 -1
  70. package/dist/_chunks/index-C5E7jC83.js.map +0 -1
  71. package/dist/_chunks/index-CCEHGHWW.mjs.map +0 -1
  72. package/dist/_chunks/index-Cze6kL5_.mjs.map +0 -1
  73. package/dist/_chunks/index-DK1he91f.js.map +0 -1
  74. package/dist/_chunks/index-DzHgwpS9.mjs.map +0 -1
@@ -10,10 +10,10 @@ const styledComponents = require("styled-components");
10
10
  const byteSize = require("byte-size");
11
11
  const dateFns = require("date-fns");
12
12
  const qs = require("qs");
13
+ const yup = require("yup");
13
14
  const reactQuery = require("react-query");
14
15
  const formik = require("formik");
15
16
  const isEqual = require("lodash/isEqual");
16
- const yup = require("yup");
17
17
  const ReactSelect = require("react-select");
18
18
  const Cropper = require("cropperjs");
19
19
  require("cropperjs/dist/cropper.css");
@@ -44,8 +44,8 @@ function _interopNamespace(e) {
44
44
  const React__namespace = /* @__PURE__ */ _interopNamespace(React);
45
45
  const PropTypes__default = /* @__PURE__ */ _interopDefault(PropTypes);
46
46
  const byteSize__default = /* @__PURE__ */ _interopDefault(byteSize);
47
- const isEqual__default = /* @__PURE__ */ _interopDefault(isEqual);
48
47
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
48
+ const isEqual__default = /* @__PURE__ */ _interopDefault(isEqual);
49
49
  const ReactSelect__default = /* @__PURE__ */ _interopDefault(ReactSelect);
50
50
  const Cropper__default = /* @__PURE__ */ _interopDefault(Cropper);
51
51
  const isEmpty__default = /* @__PURE__ */ _interopDefault(isEmpty);
@@ -60,7 +60,7 @@ const __variableDynamicImportRuntimeHelper = (glob, path) => {
60
60
  });
61
61
  };
62
62
  const name$1 = "@strapi/upload";
63
- const version = "5.0.2";
63
+ const version = "5.0.4";
64
64
  const description = "Makes it easy to upload images and files to your Strapi Application.";
65
65
  const license = "SEE LICENSE IN LICENSE";
66
66
  const author = {
@@ -147,6 +147,7 @@ const devDependencies = {
147
147
  "@testing-library/dom": "10.1.0",
148
148
  "@testing-library/react": "15.0.7",
149
149
  "@testing-library/user-event": "14.5.2",
150
+ "@types/byte-size": "8.1.2",
150
151
  "@types/fs-extra": "11.0.4",
151
152
  "@types/koa": "2.13.4",
152
153
  "@types/koa-range": "0.3.5",
@@ -168,7 +169,7 @@ const peerDependencies = {
168
169
  "styled-components": "^6.0.0"
169
170
  };
170
171
  const engines = {
171
- node: ">=18.0.0 <=20.x.x",
172
+ node: ">=18.0.0 <=22.x.x",
172
173
  npm: ">=6.0.0"
173
174
  };
174
175
  const strapi = {
@@ -200,7 +201,7 @@ const appendSearchParamsToUrl = ({ url, params }) => {
200
201
  }
201
202
  const urlObj = new URL(url, window.strapi.backendURL);
202
203
  Object.entries(params).forEach(([key, value]) => {
203
- if (value !== void 0) {
204
+ if (value !== void 0 && value !== null) {
204
205
  urlObj.searchParams.append(key, value);
205
206
  }
206
207
  });
@@ -229,6 +230,43 @@ const createAssetUrl = (asset, forThumbnail = true) => {
229
230
  const assetUrl = forThumbnail ? asset?.formats?.thumbnail?.url || asset.url : asset.url;
230
231
  return prefixFileUrlWithBackendUrl(assetUrl);
231
232
  };
233
+ const displayedFilters = [
234
+ {
235
+ name: "createdAt",
236
+ fieldSchema: {
237
+ type: "date"
238
+ },
239
+ metadatas: { label: "createdAt" }
240
+ },
241
+ {
242
+ name: "updatedAt",
243
+ fieldSchema: {
244
+ type: "date"
245
+ },
246
+ metadatas: { label: "updatedAt" }
247
+ },
248
+ {
249
+ name: "mime",
250
+ fieldSchema: {
251
+ type: "enumeration",
252
+ options: [
253
+ { label: "audio", value: "audio" },
254
+ { label: "file", value: "file" },
255
+ { label: "image", value: "image" },
256
+ { label: "video", value: "video" }
257
+ ]
258
+ },
259
+ metadatas: { label: "type" }
260
+ }
261
+ ];
262
+ const downloadFile = async (url, fileName) => {
263
+ const fileBlob = await fetch(url).then((res) => res.blob());
264
+ const urlDownload = window.URL.createObjectURL(fileBlob);
265
+ const link = document.createElement("a");
266
+ link.href = urlDownload;
267
+ link.setAttribute("download", fileName);
268
+ link.click();
269
+ };
232
270
  function findRecursiveFolderByValue(data, value) {
233
271
  let result;
234
272
  function iter(a) {
@@ -242,7 +280,8 @@ function findRecursiveFolderByValue(data, value) {
242
280
  return result;
243
281
  }
244
282
  function formatBytes(receivedBytes, decimals = 0) {
245
- const { value, unit } = byteSize__default.default(receivedBytes * 1e3, { precision: decimals });
283
+ const realBytes = typeof receivedBytes === "string" ? Number(receivedBytes) : receivedBytes;
284
+ const { value, unit } = byteSize__default.default(realBytes * 1e3, { precision: decimals });
246
285
  if (!unit) {
247
286
  return "0B";
248
287
  }
@@ -253,9 +292,81 @@ const formatDuration = (durationInSecond) => {
253
292
  const duration = dateFns.intervalToDuration({ start: 0, end: durationInSecond * 1e3 });
254
293
  return `${zeroPad(duration.hours)}:${zeroPad(duration.minutes)}:${zeroPad(duration.seconds)}`;
255
294
  };
295
+ const toSingularTypes = (types) => {
296
+ if (!types) {
297
+ return [];
298
+ }
299
+ return types.map((type) => type.substring(0, type.length - 1));
300
+ };
301
+ const getAllowedFiles = (pluralTypes, files2) => {
302
+ const singularTypes = toSingularTypes(pluralTypes);
303
+ const allowedFiles = files2.filter((file) => {
304
+ const fileType = file?.mime?.split("/")[0];
305
+ if (!fileType) {
306
+ return false;
307
+ }
308
+ if (singularTypes.includes("file") && !["video", "image", "audio"].includes(fileType)) {
309
+ return true;
310
+ }
311
+ return singularTypes.includes(fileType);
312
+ });
313
+ return allowedFiles;
314
+ };
315
+ function getPrefixedId(message, callback) {
316
+ const prefixedMessage = `apiError.${message}`;
317
+ if (typeof callback === "function") {
318
+ return callback(prefixedMessage);
319
+ }
320
+ return prefixedMessage;
321
+ }
322
+ function normalizeError(error, { name: name2, intlMessagePrefixCallback }) {
323
+ const { message } = error;
324
+ const normalizedError = {
325
+ id: getPrefixedId(message, intlMessagePrefixCallback),
326
+ defaultMessage: message,
327
+ name: error.name ?? name2,
328
+ values: {}
329
+ };
330
+ if ("path" in error) {
331
+ normalizedError.values = { path: error.path.join(".") };
332
+ }
333
+ return normalizedError;
334
+ }
335
+ const validateErrorIsYupValidationError = (err) => typeof err.details === "object" && err.details !== null && "errors" in err.details;
336
+ function normalizeAPIError(apiError, intlMessagePrefixCallback) {
337
+ const error = apiError.response?.data.error;
338
+ if (error) {
339
+ if (validateErrorIsYupValidationError(error)) {
340
+ return {
341
+ name: error.name,
342
+ message: error?.message || null,
343
+ errors: error.details.errors.map(
344
+ (err) => normalizeError(err, { name: error.name, intlMessagePrefixCallback })
345
+ )
346
+ };
347
+ }
348
+ return normalizeError(error, { intlMessagePrefixCallback });
349
+ }
350
+ return null;
351
+ }
352
+ function getAPIInnerErrors(error, { getTrad: getTrad2 }) {
353
+ const normalizedError = normalizeAPIError(error, getTrad2);
354
+ if (normalizedError && "errors" in normalizedError) {
355
+ return normalizedError.errors.reduce((acc, error2) => {
356
+ if ("path" in error2.values) {
357
+ acc[error2.values.path] = {
358
+ id: error2.id,
359
+ defaultMessage: error2.defaultMessage
360
+ };
361
+ }
362
+ return acc;
363
+ }, {});
364
+ }
365
+ return normalizedError?.defaultMessage;
366
+ }
256
367
  const pluginId = pluginPkg.name.replace(/^@strapi\//i, "");
257
368
  const getTrad = (id2) => `${pluginId}.${id2}`;
258
- const getBreadcrumbDataML = (folder) => {
369
+ const getBreadcrumbDataCM = (folder) => {
259
370
  let data = [
260
371
  {
261
372
  id: null,
@@ -293,7 +404,8 @@ const getFolderURL = (pathname, currentQuery, { folder, folderPath } = {}) => {
293
404
  );
294
405
  return `${pathname}${queryParamsString ? `?${queryParamsString}` : ""}`;
295
406
  };
296
- function flattenTree(tree, parent, depth = 0) {
407
+ const getFileExtension = (ext) => ext && ext[0] === "." ? ext.substring(1) : ext;
408
+ function flattenTree(tree, parent = null, depth = 0) {
297
409
  return tree.flatMap(
298
410
  (item) => item.children ? [{ ...item, parent: parent?.value, depth }, ...flattenTree(item.children, item, depth + 1)] : { ...item, depth, parent: parent?.value }
299
411
  );
@@ -308,70 +420,178 @@ const getFolderParents = (folders, currentFolderId) => {
308
420
  let { parent } = currentFolder;
309
421
  while (parent !== void 0) {
310
422
  let parentToStore = flatFolders.find(({ value }) => value === parent);
311
- parents.push({ id: parentToStore.value, label: parentToStore.label });
312
- parent = parentToStore.parent;
423
+ parents.push({ id: parentToStore?.value, label: parentToStore?.label });
424
+ parent = parentToStore?.parent;
313
425
  }
314
426
  return parents.reverse();
315
427
  };
316
- const toSingularTypes = (types) => {
317
- if (!types) {
318
- return [];
428
+ const move = (array, oldIndex, newIndex) => {
429
+ if (newIndex >= array.length) {
430
+ newIndex = array.length - 1;
319
431
  }
320
- return types.map((type) => type.substring(0, type.length - 1));
432
+ array.splice(newIndex, 0, array.splice(oldIndex, 1)[0]);
433
+ return array;
321
434
  };
322
- const getFileExtension = (ext) => ext && ext[0] === "." ? ext.substring(1) : ext;
323
- function getPrefixedId(message, callback) {
324
- const prefixedMessage = `apiError.${message}`;
325
- if (typeof callback === "function") {
326
- return callback(prefixedMessage);
435
+ const moveElement = (array, index2, offset) => {
436
+ const newIndex = index2 + offset;
437
+ return move(array, index2, newIndex);
438
+ };
439
+ const prefixPluginTranslations = (trad, pluginId2) => {
440
+ if (!pluginId2) {
441
+ throw new TypeError("pluginId can't be empty");
327
442
  }
328
- return prefixedMessage;
329
- }
330
- function normalizeError(error, { name: name2, intlMessagePrefixCallback }) {
331
- const { message } = error;
332
- const normalizedError = {
333
- id: getPrefixedId(message, intlMessagePrefixCallback),
334
- defaultMessage: message,
335
- name: error.name ?? name2,
336
- values: {}
337
- };
338
- if ("path" in error) {
339
- normalizedError.values = { path: error.path.join(".") };
443
+ return Object.keys(trad).reduce((acc, current) => {
444
+ acc[`${pluginId2}.${current}`] = trad[current];
445
+ return acc;
446
+ }, {});
447
+ };
448
+ var AssetType$1 = /* @__PURE__ */ ((AssetType2) => {
449
+ AssetType2["Video"] = "video";
450
+ AssetType2["Image"] = "image";
451
+ AssetType2["Document"] = "doc";
452
+ AssetType2["Audio"] = "audio";
453
+ return AssetType2;
454
+ })(AssetType$1 || {});
455
+ var AssetSource$1 = /* @__PURE__ */ ((AssetSource2) => {
456
+ AssetSource2["Url"] = "url";
457
+ AssetSource2["Computer"] = "computer";
458
+ return AssetSource2;
459
+ })(AssetSource$1 || {});
460
+ const PERMISSIONS$1 = {
461
+ // This permission regards the main component (App) and is used to tell
462
+ // If the plugin link should be displayed in the menu
463
+ // And also if the plugin is accessible. This use case is found when a user types the url of the
464
+ // plugin directly in the browser
465
+ main: [
466
+ { action: "plugin::upload.read", subject: null },
467
+ {
468
+ action: "plugin::upload.assets.create",
469
+ subject: null
470
+ },
471
+ {
472
+ action: "plugin::upload.assets.update",
473
+ subject: null
474
+ }
475
+ ],
476
+ copyLink: [
477
+ {
478
+ action: "plugin::upload.assets.copy-link",
479
+ subject: null
480
+ }
481
+ ],
482
+ create: [
483
+ {
484
+ action: "plugin::upload.assets.create",
485
+ subject: null
486
+ }
487
+ ],
488
+ download: [
489
+ {
490
+ action: "plugin::upload.assets.download",
491
+ subject: null
492
+ }
493
+ ],
494
+ read: [{ action: "plugin::upload.read", subject: null }],
495
+ configureView: [{ action: "plugin::upload.configure-view", subject: null }],
496
+ settings: [{ action: "plugin::upload.settings.read", subject: null }],
497
+ update: [{ action: "plugin::upload.assets.update", subject: null, fields: null }]
498
+ };
499
+ const typeFromMime = (mime) => {
500
+ if (mime.includes(AssetType$1.Image)) {
501
+ return AssetType$1.Image;
340
502
  }
341
- return normalizedError;
503
+ if (mime.includes(AssetType$1.Video)) {
504
+ return AssetType$1.Video;
505
+ }
506
+ if (mime.includes(AssetType$1.Audio)) {
507
+ return AssetType$1.Audio;
508
+ }
509
+ return AssetType$1.Document;
510
+ };
511
+ const rawFileToAsset = (rawFile, assetSource) => {
512
+ return {
513
+ size: rawFile.size / 1e3,
514
+ createdAt: new Date(rawFile.lastModified).toISOString(),
515
+ name: rawFile.name,
516
+ source: assetSource,
517
+ type: typeFromMime(rawFile.type),
518
+ url: URL.createObjectURL(rawFile),
519
+ ext: rawFile.name.split(".").pop(),
520
+ mime: rawFile.type,
521
+ rawFile,
522
+ isLocal: true
523
+ };
524
+ };
525
+ function getFilenameFromURL(url) {
526
+ return new URL(url).pathname.split("/").pop();
342
527
  }
343
- const validateErrorIsYupValidationError = (err) => typeof err.details === "object" && err.details !== null && "errors" in err.details;
344
- function normalizeAPIError(apiError, intlMessagePrefixCallback) {
345
- const error = apiError.response?.data.error;
346
- if (error) {
347
- if (validateErrorIsYupValidationError(error)) {
528
+ const urlsToAssets = async (urls) => {
529
+ const assetPromises = urls.map(
530
+ (url) => fetch(url).then(async (res) => {
531
+ const blob = await res.blob();
532
+ const loadedFile = new File([blob], getFilenameFromURL(res.url), {
533
+ type: res.headers.get("content-type") || void 0
534
+ });
348
535
  return {
349
- name: error.name,
350
- message: error?.message || null,
351
- errors: error.details.errors.map(
352
- (err) => normalizeError(err, { name: error.name, intlMessagePrefixCallback })
353
- )
536
+ name: loadedFile.name,
537
+ url: res.url,
538
+ mime: res.headers.get("content-type"),
539
+ rawFile: loadedFile
354
540
  };
355
- }
356
- return normalizeError(error, { intlMessagePrefixCallback });
357
- }
358
- return null;
359
- }
360
- function getAPIInnerErrors(error, { getTrad: getTrad2 }) {
361
- const normalizedError = normalizeAPIError(error, getTrad2);
362
- if (normalizedError && "errors" in normalizedError) {
363
- return normalizedError.errors.reduce((acc, error2) => {
364
- if ("path" in error2.values) {
365
- acc[error2.values.path] = {
366
- id: error2.id,
367
- defaultMessage: error2.defaultMessage
368
- };
541
+ })
542
+ );
543
+ const assetsResults = await Promise.all(assetPromises);
544
+ const assets = assetsResults.map((fullFilledAsset) => ({
545
+ source: AssetSource$1.Url,
546
+ name: fullFilledAsset.name,
547
+ type: typeFromMime(fullFilledAsset.mime),
548
+ url: fullFilledAsset.url,
549
+ ext: fullFilledAsset.url.split(".").pop(),
550
+ mime: fullFilledAsset.mime,
551
+ rawFile: fullFilledAsset.rawFile
552
+ }));
553
+ return assets;
554
+ };
555
+ const urlSchema = yup__namespace.object().shape({
556
+ urls: yup__namespace.string().test({
557
+ name: "isUrlValid",
558
+ // eslint-disable-next-line no-template-curly-in-string
559
+ message: "${path}",
560
+ test(values = "") {
561
+ const urls = values.split(/\r?\n/);
562
+ if (urls.length === 0) {
563
+ return this.createError({
564
+ path: this.path,
565
+ message: strapiAdmin.translatedErrors.min.id
566
+ });
369
567
  }
370
- return acc;
371
- }, {});
372
- }
373
- return normalizedError?.defaultMessage;
374
- }
568
+ if (urls.length > 20) {
569
+ return this.createError({
570
+ path: this.path,
571
+ message: strapiAdmin.translatedErrors.max.id
572
+ });
573
+ }
574
+ const filtered = urls.filter((val) => {
575
+ try {
576
+ new URL(val);
577
+ return false;
578
+ } catch (err) {
579
+ return true;
580
+ }
581
+ });
582
+ const filteredLength = filtered.length;
583
+ if (filteredLength === 0) {
584
+ return true;
585
+ }
586
+ const errorMessage = filteredLength > 1 ? "form.upload-url.error.url.invalids" : "form.upload-url.error.url.invalid";
587
+ return this.createError({
588
+ path: this.path,
589
+ message: getTrad(errorMessage),
590
+ params: { number: filtered.length }
591
+ });
592
+ }
593
+ })
594
+ });
375
595
  const AssetType = {
376
596
  Video: "video",
377
597
  Image: "image",
@@ -620,7 +840,7 @@ const useAssets = ({ skipWhen = false, query = {} } = {}) => {
620
840
  }
621
841
  }
622
842
  );
623
- React.useEffect(() => {
843
+ React__namespace.useEffect(() => {
624
844
  if (data) {
625
845
  notifyStatus(
626
846
  formatMessage({
@@ -630,7 +850,7 @@ const useAssets = ({ skipWhen = false, query = {} } = {}) => {
630
850
  );
631
851
  }
632
852
  }, [data, formatMessage, notifyStatus]);
633
- React.useEffect(() => {
853
+ React__namespace.useEffect(() => {
634
854
  if (error) {
635
855
  toggleNotification({
636
856
  type: "danger",
@@ -707,7 +927,7 @@ const useFolders = ({ enabled = true, query = {} } = {}) => {
707
927
  }, [data, formatMessage, notifyStatus]);
708
928
  return { data, error, isLoading };
709
929
  };
710
- const { main, ...restPermissions } = PERMISSIONS;
930
+ const { main, ...restPermissions } = PERMISSIONS$1;
711
931
  const useMediaLibraryPermissions = () => {
712
932
  const { allowedActions, isLoading } = strapiAdmin.useRBAC(restPermissions);
713
933
  return { ...allowedActions, isLoading };
@@ -735,7 +955,7 @@ const useConfig = () => {
735
955
  /**
736
956
  * We're cementing that we always expect an object to be returned.
737
957
  */
738
- select: (data) => !data ? {} : data
958
+ select: (data) => data || {}
739
959
  }
740
960
  );
741
961
  const putMutation = reactQuery.useMutation(
@@ -765,7 +985,7 @@ const useModalQueryParams = (initialState) => {
765
985
  const {
766
986
  config: { data: config }
767
987
  } = useConfig();
768
- const [queryObject, setQueryObject] = React.useState({
988
+ const [queryObject, setQueryObject] = React__namespace.useState({
769
989
  page: 1,
770
990
  sort: "updatedAt:DESC",
771
991
  pageSize: 10,
@@ -774,8 +994,8 @@ const useModalQueryParams = (initialState) => {
774
994
  },
775
995
  ...initialState
776
996
  });
777
- React.useEffect(() => {
778
- if (config) {
997
+ React__namespace.useEffect(() => {
998
+ if (config && "sort" in config && "pageSize" in config) {
779
999
  setQueryObject((prevQuery) => ({
780
1000
  ...prevQuery,
781
1001
  sort: config.sort,
@@ -784,24 +1004,32 @@ const useModalQueryParams = (initialState) => {
784
1004
  }
785
1005
  }, [config]);
786
1006
  const handleChangeFilters = (nextFilters) => {
787
- trackUsage("didFilterMediaLibraryElements", {
788
- location: "content-manager",
789
- filter: Object.keys(nextFilters[nextFilters.length - 1])[0]
790
- });
791
- setQueryObject((prev) => ({ ...prev, page: 1, filters: { $and: nextFilters } }));
1007
+ if (nextFilters) {
1008
+ trackUsage("didFilterMediaLibraryElements", {
1009
+ location: "content-manager",
1010
+ filter: Object.keys(nextFilters[nextFilters.length - 1])[0]
1011
+ });
1012
+ setQueryObject((prev) => ({ ...prev, page: 1, filters: { $and: nextFilters } }));
1013
+ }
792
1014
  };
793
1015
  const handleChangePageSize = (pageSize) => {
794
- setQueryObject((prev) => ({ ...prev, pageSize: parseInt(pageSize, 10), page: 1 }));
1016
+ setQueryObject((prev) => ({
1017
+ ...prev,
1018
+ pageSize: typeof pageSize === "string" ? parseInt(pageSize, 10) : pageSize,
1019
+ page: 1
1020
+ }));
795
1021
  };
796
1022
  const handeChangePage = (page) => {
797
1023
  setQueryObject((prev) => ({ ...prev, page }));
798
1024
  };
799
1025
  const handleChangeSort = (sort) => {
800
- trackUsage("didSortMediaLibraryElements", {
801
- location: "content-manager",
802
- sort
803
- });
804
- setQueryObject((prev) => ({ ...prev, sort }));
1026
+ if (sort) {
1027
+ trackUsage("didSortMediaLibraryElements", {
1028
+ location: "content-manager",
1029
+ sort
1030
+ });
1031
+ setQueryObject((prev) => ({ ...prev, sort }));
1032
+ }
805
1033
  };
806
1034
  const handleChangeSearch = (_q) => {
807
1035
  if (_q) {
@@ -890,28 +1118,6 @@ const useSelectionState = (keys, initialValue) => {
890
1118
  { selectOne, selectAll, selectOnly, selectMultiple, deselectMultiple, setSelections }
891
1119
  ];
892
1120
  };
893
- const getAllowedFiles = (pluralTypes, files2) => {
894
- const singularTypes = toSingularTypes(pluralTypes);
895
- const allowedFiles = files2.filter((file) => {
896
- const fileType = file.mime.split("/")[0];
897
- if (singularTypes.includes("file") && !["video", "image", "audio"].includes(fileType)) {
898
- return true;
899
- }
900
- return singularTypes.includes(fileType);
901
- });
902
- return allowedFiles;
903
- };
904
- const move = (array, oldIndex, newIndex) => {
905
- if (newIndex >= array.length) {
906
- newIndex = array.length - 1;
907
- }
908
- array.splice(newIndex, 0, array.splice(oldIndex, 1)[0]);
909
- return array;
910
- };
911
- const moveElement = (array, index2, offset) => {
912
- const newIndex = index2 + offset;
913
- return move(array, index2, newIndex);
914
- };
915
1121
  const editAssetRequest = (asset, file, signal, onProgress, post) => {
916
1122
  const endpoint2 = `/${pluginId}?id=${asset.id}`;
917
1123
  const formData = new FormData();
@@ -932,33 +1138,30 @@ const editAssetRequest = (asset, file, signal, onProgress, post) => {
932
1138
  }).then((res) => res.data);
933
1139
  };
934
1140
  const useEditAsset = () => {
935
- const [progress, setProgress] = React.useState(0);
1141
+ const [progress, setProgress] = React__namespace.useState(0);
936
1142
  const { formatMessage } = reactIntl.useIntl();
937
1143
  const { toggleNotification } = strapiAdmin.useNotification();
938
1144
  const queryClient = reactQuery.useQueryClient();
939
1145
  const abortController = new AbortController();
940
1146
  const signal = abortController.signal;
941
1147
  const { post } = strapiAdmin.useFetchClient();
942
- const mutation = reactQuery.useMutation(
943
- ({ asset, file }) => editAssetRequest(asset, file, signal, setProgress, post),
944
- {
945
- onSuccess() {
946
- queryClient.refetchQueries([pluginId, "assets"], { active: true });
947
- queryClient.refetchQueries([pluginId, "asset-count"], { active: true });
948
- queryClient.refetchQueries([pluginId, "folders"], { active: true });
949
- },
950
- onError(reason) {
951
- if (reason.response.status === 403) {
952
- toggleNotification({
953
- type: "info",
954
- message: formatMessage({ id: getTrad("permissions.not-allowed.update") })
955
- });
956
- } else {
957
- toggleNotification({ type: "danger", message: reason.message });
958
- }
1148
+ const mutation = reactQuery.useMutation(({ asset, file }) => editAssetRequest(asset, file, signal, setProgress, post), {
1149
+ onSuccess() {
1150
+ queryClient.refetchQueries([pluginId, "assets"], { active: true });
1151
+ queryClient.refetchQueries([pluginId, "asset-count"], { active: true });
1152
+ queryClient.refetchQueries([pluginId, "folders"], { active: true });
1153
+ },
1154
+ onError(reason) {
1155
+ if (reason?.response?.status === 403) {
1156
+ toggleNotification({
1157
+ type: "info",
1158
+ message: formatMessage({ id: getTrad("permissions.not-allowed.update") })
1159
+ });
1160
+ } else {
1161
+ toggleNotification({ type: "danger", message: reason?.message });
959
1162
  }
960
1163
  }
961
- );
1164
+ });
962
1165
  const editAsset = (asset, file) => mutation.mutateAsync({ asset, file });
963
1166
  const cancel = () => abortController.abort();
964
1167
  return { ...mutation, cancel, editAsset, progress, status: mutation.status };
@@ -980,7 +1183,9 @@ const useFolderStructure = ({ enabled = true } = {}) => {
980
1183
  const {
981
1184
  data: { data: data2 }
982
1185
  } = await get("/upload/folder-structure");
983
- const children = data2.map((f) => recursiveRenameKeys(f, (key) => FIELD_MAPPING?.[key] ?? key));
1186
+ const children = data2.map(
1187
+ (f) => recursiveRenameKeys(f, (key) => FIELD_MAPPING?.[key] ?? key)
1188
+ );
984
1189
  return [
985
1190
  {
986
1191
  value: null,
@@ -1350,10 +1555,10 @@ const DialogHeader = () => {
1350
1555
  };
1351
1556
  const QUALITY = 1;
1352
1557
  const useCropImg = () => {
1353
- const cropperRef = React.useRef();
1354
- const [isCropping, setIsCropping] = React.useState(false);
1355
- const [size, setSize] = React.useState({ width: void 0, height: void 0 });
1356
- React.useEffect(() => {
1558
+ const cropperRef = React__namespace.useRef();
1559
+ const [isCropping, setIsCropping] = React__namespace.useState(false);
1560
+ const [size, setSize] = React__namespace.useState({ width: void 0, height: void 0 });
1561
+ React__namespace.useEffect(() => {
1357
1562
  return () => {
1358
1563
  if (cropperRef.current) {
1359
1564
  cropperRef.current.destroy();
@@ -1400,7 +1605,7 @@ const useCropImg = () => {
1400
1605
  resolve(
1401
1606
  new File([blob], name2, {
1402
1607
  type: mimeType,
1403
- lastModifiedDate
1608
+ lastModified: new Date(lastModifiedDate).getTime()
1404
1609
  })
1405
1610
  );
1406
1611
  },
@@ -1437,7 +1642,7 @@ const uploadAsset = (asset, folderId, signal, onProgress, post) => {
1437
1642
  }).then((res) => res.data);
1438
1643
  };
1439
1644
  const useUpload = () => {
1440
- const [progress, setProgress] = React.useState(0);
1645
+ const [progress, setProgress] = React__namespace.useState(0);
1441
1646
  const queryClient = reactQuery.useQueryClient();
1442
1647
  const abortController = new AbortController();
1443
1648
  const signal = abortController.signal;
@@ -1463,14 +1668,6 @@ const useUpload = () => {
1463
1668
  status: mutation.status
1464
1669
  };
1465
1670
  };
1466
- const downloadFile = async (url, fileName) => {
1467
- const fileBlob = await fetch(url).then((res) => res.blob());
1468
- const urlDownload = window.URL.createObjectURL(fileBlob);
1469
- const link = document.createElement("a");
1470
- link.href = urlDownload;
1471
- link.setAttribute("download", fileName);
1472
- link.click();
1473
- };
1474
1671
  const useClipboard = () => {
1475
1672
  const copy = React.useCallback(async (value) => {
1476
1673
  try {
@@ -1582,23 +1779,26 @@ const useRemoveAsset = (onSuccess) => {
1582
1779
  const { formatMessage } = reactIntl.useIntl();
1583
1780
  const queryClient = reactQuery.useQueryClient();
1584
1781
  const { del } = strapiAdmin.useFetchClient();
1585
- const mutation = reactQuery.useMutation((assetId) => del(`/upload/files/${assetId}`), {
1586
- onSuccess() {
1587
- queryClient.refetchQueries([pluginId, "assets"], { active: true });
1588
- queryClient.refetchQueries([pluginId, "asset-count"], { active: true });
1589
- toggleNotification({
1590
- type: "success",
1591
- message: formatMessage({
1592
- id: "modal.remove.success-label",
1593
- defaultMessage: "Elements have been successfully deleted."
1594
- })
1595
- });
1596
- onSuccess();
1597
- },
1598
- onError(error) {
1599
- toggleNotification({ type: "danger", message: error.message });
1782
+ const mutation = reactQuery.useMutation(
1783
+ (assetId) => del(`/upload/files/${assetId}`),
1784
+ {
1785
+ onSuccess() {
1786
+ queryClient.refetchQueries([pluginId, "assets"], { active: true });
1787
+ queryClient.refetchQueries([pluginId, "asset-count"], { active: true });
1788
+ toggleNotification({
1789
+ type: "success",
1790
+ message: formatMessage({
1791
+ id: "modal.remove.success-label",
1792
+ defaultMessage: "Elements have been successfully deleted."
1793
+ })
1794
+ });
1795
+ onSuccess();
1796
+ },
1797
+ onError(error) {
1798
+ toggleNotification({ type: "danger", message: error.message });
1799
+ }
1600
1800
  }
1601
- });
1801
+ );
1602
1802
  const removeAsset = async (assetId) => {
1603
1803
  await mutation.mutateAsync(assetId);
1604
1804
  };
@@ -2393,7 +2593,7 @@ const useBulkRemove = () => {
2393
2593
  });
2394
2594
  },
2395
2595
  onError(error) {
2396
- toggleNotification({ type: "danger", message: error.message });
2596
+ toggleNotification({ type: "danger", message: error?.message });
2397
2597
  }
2398
2598
  });
2399
2599
  const remove = (...args) => mutation.mutateAsync(...args);
@@ -3837,35 +4037,6 @@ TableList.propTypes = {
3837
4037
  shouldDisableBulkSelect: PropTypes__default.default.bool,
3838
4038
  sortQuery: PropTypes__default.default.string
3839
4039
  };
3840
- const displayedFilters = [
3841
- {
3842
- name: "createdAt",
3843
- fieldSchema: {
3844
- type: "date"
3845
- },
3846
- metadatas: { label: "createdAt" }
3847
- },
3848
- {
3849
- name: "updatedAt",
3850
- fieldSchema: {
3851
- type: "date"
3852
- },
3853
- metadatas: { label: "updatedAt" }
3854
- },
3855
- {
3856
- name: "mime",
3857
- fieldSchema: {
3858
- type: "enumeration",
3859
- options: [
3860
- { label: "audio", value: "audio" },
3861
- { label: "file", value: "file" },
3862
- { label: "image", value: "image" },
3863
- { label: "video", value: "video" }
3864
- ]
3865
- },
3866
- metadatas: { label: "type" }
3867
- }
3868
- ];
3869
4040
  const FilterTag = ({ attribute, filter, onClick, operator, value }) => {
3870
4041
  const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
3871
4042
  const handleClick = () => {
@@ -4725,7 +4896,7 @@ const BrowseStep = ({
4725
4896
  isSelectable: isSelectable(singularTypes, asset?.mime),
4726
4897
  type: "asset"
4727
4898
  }));
4728
- const breadcrumbs = !isCurrentFolderLoading && getBreadcrumbDataML(currentFolder);
4899
+ const breadcrumbs = !isCurrentFolderLoading && getBreadcrumbDataCM(currentFolder);
4729
4900
  const allAllowedAsset = getAllowedFiles(allowedTypes, assets);
4730
4901
  const areAllAssetSelected = allAllowedAsset.length > 0 && selectedAssets.length > 0 && allAllowedAsset.every(
4731
4902
  (asset) => selectedAssets.findIndex((currAsset) => currAsset.id === asset.id) !== -1
@@ -5319,32 +5490,6 @@ const TabsRoot = styledComponents.styled(designSystem.Tabs.Root)`
5319
5490
  flex-direction: column;
5320
5491
  overflow: hidden;
5321
5492
  `;
5322
- const typeFromMime = (mime) => {
5323
- if (mime.includes(AssetType.Image)) {
5324
- return AssetType.Image;
5325
- }
5326
- if (mime.includes(AssetType.Video)) {
5327
- return AssetType.Video;
5328
- }
5329
- if (mime.includes(AssetType.Audio)) {
5330
- return AssetType.Audio;
5331
- }
5332
- return AssetType.Document;
5333
- };
5334
- const rawFileToAsset = (rawFile, assetSource) => {
5335
- return {
5336
- size: rawFile.size / 1e3,
5337
- createdAt: new Date(rawFile.lastModified).toISOString(),
5338
- name: rawFile.name,
5339
- source: assetSource,
5340
- type: typeFromMime(rawFile.type),
5341
- url: URL.createObjectURL(rawFile),
5342
- ext: rawFile.name.split(".").pop(),
5343
- mime: rawFile.type,
5344
- rawFile,
5345
- isLocal: true
5346
- };
5347
- };
5348
5493
  const Wrapper = styledComponents.styled(designSystem.Flex)`
5349
5494
  flex-direction: column;
5350
5495
  `;
@@ -5467,76 +5612,6 @@ FromComputerForm.propTypes = {
5467
5612
  onAddAssets: PropTypes__default.default.func.isRequired,
5468
5613
  trackedLocation: PropTypes__default.default.string
5469
5614
  };
5470
- function getFilenameFromURL(url) {
5471
- return new URL(url).pathname.split("/").pop();
5472
- }
5473
- const urlsToAssets = async (urls) => {
5474
- const assetPromises = urls.map(
5475
- (url) => fetch(url).then(async (res) => {
5476
- const blob = await res.blob();
5477
- const loadedFile = new File([blob], getFilenameFromURL(res.url), {
5478
- type: res.headers.get("content-type")
5479
- });
5480
- return {
5481
- name: loadedFile.name,
5482
- url: res.url,
5483
- mime: res.headers.get("content-type"),
5484
- rawFile: loadedFile
5485
- };
5486
- })
5487
- );
5488
- const assetsResults = await Promise.all(assetPromises);
5489
- const assets = assetsResults.map((fullFilledAsset) => ({
5490
- source: AssetSource.Url,
5491
- name: fullFilledAsset.name,
5492
- type: typeFromMime(fullFilledAsset.mime),
5493
- url: fullFilledAsset.url,
5494
- ext: fullFilledAsset.url.split(".").pop(),
5495
- mime: fullFilledAsset.mime,
5496
- rawFile: fullFilledAsset.rawFile
5497
- }));
5498
- return assets;
5499
- };
5500
- const urlSchema = yup__namespace.object().shape({
5501
- urls: yup__namespace.string().test({
5502
- name: "isUrlValid",
5503
- // eslint-disable-next-line no-template-curly-in-string
5504
- message: "${path}",
5505
- test(values = "") {
5506
- const urls = values.split(/\r?\n/);
5507
- if (urls.length === 0) {
5508
- return this.createError({
5509
- path: this.path,
5510
- message: strapiAdmin.translatedErrors.min.id
5511
- });
5512
- }
5513
- if (urls.length > 20) {
5514
- return this.createError({
5515
- path: this.path,
5516
- message: strapiAdmin.translatedErrors.max.id
5517
- });
5518
- }
5519
- const filtered = urls.filter((val) => {
5520
- try {
5521
- new URL(val);
5522
- return false;
5523
- } catch (err) {
5524
- return true;
5525
- }
5526
- });
5527
- const filteredLength = filtered.length;
5528
- if (filteredLength === 0) {
5529
- return true;
5530
- }
5531
- const errorMessage = filteredLength > 1 ? "form.upload-url.error.url.invalids" : "form.upload-url.error.url.invalid";
5532
- return this.createError({
5533
- path: this.path,
5534
- message: getTrad(errorMessage),
5535
- params: { number: filtered.length }
5536
- });
5537
- }
5538
- })
5539
- });
5540
5615
  const FromUrlForm = ({ onClose, onAddAsset, trackedLocation }) => {
5541
5616
  const [loading, setLoading] = React.useState(false);
5542
5617
  const [error, setError] = React.useState(void 0);
@@ -6569,15 +6644,6 @@ MediaLibraryInput.propTypes = {
6569
6644
  name: PropTypes__default.default.string.isRequired,
6570
6645
  required: PropTypes__default.default.bool
6571
6646
  };
6572
- const prefixPluginTranslations = (trad, pluginId2) => {
6573
- if (!pluginId2) {
6574
- throw new TypeError("pluginId can't be empty");
6575
- }
6576
- return Object.keys(trad).reduce((acc, current) => {
6577
- acc[`${pluginId2}.${current}`] = trad[current];
6578
- return acc;
6579
- }, {});
6580
- };
6581
6647
  const name = pluginPkg.strapi.name;
6582
6648
  const index = {
6583
6649
  register(app) {
@@ -6589,7 +6655,7 @@ const index = {
6589
6655
  defaultMessage: "Media Library"
6590
6656
  },
6591
6657
  permissions: PERMISSIONS.main,
6592
- Component: () => Promise.resolve().then(() => require("./index-C5E7jC83.js")),
6658
+ Component: () => Promise.resolve().then(() => require("./index-Dztfplsk.js")),
6593
6659
  position: 4
6594
6660
  });
6595
6661
  app.addSettingsLink("global", {
@@ -6599,7 +6665,7 @@ const index = {
6599
6665
  defaultMessage: "Media Library"
6600
6666
  },
6601
6667
  to: "media-library",
6602
- Component: () => Promise.resolve().then(() => require("./index-ox-PAURv.js")),
6668
+ Component: () => Promise.resolve().then(() => require("./index-boOjOtd3.js")),
6603
6669
  permissions: PERMISSIONS.settings
6604
6670
  });
6605
6671
  app.addFields({ type: "media", Component: MediaLibraryInput });
@@ -6668,4 +6734,4 @@ exports.useMediaLibraryPermissions = useMediaLibraryPermissions;
6668
6734
  exports.usePersistentState = usePersistentState;
6669
6735
  exports.useSelectionState = useSelectionState;
6670
6736
  exports.viewOptions = viewOptions;
6671
- //# sourceMappingURL=index-BwMdH-eI.js.map
6737
+ //# sourceMappingURL=index-C7Nj9ETW.js.map