Skip to content

Commit ab98ea5

Browse files
authored
V15: Show upload progress for dropped files in the Media Library (#18148)
* feat: shows notification when no suitable media type is found * chore: rearrange imports * feat: use a forward ref to find the dropzone * chore: rearrange imports * chore(mock): send back correct header * feat: avoid using the context consumer to get a token, but instead mimick the OpenAPI generator * chore(mock): allow more file types * chore(mock): create more upload fields * chore(mock): also look for mediaPicker fields * chore(mock): improve media mock db * chore(mock): add missing endpoints * chore(mock): update media data * chore(mock): fix aliases for media grid and table * chore(mock): add urls to media * chore(mock): adds missing endpoint for imaging * fix: reverse order of properties to overwrite existing status * feat: listen to progress updates on upload and update the `progress` property * feat: adds tracking of upload progress to placeholders * feat: bind the progress number up on the temporary file badge to indicate upload status * feat: optimises progress calculation and makes the badge bigger to be able to show the progress in percent * feat: allow text to be normal * chore: use correct localization * feat: shows error status for anything that isn't waiting or complete * feat: makes `progress` optional
1 parent bca74e0 commit ab98ea5

21 files changed

+259
-112
lines changed

src/Umbraco.Web.UI.Client/src/mocks/data/data-type/data-type.data.ts

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,70 @@ export const data: Array<UmbMockDataTypeModel> = [
722722
values: [
723723
{
724724
alias: 'fileExtensions',
725-
value: ['jpg', 'jpeg', 'png', 'pdf'],
725+
value: ['jpg', 'jpeg', 'png', 'svg'],
726+
},
727+
{
728+
alias: 'multiple',
729+
value: true,
730+
},
731+
],
732+
},
733+
{
734+
name: 'Upload Field (Files)',
735+
id: 'dt-uploadFieldFiles',
736+
parent: null,
737+
editorAlias: 'Umbraco.UploadField',
738+
editorUiAlias: 'Umb.PropertyEditorUi.UploadField',
739+
hasChildren: false,
740+
isFolder: false,
741+
isDeletable: true,
742+
canIgnoreStartNodes: false,
743+
values: [
744+
{
745+
alias: 'fileExtensions',
746+
value: ['pdf', 'iso'],
747+
},
748+
{
749+
alias: 'multiple',
750+
value: true,
751+
},
752+
],
753+
},
754+
{
755+
name: 'Upload Field (Movies)',
756+
id: 'dt-uploadFieldMovies',
757+
parent: null,
758+
editorAlias: 'Umbraco.UploadField',
759+
editorUiAlias: 'Umb.PropertyEditorUi.UploadField',
760+
hasChildren: false,
761+
isFolder: false,
762+
isDeletable: true,
763+
canIgnoreStartNodes: false,
764+
values: [
765+
{
766+
alias: 'fileExtensions',
767+
value: ['mp4', 'mov'],
768+
},
769+
{
770+
alias: 'multiple',
771+
value: true,
772+
},
773+
],
774+
},
775+
{
776+
name: 'Upload Field (Vector)',
777+
id: 'dt-uploadFieldVector',
778+
parent: null,
779+
editorAlias: 'Umbraco.UploadField',
780+
editorUiAlias: 'Umb.PropertyEditorUi.UploadField',
781+
hasChildren: false,
782+
isFolder: false,
783+
isDeletable: true,
784+
canIgnoreStartNodes: false,
785+
values: [
786+
{
787+
alias: 'fileExtensions',
788+
value: ['svg'],
726789
},
727790
{
728791
alias: 'multiple',
@@ -912,8 +975,16 @@ export const data: Array<UmbMockDataTypeModel> = [
912975
{
913976
alias: 'layouts',
914977
value: [
915-
{ icon: 'icon-grid', isSystem: true, name: 'Grid', path: '', selected: true },
916-
{ icon: 'icon-list', isSystem: true, name: 'Table', path: '', selected: true },
978+
{
979+
icon: 'icon-grid',
980+
name: 'Media Grid Collection View',
981+
collectionView: 'Umb.CollectionView.Media.Grid',
982+
},
983+
{
984+
icon: 'icon-list',
985+
name: 'Media Table Collection View',
986+
collectionView: 'Umb.CollectionView.Media.Table',
987+
},
917988
],
918989
},
919990
{ alias: 'icon', value: 'icon-layers' },

src/Umbraco.Web.UI.Client/src/mocks/data/media-type/media-type.data.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export type UmbMockMediaTypeUnionModel =
1515

1616
export const data: Array<UmbMockMediaTypeModel> = [
1717
{
18-
name: 'Media Type 1',
18+
name: 'Image',
1919
id: 'media-type-1-id',
2020
parent: null,
2121
description: 'Media type 1 description',
@@ -105,7 +105,7 @@ export const data: Array<UmbMockMediaTypeModel> = [
105105
aliasCanBeChanged: false,
106106
},
107107
{
108-
name: 'Media Type 2',
108+
name: 'Audio',
109109
id: 'media-type-2-id',
110110
parent: null,
111111
description: 'Media type 2 description',
@@ -118,7 +118,7 @@ export const data: Array<UmbMockMediaTypeModel> = [
118118
alias: 'umbracoFile',
119119
name: 'File',
120120
description: '',
121-
dataType: { id: 'dt-uploadField' },
121+
dataType: { id: 'dt-uploadFieldFiles' },
122122
variesByCulture: false,
123123
variesBySegment: false,
124124
sortOrder: 0,
@@ -155,7 +155,7 @@ export const data: Array<UmbMockMediaTypeModel> = [
155155
aliasCanBeChanged: false,
156156
},
157157
{
158-
name: 'Media Type 3',
158+
name: 'Vector Graphics',
159159
id: 'media-type-3-id',
160160
parent: null,
161161
description: 'Media type 3 description',
@@ -168,7 +168,7 @@ export const data: Array<UmbMockMediaTypeModel> = [
168168
alias: 'umbracoFile',
169169
name: 'File',
170170
description: '',
171-
dataType: { id: 'dt-uploadField' },
171+
dataType: { id: 'dt-uploadFieldVector' },
172172
variesByCulture: false,
173173
variesBySegment: false,
174174
sortOrder: 0,
@@ -205,7 +205,7 @@ export const data: Array<UmbMockMediaTypeModel> = [
205205
aliasCanBeChanged: false,
206206
},
207207
{
208-
name: 'Media Type 4',
208+
name: 'Movie',
209209
id: 'media-type-4-id',
210210
parent: null,
211211
description: 'Media type 4 description',
@@ -218,7 +218,7 @@ export const data: Array<UmbMockMediaTypeModel> = [
218218
alias: 'umbracoFile',
219219
name: 'File',
220220
description: '',
221-
dataType: { id: 'dt-uploadField' },
221+
dataType: { id: 'dt-uploadFieldMovies' },
222222
variesByCulture: false,
223223
variesBySegment: false,
224224
sortOrder: 0,
@@ -268,7 +268,7 @@ export const data: Array<UmbMockMediaTypeModel> = [
268268
alias: 'umbracoFile',
269269
name: 'File',
270270
description: '',
271-
dataType: { id: 'dt-uploadField' },
271+
dataType: { id: 'dt-uploadFieldFiles' },
272272
variesByCulture: false,
273273
variesBySegment: false,
274274
sortOrder: 0,

src/Umbraco.Web.UI.Client/src/mocks/data/media-type/media-type.db.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class UmbMediaTypeMockDB extends UmbEntityMockDbBase<UmbMockMediaTypeModel> {
5252
const allowedTypes = this.data.filter((field) => {
5353
const allProperties = field.properties.flat();
5454

55-
const fileUploadType = allProperties.find((prop) => prop.alias === 'umbracoFile');
55+
const fileUploadType = allProperties.find((prop) => prop.alias === 'umbracoFile' || prop.alias === 'mediaPicker');
5656
if (!fileUploadType) return false;
5757

5858
const dataType = umbDataTypeMockDb.read(fileUploadType.dataType.id);

src/Umbraco.Web.UI.Client/src/mocks/data/media/media.data.ts

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,38 @@ export const data: Array<UmbMockMediaModel> = [
1616
isTrashed: false,
1717
mediaType: {
1818
id: 'media-type-1-id',
19-
icon: 'icon-bug',
19+
icon: 'icon-picture',
2020
},
2121
values: [
22+
{
23+
editorAlias: 'Umbraco.UploadField',
24+
alias: 'mediaPicker',
25+
value: {
26+
src: '/umbraco/backoffice/assets/installer-illustration.svg',
27+
},
28+
},
2229
{
2330
editorAlias: 'Umbraco.TextBox',
24-
alias: 'myMediaHeadline',
31+
alias: 'mediaType1Property1',
2532
value: 'The daily life at Umbraco HQ',
2633
},
2734
],
2835
variants: [
2936
{
3037
publishDate: '2023-02-06T15:31:51.354764',
31-
culture: 'en-us',
38+
culture: null,
3239
segment: null,
3340
name: 'Flipped Car',
3441
createDate: '2023-02-06T15:31:46.876902',
3542
updateDate: '2023-02-06T15:31:51.354764',
3643
},
3744
],
38-
urls: [],
45+
urls: [
46+
{
47+
culture: null,
48+
url: '/umbraco/backoffice/assets/installer-illustration.svg',
49+
},
50+
],
3951
},
4052
{
4153
hasChildren: false,
@@ -51,14 +63,14 @@ export const data: Array<UmbMockMediaModel> = [
5163
values: [
5264
{
5365
editorAlias: 'Umbraco.TextBox',
54-
alias: 'myMediaDescription',
66+
alias: 'mediaType1Property1',
5567
value: 'Every day, a rabbit in a military costume greets me at the front door',
5668
},
5769
],
5870
variants: [
5971
{
6072
publishDate: '2023-02-06T15:31:51.354764',
61-
culture: 'en-us',
73+
culture: null,
6274
segment: null,
6375
name: 'Umbracoffee',
6476
createDate: '2023-02-06T15:31:46.876902',
@@ -83,7 +95,7 @@ export const data: Array<UmbMockMediaModel> = [
8395
variants: [
8496
{
8597
publishDate: '2023-02-06T15:31:51.354764',
86-
culture: 'en-us',
98+
culture: null,
8799
segment: null,
88100
name: 'People',
89101
createDate: '2023-02-06T15:31:46.876902',
@@ -108,7 +120,7 @@ export const data: Array<UmbMockMediaModel> = [
108120
variants: [
109121
{
110122
publishDate: '2023-02-06T15:31:51.354764',
111-
culture: 'en-us',
123+
culture: null,
112124
segment: null,
113125
name: 'John Smith',
114126
createDate: '2023-02-06T15:31:46.876902',
@@ -131,14 +143,14 @@ export const data: Array<UmbMockMediaModel> = [
131143
values: [
132144
{
133145
editorAlias: 'Umbraco.TextBox',
134-
alias: 'myMediaDescription',
146+
alias: 'mediaType1Property1',
135147
value: 'Every day, a rabbit in a military costume greets me at the front door',
136148
},
137149
],
138150
variants: [
139151
{
140152
publishDate: '2023-02-06T15:31:51.354764',
141-
culture: 'en-us',
153+
culture: null,
142154
segment: null,
143155
name: 'Jane Doe',
144156
createDate: '2023-02-06T15:31:46.876902',
@@ -161,14 +173,14 @@ export const data: Array<UmbMockMediaModel> = [
161173
values: [
162174
{
163175
editorAlias: 'Umbraco.TextBox',
164-
alias: 'myMediaDescription',
176+
alias: 'mediaType1Property1',
165177
value: 'Every day, a rabbit in a military costume greets me at the front door',
166178
},
167179
],
168180
variants: [
169181
{
170182
publishDate: '2023-02-06T15:31:51.354764',
171-
culture: 'en-us',
183+
culture: null,
172184
segment: null,
173185
name: 'John Doe',
174186
createDate: '2023-02-06T15:31:46.876902',
@@ -191,14 +203,14 @@ export const data: Array<UmbMockMediaModel> = [
191203
values: [
192204
{
193205
editorAlias: 'Umbraco.TextBox',
194-
alias: 'myMediaDescription',
206+
alias: 'mediaType1Property1',
195207
value: 'Every day, a rabbit in a military costume greets me at the front door',
196208
},
197209
],
198210
variants: [
199211
{
200212
publishDate: '2023-02-06T15:31:51.354764',
201-
culture: 'en-us',
213+
culture: null,
202214
segment: null,
203215
name: 'A very nice hat',
204216
createDate: '2023-02-06T15:31:46.876902',
@@ -221,14 +233,14 @@ export const data: Array<UmbMockMediaModel> = [
221233
values: [
222234
{
223235
editorAlias: 'Umbraco.TextBox',
224-
alias: 'myMediaDescription',
236+
alias: 'mediaType1Property1',
225237
value: 'Every day, a rabbit in a military costume greets me at the front door',
226238
},
227239
],
228240
variants: [
229241
{
230242
publishDate: '2023-02-06T15:31:51.354764',
231-
culture: 'en-us',
243+
culture: null,
232244
segment: null,
233245
name: 'Fancy old chair',
234246
createDate: '2023-02-06T15:31:46.876902',

src/Umbraco.Web.UI.Client/src/mocks/handlers/media/detail.handlers.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
UpdateMediaRequestModel,
99
} from '@umbraco-cms/backoffice/external/backend-api';
1010
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
11+
import type { UmbMediaDetailModel } from '@umbraco-cms/backoffice/media';
1112

1213
export const detailHandlers = [
1314
rest.post(umbracoPath(`${UMB_SLUG}`), async (req, res, ctx) => {
@@ -44,6 +45,23 @@ export const detailHandlers = [
4445
return res(ctx.status(200), ctx.json(response));
4546
}),
4647

48+
rest.put<UmbMediaDetailModel>(umbracoPath(`${UMB_SLUG}/:id/validate`), async (req, res, ctx) => {
49+
const id = req.params.id as string;
50+
if (!id) return res(ctx.status(400));
51+
const model = await req.json<UmbMediaDetailModel>();
52+
if (!model) return res(ctx.status(400));
53+
54+
const hasMediaPickerOrFileUploadValue = model.values.some((v) => {
55+
return v.editorAlias === 'Umbraco.UploadField' && v.value;
56+
});
57+
58+
if (!hasMediaPickerOrFileUploadValue) {
59+
return res(ctx.status(400, 'No media picker or file upload value found'));
60+
}
61+
62+
return res(ctx.status(200));
63+
}),
64+
4765
rest.put(umbracoPath(`${UMB_SLUG}/:id`), async (req, res, ctx) => {
4866
const id = req.params.id as string;
4967
if (!id) return res(ctx.status(400));
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const { rest } = window.MockServiceWorker;
2+
import { umbMediaMockDb } from '../../data/media/media.db.js';
3+
import type { GetImagingResizeUrlsResponse } from '@umbraco-cms/backoffice/external/backend-api';
4+
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
5+
6+
export const imagingHandlers = [
7+
rest.get(umbracoPath('/imaging/resize/urls'), (req, res, ctx) => {
8+
const ids = req.url.searchParams.getAll('id');
9+
if (!ids) return res(ctx.status(404));
10+
11+
const media = umbMediaMockDb.getAll().filter((item) => ids.includes(item.id));
12+
13+
const response: GetImagingResizeUrlsResponse = media.map((item) => ({
14+
id: item.id,
15+
urlInfos: item.urls,
16+
}));
17+
18+
return res(
19+
// Respond with a 200 status code
20+
ctx.status(200),
21+
ctx.json(response),
22+
);
23+
}),
24+
];

src/Umbraco.Web.UI.Client/src/mocks/handlers/media/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import { treeHandlers } from './tree.handlers.js';
33
import { itemHandlers } from './item.handlers.js';
44
import { detailHandlers } from './detail.handlers.js';
55
import { collectionHandlers } from './collection.handlers.js';
6+
import { imagingHandlers } from './imaging.handlers.js';
67

78
export const handlers = [
89
...recycleBinHandlers,
910
...treeHandlers,
1011
...itemHandlers,
1112
...detailHandlers,
1213
...collectionHandlers,
14+
...imagingHandlers,
1315
];

0 commit comments

Comments
 (0)