@strapi/upload 5.35.0 → 5.36.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/dist/admin/future/App.js +8 -20
  2. package/dist/admin/future/App.js.map +1 -1
  3. package/dist/admin/future/App.mjs +8 -20
  4. package/dist/admin/future/App.mjs.map +1 -1
  5. package/dist/admin/future/components/UploadProgressDialog.js +494 -0
  6. package/dist/admin/future/components/UploadProgressDialog.js.map +1 -0
  7. package/dist/admin/future/components/UploadProgressDialog.mjs +473 -0
  8. package/dist/admin/future/components/UploadProgressDialog.mjs.map +1 -0
  9. package/dist/admin/future/enums.js +12 -0
  10. package/dist/admin/future/enums.js.map +1 -0
  11. package/dist/admin/future/enums.mjs +10 -0
  12. package/dist/admin/future/enums.mjs.map +1 -0
  13. package/dist/admin/future/pages/Assets/AssetsPage.js +311 -0
  14. package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -0
  15. package/dist/admin/future/pages/Assets/AssetsPage.mjs +290 -0
  16. package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -0
  17. package/dist/admin/future/pages/Assets/components/AssetsGrid.js +164 -0
  18. package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -0
  19. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +162 -0
  20. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -0
  21. package/dist/admin/future/pages/Assets/components/AssetsTable.js +198 -0
  22. package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -0
  23. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +196 -0
  24. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -0
  25. package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZone.js +127 -0
  26. package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZone.js.map +1 -0
  27. package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZone.mjs +105 -0
  28. package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZone.mjs.map +1 -0
  29. package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZoneContext.js +107 -0
  30. package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZoneContext.js.map +1 -0
  31. package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZoneContext.mjs +104 -0
  32. package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZoneContext.mjs.map +1 -0
  33. package/dist/admin/future/pages/Assets/constants.js +54 -0
  34. package/dist/admin/future/pages/Assets/constants.js.map +1 -0
  35. package/dist/admin/future/pages/Assets/constants.mjs +50 -0
  36. package/dist/admin/future/pages/Assets/constants.mjs.map +1 -0
  37. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js +77 -0
  38. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js.map +1 -0
  39. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs +74 -0
  40. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs.map +1 -0
  41. package/dist/admin/future/services/api.js +419 -9
  42. package/dist/admin/future/services/api.js.map +1 -1
  43. package/dist/admin/future/services/api.mjs +417 -9
  44. package/dist/admin/future/services/api.mjs.map +1 -1
  45. package/dist/admin/future/services/assets.js +37 -0
  46. package/dist/admin/future/services/assets.js.map +1 -0
  47. package/dist/admin/future/services/assets.mjs +35 -0
  48. package/dist/admin/future/services/assets.mjs.map +1 -0
  49. package/dist/admin/future/store/hooks.js +10 -0
  50. package/dist/admin/future/store/hooks.js.map +1 -0
  51. package/dist/admin/future/store/hooks.mjs +7 -0
  52. package/dist/admin/future/store/hooks.mjs.map +1 -0
  53. package/dist/admin/future/store/uploadProgress.js +156 -0
  54. package/dist/admin/future/store/uploadProgress.js.map +1 -0
  55. package/dist/admin/future/store/uploadProgress.mjs +143 -0
  56. package/dist/admin/future/store/uploadProgress.mjs.map +1 -0
  57. package/dist/admin/future/utils/files.js +23 -0
  58. package/dist/admin/future/utils/files.js.map +1 -0
  59. package/dist/admin/future/utils/files.mjs +19 -0
  60. package/dist/admin/future/utils/files.mjs.map +1 -0
  61. package/dist/admin/future/utils/getAssetIcon.js +28 -0
  62. package/dist/admin/future/utils/getAssetIcon.js.map +1 -0
  63. package/dist/admin/future/utils/getAssetIcon.mjs +26 -0
  64. package/dist/admin/future/utils/getAssetIcon.mjs.map +1 -0
  65. package/dist/admin/index.js +11 -0
  66. package/dist/admin/index.js.map +1 -1
  67. package/dist/admin/index.mjs +11 -0
  68. package/dist/admin/index.mjs.map +1 -1
  69. package/dist/admin/package.json.js +11 -9
  70. package/dist/admin/package.json.js.map +1 -1
  71. package/dist/admin/package.json.mjs +11 -9
  72. package/dist/admin/package.json.mjs.map +1 -1
  73. package/dist/admin/src/future/components/UploadProgressDialog.d.ts +1 -0
  74. package/dist/admin/src/future/enums.d.ts +6 -0
  75. package/dist/admin/src/future/pages/Assets/AssetsPage.d.ts +1 -0
  76. package/dist/admin/src/future/pages/Assets/components/AssetsGrid.d.ts +6 -0
  77. package/dist/admin/src/future/pages/Assets/components/AssetsTable.d.ts +6 -0
  78. package/dist/admin/src/future/pages/Assets/components/DropZone/UploadDropZone.d.ts +9 -0
  79. package/dist/admin/src/future/pages/Assets/components/DropZone/UploadDropZoneContext.d.ts +11 -0
  80. package/dist/admin/src/future/pages/Assets/constants.d.ts +17 -0
  81. package/dist/admin/src/future/pages/Assets/hooks/useInfiniteAssets.d.ts +17 -0
  82. package/dist/admin/src/future/services/api.d.ts +21 -3
  83. package/dist/admin/src/future/services/assets.d.ts +13 -0
  84. package/dist/admin/src/future/store/hooks.d.ts +6 -0
  85. package/dist/admin/src/future/store/uploadProgress.d.ts +46 -0
  86. package/dist/admin/src/future/utils/files.d.ts +3 -0
  87. package/dist/admin/src/future/utils/getAssetIcon.d.ts +12 -0
  88. package/dist/admin/translations/en.json.js +25 -0
  89. package/dist/admin/translations/en.json.js.map +1 -1
  90. package/dist/admin/translations/en.json.mjs +25 -0
  91. package/dist/admin/translations/en.json.mjs.map +1 -1
  92. package/dist/server/controllers/admin-upload.js +151 -2
  93. package/dist/server/controllers/admin-upload.js.map +1 -1
  94. package/dist/server/controllers/admin-upload.mjs +151 -2
  95. package/dist/server/controllers/admin-upload.mjs.map +1 -1
  96. package/dist/server/controllers/content-api.js +8 -2
  97. package/dist/server/controllers/content-api.js.map +1 -1
  98. package/dist/server/controllers/content-api.mjs +9 -3
  99. package/dist/server/controllers/content-api.mjs.map +1 -1
  100. package/dist/server/routes/admin.js +10 -0
  101. package/dist/server/routes/admin.js.map +1 -1
  102. package/dist/server/routes/admin.mjs +10 -0
  103. package/dist/server/routes/admin.mjs.map +1 -1
  104. package/dist/server/src/controllers/admin-upload.d.ts +12 -0
  105. package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
  106. package/dist/server/src/controllers/content-api.d.ts.map +1 -1
  107. package/dist/server/src/controllers/index.d.ts +1 -0
  108. package/dist/server/src/controllers/index.d.ts.map +1 -1
  109. package/dist/server/src/index.d.ts +1 -0
  110. package/dist/server/src/index.d.ts.map +1 -1
  111. package/dist/server/src/routes/admin.d.ts.map +1 -1
  112. package/dist/server/src/utils/mime-validation.d.ts +5 -0
  113. package/dist/server/src/utils/mime-validation.d.ts.map +1 -1
  114. package/dist/server/utils/mime-validation.js +7 -4
  115. package/dist/server/utils/mime-validation.js.map +1 -1
  116. package/dist/server/utils/mime-validation.mjs +7 -4
  117. package/dist/server/utils/mime-validation.mjs.map +1 -1
  118. package/dist/shared/contracts/files.d.ts +52 -0
  119. package/dist/shared/contracts/files.d.ts.map +1 -0
  120. package/package.json +11 -9
  121. package/dist/admin/future/pages/AIGenerationPage.js +0 -24
  122. package/dist/admin/future/pages/AIGenerationPage.js.map +0 -1
  123. package/dist/admin/future/pages/AIGenerationPage.mjs +0 -22
  124. package/dist/admin/future/pages/AIGenerationPage.mjs.map +0 -1
  125. package/dist/admin/future/pages/MediaLibraryPage.js +0 -119
  126. package/dist/admin/future/pages/MediaLibraryPage.js.map +0 -1
  127. package/dist/admin/future/pages/MediaLibraryPage.mjs +0 -98
  128. package/dist/admin/future/pages/MediaLibraryPage.mjs.map +0 -1
  129. package/dist/admin/src/future/pages/AIGenerationPage.d.ts +0 -1
  130. package/dist/admin/src/future/pages/MediaLibraryPage.d.ts +0 -1
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var name = "@strapi/upload";
6
- var version = "5.35.0";
6
+ var version = "5.36.1";
7
7
  var description = "Makes it easy to upload images and files to your Strapi Application.";
