diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties index 6fd9ac34e..a759dec92 100644 --- a/backend/src/main/resources/i18n/messages.properties +++ b/backend/src/main/resources/i18n/messages.properties @@ -468,6 +468,7 @@ message.unsaved-source-2=icon on the dashboard. message.service-resolver-name-required=Service Provider Name is required message.entity-id-required=Entity ID is required message.entity-id-must-be-unique=Entity ID must be unique +message.target-required=Entity ID to copy is required message.file-upload-alert=Note: You can only import a file with a single entityID (EntityDescriptor element) in it. Anything more in that file will result in an error. message.add-new-md-resolver=Add a new metadata source message.wizard-status=Step { index } of { length } diff --git a/backend/src/main/resources/i18n/messages_en.properties b/backend/src/main/resources/i18n/messages_en.properties index 3384f478a..b5bade203 100644 --- a/backend/src/main/resources/i18n/messages_en.properties +++ b/backend/src/main/resources/i18n/messages_en.properties @@ -432,6 +432,7 @@ message.unsaved-source-2=icon on the dashboard. message.service-resolver-name-required=Service Provider Name is required message.entity-id-required=Entity ID is required message.entity-id-must-be-unique=Entity ID must be unique +message.target-required=Entity ID to copy is required message.file-upload-alert=Note: You can only import a file with a single entityID (EntityDescriptor element) in it. Anything more in that file will result in an error. message.add-new-md-resolver=Add a new metadata source message.wizard-status=Step { index } of { length } diff --git a/backend/src/main/resources/metadata-sources-ui-schema.json b/backend/src/main/resources/metadata-sources-ui-schema.json index 6d556d606..9a0b4fb9e 100644 --- a/backend/src/main/resources/metadata-sources-ui-schema.json +++ b/backend/src/main/resources/metadata-sources-ui-schema.json @@ -269,7 +269,7 @@ "title": "label.contact-email-address", "description": "tooltip.contact-email", "type": "string", - "pattern": "^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$", + "pattern": "^(mailto:)?(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$", "minLength": 1, "maxLength": 255 } diff --git a/ui/src/app/metadata/configuration/container/metadata-options.component.html b/ui/src/app/metadata/configuration/container/metadata-options.component.html index 09b72b7f9..63f8e522b 100644 --- a/ui/src/app/metadata/configuration/container/metadata-options.component.html +++ b/ui/src/app/metadata/configuration/container/metadata-options.component.html @@ -21,8 +21,8 @@

-
- +
+ Toggle view: Options diff --git a/ui/src/app/metadata/configuration/container/metadata-xml.component.html b/ui/src/app/metadata/configuration/container/metadata-xml.component.html index 2b5837944..fc550b06e 100644 --- a/ui/src/app/metadata/configuration/container/metadata-xml.component.html +++ b/ui/src/app/metadata/configuration/container/metadata-xml.component.html @@ -5,12 +5,12 @@

-
+
Toggle view: Options - + Toggle view: XML diff --git a/ui/src/app/metadata/resolver/container/copy-resolver.component.html b/ui/src/app/metadata/resolver/container/copy-resolver.component.html index 6ea4fce81..6dfed8e87 100644 --- a/ui/src/app/metadata/resolver/container/copy-resolver.component.html +++ b/ui/src/app/metadata/resolver/container/copy-resolver.component.html @@ -38,39 +38,48 @@

[required]="true" role="textbox" i18n-aria-label="@@label.select-entity-id-to-copy" - aria-label="Select the Entity ID to copy"> + aria-label="Select the Entity ID to copy" + aria-describedby="target-help"> - - - Service Resolver Name is Required - - + + Entity ID to copy is Required +

- - - - Service Resolver Name is required - - + + + Service Resolver Name is required +
- - - + + + Entity ID is required - - - - Entity ID must be unique + + + Entity ID must be unique +
- \ No newline at end of file +

+
diff --git a/ui/src/app/shared/autocomplete/autocomplete.component.ts b/ui/src/app/shared/autocomplete/autocomplete.component.ts index a3d7d109a..cda5d6406 100644 --- a/ui/src/app/shared/autocomplete/autocomplete.component.ts +++ b/ui/src/app/shared/autocomplete/autocomplete.component.ts @@ -51,6 +51,7 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte @Input() processing = false; @Input() dropdown = false; @Input() placeholder = ''; + @Input() count = null; @Output() more: EventEmitter = new EventEmitter(); @Output() onChange: EventEmitter = new EventEmitter(); @@ -118,14 +119,16 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte } ngOnChanges(changes: SimpleChanges): void { - if (changes.matches && this.matches) { + if (changes.matches && this.matches && this.state.currentState.menuOpen) { this.announceResults(); } } announceResults(): void { const count = this.matches.length; - this.live.announce(count === 0 ? 'No results available' : `${count} result${count === 1 ? '' : 's'} available`); + this.live.announce(count === 0 ? + `${this.noneFoundText}` : + `${count} result${count === 1 ? '' : 's'} available`, 'polite', 5000); } writeValue(value: any): void { @@ -157,6 +160,12 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte }); } + handleDropdown($event: MouseEvent | KeyboardEvent | Event): void { + const open = this.state.currentState.menuOpen; + this.state.setState({menuOpen: !open}); + this.handleOptionFocus(0); + } + handleViewMore($event: MouseEvent | KeyboardEvent | Event): void { $event.preventDefault(); $event.stopPropagation(); @@ -216,7 +225,6 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte handleInputChange(query: string): void { query = query || ''; - const queryEmpty = query.length === 0; const autoselect = this.hasAutoselect; const optionsAvailable = this.matches.length > 0; @@ -227,8 +235,6 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte selected: searchForOptions ? ((autoselect && optionsAvailable) ? 0 : -1) : null }); this.propagateChange(query); - - setTimeout(() => this.announceResults(), 250); } handleInputFocus(): void { @@ -284,7 +290,6 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte } handleDownArrow(event: KeyboardEvent): void { - event.preventDefault(); let isNotAtBottom = this.state.currentState.selected !== this.matches.length - 1; if (this.showMoreAvailable) { isNotAtBottom = this.state.currentState.selected !== this.matches.length; @@ -293,6 +298,7 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte if (allowMoveDown) { this.handleOptionFocus(this.state.currentState.selected + 1); } + event.preventDefault(); } handleSpace(event: KeyboardEvent): void { @@ -349,8 +355,8 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte return !!(agent.match(/(iPod|iPhone|iPad)/g) && agent.match(/AppleWebKit/g)); } - getOptionId(index): string { - return `${this.fieldId}__option--${index}`; + getOptionId(index: string | number): string { + return `${this.fieldId}__option--${index}`.replace('/', ''); } get hasAutoselect(): boolean {