From 72c7d5cbe682acc897451aa80df1f19cd0ee63e8 Mon Sep 17 00:00:00 2001 From: Angelika Kinas Date: Mon, 11 Nov 2024 15:49:24 +0100 Subject: [PATCH 1/9] feat: make use of minCharCount and clearOnSelection --- .../generic-keywords/generic-keywords.component.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html b/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html index b7bf99890..9b5d13c75 100644 --- a/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html +++ b/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html @@ -5,8 +5,9 @@ [action]="autoCompleteAction" (itemSelected)="handleItemSelection($event)" [preventCompleteOnSelection]="true" - [minCharacterCount]="0" + [minCharacterCount]="1" [allowSubmit]="false" + [clearOnSelection]="true" >
Date: Tue, 12 Nov 2024 09:22:15 +0100 Subject: [PATCH 2/9] chore: fix e2e test --- apps/metadata-editor-e2e/src/e2e/edit.cy.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/metadata-editor-e2e/src/e2e/edit.cy.ts b/apps/metadata-editor-e2e/src/e2e/edit.cy.ts index 3fd0fd98a..c47608a4f 100644 --- a/apps/metadata-editor-e2e/src/e2e/edit.cy.ts +++ b/apps/metadata-editor-e2e/src/e2e/edit.cy.ts @@ -432,7 +432,7 @@ describe('editor form', () => { .should('have.length', 0) cy.get('gn-ui-form-field-spatial-extent') .find('gn-ui-autocomplete') - .click() + .type('a') cy.get('mat-option').eq(1).click() cy.editor_publishAndReload() cy.get('@saveStatus').should('eq', 'record_up_to_date') @@ -629,7 +629,9 @@ describe('editor form', () => { }) it('should add a keyword', () => { cy.editor_wrapPreviousDraft() - cy.get('gn-ui-form-field-keywords').find('gn-ui-autocomplete').click() + cy.get('gn-ui-form-field-keywords') + .find('gn-ui-autocomplete') + .type('a') cy.get('mat-option').first().click() cy.editor_publishAndReload() cy.get('@saveStatus').should('eq', 'record_up_to_date') From d2d79cc7ca8e4f51660306c07c2deb6b6e3d5966 Mon Sep 17 00:00:00 2001 From: Angelika Kinas Date: Mon, 25 Nov 2024 15:46:12 +0100 Subject: [PATCH 3/9] fix(autocomplete): clear input after selecting option --- libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts b/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts index 62b9f047c..f493430a8 100644 --- a/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +++ b/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts @@ -239,7 +239,6 @@ export class AutocompleteComponent this.lastInputValue$.pipe(first()).subscribe((lastInputValue) => { this.inputRef.nativeElement.value = lastInputValue }) - return } if (this.clearOnSelection) { this.inputRef.nativeElement.value = '' From 3a2a1b13a7f6057b0125069ee55aa97d275b95be Mon Sep 17 00:00:00 2001 From: cmoinier Date: Tue, 26 Nov 2024 13:22:04 +0100 Subject: [PATCH 4/9] fix: get autocomplete working --- .../autocomplete/autocomplete.component.ts | 70 +++++++++++++------ 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts b/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts index f493430a8..9efca58b6 100644 --- a/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +++ b/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts @@ -20,7 +20,15 @@ import { MatAutocompleteSelectedEvent, MatAutocompleteTrigger, } from '@angular/material/autocomplete' -import { first, merge, Observable, of, ReplaySubject, Subscription } from 'rxjs' +import { + first, + merge, + Observable, + of, + ReplaySubject, + Subject, + Subscription, +} from 'rxjs' import { catchError, debounceTime, @@ -30,6 +38,7 @@ import { map, switchMap, take, + takeUntil, tap, } from 'rxjs/operators' import { PopupAlertComponent } from '@geonetwork-ui/ui/widgets' @@ -98,6 +107,7 @@ export class AutocompleteComponent error: string | null = null suggestions$: Observable subscription = new Subscription() + clearSuggestions$ = new Subject() @Input() displayWithFn: (item: AutocompleteItem) => string = (item) => item.toString() @@ -130,33 +140,47 @@ export class AutocompleteComponent ) ) - const externalValueChange$ = this.control.valueChanges.pipe( - filter((value) => typeof value === 'object' && value.title), - map((item) => item.title) - ) - // this observable emits arrays of suggestions loaded using the given action - const suggestionsFromAction = merge( - newValue$.pipe( - filter((value: string) => value.length >= this.minCharacterCount) - ), - externalValueChange$ - ).pipe( + const suggestionsFromAction = newValue$.pipe( + switchMap((value: string) => { + if (value.length === 0) { + return of([]) // Emit an empty array for an empty value + } else if (value.length >= this.minCharacterCount) { + return merge( + of(value), + this.control.valueChanges.pipe( + filter( + (controlValue) => + typeof controlValue === 'object' && controlValue.title + ), + map((item) => item.title), + distinctUntilChanged() + ) + ).pipe( + takeUntil(this.clearSuggestions$), // Stop emitting when suggestions are cleared + switchMap((title) => + this.action(title).pipe( + catchError((error: Error) => { + this.error = error.message + return of([]) + }), + finalize(() => (this.searching = false)) + ) + ) + ) + } else { + return of([]) + } + }), tap(() => { this.searching = true this.error = null - }), - switchMap((value) => this.action(value)), - catchError((error: Error) => { - this.error = error.message - return of([]) - }), - finalize(() => (this.searching = false)) + }) ) this.suggestions$ = merge( + this.clearSuggestions$.pipe(map(() => [])), // Clearing has the highest priority suggestionsFromAction, - // if a new value is under the min char count, clear suggestions newValue$.pipe( filter((value: string) => value.length < this.minCharacterCount), map(() => []) @@ -204,11 +228,15 @@ export class AutocompleteComponent if (this.inputRef) { this.inputRef.nativeElement.value = (value as any)?.title || '' } + if (this.clearOnSelection) { + this.clearSuggestions$.next() + } } clear(): void { this.inputRef.nativeElement.value = '' this.inputCleared.emit() + this.clearSuggestions$.next() this.selectionSubject .pipe(take(1)) .subscribe((selection) => selection && selection.option.deselect()) @@ -241,7 +269,7 @@ export class AutocompleteComponent }) } if (this.clearOnSelection) { - this.inputRef.nativeElement.value = '' + this.clear() } } } From a107dd11a1aca685334bfbf4d7770346f8ac9b9b Mon Sep 17 00:00:00 2001 From: cmoinier Date: Tue, 26 Nov 2024 13:28:36 +0100 Subject: [PATCH 5/9] fix: suggestions should show up when typing same letter as before --- libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts b/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts index 9efca58b6..7a38280fa 100644 --- a/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +++ b/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts @@ -135,7 +135,6 @@ export class AutocompleteComponent this.inputCleared.pipe(map(() => '')), this.control.valueChanges.pipe( filter((value) => typeof value === 'string'), - distinctUntilChanged(), debounceTime(400) ) ) @@ -153,8 +152,7 @@ export class AutocompleteComponent (controlValue) => typeof controlValue === 'object' && controlValue.title ), - map((item) => item.title), - distinctUntilChanged() + map((item) => item.title) ) ).pipe( takeUntil(this.clearSuggestions$), // Stop emitting when suggestions are cleared From 1139a884ec7301421342f58bba2e4fb0bfb16e40 Mon Sep 17 00:00:00 2001 From: Angelika Kinas Date: Mon, 9 Dec 2024 15:20:12 +0100 Subject: [PATCH 6/9] fix: autocomplete clear input after selecting an option the input should be cleared clicking inside the input does not show the previous selected option --- .../generic-keywords.component.html | 2 +- .../autocomplete/autocomplete.component.ts | 87 ++++++++----------- 2 files changed, 39 insertions(+), 50 deletions(-) diff --git a/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html b/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html index 9b5d13c75..260a1418b 100644 --- a/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html +++ b/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html @@ -4,7 +4,7 @@ [displayWithFn]="displayWithFn" [action]="autoCompleteAction" (itemSelected)="handleItemSelection($event)" - [preventCompleteOnSelection]="true" + [preventCompleteOnSelection]="false" [minCharacterCount]="1" [allowSubmit]="false" [clearOnSelection]="true" diff --git a/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts b/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts index 7a38280fa..55a058191 100644 --- a/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +++ b/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts @@ -20,15 +20,7 @@ import { MatAutocompleteSelectedEvent, MatAutocompleteTrigger, } from '@angular/material/autocomplete' -import { - first, - merge, - Observable, - of, - ReplaySubject, - Subject, - Subscription, -} from 'rxjs' +import { first, merge, Observable, of, ReplaySubject, Subscription } from 'rxjs' import { catchError, debounceTime, @@ -38,7 +30,6 @@ import { map, switchMap, take, - takeUntil, tap, } from 'rxjs/operators' import { PopupAlertComponent } from '@geonetwork-ui/ui/widgets' @@ -107,7 +98,6 @@ export class AutocompleteComponent error: string | null = null suggestions$: Observable subscription = new Subscription() - clearSuggestions$ = new Subject() @Input() displayWithFn: (item: AutocompleteItem) => string = (item) => item.toString() @@ -135,53 +125,54 @@ export class AutocompleteComponent this.inputCleared.pipe(map(() => '')), this.control.valueChanges.pipe( filter((value) => typeof value === 'string'), + distinctUntilChanged(), debounceTime(400) ) + ).pipe( + tap((suggestionsFromAction) => { + console.log('newValue', suggestionsFromAction) + }) + ) + + const externalValueChange$ = this.control.valueChanges.pipe( + filter((value) => typeof value === 'object' && value.title), + map((item) => item.title), + tap((suggestionsFromAction) => { + console.log('externalValueChange', suggestionsFromAction) + }) ) // this observable emits arrays of suggestions loaded using the given action - const suggestionsFromAction = newValue$.pipe( - switchMap((value: string) => { - if (value.length === 0) { - return of([]) // Emit an empty array for an empty value - } else if (value.length >= this.minCharacterCount) { - return merge( - of(value), - this.control.valueChanges.pipe( - filter( - (controlValue) => - typeof controlValue === 'object' && controlValue.title - ), - map((item) => item.title) - ) - ).pipe( - takeUntil(this.clearSuggestions$), // Stop emitting when suggestions are cleared - switchMap((title) => - this.action(title).pipe( - catchError((error: Error) => { - this.error = error.message - return of([]) - }), - finalize(() => (this.searching = false)) - ) - ) - ) - } else { - return of([]) - } - }), + const suggestionsFromAction = merge( + newValue$.pipe( + filter((value: string) => value.length >= this.minCharacterCount) + ), + externalValueChange$ + ).pipe( tap(() => { this.searching = true this.error = null - }) + }), + switchMap((value) => this.action(value)), + catchError((error: Error) => { + this.error = error.message + return of([]) + }), + tap((suggestionsFromAction) => { + console.log('suggestionsfromaction', suggestionsFromAction) + }), + finalize(() => (this.searching = false)) ) this.suggestions$ = merge( - this.clearSuggestions$.pipe(map(() => [])), // Clearing has the highest priority suggestionsFromAction, + // if a new value is under the min char count, clear suggestions newValue$.pipe( filter((value: string) => value.length < this.minCharacterCount), - map(() => []) + map(() => []), + tap((suggestionsFromAction) => { + console.log('suggestionsfromCLEAR', suggestionsFromAction) + }) ) ) @@ -226,15 +217,11 @@ export class AutocompleteComponent if (this.inputRef) { this.inputRef.nativeElement.value = (value as any)?.title || '' } - if (this.clearOnSelection) { - this.clearSuggestions$.next() - } } clear(): void { this.inputRef.nativeElement.value = '' this.inputCleared.emit() - this.clearSuggestions$.next() this.selectionSubject .pipe(take(1)) .subscribe((selection) => selection && selection.option.deselect()) @@ -265,9 +252,11 @@ export class AutocompleteComponent this.lastInputValue$.pipe(first()).subscribe((lastInputValue) => { this.inputRef.nativeElement.value = lastInputValue }) + return } if (this.clearOnSelection) { - this.clear() + this.inputRef.nativeElement.value = '' + this.control.setValue('') } } } From 71c7b18addc47f0146066bae45b4f306be31df2b Mon Sep 17 00:00:00 2001 From: Angelika Kinas Date: Mon, 9 Dec 2024 15:25:07 +0100 Subject: [PATCH 7/9] chore: remove console logs --- .../lib/autocomplete/autocomplete.component.ts | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts b/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts index 55a058191..bf81d7278 100644 --- a/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +++ b/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts @@ -128,18 +128,11 @@ export class AutocompleteComponent distinctUntilChanged(), debounceTime(400) ) - ).pipe( - tap((suggestionsFromAction) => { - console.log('newValue', suggestionsFromAction) - }) ) const externalValueChange$ = this.control.valueChanges.pipe( filter((value) => typeof value === 'object' && value.title), - map((item) => item.title), - tap((suggestionsFromAction) => { - console.log('externalValueChange', suggestionsFromAction) - }) + map((item) => item.title) ) // this observable emits arrays of suggestions loaded using the given action @@ -158,9 +151,6 @@ export class AutocompleteComponent this.error = error.message return of([]) }), - tap((suggestionsFromAction) => { - console.log('suggestionsfromaction', suggestionsFromAction) - }), finalize(() => (this.searching = false)) ) @@ -169,10 +159,7 @@ export class AutocompleteComponent // if a new value is under the min char count, clear suggestions newValue$.pipe( filter((value: string) => value.length < this.minCharacterCount), - map(() => []), - tap((suggestionsFromAction) => { - console.log('suggestionsfromCLEAR', suggestionsFromAction) - }) + map(() => []) ) ) From 5ec61f856a7f2226e4f8807a5c71fc92614f54fb Mon Sep 17 00:00:00 2001 From: Angelika Kinas Date: Thu, 12 Dec 2024 13:28:49 +0100 Subject: [PATCH 8/9] chore(e2e): add test --- apps/metadata-editor-e2e/src/e2e/edit.cy.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/metadata-editor-e2e/src/e2e/edit.cy.ts b/apps/metadata-editor-e2e/src/e2e/edit.cy.ts index c47608a4f..0ed6eeaa4 100644 --- a/apps/metadata-editor-e2e/src/e2e/edit.cy.ts +++ b/apps/metadata-editor-e2e/src/e2e/edit.cy.ts @@ -643,6 +643,17 @@ describe('editor form', () => { .find('span') .should('have.text', 'Addresses ') }) + it('should close the autocomplete and clear the input after selecting a keyword', () => { + cy.get('gn-ui-form-field-keywords') + .find('gn-ui-autocomplete') + .type('a') + cy.get('mat-option').first().click() + cy.get('mat-option').should('not.exist') + cy.get('gn-ui-form-field-keywords') + .find('gn-ui-autocomplete') + .find('input') + .should('have.value', '') + }) it('should delete a keyword', () => { cy.editor_wrapPreviousDraft() cy.get('gn-ui-form-field-keywords') From e5896362b58b22abf13dcaaf5a66f4f9836bf3d1 Mon Sep 17 00:00:00 2001 From: Angelika Kinas Date: Thu, 12 Dec 2024 13:39:10 +0100 Subject: [PATCH 9/9] chore: fix wording in attribute --- .../form-field-online-link-resources.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-link-resources/form-field-online-link-resources.component.html b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-link-resources/form-field-online-link-resources.component.html index 141c397bf..dd83fc736 100644 --- a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-link-resources/form-field-online-link-resources.component.html +++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-link-resources/form-field-online-link-resources.component.html @@ -51,7 +51,7 @@

*ngIf="disabled$ | async" class="p-4 text-sm border border-primary bg-primary-lightest rounded-lg" translate - data-testid="disabled-message" + data-test="disabled-message" > editor.record.form.field.draft.only.disabled