8
8
  var license = "SEE LICENSE IN LICENSE";
9
9
  var author = {
@@ -64,12 +64,14 @@ var scripts = {
64
64
  };
65
65
  var dependencies = {
66
66
  "@mux/mux-player-react": "3.1.0",
67
+ "@radix-ui/react-dialog": "1.1.15",
68
+ "@radix-ui/react-toggle-group": "1.1.11",
67
69
  "@reduxjs/toolkit": "1.9.7",
68
- "@strapi/database": "5.33.3",
70
+ "@strapi/database": "5.36.1",
69
71
  "@strapi/design-system": "2.1.2",
70
72
  "@strapi/icons": "2.1.2",
71
- "@strapi/provider-upload-local": "5.35.0",
72
- "@strapi/utils": "5.35.0",
73
+ "@strapi/provider-upload-local": "5.36.1",
74
+ "@strapi/utils": "5.36.1",
73
75
  "byte-size": "8.1.1",
74
76
  cropperjs: "1.6.1",
75
77
  "date-fns": "2.30.0",
@@ -82,7 +84,7 @@ var dependencies = {
82
84
  lodash: "4.17.21",
83
85
  "mime-types": "2.1.35",
84
86
  "prop-types": "^15.8.1",
85
- qs: "6.14.1",
87
+ qs: "6.14.2",
86
88
  "react-dnd": "16.0.1",
87
89
  "react-intl": "6.6.2",
88
90
  "react-query": "3.39.3",
@@ -93,8 +95,8 @@ var dependencies = {
93
95
  zod: "3.25.67"
94
96
  };
95
97
  var devDependencies = {
96
- "@strapi/admin": "5.35.0",
97
- "@strapi/types": "5.35.0",
98
+ "@strapi/admin": "5.36.1",
99
+ "@strapi/types": "5.36.1",
98
100
  "@testing-library/dom": "10.4.1",
99
101
  "@testing-library/react": "16.3.0",
100
102
  "@testing-library/user-event": "14.6.1",
@@ -109,14 +111,14 @@ var devDependencies = {
109
111
  msw: "1.3.0",
110
112
  react: "18.3.1",
111
113
  "react-dom": "18.3.1",
112
- "react-router-dom": "6.22.3",
114
+ "react-router-dom": "6.30.3",
113
115
  "styled-components": "6.1.8"
114
116
  };
115
117
  var peerDependencies = {
116
118
  "@strapi/admin": "^5.0.0",
117
119
  react: "^17.0.0 || ^18.0.0",
118
120
  "react-dom": "^17.0.0 || ^18.0.0",
119
- "react-router-dom": "^6.0.0",
121
+ "react-router-dom": "^6.30.3",
120
122
  "styled-components": "^6.0.0"
121
123
  };
122
124
  var engines = {
@@ -1 +1 @@
1
- {"version":3,"file":"package.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"package.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,5 +1,5 @@
1
1
  var name = "@strapi/upload";
2
- var version = "5.35.0";
2
+ var version = "5.36.1";
3
3
  var description = "Makes it easy to upload images and files to your Strapi Application.";
4
4
  var license = "SEE LICENSE IN LICENSE";
5
5
  var author = {
@@ -60,12 +60,14 @@ var scripts = {
60
60
  };
61
61
  var dependencies = {
62
62
  "@mux/mux-player-react": "3.1.0",
63
+ "@radix-ui/react-dialog": "1.1.15",
64
+ "@radix-ui/react-toggle-group": "1.1.11",
63
65
  "@reduxjs/toolkit": "1.9.7",
64
- "@strapi/database": "5.33.3",
66
+ "@strapi/database": "5.36.1",
65
67
  "@strapi/design-system": "2.1.2",
66
68
  "@strapi/icons": "2.1.2",
67
- "@strapi/provider-upload-local": "5.35.0",
68
- "@strapi/utils": "5.35.0",
69
+ "@strapi/provider-upload-local": "5.36.1",
70
+ "@strapi/utils": "5.36.1",
69
71
  "byte-size": "8.1.1",
70
72
  cropperjs: "1.6.1",
71
73
  "date-fns": "2.30.0",
@@ -78,7 +80,7 @@ var dependencies = {
78
80
  lodash: "4.17.21",
79
81
  "mime-types": "2.1.35",
80
82
  "prop-types": "^15.8.1",
81
- qs: "6.14.1",
83
+ qs: "6.14.2",
82
84
  "react-dnd": "16.0.1",
83
85
  "react-intl": "6.6.2",
84
86
  "react-query": "3.39.3",
@@ -89,8 +91,8 @@ var dependencies = {
89
91
  zod: "3.25.67"
90
92
  };
91
93
  var devDependencies = {
92
- "@strapi/admin": "5.35.0",
93
- "@strapi/types": "5.35.0",
94
+ "@strapi/admin": "5.36.1",
95
+ "@strapi/types": "5.36.1",
94
96
  "@testing-library/dom": "10.4.1",
95
97
  "@testing-library/react": "16.3.0",
96
98
  "@testing-library/user-event": "14.6.1",
@@ -105,14 +107,14 @@ var devDependencies = {
105
107
  msw: "1.3.0",
106
108
  react: "18.3.1",
107
109
  "react-dom": "18.3.1",
108
- "react-router-dom": "6.22.3",
110
+ "react-router-dom": "6.30.3",
109
111
  "styled-components": "6.1.8"
110
112
  };
111
113
  var peerDependencies = {
112
114
  "@strapi/admin": "^5.0.0",
113
115
  react: "^17.0.0 || ^18.0.0",
114
116
  "react-dom": "^17.0.0 || ^18.0.0",
115
- "react-router-dom": "^6.0.0",
117
+ "react-router-dom": "^6.30.3",
116
118
  "styled-components": "^6.0.0"
117
119
  };
118
120
  var engines = {
@@ -1 +1 @@
1
- {"version":3,"file":"package.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"package.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1 @@
1
+ export declare const UploadProgressDialog: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ export declare enum AssetType {
2
+ Video = "video",
3
+ Image = "image",
4
+ Document = "doc",
5
+ Audio = "audio"
6
+ }
@@ -0,0 +1 @@
1
+ export declare const AssetsPage: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import type { File } from '../../../../../../shared/contracts/files';
2
+ interface AssetsGridProps {
3
+ assets: File[];
4
+ }
5
+ export declare const AssetsGrid: ({ assets }: AssetsGridProps) => import("react/jsx-runtime").JSX.Element;
6
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { File } from '../../../../../../shared/contracts/files';
2
+ interface AssetsTableProps {
3
+ assets: File[];
4
+ }
5
+ export declare const AssetsTable: ({ assets }: AssetsTableProps) => import("react/jsx-runtime").JSX.Element;
6
+ export {};
@@ -0,0 +1,9 @@
1
+ import * as React from 'react';
2
+ declare const DropZoneWithOverlay: ({ children }: {
3
+ children: React.ReactNode;
4
+ }) => import("react/jsx-runtime").JSX.Element;
5
+ interface DropFilesMessageProps {
6
+ uploadDropZoneRef?: React.RefObject<HTMLDivElement>;
7
+ }
8
+ declare const DropFilesMessage: ({ uploadDropZoneRef }: DropFilesMessageProps) => import("react/jsx-runtime").JSX.Element | null;
9
+ export { DropZoneWithOverlay, DropFilesMessage };
@@ -0,0 +1,11 @@
1
+ import { type ReactNode } from 'react';
2
+ type DropHandler = (files: File[]) => void | Promise<void>;
3
+ interface UploadDropZoneProps {
4
+ children: ReactNode;
5
+ onDrop?: DropHandler;
6
+ }
7
+ export declare const UploadDropZoneProvider: ({ children, onDrop }: UploadDropZoneProps) => import("react/jsx-runtime").JSX.Element;
8
+ export declare const useUploadDropZone: () => {
9
+ isDragging: boolean;
10
+ };
11
+ export {};
@@ -0,0 +1,17 @@
1
+ export declare const localStorageKeys: {
2
+ view: string;
3
+ };
4
+ export declare const viewOptions: {
5
+ GRID: number;
6
+ TABLE: number;
7
+ };
8
+ interface TableHeader {
9
+ name: string;
10
+ label: {
11
+ id: string;
12
+ defaultMessage: string;
13
+ };
14
+ isVisuallyHidden?: boolean;
15
+ }
16
+ export declare const TABLE_HEADERS: TableHeader[];
17
+ export {};
@@ -0,0 +1,17 @@
1
+ import type { File } from '../../../../../../shared/contracts/files';
2
+ declare const PAGE_SIZE = 20;
3
+ interface UseInfiniteAssetsOptions {
4
+ folder?: number | null;
5
+ sort?: string;
6
+ }
7
+ declare const useInfiniteAssets: ({ folder, sort }?: UseInfiniteAssetsOptions) => {
8
+ assets: File[];
9
+ pagination: import("../../../../../../shared/contracts/files").Pagination | undefined;
10
+ isLoading: boolean;
11
+ isFetchingMore: boolean;
12
+ hasNextPage: boolean;
13
+ fetchNextPage: () => void;
14
+ error: import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError | undefined;
15
+ };
16
+ export { useInfiniteAssets };
17
+ export { PAGE_SIZE };
@@ -1,6 +1,24 @@
1
- import type { CreateFile } from '../../../../shared/contracts/files';
1
+ import type { CreateFilesStream } from '../../../../shared/contracts/files';
2
+ interface UploadFilesArgs {
3
+ formData: FormData;
4
+ totalFiles: number;
5
+ }
6
+ /**
7
+ * Aborts an upload by its uploadId.
8
+ * Called from the UploadProgressDialog when the user clicks cancel or close.
9
+ */
10
+ export declare const abortUpload: (uploadId: number) => void;
2
11
  declare const uploadApi: import("@reduxjs/toolkit/query").Api<import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError, {}, {}>, import("@reduxjs/toolkit/dist/query/endpointDefinitions").UpdateDefinitions<{}, "GuidedTourMeta" | "HomepageKeyStatistics" | "AIUsage" | "AIFeatureConfig" | "Asset" | "Folder", never> & {
3
- uploadFiles: import("@reduxjs/toolkit/query").MutationDefinition<FormData, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AIUsage" | "AIFeatureConfig" | "Asset" | "Folder", CreateFile.Response, "adminApi">;
12
+ /**
13
+ * Stream upload files to the /upload/unstable/stream endpoint.
14
+ * Reads SSE stream for per-file progress updates.
15
+ */
16
+ uploadFilesStream: import("@reduxjs/toolkit/query").MutationDefinition<UploadFilesArgs, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AIUsage" | "AIFeatureConfig" | "Asset" | "Folder", CreateFilesStream.Response, "adminApi">;
17
+ /**
18
+ * Retry uploading cancelled files.
19
+ * Retrieves original File objects and re-uploads only the cancelled ones.
20
+ */
21
+ retryCancelledFilesStream: import("@reduxjs/toolkit/query").MutationDefinition<void, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AIUsage" | "AIFeatureConfig" | "Asset" | "Folder", CreateFilesStream.Response, "adminApi">;
4
22
  }, "adminApi", "GuidedTourMeta" | "HomepageKeyStatistics" | "AIUsage" | "AIFeatureConfig" | "Asset" | "Folder", typeof import("@reduxjs/toolkit/query").coreModuleName | typeof import("@reduxjs/toolkit/dist/query/react").reactHooksModuleName>;
5
- export declare const useUploadFilesMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<FormData, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AIUsage" | "AIFeatureConfig" | "Asset" | "Folder", CreateFile.Response, "adminApi">>;
23
+ export declare const useUploadFilesStreamMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<UploadFilesArgs, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AIUsage" | "AIFeatureConfig" | "Asset" | "Folder", CreateFilesStream.Response, "adminApi">>, useRetryCancelledFilesStreamMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<void, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AIUsage" | "AIFeatureConfig" | "Asset" | "Folder", CreateFilesStream.Response, "adminApi">>;
6
24
  export { uploadApi };
@@ -0,0 +1,13 @@
1
+ import type { File, Pagination } from '../../../../shared/contracts/files';
2
+ interface GetAssetsParams {
3
+ page?: number;
4
+ pageSize?: number;
5
+ folder?: number | null;
6
+ sort?: string;
7
+ }
8
+ interface GetAssetsResponse {
9
+ results: File[];
10
+ pagination: Pagination;
11
+ }
12
+ export declare const useGetAssetsQuery: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseQuery<import("@reduxjs/toolkit/query").QueryDefinition<void | GetAssetsParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AIUsage" | "AIFeatureConfig" | "Asset" | "Folder", GetAssetsResponse, "adminApi">>;
13
+ export {};
@@ -0,0 +1,6 @@
1
+ import { Dispatch } from '@reduxjs/toolkit';
2
+ import { TypedUseSelectorHook } from 'react-redux';
3
+ import type { RootState } from './uploadProgress';
4
+ declare const useTypedDispatch: () => Dispatch;
5
+ declare const useTypedSelector: TypedUseSelectorHook<RootState>;
6
+ export { useTypedSelector, useTypedDispatch };
@@ -0,0 +1,46 @@
1
+ import type { File } from '../../../../shared/contracts/files';
2
+ export interface FileUploadError {
3
+ name: string;
4
+ message: string;
5
+ }
6
+ export type FileProgressStatus = 'pending' | 'uploading' | 'complete' | 'error' | 'cancelled';
7
+ export interface FileProgress {
8
+ name: string;
9
+ index: number;
10
+ status: FileProgressStatus;
11
+ size: number;
12
+ file?: File;
13
+ error?: string;
14
+ }
15
+ export interface UploadProgressState {
16
+ isVisible: boolean;
17
+ isMinimized: boolean;
18
+ progress: number;
19
+ totalFiles: number;
20
+ files: FileProgress[];
21
+ errors: FileUploadError[];
22
+ uploadId: number;
23
+ }
24
+ export interface RootState {
25
+ uploadProgress: UploadProgressState;
26
+ }
27
+ export declare const openUploadProgress: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
28
+ totalFiles: number;
29
+ fileNames: string[];
30
+ fileSizes: number[];
31
+ }, "uploadProgress/openUploadProgress">, setFileUploading: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
32
+ name: string;
33
+ index: number;
34
+ total: number;
35
+ size: number;
36
+ }, "uploadProgress/setFileUploading">, setFileComplete: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
37
+ index: number;
38
+ file: File;
39
+ }, "uploadProgress/setFileComplete">, setFileError: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
40
+ index: number;
41
+ name: string;
42
+ message: string;
43
+ }, "uploadProgress/setFileError">, updateProgress: import("@reduxjs/toolkit").ActionCreatorWithPayload<number, "uploadProgress/updateProgress">, addUploadErrors: import("@reduxjs/toolkit").ActionCreatorWithPayload<FileUploadError[], "uploadProgress/addUploadErrors">, closeUploadProgress: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"uploadProgress/closeUploadProgress">, toggleMinimize: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"uploadProgress/toggleMinimize">, cancelUpload: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"uploadProgress/cancelUpload">, setUploadFailed: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
44
+ message: string;
45
+ }, "uploadProgress/setUploadFailed">, retryCancelledFiles: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"uploadProgress/retryCancelledFiles">;
46
+ export declare const uploadProgressReducer: import("redux").Reducer<UploadProgressState>;
@@ -0,0 +1,3 @@
1
+ export declare function formatBytes(receivedBytes: number | string, decimals?: number): string;
2
+ export declare const getFileExtension: (ext?: string | null) => string | null | undefined;
3
+ export declare const prefixFileUrlWithBackendUrl: (fileURL?: string) => string | undefined;
@@ -0,0 +1,12 @@
1
+ import { SVGProps } from 'react';
2
+ import { DefaultTheme } from 'styled-components';
3
+ interface IconProps extends Omit<SVGProps<SVGSVGElement>, 'fill' | 'stroke'> {
4
+ /**
5
+ * @default "currentColor"
6
+ */
7
+ fill?: keyof DefaultTheme['colors'] | string;
8
+ stroke?: keyof DefaultTheme['colors'] | string;
9
+ }
10
+ type IconComponent = React.FC<IconProps>;
11
+ export declare const getAssetIcon: (mime: string | undefined, ext: string | undefined) => IconComponent;
12
+ export {};
@@ -4,6 +4,28 @@ var en = {
4
4
  "apiError.FileTooBig": "The uploaded file exceeds the maximum allowed asset size.",
5
5
  "assets.uploaded": "{number, plural, one {# asset} other {# assets}} uploaded successfully",
6
6
  "upload.generic-error": "An error occurred while uploading the file.",
7
+ "upload.progress": "Upload progress",
8
+ "upload.progress.failed": "Upload failed",
9
+ "upload.progress.failed.subtitle": "Please try to upload files again",
10
+ "upload.progress.success": "Upload successful!",
11
+ "upload.progress.success.subtitle": "{count, plural, one {# file uploaded successfully} other {# files uploaded successfully}}",
12
+ "upload.progress.uploading.withCount": "Uploading {total} items ({percentage}%)",
13
+ "upload.progress.uploading-files": "Uploading {count, plural, one {# file} other {# files}}",
14
+ "upload.progress.indicator.in-progress": "Upload in progress indicator",
15
+ "upload.progress.indicator.complete": "Upload complete indicator",
16
+ "upload.progress.label": "Upload",
17
+ "upload.progress.errors.title": "Failed to upload:",
18
+ "upload.progress.cancel": "Cancel",
19
+ "upload.progress.canceled": "Uploads canceled",
20
+ "upload.progress.canceled.subtitle": "Some files were not uploaded",
21
+ "upload.progress.canceled.subtitle.all": "All uploads were canceled",
22
+ "upload.progress.retry": "Retry",
23
+ "upload.progress.file.uploading": "Uploading...",
24
+ "upload.progress.file.canceled": "Canceled",
25
+ "upload.progress.file.uploaded": "Uploaded",
26
+ "upload.progress.maximize": "Maximize",
27
+ "upload.progress.minimize": "Minimize",
28
+ "upload.progress.close": "Close",
7
29
  "bulk.select.label": "Select all assets",
8
30
  "button.next": "Next",
9
31
  "new": "New",
@@ -24,6 +46,7 @@ var en = {
24
46
  "control-card.replace-media": "Replace Media",
25
47
  "control-card.save": "Save",
26
48
  "control-card.stop-crop": "Stop cropping",
49
+ "dropzone.upload.message": "Drop here to upload to",
27
50
  "filter.add": "Add filter",
28
51
  "form.button.replace-media": "Replace media",
29
52
  "form.input.description.file-alt": "This text will be displayed if the asset can’t be shown.",
@@ -145,6 +168,8 @@ var en = {
145
168
  "list.table.header.size": "size",
146
169
  "list.table.header.createdAt": "created",
147
170
  "list.table.header.updatedAt": "last update",
171
+ "list.table.header.creationDate": "Creation Date",
172
+ "list.table.header.lastModified": "Last Modified",
148
173
  "list.table.header.sort": "Sort on {label}",
149
174
  "list.table.content.empty-label": "This field is empty",
150
175
  "tabs.title": "How do you want to upload your assets?",
@@ -1 +1 @@
1
- {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -2,6 +2,28 @@ var en = {
2
2
  "apiError.FileTooBig": "The uploaded file exceeds the maximum allowed asset size.",
3
3
  "assets.uploaded": "{number, plural, one {# asset} other {# assets}} uploaded successfully",
4
4
  "upload.generic-error": "An error occurred while uploading the file.",
5
+ "upload.progress": "Upload progress",
6
+ "upload.progress.failed": "Upload failed",
7
+ "upload.progress.failed.subtitle": "Please try to upload files again",
8
+ "upload.progress.success": "Upload successful!",
9
+ "upload.progress.success.subtitle": "{count, plural, one {# file uploaded successfully} other {# files uploaded successfully}}",
10
+ "upload.progress.uploading.withCount": "Uploading {total} items ({percentage}%)",
11
+ "upload.progress.uploading-files": "Uploading {count, plural, one {# file} other {# files}}",
12
+ "upload.progress.indicator.in-progress": "Upload in progress indicator",
13
+ "upload.progress.indicator.complete": "Upload complete indicator",
14
+ "upload.progress.label": "Upload",
15
+ "upload.progress.errors.title": "Failed to upload:",
16
+ "upload.progress.cancel": "Cancel",
17
+ "upload.progress.canceled": "Uploads canceled",
18
+ "upload.progress.canceled.subtitle": "Some files were not uploaded",
19
+ "upload.progress.canceled.subtitle.all": "All uploads were canceled",
20
+ "upload.progress.retry": "Retry",
21
+ "upload.progress.file.uploading": "Uploading...",
22
+ "upload.progress.file.canceled": "Canceled",
23
+ "upload.progress.file.uploaded": "Uploaded",
24
+ "upload.progress.maximize": "Maximize",
25
+ "upload.progress.minimize": "Minimize",
26
+ "upload.progress.close": "Close",
5
27
  "bulk.select.label": "Select all assets",
6
28
  "button.next": "Next",
7
29
  "new": "New",
@@ -22,6 +44,7 @@ var en = {
22
44
  "control-card.replace-media": "Replace Media",
23
45
  "control-card.save": "Save",
24
46
  "control-card.stop-crop": "Stop cropping",
47
+ "dropzone.upload.message": "Drop here to upload to",
25
48
  "filter.add": "Add filter",
26
49
  "form.button.replace-media": "Replace media",
27
50
  "form.input.description.file-alt": "This text will be displayed if the asset can’t be shown.",
@@ -143,6 +166,8 @@ var en = {
143
166
  "list.table.header.size": "size",
144
167
  "list.table.header.createdAt": "created",
145
168
  "list.table.header.updatedAt": "last update",
169
+ "list.table.header.creationDate": "Creation Date",
170
+ "list.table.header.lastModified": "Last Modified",
146
171
  "list.table.header.sort": "Sort on {label}",
147
172
  "list.table.content.empty-label": "This field is empty",
148
173
  "tabs.title": "How do you want to upload your assets?",
@@ -1 +1 @@
1
- {"version":3,"file":"en.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"en.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -49,7 +49,10 @@ var adminUpload = {
49
49
  if (Array.isArray(files)) {
50
50
  throw new utils.errors.ApplicationError('Cannot replace a file with multiple ones');
51
51
  }
52
- const { validFiles, filteredBody } = await mimeValidation.prepareUploadRequest(files, body, strapi);
52
+ const { validFiles, filteredBody, errors: validationErrors } = await mimeValidation.prepareUploadRequest(files, body, strapi);
53
+ if (validFiles.length === 0) {
54
+ throw new utils.errors.ValidationError(validationErrors[0].message);
55
+ }
53
56
  const data = await upload.validateUploadBody(filteredBody);
54
57
  const replacedFile = await uploadService.replace(id, {
55
58
  data,
@@ -74,7 +77,10 @@ var adminUpload = {
74
77
  if (!pm.isAllowed) {
75
78
  return ctx.forbidden();
76
79
  }
77
- const { validFiles, filteredBody } = await mimeValidation.prepareUploadRequest(files, body, strapi);
80
+ const { validFiles, filteredBody, errors: validationErrors } = await mimeValidation.prepareUploadRequest(files, body, strapi);
81
+ if (validFiles.length === 0) {
82
+ throw new utils.errors.ValidationError(validationErrors[0].message);
83
+ }
78
84
  const isMultipleFiles = validFiles.length > 1;
79
85
  const data = await upload.validateUploadBody(filteredBody, isMultipleFiles);
80
86
  let filesArray = validFiles;
@@ -115,6 +121,149 @@ var adminUpload = {
115
121
  });
116
122
  ctx.status = 201;
117
123
  },
124
+ /**
125
+ * @experimental
126
+ * Stream upload files with SSE streaming for per-file progress
127
+ *
128
+ * Streams Server-Sent Events as each file is validated and uploaded:
129
+ * - file:uploading — when processing starts for a file
130
+ * - file:complete — when a file is successfully uploaded
131
+ * - file:error — when a file fails validation or upload
132
+ * - stream:complete — final summary with all results
133
+ *
134
+ */ async unstable_uploadFilesStream (ctx) {
135
+ const { state: { userAbility, user }, request: { body, files: { files } = {} } } = ctx;
136
+ const uploadService = index.getService('upload');
137
+ const pm = strapi.service('admin::permission').createPermissionsManager({
138
+ ability: userAbility,
139
+ action: constants.ACTIONS.create,
140
+ model: constants.FILE_MODEL_UID
141
+ });
142
+ if (!pm.isAllowed) {
143
+ return ctx.forbidden();
144
+ }
145
+ if (_.isEmpty(files) || !Array.isArray(files) && files.size === 0) {
146
+ throw new utils.errors.ApplicationError('Files are empty');
147
+ }
148
+ // Take manual control of the response for SSE streaming
149
+ ctx.respond = false;
150
+ const res = ctx.res;
151
+ res.writeHead(200, {
152
+ 'Content-Type': 'text/event-stream',
153
+ 'Cache-Control': 'no-cache',
154
+ Connection: 'keep-alive'
155
+ });
156
+ const writeSSE = (event, data)=>{
157
+ res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
158
+ };
159
+ // Normalize files to an array
160
+ const filesArray = Array.isArray(files) ? files : [
161
+ files
162
+ ];
163
+ const total = filesArray.length;
164
+ // Parse fileInfo from body
165
+ // Multipart forms send fileInfo as either:
166
+ // - An array of JSON strings (one per file)
167
+ // - A single JSON string (one file, or a JSON-encoded array)
168
+ let parsedFileInfo = [];
169
+ if (body?.fileInfo) {
170
+ const raw = body.fileInfo;
171
+ if (Array.isArray(raw)) {
172
+ parsedFileInfo = raw.map((fi)=>typeof fi === 'string' ? JSON.parse(fi) : fi);
173
+ } else if (typeof raw === 'string') {
174
+ const parsed = JSON.parse(raw);
175
+ // Handle case where a single string contains a JSON array
176
+ parsedFileInfo = Array.isArray(parsed) ? parsed : [
177
+ parsed
178
+ ];
179
+ } else {
180
+ parsedFileInfo = [
181
+ raw
182
+ ];
183
+ }
184
+ }
185
+ const uploadErrors = [];
186
+ const successfulFiles = [];
187
+ // Process each file sequentially with inline validation
188
+ for(let i = 0; i < filesArray.length; i += 1){
189
+ const file = filesArray[i];
190
+ const fileName = file.originalFilename || 'unknown';
191
+ const fileInfo = parsedFileInfo[i] || {
192
+ name: fileName,
193
+ caption: null,
194
+ alternativeText: null,
195
+ folder: null
196
+ };
197
+ writeSSE('file:uploading', {
198
+ name: fileName,
199
+ index: i,
200
+ total,
201
+ size: file.size || 0
202
+ });
203
+ try {
204
+ // Validate this single file using security checks
205
+ const { validFiles, errors: validationErrors } = await mimeValidation.prepareUploadRequest(file, {
206
+ fileInfo: JSON.stringify(fileInfo)
207
+ }, strapi);
208
+ if (validFiles.length === 0) {
209
+ const errorMessage = validationErrors[0]?.message || 'Validation failed';
210
+ uploadErrors.push({
211
+ name: fileName,
212
+ message: errorMessage
213
+ });
214
+ writeSSE('file:error', {
215
+ name: fileName,
216
+ index: i,
217
+ message: errorMessage
218
+ });
219
+ } else {
220
+ // Validate using the already-parsed single fileInfo object directly
221
+ const data = await upload.validateUploadBody({
222
+ fileInfo
223
+ }, false);
224
+ const [uploadedFile] = await uploadService.upload({
225
+ data,
226
+ files: [
227
+ validFiles[0]
228
+ ]
229
+ }, {
230
+ user
231
+ });
232
+ // Sign file url
233
+ const signedFile = await index.getService('file').signFileUrls(uploadedFile);
234
+ successfulFiles.push(signedFile);
235
+ writeSSE('file:complete', {
236
+ name: fileName,
237
+ index: i,
238
+ file: signedFile
239
+ });
240
+ }
241
+ } catch (error) {
242
+ const errorMessage = error instanceof Error ? error.message : String(error);
243
+ uploadErrors.push({
244
+ name: fileName,
245
+ message: errorMessage
246
+ });
247
+ writeSSE('file:error', {
248
+ name: fileName,
249
+ index: i,
250
+ message: errorMessage
251
+ });
252
+ }
253
+ }
254
+ // Track image upload metric once if any images were uploaded
255
+ if (successfulFiles.some((file)=>file.mime?.startsWith('image/'))) {
256
+ await index.getService('metrics').trackUsage('didUploadImage');
257
+ }
258
+ // Send final stream summary
259
+ writeSSE('stream:complete', {
260
+ data: await pm.sanitizeOutput(successfulFiles, {
261
+ action: constants.ACTIONS.read
262
+ }),
263
+ errors: uploadErrors
264
+ });
265
+ res.end();
266
+ },
118
267
  // TODO: split into multiple endpoints
119
268
  async upload (ctx) {
120
269
  const { query: { id }, request: { files: { files } = {} } } = ctx;