Skip to content

Commit 02b3ec4

Browse files
authored
Merge branch 'v15/dev' into v15/bugfix/18000
2 parents 40f671d + 058f901 commit 02b3ec4

File tree

15 files changed

+325
-62
lines changed

15 files changed

+325
-62
lines changed

src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,7 @@ export default {
822822
error: 'Error',
823823
field: 'Field',
824824
fieldFor: 'Field for %0%',
825+
toggleFor: 'Toggle for %0%',
825826
findDocument: 'Find',
826827
first: 'First',
827828
focalPoint: 'Focal point',

src/Umbraco.Web.UI.Client/src/assets/lang/en.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,8 @@ export default {
372372
fileSecurityValidationFailure: 'One or more file security validations have failed',
373373
moveToSameFolderFailed: 'Parent and destination folders cannot be the same',
374374
uploadNotAllowed: 'Upload is not allowed in this location.',
375+
noticeExtensionsServerOverride:
376+
'Regardless of the allowed file types, the following limitations apply system-wide due to the server configuration:',
375377
},
376378
member: {
377379
'2fa': 'Two-Factor Authentication',
@@ -817,6 +819,7 @@ export default {
817819
error: 'Error',
818820
field: 'Field',
819821
fieldFor: 'Field for %0%',
822+
toggleFor: 'Toggle for %0%',
820823
findDocument: 'Find',
821824
first: 'First',
822825
focalPoint: 'Focal point',
@@ -885,6 +888,7 @@ export default {
885888
retrieve: 'Retrieve',
886889
retry: 'Retry',
887890
rights: 'Permissions',
891+
serverConfiguration: 'Server Configuration',
888892
scheduledPublishing: 'Scheduled Publishing',
889893
umbracoInfo: 'Umbraco info',
890894
search: 'Search',
@@ -2138,6 +2142,9 @@ export default {
21382142
numberMinimum: "Value must be greater than or equal to '%0%'.",
21392143
numberMaximum: "Value must be less than or equal to '%0%'.",
21402144
numberMisconfigured: "Minimum value '%0%' must be less than the maximum value '%1%'.",
2145+
invalidExtensions: 'One or more of the extensions are invalid.',
2146+
allowedExtensions: 'Allowed extensions are:',
2147+
disallowedExtensions: 'Disallowed extensions are:',
21412148
},
21422149
healthcheck: {
21432150
checkSuccessMessage: "Value is set to the recommended value: '%0%'.",

src/Umbraco.Web.UI.Client/src/packages/core/components/input-toggle/input-toggle.element.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ export class UmbInputToggleElement extends UUIFormControlMixin(UmbLitElement, ''
2626
@property({ type: String })
2727
labelOff?: string;
2828

29+
@property({ type: String, attribute: 'aria-label' })
30+
override ariaLabel: string | null = null;
31+
2932
/**
3033
* Sets the input to readonly mode, meaning value cannot be changed but still able to read and select its content.
3134
* @type {boolean}
@@ -42,6 +45,8 @@ export class UmbInputToggleElement extends UUIFormControlMixin(UmbLitElement, ''
4245
return undefined;
4346
}
4447

48+
// test
49+
4550
override connectedCallback(): void {
4651
super.connectedCallback();
4752
this.#updateLabel();
@@ -54,15 +59,15 @@ export class UmbInputToggleElement extends UUIFormControlMixin(UmbLitElement, ''
5459
}
5560

5661
#updateLabel() {
57-
this._currentLabel = this.showLabels ? (this.checked ? this.labelOn : this.labelOff) : '';
62+
this._currentLabel = this.showLabels ? (this.checked ? this.labelOn : this.labelOff) : '';
5863
}
5964

6065
override render() {
6166
return html`<uui-toggle
6267
.checked=${this.#checked}
63-
.label=${this._currentLabel}
68+
.label="${this.ariaLabel}"
6469
@change=${this.#onChange}
65-
?readonly=${this.readonly}></uui-toggle>`;
70+
?readonly=${this.readonly}><span>${this._currentLabel}</span> </uui-toggle>`;
6671
}
6772

6873
static override styles = [

src/Umbraco.Web.UI.Client/src/packages/core/components/multiple-text-string-input/input-multiple-text-string-item.element.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@ export class UmbInputMultipleTextStringItemElement extends UUIFormControlMixin(U
6565
}
6666

6767
// Prevent valid events from bubbling outside the message element
68-
#onValid(event: any) {
68+
#onValid(event: Event) {
6969
event.stopPropagation();
7070
}
7171

7272
// Prevent invalid events from bubbling outside the message element
73-
#onInvalid(event: any) {
73+
#onInvalid(event: Event) {
7474
event.stopPropagation();
7575
}
7676

src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-upload-field/preview/input-upload-field-file.element.ts

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1+
import { html, customElement, property, state, css, when } from '@umbraco-cms/backoffice/external/lit';
2+
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
13
import { UMB_APP_CONTEXT } from '@umbraco-cms/backoffice/app';
24
import type { PropertyValueMap } from '@umbraco-cms/backoffice/external/lit';
3-
import { html, customElement, property, state, css } from '@umbraco-cms/backoffice/external/lit';
4-
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
55

66
@customElement('umb-input-upload-field-file')
77
export default class UmbInputUploadFieldFileElement extends UmbLitElement {
8-
@property({ type: String })
8+
#loadingText = `(${this.localize.term('general_loading')}...)`;
9+
10+
#serverUrl = '';
11+
12+
@property()
913
path: string = '';
1014

1115
/**
@@ -22,53 +26,39 @@ export default class UmbInputUploadFieldFileElement extends UmbLitElement {
2226
@state()
2327
label = '';
2428

25-
#serverUrl = '';
26-
27-
#loadingText = `(${this.localize.term('general_loading')}...)`;
28-
29-
/**
30-
*
31-
*/
3229
constructor() {
3330
super();
31+
3432
this.consumeContext(UMB_APP_CONTEXT, (instance) => {
3533
this.#serverUrl = instance.getServerUrl();
36-
}).asPromise();
34+
});
3735
}
3836

3937
protected override updated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
4038
super.updated(_changedProperties);
39+
4140
if (_changedProperties.has('file') && this.file) {
4241
this.extension = this.file.name.split('.').pop() ?? '';
4342
this.label = this.file.name || this.#loadingText;
4443
}
4544

46-
if (_changedProperties.has('path')) {
47-
if (this.#serverUrl) {
48-
if (this.file) return;
49-
50-
this.extension = this.path.split('.').pop() ?? '';
51-
this.label = this.#serverUrl ? this.path.substring(this.#serverUrl.length) : this.#loadingText;
52-
}
45+
if (_changedProperties.has('path') && !this.file) {
46+
this.extension = this.path.split('.').pop() ?? '';
47+
this.label = this.path.split('/').pop() ?? this.#loadingText;
5348
}
5449
}
5550

56-
#renderLabel() {
57-
if (this.path) {
58-
// Don't make it a link if it's a temp file upload.
59-
return this.file ? this.label : html`<a id="label" href=${this.path} target="_blank">${this.label}</a>`;
60-
}
61-
62-
return html`<span id="label">${this.label}</span>`;
63-
}
64-
6551
override render() {
6652
if (!this.label && !this.extension) return html`<uui-loader></uui-loader>`;
6753

6854
return html`
6955
<div id="main">
7056
<uui-symbol-file id="file-symbol" .type=${this.extension}></uui-symbol-file>
71-
${this.#renderLabel()}
57+
${when(
58+
!this.file && this.path,
59+
() => html`<a id="label" href="${this.#serverUrl}${this.path}" target="_blank">${this.label}</a>`,
60+
() => html`<span id="label">${this.label}</span>`,
61+
)}
7262
</div>
7363
`;
7464
}
@@ -81,26 +71,30 @@ export default class UmbInputUploadFieldFileElement extends UmbLitElement {
8171
box-sizing: border-box;
8272
color: var(--uui-color-text);
8373
}
74+
8475
#file-symbol {
8576
aspect-ratio: 1 / 1;
8677
margin: auto;
8778
max-width: 100%;
8879
max-height: 100%;
8980
}
81+
9082
#label {
9183
text-align: center;
9284
overflow: hidden;
9385
text-overflow: ellipsis;
9486
white-space: nowrap;
9587
color: var(--uui-color-text);
96-
}
97-
a#label {
98-
text-decoration: none;
99-
color: var(--uui-color-interactive);
100-
}
101-
a#label:hover {
102-
text-decoration: underline;
103-
color: var(--uui-color-interactive-emphasis);
88+
89+
&:is(a) {
90+
text-decoration: none;
91+
color: var(--uui-color-interactive);
92+
93+
&:hover {
94+
text-decoration: underline;
95+
color: var(--uui-color-interactive-emphasis);
96+
}
97+
}
10498
}
10599
`,
106100
];

src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/upload-field/Umbraco.UploadField.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export const manifest: ManifestPropertyEditorSchema = {
1111
{
1212
alias: 'fileExtensions',
1313
label: 'Accepted file extensions',
14-
propertyEditorUiAlias: 'Umb.PropertyEditorUi.MultipleTextString',
14+
propertyEditorUiAlias: 'Umb.PropertyEditorUi.AcceptedUploadTypes',
1515
},
1616
],
1717
},
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './property-editor-ui-accepted-upload-types.element.js';
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { ManifestPropertyEditorUi } from '@umbraco-cms/backoffice/property-editor';
2+
3+
export const manifest: ManifestPropertyEditorUi = {
4+
type: 'propertyEditorUi',
5+
alias: 'Umb.PropertyEditorUi.AcceptedUploadTypes',
6+
name: 'Accepted Upload Types Property Editor UI',
7+
element: () => import('./property-editor-ui-accepted-upload-types.element.js'),
8+
meta: {
9+
label: 'Accepted Upload Types',
10+
propertyEditorSchemaAlias: 'Umbraco.MultipleTextstring',
11+
icon: 'icon-ordered-list',
12+
group: 'lists',
13+
supportsReadOnly: true,
14+
},
15+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import { UmbPropertyEditorUIMultipleTextStringElement } from '../multiple-text-string/property-editor-ui-multiple-text-string.element.js';
2+
import { css, customElement, html, nothing, state, when } from '@umbraco-cms/backoffice/external/lit';
3+
import { formatBytes } from '@umbraco-cms/backoffice/utils';
4+
import { UmbTemporaryFileConfigRepository } from '@umbraco-cms/backoffice/temporary-file';
5+
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/property-editor';
6+
import type { UmbTemporaryFileConfigurationModel } from '@umbraco-cms/backoffice/temporary-file';
7+
8+
/**
9+
* @element umb-property-editor-ui-accepted-upload-types
10+
*/
11+
@customElement('umb-property-editor-ui-accepted-upload-types')
12+
export class UmbPropertyEditorUIAcceptedUploadTypesElement
13+
extends UmbPropertyEditorUIMultipleTextStringElement
14+
implements UmbPropertyEditorUiElement
15+
{
16+
#temporaryFileConfigRepository = new UmbTemporaryFileConfigRepository(this);
17+
18+
@state()
19+
protected _acceptedTypes: string[] = [];
20+
21+
@state()
22+
protected _disallowedTypes: string[] = [];
23+
24+
@state()
25+
protected _maxFileSize?: number | null;
26+
27+
override async connectedCallback() {
28+
super.connectedCallback();
29+
30+
await this.#temporaryFileConfigRepository.initialized;
31+
this.observe(this.#temporaryFileConfigRepository.all(), (config) => {
32+
if (!config) return;
33+
34+
this.#addValidators(config);
35+
36+
this._acceptedTypes = config.allowedUploadedFileExtensions;
37+
this._disallowedTypes = config.disallowedUploadedFilesExtensions;
38+
this._maxFileSize = config.maxFileSize ? config.maxFileSize * 1024 : null;
39+
});
40+
}
41+
42+
#addValidators(config: UmbTemporaryFileConfigurationModel) {
43+
this._inputElement?.addValidator(
44+
'badInput',
45+
() => {
46+
let message = this.localize.term('validation_invalidExtensions');
47+
if (config.allowedUploadedFileExtensions.length) {
48+
message += `<br>${this.localize.term('validation_allowedExtensions')} ${config.allowedUploadedFileExtensions.join(', ')}`;
49+
}
50+
if (config.disallowedUploadedFilesExtensions.length) {
51+
message += `<br>${this.localize.term('validation_disallowedExtensions')} ${config.disallowedUploadedFilesExtensions.join(', ')}`;
52+
}
53+
return message;
54+
},
55+
() => {
56+
const extensions = this._inputElement?.items;
57+
if (!extensions) return false;
58+
if (
59+
config.allowedUploadedFileExtensions.length &&
60+
!config.allowedUploadedFileExtensions.some((ext) => extensions.includes(ext))
61+
) {
62+
return true;
63+
}
64+
if (config.disallowedUploadedFilesExtensions.some((ext) => extensions.includes(ext))) {
65+
return true;
66+
}
67+
return false;
68+
},
69+
);
70+
}
71+
72+
#renderAcceptedTypes() {
73+
if (!this._acceptedTypes.length && !this._disallowedTypes.length && !this._maxFileSize) {
74+
return nothing;
75+
}
76+
77+
return html`
78+
<uui-box id="notice" headline=${this.localize.term('general_serverConfiguration')}>
79+
<p><umb-localize key="media_noticeExtensionsServerOverride"></umb-localize></p>
80+
${when(
81+
this._acceptedTypes.length,
82+
() => html`
83+
<p>
84+
<umb-localize key="validation_allowedExtensions"></umb-localize>
85+
<strong>${this._acceptedTypes.join(', ')}</strong>
86+
</p>
87+
`,
88+
)}
89+
${when(
90+
this._disallowedTypes.length,
91+
() => html`
92+
<p>
93+
<umb-localize key="validation_disallowedExtensions"></umb-localize>
94+
<strong>${this._disallowedTypes.join(', ')}</strong>
95+
</p>
96+
`,
97+
)}
98+
${when(
99+
this._maxFileSize,
100+
() => html`
101+
<p>
102+
${this.localize.term('media_maxFileSize')}
103+
<strong title="${this.localize.number(this._maxFileSize!)} bytes"
104+
>${formatBytes(this._maxFileSize!, { decimals: 2 })}</strong
105+
>.
106+
</p>
107+
`,
108+
)}
109+
</uui-box>
110+
`;
111+
}
112+
113+
override render() {
114+
return html`${this.#renderAcceptedTypes()} ${super.render()}`;
115+
}
116+
117+
static override readonly styles = [
118+
css`
119+
#notice {
120+
--uui-box-default-padding: var(--uui-size-space-4);
121+
--uui-box-header-padding: var(--uui-size-space-4);
122+
--uui-color-divider-standalone: var(--uui-color-warning-standalone);
123+
124+
border: 1px solid var(--uui-color-divider-standalone);
125+
background-color: var(--uui-color-warning);
126+
color: var(--uui-color-warning-contrast);
127+
margin-bottom: var(--uui-size-layout-1);
128+
129+
p {
130+
margin: 0.5rem 0;
131+
}
132+
}
133+
`,
134+
];
135+
}
136+
137+
export default UmbPropertyEditorUIAcceptedUploadTypesElement;
138+
139+
declare global {
140+
interface HTMLElementTagNameMap {
141+
'umb-property-editor-ui-accepted-upload-types': UmbPropertyEditorUIAcceptedUploadTypesElement;
142+
}
143+
}

0 commit comments

Comments
 (0)