@strapi/upload 5.47.1 → 5.48.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/components/EditAssetDialog/EditAssetContent.js +12 -2
- package/dist/admin/components/EditAssetDialog/EditAssetContent.js.map +1 -1
- package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs +12 -2
- package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs.map +1 -1
- package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.js +1 -0
- package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.js.map +1 -1
- package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.mjs +1 -0
- package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.mjs.map +1 -1
- package/dist/admin/future/components/Drawer.js +7 -8
- package/dist/admin/future/components/Drawer.js.map +1 -1
- package/dist/admin/future/components/Drawer.mjs +7 -8
- package/dist/admin/future/components/Drawer.mjs.map +1 -1
- package/dist/admin/future/components/UploadProgressDialog.js +33 -29
- package/dist/admin/future/components/UploadProgressDialog.js.map +1 -1
- package/dist/admin/future/components/UploadProgressDialog.mjs +36 -32
- package/dist/admin/future/components/UploadProgressDialog.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/AssetsPage.js +2 -2
- package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
- package/dist/admin/future/pages/Assets/AssetsPage.mjs +3 -3
- package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +626 -169
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +630 -175
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.js +25 -5
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.mjs +25 -5
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.mjs.map +1 -1
- package/dist/admin/future/services/api.js +124 -200
- package/dist/admin/future/services/api.js.map +1 -1
- package/dist/admin/future/services/api.mjs +124 -200
- package/dist/admin/future/services/api.mjs.map +1 -1
- package/dist/admin/future/services/assets.js +57 -1
- package/dist/admin/future/services/assets.js.map +1 -1
- package/dist/admin/future/services/assets.mjs +56 -2
- package/dist/admin/future/services/assets.mjs.map +1 -1
- package/dist/admin/future/services/settings.js +18 -0
- package/dist/admin/future/services/settings.js.map +1 -0
- package/dist/admin/future/services/settings.mjs +16 -0
- package/dist/admin/future/services/settings.mjs.map +1 -0
- package/dist/admin/future/services/uploadFileViaXHR.js +92 -0
- package/dist/admin/future/services/uploadFileViaXHR.js.map +1 -0
- package/dist/admin/future/services/uploadFileViaXHR.mjs +88 -0
- package/dist/admin/future/services/uploadFileViaXHR.mjs.map +1 -0
- package/dist/admin/future/store/uploadProgress.js +32 -26
- package/dist/admin/future/store/uploadProgress.js.map +1 -1
- package/dist/admin/future/store/uploadProgress.mjs +32 -27
- package/dist/admin/future/store/uploadProgress.mjs.map +1 -1
- package/dist/admin/future/utils/createRafBatcher.js +42 -0
- package/dist/admin/future/utils/createRafBatcher.js.map +1 -0
- package/dist/admin/future/utils/createRafBatcher.mjs +40 -0
- package/dist/admin/future/utils/createRafBatcher.mjs.map +1 -0
- package/dist/admin/future/utils/downloadFile.js +19 -0
- package/dist/admin/future/utils/downloadFile.js.map +1 -0
- package/dist/admin/future/utils/downloadFile.mjs +17 -0
- package/dist/admin/future/utils/downloadFile.mjs.map +1 -0
- package/dist/admin/hooks/useAssets.js +5 -3
- package/dist/admin/hooks/useAssets.js.map +1 -1
- package/dist/admin/hooks/useAssets.mjs +5 -3
- package/dist/admin/hooks/useAssets.mjs.map +1 -1
- package/dist/admin/src/components/EditAssetDialog/EditAssetContent.d.ts +2 -1
- package/dist/admin/src/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.d.ts +15 -1
- package/dist/admin/src/future/pages/Assets/components/AssetDetails/AssetPreview.d.ts +4 -1
- package/dist/admin/src/future/services/api.d.ts +9 -8
- package/dist/admin/src/future/services/assets.d.ts +6 -1
- package/dist/admin/src/future/services/uploadFileViaXHR.d.ts +34 -0
- package/dist/admin/src/future/store/uploadProgress.d.ts +17 -4
- package/dist/admin/src/future/utils/createRafBatcher.d.ts +23 -0
- package/dist/admin/src/future/utils/downloadFile.d.ts +6 -0
- package/dist/admin/translations/en.json.js +21 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +21 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/server/controllers/admin-upload.js +69 -118
- package/dist/server/controllers/admin-upload.js.map +1 -1
- package/dist/server/controllers/admin-upload.mjs +69 -118
- package/dist/server/controllers/admin-upload.mjs.map +1 -1
- package/dist/server/controllers/content-api.js +12 -0
- package/dist/server/controllers/content-api.js.map +1 -1
- package/dist/server/controllers/content-api.mjs +12 -0
- package/dist/server/controllers/content-api.mjs.map +1 -1
- package/dist/server/routes/admin.js +2 -2
- package/dist/server/routes/admin.js.map +1 -1
- package/dist/server/routes/admin.mjs +2 -2
- package/dist/server/routes/admin.mjs.map +1 -1
- package/dist/server/routes/content-api.js +15 -0
- package/dist/server/routes/content-api.js.map +1 -1
- package/dist/server/routes/content-api.mjs +15 -0
- package/dist/server/routes/content-api.mjs.map +1 -1
- package/dist/server/routes/validation/upload.js +28 -0
- package/dist/server/routes/validation/upload.js.map +1 -1
- package/dist/server/routes/validation/upload.mjs +28 -0
- package/dist/server/routes/validation/upload.mjs.map +1 -1
- package/dist/server/services/image-manipulation.js +16 -8
- package/dist/server/services/image-manipulation.js.map +1 -1
- package/dist/server/services/image-manipulation.mjs +16 -8
- package/dist/server/services/image-manipulation.mjs.map +1 -1
- package/dist/server/services/upload.js +90 -1
- package/dist/server/services/upload.js.map +1 -1
- package/dist/server/services/upload.mjs +91 -2
- package/dist/server/services/upload.mjs.map +1 -1
- package/dist/server/src/controllers/admin-upload.d.ts +6 -8
- package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
- package/dist/server/src/controllers/content-api.d.ts +1 -0
- package/dist/server/src/controllers/content-api.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts +2 -1
- package/dist/server/src/controllers/index.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +6 -1
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/routes/content-api.d.ts.map +1 -1
- package/dist/server/src/routes/validation/upload.d.ts +45 -0
- package/dist/server/src/routes/validation/upload.d.ts.map +1 -1
- package/dist/server/src/services/image-manipulation.d.ts +5 -0
- package/dist/server/src/services/image-manipulation.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +4 -0
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/upload.d.ts +5 -0
- package/dist/server/src/services/upload.d.ts.map +1 -1
- package/dist/server/src/types.d.ts +2 -2
- package/dist/server/src/types.d.ts.map +1 -1
- package/dist/shared/contracts/files.d.ts +19 -2
- package/dist/shared/contracts/files.d.ts.map +1 -1
- package/package.json +8 -8
|
@@ -99,12 +99,68 @@ const assetsApi = api.uploadApi.injectEndpoints({
|
|
|
99
99
|
id: 'LIST'
|
|
100
100
|
}
|
|
101
101
|
]
|
|
102
|
+
}),
|
|
103
|
+
/**
|
|
104
|
+
* Replace the binary content of an existing asset.
|
|
105
|
+
* Hits `POST /upload?id=<id>` with a multipart body — the controller
|
|
106
|
+
* dispatches to `admin-upload.replaceFile` when a `files` part is present.
|
|
107
|
+
* Uses the standard axios baseQuery (no streaming) since we only ever
|
|
108
|
+
* replace one file at a time and don't need per-byte progress here.
|
|
109
|
+
*/ replaceAsset: builder.mutation({
|
|
110
|
+
query: ({ id, file, fileInfo })=>{
|
|
111
|
+
const formData = new FormData();
|
|
112
|
+
formData.append('files', file);
|
|
113
|
+
if (fileInfo) {
|
|
114
|
+
formData.append('fileInfo', JSON.stringify(fileInfo));
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
url: '/upload',
|
|
118
|
+
method: 'POST',
|
|
119
|
+
data: formData,
|
|
120
|
+
config: {
|
|
121
|
+
params: {
|
|
122
|
+
id
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
invalidatesTags: (_result, _error, { id })=>[
|
|
128
|
+
{
|
|
129
|
+
type: 'Asset',
|
|
130
|
+
id
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
type: 'Asset',
|
|
134
|
+
id: 'LIST'
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
}),
|
|
138
|
+
/**
|
|
139
|
+
* Permanently delete an asset by id. Hits the same endpoint as the legacy
|
|
140
|
+
* `useRemoveAsset` hook so server behaviour is unchanged.
|
|
141
|
+
*/ deleteAsset: builder.mutation({
|
|
142
|
+
query: (id)=>({
|
|
143
|
+
url: `/upload/files/${id}`,
|
|
144
|
+
method: 'DELETE'
|
|
145
|
+
}),
|
|
146
|
+
invalidatesTags: (_result, _error, id)=>[
|
|
147
|
+
{
|
|
148
|
+
type: 'Asset',
|
|
149
|
+
id
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
type: 'Asset',
|
|
153
|
+
id: 'LIST'
|
|
154
|
+
}
|
|
155
|
+
]
|
|
102
156
|
})
|
|
103
157
|
})
|
|
104
158
|
});
|
|
105
|
-
const { useGetAssetsQuery, useGetAssetQuery, useUpdateAssetMutation } = assetsApi;
|
|
159
|
+
const { useGetAssetsQuery, useGetAssetQuery, useUpdateAssetMutation, useReplaceAssetMutation, useDeleteAssetMutation } = assetsApi;
|
|
106
160
|
|
|
161
|
+
exports.useDeleteAssetMutation = useDeleteAssetMutation;
|
|
107
162
|
exports.useGetAssetQuery = useGetAssetQuery;
|
|
108
163
|
exports.useGetAssetsQuery = useGetAssetsQuery;
|
|
164
|
+
exports.useReplaceAssetMutation = useReplaceAssetMutation;
|
|
109
165
|
exports.useUpdateAssetMutation = useUpdateAssetMutation;
|
|
110
166
|
//# sourceMappingURL=assets.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets.js","sources":["../../../../admin/src/future/services/assets.ts"],"sourcesContent":["import { uploadApi } from './api';\n\nimport type {\n GetFiles,\n File,\n Pagination,\n UploadFileInfo,\n AssetWithPopulatedCreatedBy,\n} from '../../../../shared/contracts/files';\n\ninterface GetAssetsParams {\n page?: number;\n pageSize?: number;\n folder?: number | null;\n sort?: string;\n}\n\ninterface GetAssetsResponse {\n results: File[];\n pagination: Pagination;\n}\n\ninterface UpdateAssetArgs {\n id: number;\n fileInfo: Partial<UploadFileInfo>;\n}\n\nconst assetsApi = uploadApi.injectEndpoints({\n endpoints: (builder) => ({\n getAssets: builder.query<GetAssetsResponse, GetAssetsParams | void>({\n query: (params = {}) => {\n const { folder, ...rest } = params as GetAssetsParams;\n\n const queryParams: Record<string, unknown> = { ...rest };\n\n if (folder != null) {\n queryParams['filters'] = {\n $and: [{ folder: { id: folder } }],\n };\n } else {\n queryParams['filters'] = {\n $and: [{ folder: { id: { $null: true } } }],\n };\n }\n\n return {\n url: '/upload/files',\n method: 'GET',\n config: { params: queryParams },\n };\n },\n transformResponse: (response: GetFiles.Response['data']) => response,\n providesTags: (result) =>\n result\n ? [\n ...result.results.map(({ id }) => ({ type: 'Asset' as const, id })),\n { type: 'Asset', id: 'LIST' },\n ]\n : [{ type: 'Asset', id: 'LIST' }],\n }),\n getAsset: builder.query<AssetWithPopulatedCreatedBy, number>({\n query: (id) => ({\n url: `/upload/files/${id}`,\n method: 'GET',\n }),\n providesTags: (_result, _error, id) => [{ type: 'Asset' as const, id }],\n }),\n /**\n * Update the editable metadata of an existing asset.\n * Hits the legacy `POST /upload?id=<id>` endpoint which dispatches to\n * `admin-upload.updateFileInfo`.\n */\n updateAsset: builder.mutation<AssetWithPopulatedCreatedBy, UpdateAssetArgs>({\n query: ({ id, fileInfo }) => {\n const formData = new FormData();\n formData.append('fileInfo', JSON.stringify(fileInfo));\n\n return {\n url: '/upload',\n method: 'POST',\n data: formData,\n config: { params: { id } },\n };\n },\n invalidatesTags: (_result, _error, { id }) => [\n { type: 'Asset' as const, id },\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n
|
|
1
|
+
{"version":3,"file":"assets.js","sources":["../../../../admin/src/future/services/assets.ts"],"sourcesContent":["import { uploadApi } from './api';\n\nimport type {\n GetFiles,\n File,\n Pagination,\n UploadFileInfo,\n AssetWithPopulatedCreatedBy,\n} from '../../../../shared/contracts/files';\n\ninterface GetAssetsParams {\n page?: number;\n pageSize?: number;\n folder?: number | null;\n sort?: string;\n}\n\ninterface GetAssetsResponse {\n results: File[];\n pagination: Pagination;\n}\n\ninterface UpdateAssetArgs {\n id: number;\n fileInfo: Partial<UploadFileInfo>;\n}\n\ninterface ReplaceAssetArgs {\n id: number;\n // `File` is shadowed in this module by the asset-file contract type; the\n // global browser File is what we need for FormData.\n file: globalThis.File;\n fileInfo?: Partial<UploadFileInfo>;\n}\n\nconst assetsApi = uploadApi.injectEndpoints({\n endpoints: (builder) => ({\n getAssets: builder.query<GetAssetsResponse, GetAssetsParams | void>({\n query: (params = {}) => {\n const { folder, ...rest } = params as GetAssetsParams;\n\n const queryParams: Record<string, unknown> = { ...rest };\n\n if (folder != null) {\n queryParams['filters'] = {\n $and: [{ folder: { id: folder } }],\n };\n } else {\n queryParams['filters'] = {\n $and: [{ folder: { id: { $null: true } } }],\n };\n }\n\n return {\n url: '/upload/files',\n method: 'GET',\n config: { params: queryParams },\n };\n },\n transformResponse: (response: GetFiles.Response['data']) => response,\n providesTags: (result) =>\n result\n ? [\n ...result.results.map(({ id }) => ({ type: 'Asset' as const, id })),\n { type: 'Asset', id: 'LIST' },\n ]\n : [{ type: 'Asset', id: 'LIST' }],\n }),\n getAsset: builder.query<AssetWithPopulatedCreatedBy, number>({\n query: (id) => ({\n url: `/upload/files/${id}`,\n method: 'GET',\n }),\n providesTags: (_result, _error, id) => [{ type: 'Asset' as const, id }],\n }),\n /**\n * Update the editable metadata of an existing asset.\n * Hits the legacy `POST /upload?id=<id>` endpoint which dispatches to\n * `admin-upload.updateFileInfo`.\n */\n updateAsset: builder.mutation<AssetWithPopulatedCreatedBy, UpdateAssetArgs>({\n query: ({ id, fileInfo }) => {\n const formData = new FormData();\n formData.append('fileInfo', JSON.stringify(fileInfo));\n\n return {\n url: '/upload',\n method: 'POST',\n data: formData,\n config: { params: { id } },\n };\n },\n invalidatesTags: (_result, _error, { id }) => [\n { type: 'Asset' as const, id },\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n /**\n * Replace the binary content of an existing asset.\n * Hits `POST /upload?id=<id>` with a multipart body — the controller\n * dispatches to `admin-upload.replaceFile` when a `files` part is present.\n * Uses the standard axios baseQuery (no streaming) since we only ever\n * replace one file at a time and don't need per-byte progress here.\n */\n replaceAsset: builder.mutation<AssetWithPopulatedCreatedBy, ReplaceAssetArgs>({\n query: ({ id, file, fileInfo }) => {\n const formData = new FormData();\n formData.append('files', file);\n if (fileInfo) {\n formData.append('fileInfo', JSON.stringify(fileInfo));\n }\n return {\n url: '/upload',\n method: 'POST',\n data: formData,\n config: { params: { id } },\n };\n },\n invalidatesTags: (_result, _error, { id }) => [\n { type: 'Asset' as const, id },\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n /**\n * Permanently delete an asset by id. Hits the same endpoint as the legacy\n * `useRemoveAsset` hook so server behaviour is unchanged.\n */\n deleteAsset: builder.mutation<unknown, number>({\n query: (id) => ({\n url: `/upload/files/${id}`,\n method: 'DELETE',\n }),\n invalidatesTags: (_result, _error, id) => [\n { type: 'Asset' as const, id },\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n }),\n});\n\nexport const {\n useGetAssetsQuery,\n useGetAssetQuery,\n useUpdateAssetMutation,\n useReplaceAssetMutation,\n useDeleteAssetMutation,\n} = assetsApi;\n"],"names":["assetsApi","uploadApi","injectEndpoints","endpoints","builder","getAssets","query","params","folder","rest","queryParams","$and","id","$null","url","method","config","transformResponse","response","providesTags","result","results","map","type","getAsset","_result","_error","updateAsset","mutation","fileInfo","formData","FormData","append","JSON","stringify","data","invalidatesTags","replaceAsset","file","deleteAsset","useGetAssetsQuery","useGetAssetQuery","useUpdateAssetMutation","useReplaceAssetMutation","useDeleteAssetMutation"],"mappings":"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"}
|
|
@@ -97,10 +97,64 @@ const assetsApi = uploadApi.injectEndpoints({
|
|
|
97
97
|
id: 'LIST'
|
|
98
98
|
}
|
|
99
99
|
]
|
|
100
|
+
}),
|
|
101
|
+
/**
|
|
102
|
+
* Replace the binary content of an existing asset.
|
|
103
|
+
* Hits `POST /upload?id=<id>` with a multipart body — the controller
|
|
104
|
+
* dispatches to `admin-upload.replaceFile` when a `files` part is present.
|
|
105
|
+
* Uses the standard axios baseQuery (no streaming) since we only ever
|
|
106
|
+
* replace one file at a time and don't need per-byte progress here.
|
|
107
|
+
*/ replaceAsset: builder.mutation({
|
|
108
|
+
query: ({ id, file, fileInfo })=>{
|
|
109
|
+
const formData = new FormData();
|
|
110
|
+
formData.append('files', file);
|
|
111
|
+
if (fileInfo) {
|
|
112
|
+
formData.append('fileInfo', JSON.stringify(fileInfo));
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
url: '/upload',
|
|
116
|
+
method: 'POST',
|
|
117
|
+
data: formData,
|
|
118
|
+
config: {
|
|
119
|
+
params: {
|
|
120
|
+
id
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
},
|
|
125
|
+
invalidatesTags: (_result, _error, { id })=>[
|
|
126
|
+
{
|
|
127
|
+
type: 'Asset',
|
|
128
|
+
id
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
type: 'Asset',
|
|
132
|
+
id: 'LIST'
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
}),
|
|
136
|
+
/**
|
|
137
|
+
* Permanently delete an asset by id. Hits the same endpoint as the legacy
|
|
138
|
+
* `useRemoveAsset` hook so server behaviour is unchanged.
|
|
139
|
+
*/ deleteAsset: builder.mutation({
|
|
140
|
+
query: (id)=>({
|
|
141
|
+
url: `/upload/files/${id}`,
|
|
142
|
+
method: 'DELETE'
|
|
143
|
+
}),
|
|
144
|
+
invalidatesTags: (_result, _error, id)=>[
|
|
145
|
+
{
|
|
146
|
+
type: 'Asset',
|
|
147
|
+
id
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
type: 'Asset',
|
|
151
|
+
id: 'LIST'
|
|
152
|
+
}
|
|
153
|
+
]
|
|
100
154
|
})
|
|
101
155
|
})
|
|
102
156
|
});
|
|
103
|
-
const { useGetAssetsQuery, useGetAssetQuery, useUpdateAssetMutation } = assetsApi;
|
|
157
|
+
const { useGetAssetsQuery, useGetAssetQuery, useUpdateAssetMutation, useReplaceAssetMutation, useDeleteAssetMutation } = assetsApi;
|
|
104
158
|
|
|
105
|
-
export { useGetAssetQuery, useGetAssetsQuery, useUpdateAssetMutation };
|
|
159
|
+
export { useDeleteAssetMutation, useGetAssetQuery, useGetAssetsQuery, useReplaceAssetMutation, useUpdateAssetMutation };
|
|
106
160
|
//# sourceMappingURL=assets.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets.mjs","sources":["../../../../admin/src/future/services/assets.ts"],"sourcesContent":["import { uploadApi } from './api';\n\nimport type {\n GetFiles,\n File,\n Pagination,\n UploadFileInfo,\n AssetWithPopulatedCreatedBy,\n} from '../../../../shared/contracts/files';\n\ninterface GetAssetsParams {\n page?: number;\n pageSize?: number;\n folder?: number | null;\n sort?: string;\n}\n\ninterface GetAssetsResponse {\n results: File[];\n pagination: Pagination;\n}\n\ninterface UpdateAssetArgs {\n id: number;\n fileInfo: Partial<UploadFileInfo>;\n}\n\nconst assetsApi = uploadApi.injectEndpoints({\n endpoints: (builder) => ({\n getAssets: builder.query<GetAssetsResponse, GetAssetsParams | void>({\n query: (params = {}) => {\n const { folder, ...rest } = params as GetAssetsParams;\n\n const queryParams: Record<string, unknown> = { ...rest };\n\n if (folder != null) {\n queryParams['filters'] = {\n $and: [{ folder: { id: folder } }],\n };\n } else {\n queryParams['filters'] = {\n $and: [{ folder: { id: { $null: true } } }],\n };\n }\n\n return {\n url: '/upload/files',\n method: 'GET',\n config: { params: queryParams },\n };\n },\n transformResponse: (response: GetFiles.Response['data']) => response,\n providesTags: (result) =>\n result\n ? [\n ...result.results.map(({ id }) => ({ type: 'Asset' as const, id })),\n { type: 'Asset', id: 'LIST' },\n ]\n : [{ type: 'Asset', id: 'LIST' }],\n }),\n getAsset: builder.query<AssetWithPopulatedCreatedBy, number>({\n query: (id) => ({\n url: `/upload/files/${id}`,\n method: 'GET',\n }),\n providesTags: (_result, _error, id) => [{ type: 'Asset' as const, id }],\n }),\n /**\n * Update the editable metadata of an existing asset.\n * Hits the legacy `POST /upload?id=<id>` endpoint which dispatches to\n * `admin-upload.updateFileInfo`.\n */\n updateAsset: builder.mutation<AssetWithPopulatedCreatedBy, UpdateAssetArgs>({\n query: ({ id, fileInfo }) => {\n const formData = new FormData();\n formData.append('fileInfo', JSON.stringify(fileInfo));\n\n return {\n url: '/upload',\n method: 'POST',\n data: formData,\n config: { params: { id } },\n };\n },\n invalidatesTags: (_result, _error, { id }) => [\n { type: 'Asset' as const, id },\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n
|
|
1
|
+
{"version":3,"file":"assets.mjs","sources":["../../../../admin/src/future/services/assets.ts"],"sourcesContent":["import { uploadApi } from './api';\n\nimport type {\n GetFiles,\n File,\n Pagination,\n UploadFileInfo,\n AssetWithPopulatedCreatedBy,\n} from '../../../../shared/contracts/files';\n\ninterface GetAssetsParams {\n page?: number;\n pageSize?: number;\n folder?: number | null;\n sort?: string;\n}\n\ninterface GetAssetsResponse {\n results: File[];\n pagination: Pagination;\n}\n\ninterface UpdateAssetArgs {\n id: number;\n fileInfo: Partial<UploadFileInfo>;\n}\n\ninterface ReplaceAssetArgs {\n id: number;\n // `File` is shadowed in this module by the asset-file contract type; the\n // global browser File is what we need for FormData.\n file: globalThis.File;\n fileInfo?: Partial<UploadFileInfo>;\n}\n\nconst assetsApi = uploadApi.injectEndpoints({\n endpoints: (builder) => ({\n getAssets: builder.query<GetAssetsResponse, GetAssetsParams | void>({\n query: (params = {}) => {\n const { folder, ...rest } = params as GetAssetsParams;\n\n const queryParams: Record<string, unknown> = { ...rest };\n\n if (folder != null) {\n queryParams['filters'] = {\n $and: [{ folder: { id: folder } }],\n };\n } else {\n queryParams['filters'] = {\n $and: [{ folder: { id: { $null: true } } }],\n };\n }\n\n return {\n url: '/upload/files',\n method: 'GET',\n config: { params: queryParams },\n };\n },\n transformResponse: (response: GetFiles.Response['data']) => response,\n providesTags: (result) =>\n result\n ? [\n ...result.results.map(({ id }) => ({ type: 'Asset' as const, id })),\n { type: 'Asset', id: 'LIST' },\n ]\n : [{ type: 'Asset', id: 'LIST' }],\n }),\n getAsset: builder.query<AssetWithPopulatedCreatedBy, number>({\n query: (id) => ({\n url: `/upload/files/${id}`,\n method: 'GET',\n }),\n providesTags: (_result, _error, id) => [{ type: 'Asset' as const, id }],\n }),\n /**\n * Update the editable metadata of an existing asset.\n * Hits the legacy `POST /upload?id=<id>` endpoint which dispatches to\n * `admin-upload.updateFileInfo`.\n */\n updateAsset: builder.mutation<AssetWithPopulatedCreatedBy, UpdateAssetArgs>({\n query: ({ id, fileInfo }) => {\n const formData = new FormData();\n formData.append('fileInfo', JSON.stringify(fileInfo));\n\n return {\n url: '/upload',\n method: 'POST',\n data: formData,\n config: { params: { id } },\n };\n },\n invalidatesTags: (_result, _error, { id }) => [\n { type: 'Asset' as const, id },\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n /**\n * Replace the binary content of an existing asset.\n * Hits `POST /upload?id=<id>` with a multipart body — the controller\n * dispatches to `admin-upload.replaceFile` when a `files` part is present.\n * Uses the standard axios baseQuery (no streaming) since we only ever\n * replace one file at a time and don't need per-byte progress here.\n */\n replaceAsset: builder.mutation<AssetWithPopulatedCreatedBy, ReplaceAssetArgs>({\n query: ({ id, file, fileInfo }) => {\n const formData = new FormData();\n formData.append('files', file);\n if (fileInfo) {\n formData.append('fileInfo', JSON.stringify(fileInfo));\n }\n return {\n url: '/upload',\n method: 'POST',\n data: formData,\n config: { params: { id } },\n };\n },\n invalidatesTags: (_result, _error, { id }) => [\n { type: 'Asset' as const, id },\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n /**\n * Permanently delete an asset by id. Hits the same endpoint as the legacy\n * `useRemoveAsset` hook so server behaviour is unchanged.\n */\n deleteAsset: builder.mutation<unknown, number>({\n query: (id) => ({\n url: `/upload/files/${id}`,\n method: 'DELETE',\n }),\n invalidatesTags: (_result, _error, id) => [\n { type: 'Asset' as const, id },\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n }),\n});\n\nexport const {\n useGetAssetsQuery,\n useGetAssetQuery,\n useUpdateAssetMutation,\n useReplaceAssetMutation,\n useDeleteAssetMutation,\n} = assetsApi;\n"],"names":["assetsApi","uploadApi","injectEndpoints","endpoints","builder","getAssets","query","params","folder","rest","queryParams","$and","id","$null","url","method","config","transformResponse","response","providesTags","result","results","map","type","getAsset","_result","_error","updateAsset","mutation","fileInfo","formData","FormData","append","JSON","stringify","data","invalidatesTags","replaceAsset","file","deleteAsset","useGetAssetsQuery","useGetAssetQuery","useUpdateAssetMutation","useReplaceAssetMutation","useDeleteAssetMutation"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var api = require('./api.js');
|
|
4
|
+
|
|
5
|
+
const settingsApi = api.uploadApi.injectEndpoints({
|
|
6
|
+
endpoints: (builder)=>({
|
|
7
|
+
getSettings: builder.query({
|
|
8
|
+
query: ()=>({
|
|
9
|
+
url: '/upload/settings',
|
|
10
|
+
method: 'GET'
|
|
11
|
+
})
|
|
12
|
+
})
|
|
13
|
+
})
|
|
14
|
+
});
|
|
15
|
+
const { useGetSettingsQuery } = settingsApi;
|
|
16
|
+
|
|
17
|
+
exports.useGetSettingsQuery = useGetSettingsQuery;
|
|
18
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sources":["../../../../admin/src/future/services/settings.ts"],"sourcesContent":["import { uploadApi } from './api';\n\nimport type { GetSettings } from '../../../../shared/contracts/settings';\n\nconst settingsApi = uploadApi.injectEndpoints({\n endpoints: (builder) => ({\n getSettings: builder.query<GetSettings.Response['data'], void>({\n query: () => ({\n url: '/upload/settings',\n method: 'GET',\n }),\n }),\n }),\n});\n\nconst { useGetSettingsQuery } = settingsApi;\n\nexport { useGetSettingsQuery };\n"],"names":["settingsApi","uploadApi","injectEndpoints","endpoints","builder","getSettings","query","url","method","useGetSettingsQuery"],"mappings":";;;;AAIA,MAAMA,WAAAA,GAAcC,aAAAA,CAAUC,eAAe,CAAC;IAC5CC,SAAAA,EAAW,CAACC,WAAa;YACvBC,WAAAA,EAAaD,OAAAA,CAAQE,KAAK,CAAqC;AAC7DA,gBAAAA,KAAAA,EAAO,KAAO;wBACZC,GAAAA,EAAK,kBAAA;wBACLC,MAAAA,EAAQ;qBACV;AACF,aAAA;SACF;AACF,CAAA,CAAA;AAEA,MAAM,EAAEC,mBAAmB,EAAE,GAAGT;;;;"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { uploadApi } from './api.mjs';
|
|
2
|
+
|
|
3
|
+
const settingsApi = uploadApi.injectEndpoints({
|
|
4
|
+
endpoints: (builder)=>({
|
|
5
|
+
getSettings: builder.query({
|
|
6
|
+
query: ()=>({
|
|
7
|
+
url: '/upload/settings',
|
|
8
|
+
method: 'GET'
|
|
9
|
+
})
|
|
10
|
+
})
|
|
11
|
+
})
|
|
12
|
+
});
|
|
13
|
+
const { useGetSettingsQuery } = settingsApi;
|
|
14
|
+
|
|
15
|
+
export { useGetSettingsQuery };
|
|
16
|
+
//# sourceMappingURL=settings.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.mjs","sources":["../../../../admin/src/future/services/settings.ts"],"sourcesContent":["import { uploadApi } from './api';\n\nimport type { GetSettings } from '../../../../shared/contracts/settings';\n\nconst settingsApi = uploadApi.injectEndpoints({\n endpoints: (builder) => ({\n getSettings: builder.query<GetSettings.Response['data'], void>({\n query: () => ({\n url: '/upload/settings',\n method: 'GET',\n }),\n }),\n }),\n});\n\nconst { useGetSettingsQuery } = settingsApi;\n\nexport { useGetSettingsQuery };\n"],"names":["settingsApi","uploadApi","injectEndpoints","endpoints","builder","getSettings","query","url","method","useGetSettingsQuery"],"mappings":";;AAIA,MAAMA,WAAAA,GAAcC,SAAAA,CAAUC,eAAe,CAAC;IAC5CC,SAAAA,EAAW,CAACC,WAAa;YACvBC,WAAAA,EAAaD,OAAAA,CAAQE,KAAK,CAAqC;AAC7DA,gBAAAA,KAAAA,EAAO,KAAO;wBACZC,GAAAA,EAAK,kBAAA;wBACLC,MAAAA,EAAQ;qBACV;AACF,aAAA;SACF;AACF,CAAA,CAAA;AAEA,MAAM,EAAEC,mBAAmB,EAAE,GAAGT;;;;"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Thrown when an upload is aborted via its `AbortSignal`.
|
|
5
|
+
* Distinct from {@link UploadFileError} so callers can tell cancellation apart
|
|
6
|
+
* from a genuine failure.
|
|
7
|
+
*/ class UploadAbortedError extends Error {
|
|
8
|
+
constructor(message = 'Upload aborted'){
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'UploadAbortedError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Thrown when an upload fails (non-2xx response, network error, or unparseable body).
|
|
15
|
+
*/ class UploadFileError extends Error {
|
|
16
|
+
constructor(message, status){
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'UploadFileError';
|
|
19
|
+
this.status = status;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Uploads a single file via `XMLHttpRequest`, exposing real byte-level upload
|
|
24
|
+
* progress through {@link XMLHttpRequest.upload}'s `progress` event.
|
|
25
|
+
*
|
|
26
|
+
* This is the only place raw XHR lives. `fetch()` is intentionally avoided here
|
|
27
|
+
* because it does not surface upload progress.
|
|
28
|
+
*
|
|
29
|
+
* @param url - The full endpoint URL to POST to.
|
|
30
|
+
* @param token - Admin auth token; the `Authorization` header is only set when present.
|
|
31
|
+
* @param formData - Prebuilt multipart body containing the single file and its `fileInfo`.
|
|
32
|
+
* @param signal - Aborts the in-flight request when triggered.
|
|
33
|
+
* @param onProgress - Called with `(loaded, total)` bytes as the upload progresses.
|
|
34
|
+
* @returns The parsed, signed `File` on a 2xx response.
|
|
35
|
+
* @throws {UploadAbortedError} When the signal aborts.
|
|
36
|
+
* @throws {UploadFileError} On a non-2xx response or network error.
|
|
37
|
+
*/ const uploadFileViaXHR = (url, token, formData, signal, onProgress)=>{
|
|
38
|
+
return new Promise((resolve, reject)=>{
|
|
39
|
+
if (signal.aborted) {
|
|
40
|
+
reject(new UploadAbortedError());
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const xhr = new XMLHttpRequest();
|
|
44
|
+
xhr.open('POST', url);
|
|
45
|
+
if (token) {
|
|
46
|
+
xhr.setRequestHeader('Authorization', `Bearer ${token}`);
|
|
47
|
+
}
|
|
48
|
+
const handleAbort = ()=>xhr.abort();
|
|
49
|
+
signal.addEventListener('abort', handleAbort);
|
|
50
|
+
const cleanup = ()=>signal.removeEventListener('abort', handleAbort);
|
|
51
|
+
if (onProgress) {
|
|
52
|
+
xhr.upload.onprogress = (event)=>{
|
|
53
|
+
if (event.lengthComputable) {
|
|
54
|
+
onProgress(event.loaded, event.total);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
xhr.onload = ()=>{
|
|
59
|
+
cleanup();
|
|
60
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
61
|
+
try {
|
|
62
|
+
resolve(JSON.parse(xhr.responseText));
|
|
63
|
+
} catch {
|
|
64
|
+
reject(new UploadFileError('Failed to parse upload response'));
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
let message = `Upload failed with status ${xhr.status}`;
|
|
69
|
+
try {
|
|
70
|
+
const parsed = JSON.parse(xhr.responseText);
|
|
71
|
+
message = parsed?.error?.message || parsed?.message || message;
|
|
72
|
+
} catch {
|
|
73
|
+
// Keep the default status-based message.
|
|
74
|
+
}
|
|
75
|
+
reject(new UploadFileError(message, xhr.status));
|
|
76
|
+
};
|
|
77
|
+
xhr.onerror = ()=>{
|
|
78
|
+
cleanup();
|
|
79
|
+
reject(new UploadFileError('Network error occurred'));
|
|
80
|
+
};
|
|
81
|
+
xhr.onabort = ()=>{
|
|
82
|
+
cleanup();
|
|
83
|
+
reject(new UploadAbortedError());
|
|
84
|
+
};
|
|
85
|
+
xhr.send(formData);
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
exports.UploadAbortedError = UploadAbortedError;
|
|
90
|
+
exports.UploadFileError = UploadFileError;
|
|
91
|
+
exports.uploadFileViaXHR = uploadFileViaXHR;
|
|
92
|
+
//# sourceMappingURL=uploadFileViaXHR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploadFileViaXHR.js","sources":["../../../../admin/src/future/services/uploadFileViaXHR.ts"],"sourcesContent":["import type { File } from '../../../../shared/contracts/files';\n\n/**\n * Thrown when an upload is aborted via its `AbortSignal`.\n * Distinct from {@link UploadFileError} so callers can tell cancellation apart\n * from a genuine failure.\n */\nexport class UploadAbortedError extends Error {\n constructor(message = 'Upload aborted') {\n super(message);\n this.name = 'UploadAbortedError';\n }\n}\n\n/**\n * Thrown when an upload fails (non-2xx response, network error, or unparseable body).\n */\nexport class UploadFileError extends Error {\n status?: number;\n\n constructor(message: string, status?: number) {\n super(message);\n this.name = 'UploadFileError';\n this.status = status;\n }\n}\n\nexport type UploadProgressCallback = (bytes: number, total: number) => void;\n\n/**\n * Uploads a single file via `XMLHttpRequest`, exposing real byte-level upload\n * progress through {@link XMLHttpRequest.upload}'s `progress` event.\n *\n * This is the only place raw XHR lives. `fetch()` is intentionally avoided here\n * because it does not surface upload progress.\n *\n * @param url - The full endpoint URL to POST to.\n * @param token - Admin auth token; the `Authorization` header is only set when present.\n * @param formData - Prebuilt multipart body containing the single file and its `fileInfo`.\n * @param signal - Aborts the in-flight request when triggered.\n * @param onProgress - Called with `(loaded, total)` bytes as the upload progresses.\n * @returns The parsed, signed `File` on a 2xx response.\n * @throws {UploadAbortedError} When the signal aborts.\n * @throws {UploadFileError} On a non-2xx response or network error.\n */\nexport const uploadFileViaXHR = (\n url: string,\n token: string | null | undefined,\n formData: FormData,\n signal: AbortSignal,\n onProgress?: UploadProgressCallback\n): Promise<File> => {\n return new Promise<File>((resolve, reject) => {\n if (signal.aborted) {\n reject(new UploadAbortedError());\n return;\n }\n\n const xhr = new XMLHttpRequest();\n xhr.open('POST', url);\n\n if (token) {\n xhr.setRequestHeader('Authorization', `Bearer ${token}`);\n }\n\n const handleAbort = () => xhr.abort();\n signal.addEventListener('abort', handleAbort);\n\n const cleanup = () => signal.removeEventListener('abort', handleAbort);\n\n if (onProgress) {\n xhr.upload.onprogress = (event: ProgressEvent) => {\n if (event.lengthComputable) {\n onProgress(event.loaded, event.total);\n }\n };\n }\n\n xhr.onload = () => {\n cleanup();\n\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n resolve(JSON.parse(xhr.responseText) as File);\n } catch {\n reject(new UploadFileError('Failed to parse upload response'));\n }\n return;\n }\n\n let message = `Upload failed with status ${xhr.status}`;\n try {\n const parsed = JSON.parse(xhr.responseText);\n message = parsed?.error?.message || parsed?.message || message;\n } catch {\n // Keep the default status-based message.\n }\n reject(new UploadFileError(message, xhr.status));\n };\n\n xhr.onerror = () => {\n cleanup();\n reject(new UploadFileError('Network error occurred'));\n };\n\n xhr.onabort = () => {\n cleanup();\n reject(new UploadAbortedError());\n };\n\n xhr.send(formData);\n });\n};\n"],"names":["UploadAbortedError","Error","message","name","UploadFileError","status","uploadFileViaXHR","url","token","formData","signal","onProgress","Promise","resolve","reject","aborted","xhr","XMLHttpRequest","open","setRequestHeader","handleAbort","abort","addEventListener","cleanup","removeEventListener","upload","onprogress","event","lengthComputable","loaded","total","onload","JSON","parse","responseText","parsed","error","onerror","onabort","send"],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown when an upload is aborted via its `AbortSignal`.
|
|
3
|
+
* Distinct from {@link UploadFileError} so callers can tell cancellation apart
|
|
4
|
+
* from a genuine failure.
|
|
5
|
+
*/ class UploadAbortedError extends Error {
|
|
6
|
+
constructor(message = 'Upload aborted'){
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = 'UploadAbortedError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Thrown when an upload fails (non-2xx response, network error, or unparseable body).
|
|
13
|
+
*/ class UploadFileError extends Error {
|
|
14
|
+
constructor(message, status){
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'UploadFileError';
|
|
17
|
+
this.status = status;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Uploads a single file via `XMLHttpRequest`, exposing real byte-level upload
|
|
22
|
+
* progress through {@link XMLHttpRequest.upload}'s `progress` event.
|
|
23
|
+
*
|
|
24
|
+
* This is the only place raw XHR lives. `fetch()` is intentionally avoided here
|
|
25
|
+
* because it does not surface upload progress.
|
|
26
|
+
*
|
|
27
|
+
* @param url - The full endpoint URL to POST to.
|
|
28
|
+
* @param token - Admin auth token; the `Authorization` header is only set when present.
|
|
29
|
+
* @param formData - Prebuilt multipart body containing the single file and its `fileInfo`.
|
|
30
|
+
* @param signal - Aborts the in-flight request when triggered.
|
|
31
|
+
* @param onProgress - Called with `(loaded, total)` bytes as the upload progresses.
|
|
32
|
+
* @returns The parsed, signed `File` on a 2xx response.
|
|
33
|
+
* @throws {UploadAbortedError} When the signal aborts.
|
|
34
|
+
* @throws {UploadFileError} On a non-2xx response or network error.
|
|
35
|
+
*/ const uploadFileViaXHR = (url, token, formData, signal, onProgress)=>{
|
|
36
|
+
return new Promise((resolve, reject)=>{
|
|
37
|
+
if (signal.aborted) {
|
|
38
|
+
reject(new UploadAbortedError());
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const xhr = new XMLHttpRequest();
|
|
42
|
+
xhr.open('POST', url);
|
|
43
|
+
if (token) {
|
|
44
|
+
xhr.setRequestHeader('Authorization', `Bearer ${token}`);
|
|
45
|
+
}
|
|
46
|
+
const handleAbort = ()=>xhr.abort();
|
|
47
|
+
signal.addEventListener('abort', handleAbort);
|
|
48
|
+
const cleanup = ()=>signal.removeEventListener('abort', handleAbort);
|
|
49
|
+
if (onProgress) {
|
|
50
|
+
xhr.upload.onprogress = (event)=>{
|
|
51
|
+
if (event.lengthComputable) {
|
|
52
|
+
onProgress(event.loaded, event.total);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
xhr.onload = ()=>{
|
|
57
|
+
cleanup();
|
|
58
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
59
|
+
try {
|
|
60
|
+
resolve(JSON.parse(xhr.responseText));
|
|
61
|
+
} catch {
|
|
62
|
+
reject(new UploadFileError('Failed to parse upload response'));
|
|
63
|
+
}
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
let message = `Upload failed with status ${xhr.status}`;
|
|
67
|
+
try {
|
|
68
|
+
const parsed = JSON.parse(xhr.responseText);
|
|
69
|
+
message = parsed?.error?.message || parsed?.message || message;
|
|
70
|
+
} catch {
|
|
71
|
+
// Keep the default status-based message.
|
|
72
|
+
}
|
|
73
|
+
reject(new UploadFileError(message, xhr.status));
|
|
74
|
+
};
|
|
75
|
+
xhr.onerror = ()=>{
|
|
76
|
+
cleanup();
|
|
77
|
+
reject(new UploadFileError('Network error occurred'));
|
|
78
|
+
};
|
|
79
|
+
xhr.onabort = ()=>{
|
|
80
|
+
cleanup();
|
|
81
|
+
reject(new UploadAbortedError());
|
|
82
|
+
};
|
|
83
|
+
xhr.send(formData);
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export { UploadAbortedError, UploadFileError, uploadFileViaXHR };
|
|
88
|
+
//# sourceMappingURL=uploadFileViaXHR.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploadFileViaXHR.mjs","sources":["../../../../admin/src/future/services/uploadFileViaXHR.ts"],"sourcesContent":["import type { File } from '../../../../shared/contracts/files';\n\n/**\n * Thrown when an upload is aborted via its `AbortSignal`.\n * Distinct from {@link UploadFileError} so callers can tell cancellation apart\n * from a genuine failure.\n */\nexport class UploadAbortedError extends Error {\n constructor(message = 'Upload aborted') {\n super(message);\n this.name = 'UploadAbortedError';\n }\n}\n\n/**\n * Thrown when an upload fails (non-2xx response, network error, or unparseable body).\n */\nexport class UploadFileError extends Error {\n status?: number;\n\n constructor(message: string, status?: number) {\n super(message);\n this.name = 'UploadFileError';\n this.status = status;\n }\n}\n\nexport type UploadProgressCallback = (bytes: number, total: number) => void;\n\n/**\n * Uploads a single file via `XMLHttpRequest`, exposing real byte-level upload\n * progress through {@link XMLHttpRequest.upload}'s `progress` event.\n *\n * This is the only place raw XHR lives. `fetch()` is intentionally avoided here\n * because it does not surface upload progress.\n *\n * @param url - The full endpoint URL to POST to.\n * @param token - Admin auth token; the `Authorization` header is only set when present.\n * @param formData - Prebuilt multipart body containing the single file and its `fileInfo`.\n * @param signal - Aborts the in-flight request when triggered.\n * @param onProgress - Called with `(loaded, total)` bytes as the upload progresses.\n * @returns The parsed, signed `File` on a 2xx response.\n * @throws {UploadAbortedError} When the signal aborts.\n * @throws {UploadFileError} On a non-2xx response or network error.\n */\nexport const uploadFileViaXHR = (\n url: string,\n token: string | null | undefined,\n formData: FormData,\n signal: AbortSignal,\n onProgress?: UploadProgressCallback\n): Promise<File> => {\n return new Promise<File>((resolve, reject) => {\n if (signal.aborted) {\n reject(new UploadAbortedError());\n return;\n }\n\n const xhr = new XMLHttpRequest();\n xhr.open('POST', url);\n\n if (token) {\n xhr.setRequestHeader('Authorization', `Bearer ${token}`);\n }\n\n const handleAbort = () => xhr.abort();\n signal.addEventListener('abort', handleAbort);\n\n const cleanup = () => signal.removeEventListener('abort', handleAbort);\n\n if (onProgress) {\n xhr.upload.onprogress = (event: ProgressEvent) => {\n if (event.lengthComputable) {\n onProgress(event.loaded, event.total);\n }\n };\n }\n\n xhr.onload = () => {\n cleanup();\n\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n resolve(JSON.parse(xhr.responseText) as File);\n } catch {\n reject(new UploadFileError('Failed to parse upload response'));\n }\n return;\n }\n\n let message = `Upload failed with status ${xhr.status}`;\n try {\n const parsed = JSON.parse(xhr.responseText);\n message = parsed?.error?.message || parsed?.message || message;\n } catch {\n // Keep the default status-based message.\n }\n reject(new UploadFileError(message, xhr.status));\n };\n\n xhr.onerror = () => {\n cleanup();\n reject(new UploadFileError('Network error occurred'));\n };\n\n xhr.onabort = () => {\n cleanup();\n reject(new UploadAbortedError());\n };\n\n xhr.send(formData);\n });\n};\n"],"names":["UploadAbortedError","Error","message","name","UploadFileError","status","uploadFileViaXHR","url","token","formData","signal","onProgress","Promise","resolve","reject","aborted","xhr","XMLHttpRequest","open","setRequestHeader","handleAbort","abort","addEventListener","cleanup","removeEventListener","upload","onprogress","event","lengthComputable","loaded","total","onload","JSON","parse","responseText","parsed","error","onerror","onabort","send"],"mappings":"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"}
|
|
@@ -5,23 +5,11 @@ var toolkit = require('@reduxjs/toolkit');
|
|
|
5
5
|
const initialState = {
|
|
6
6
|
isVisible: false,
|
|
7
7
|
isMinimized: false,
|
|
8
|
-
progress: 0,
|
|
9
8
|
totalFiles: 0,
|
|
10
9
|
files: [],
|
|
11
10
|
errors: [],
|
|
12
11
|
uploadId: 0
|
|
13
12
|
};
|
|
14
|
-
const computeProgress = (files)=>{
|
|
15
|
-
if (files.length === 0) return 0;
|
|
16
|
-
const totalSize = files.reduce((sum, f)=>sum + f.size, 0);
|
|
17
|
-
if (totalSize === 0) {
|
|
18
|
-
// Fallback to count-based if sizes are unknown
|
|
19
|
-
const completed = files.filter((f)=>f.status === 'complete' || f.status === 'error' || f.status === 'cancelled').length;
|
|
20
|
-
return Math.round(completed / files.length * 100);
|
|
21
|
-
}
|
|
22
|
-
const completedSize = files.filter((f)=>f.status === 'complete' || f.status === 'error' || f.status === 'cancelled').reduce((sum, f)=>sum + f.size, 0);
|
|
23
|
-
return Math.round(completedSize / totalSize * 100);
|
|
24
|
-
};
|
|
25
13
|
const uploadProgressSlice = toolkit.createSlice({
|
|
26
14
|
name: 'uploadProgress',
|
|
27
15
|
initialState,
|
|
@@ -29,13 +17,13 @@ const uploadProgressSlice = toolkit.createSlice({
|
|
|
29
17
|
openUploadProgress (state, action) {
|
|
30
18
|
state.isVisible = true;
|
|
31
19
|
state.isMinimized = false;
|
|
32
|
-
state.progress = 0;
|
|
33
20
|
// Create pending files for upload
|
|
34
21
|
const pendingFiles = action.payload.fileNames.map((name, index)=>({
|
|
35
22
|
name,
|
|
36
23
|
index,
|
|
37
24
|
status: 'pending',
|
|
38
|
-
size: action.payload.fileSizes?.[index] ?? 0
|
|
25
|
+
size: action.payload.fileSizes?.[index] ?? 0,
|
|
26
|
+
uploadedBytes: 0
|
|
39
27
|
}));
|
|
40
28
|
state.files = pendingFiles;
|
|
41
29
|
state.totalFiles = action.payload.totalFiles;
|
|
@@ -49,13 +37,22 @@ const uploadProgressSlice = toolkit.createSlice({
|
|
|
49
37
|
state.files[index].size = size;
|
|
50
38
|
}
|
|
51
39
|
},
|
|
40
|
+
setFileProgress (state, action) {
|
|
41
|
+
const { index, bytes } = action.payload;
|
|
42
|
+
const file = state.files[index];
|
|
43
|
+
if (file) {
|
|
44
|
+
// Clamp to the known file size so the aggregate can never exceed 100%.
|
|
45
|
+
file.uploadedBytes = Math.min(bytes, file.size);
|
|
46
|
+
}
|
|
47
|
+
},
|
|
52
48
|
setFileComplete (state, action) {
|
|
53
49
|
const { index, file } = action.payload;
|
|
54
50
|
if (state.files[index]) {
|
|
55
51
|
state.files[index].status = 'complete';
|
|
56
52
|
state.files[index].file = file;
|
|
53
|
+
// Reflect completion in the aggregate even if the final progress event was throttled.
|
|
54
|
+
state.files[index].uploadedBytes = state.files[index].size;
|
|
57
55
|
}
|
|
58
|
-
state.progress = computeProgress(state.files);
|
|
59
56
|
},
|
|
60
57
|
setFileError (state, action) {
|
|
61
58
|
const { index, name, message } = action.payload;
|
|
@@ -70,10 +67,6 @@ const uploadProgressSlice = toolkit.createSlice({
|
|
|
70
67
|
message
|
|
71
68
|
}
|
|
72
69
|
];
|
|
73
|
-
state.progress = computeProgress(state.files);
|
|
74
|
-
},
|
|
75
|
-
updateProgress (state, action) {
|
|
76
|
-
state.progress = action.payload;
|
|
77
70
|
},
|
|
78
71
|
addUploadErrors (state, action) {
|
|
79
72
|
state.errors = [
|
|
@@ -84,7 +77,6 @@ const uploadProgressSlice = toolkit.createSlice({
|
|
|
84
77
|
closeUploadProgress (state) {
|
|
85
78
|
state.isVisible = false;
|
|
86
79
|
state.isMinimized = false;
|
|
87
|
-
state.progress = 0;
|
|
88
80
|
state.totalFiles = 0;
|
|
89
81
|
state.files = [];
|
|
90
82
|
state.errors = [];
|
|
@@ -103,7 +95,6 @@ const uploadProgressSlice = toolkit.createSlice({
|
|
|
103
95
|
}
|
|
104
96
|
return file;
|
|
105
97
|
});
|
|
106
|
-
state.progress = computeProgress(state.files);
|
|
107
98
|
},
|
|
108
99
|
setUploadFailed (state, action) {
|
|
109
100
|
// Mark all pending and uploading files as errored when a catastrophic failure occurs
|
|
@@ -117,7 +108,6 @@ const uploadProgressSlice = toolkit.createSlice({
|
|
|
117
108
|
}
|
|
118
109
|
return file;
|
|
119
110
|
});
|
|
120
|
-
state.progress = 100;
|
|
121
111
|
state.errors = [
|
|
122
112
|
...state.errors,
|
|
123
113
|
{
|
|
@@ -132,16 +122,31 @@ const uploadProgressSlice = toolkit.createSlice({
|
|
|
132
122
|
if (file.status === 'cancelled') {
|
|
133
123
|
return {
|
|
134
124
|
...file,
|
|
135
|
-
status: 'pending'
|
|
125
|
+
status: 'pending',
|
|
126
|
+
uploadedBytes: 0
|
|
136
127
|
};
|
|
137
128
|
}
|
|
138
129
|
return file;
|
|
139
130
|
});
|
|
140
|
-
state.progress = computeProgress(state.files);
|
|
141
131
|
}
|
|
142
132
|
}
|
|
143
133
|
});
|
|
144
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Byte-weighted aggregate progress across the whole batch: `sum(uploadedBytes) / sum(size)`.
|
|
136
|
+
*
|
|
137
|
+
* Falls back to count-based progress (settled files / total files) when all sizes are
|
|
138
|
+
* zero — e.g. URL-flow rows where the file size is unknown up front.
|
|
139
|
+
*/ const selectAggregateProgress = toolkit.createSelector((state)=>state.uploadProgress.files, (files)=>{
|
|
140
|
+
if (files.length === 0) return 0;
|
|
141
|
+
const totalSize = files.reduce((sum, f)=>sum + f.size, 0);
|
|
142
|
+
if (totalSize === 0) {
|
|
143
|
+
const settled = files.filter((f)=>f.status === 'complete' || f.status === 'error' || f.status === 'cancelled').length;
|
|
144
|
+
return Math.round(settled / files.length * 100);
|
|
145
|
+
}
|
|
146
|
+
const uploadedBytes = files.reduce((sum, f)=>sum + f.uploadedBytes, 0);
|
|
147
|
+
return Math.round(uploadedBytes / totalSize * 100);
|
|
148
|
+
});
|
|
149
|
+
const { openUploadProgress, setFileUploading, setFileProgress, setFileComplete, setFileError, addUploadErrors, closeUploadProgress, toggleMinimize, cancelUpload, setUploadFailed, retryCancelledFiles } = uploadProgressSlice.actions;
|
|
145
150
|
const uploadProgressReducer = uploadProgressSlice.reducer;
|
|
146
151
|
|
|
147
152
|
exports.addUploadErrors = addUploadErrors;
|
|
@@ -149,11 +154,12 @@ exports.cancelUpload = cancelUpload;
|
|
|
149
154
|
exports.closeUploadProgress = closeUploadProgress;
|
|
150
155
|
exports.openUploadProgress = openUploadProgress;
|
|
151
156
|
exports.retryCancelledFiles = retryCancelledFiles;
|
|
157
|
+
exports.selectAggregateProgress = selectAggregateProgress;
|
|
152
158
|
exports.setFileComplete = setFileComplete;
|
|
153
159
|
exports.setFileError = setFileError;
|
|
160
|
+
exports.setFileProgress = setFileProgress;
|
|
154
161
|
exports.setFileUploading = setFileUploading;
|
|
155
162
|
exports.setUploadFailed = setUploadFailed;
|
|
156
163
|
exports.toggleMinimize = toggleMinimize;
|
|
157
|
-
exports.updateProgress = updateProgress;
|
|
158
164
|
exports.uploadProgressReducer = uploadProgressReducer;
|
|
159
165
|
//# sourceMappingURL=uploadProgress.js.map
|