diff --git a/apps/chrome-devtools/src/app-devtools/localization-panel/localization-panel-pres.component.ts b/apps/chrome-devtools/src/app-devtools/localization-panel/localization-panel-pres.component.ts index 9a2f07029f..0f8ab3abe0 100644 --- a/apps/chrome-devtools/src/app-devtools/localization-panel/localization-panel-pres.component.ts +++ b/apps/chrome-devtools/src/app-devtools/localization-panel/localization-panel-pres.component.ts @@ -1,5 +1,16 @@ import { AsyncPipe } from '@angular/common'; -import { ChangeDetectionStrategy, Component, computed, effect, inject, type OnDestroy, type Signal, untracked, viewChild, ViewEncapsulation } from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + computed, + effect, + inject, + type OnDestroy, + type Signal, + untracked, + viewChild, + ViewEncapsulation +} from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { DfTooltipModule } from '@design-factory/design-factory'; @@ -10,8 +21,7 @@ import type { } from '@o3r/localization'; import { Subscription } from 'rxjs'; import { map, throttleTime } from 'rxjs/operators'; -import { ChromeExtensionConnectionService } from '../../services/connection.service'; -import { LocalizationService, StateService } from '../../services'; +import { ChromeExtensionConnectionService, LocalizationService, StateService } from '../../services'; const THROTTLE_TIME = 100; @@ -36,6 +46,8 @@ export class LocalizationPanelPresComponent implements OnDestroy { private readonly connectionService = inject(ChromeExtensionConnectionService); private readonly localizationService = inject(LocalizationService); private readonly stateService = inject(StateService); + private readonly subscription = new Subscription(); + private readonly maxItemDisplayed = 20; public readonly isTranslationDeactivationEnabled = this.localizationService.isTranslationDeactivationEnabled; public readonly localizations: Signal; @@ -44,6 +56,7 @@ export class LocalizationPanelPresComponent implements OnDestroy { public readonly filteredLocalizations: Signal; public readonly languages = this.localizationService.languages; public readonly hasSeveralLanguages: Signal; + public readonly isTruncated: Signal; public readonly localizationActiveStateOverridesForCurrentLang = computed(() => { const lang = this.currentLanguage(); if (!lang) { @@ -66,22 +79,9 @@ export class LocalizationPanelPresComponent implements OnDestroy { translations: new FormGroup>({}) }); - private readonly subscription = new Subscription(); - public accordion = viewChild('acc'); constructor() { - this.connectionService.sendMessage( - 'requestMessages', - { - only: [ - 'localizations', - 'languages', - 'switchLanguage', - 'isTranslationDeactivationEnabled' - ] - } - ); this.hasSeveralLanguages = computed(() => this.languages().length >= 2); this.localizations = computed(() => this.localizationService.localizationsMetadata().filter((localization) => !localization.dictionary && !localization.ref)); this.hasLocalizations = computed(() => !!this.localizations().length); @@ -93,14 +93,20 @@ export class LocalizationPanelPresComponent implements OnDestroy { ), { initialValue: '' } ); + const searchMatch = computed(() => { + const searchText = search(); + return searchText ? + this.localizations().filter(({ key, description, tags, ref }) => + [key, description, ...(tags || []), ref].some((value) => value?.toLowerCase().includes(searchText)) + ) : this.localizations(); + }); this.filteredLocalizations = computed(() => { - const searchText = search(); - return searchText - ? this.localizations().filter(({ key, description, tags, ref }) => [key, description, ...(tags || []), ref].some((value) => value?.toLowerCase().includes(searchText))) - : this.localizations(); + return searchMatch().slice(0, this.maxItemDisplayed); }); + this.isTruncated = computed(() => this.filteredLocalizations().length < searchMatch().length); + effect(() => { const lang = this.currentLanguage(); if (lang) { @@ -120,34 +126,13 @@ export class LocalizationPanelPresComponent implements OnDestroy { }) ); effect(() => { - const translations = this.localizationService.translationsForCurrentLanguage(); + const translations = this.filteredLocalizations(); const lang = untracked(this.currentLanguage); if (!lang) { return; } - let langControl = this.form.controls.translations.controls[lang]; - if (!langControl) { - langControl = new FormGroup>({}); - this.form.controls.translations.addControl(lang, langControl); - } - Object.entries(translations).forEach(([key, value]) => { - const control = langControl.controls[key]; - const initialValue = - untracked(this.stateService.localState).localizations?.[this.form.value.lang || '']?.[key] - || value - || untracked(this.localizationService.localizationsMetadata).find((loc) => loc.key === key)?.value - || ''; - if (!control) { - const newControl = new FormControl(initialValue); - langControl.addControl(key, newControl); - this.subscription.add( - newControl.valueChanges.pipe( - throttleTime(THROTTLE_TIME, undefined, { trailing: true }) - ).subscribe((newValue) => this.onLocalizationChange(key, newValue ?? '')) - ); - } else { - control.setValue(initialValue); - } + translations.forEach(({key}) => { + this.upsertKeyForm(key, lang); }); }); effect(() => { @@ -166,14 +151,32 @@ export class LocalizationPanelPresComponent implements OnDestroy { control.disable(); } }); - const locOverride = computed(() => this.stateService.localState().localizations || {}); - effect(() => { - Object.entries(locOverride()).forEach(([lang, overridePerLang]) => - Object.entries(overridePerLang).forEach(([key, value]) => - this.form.controls.translations.controls[lang]?.controls[key]?.setValue(value) - ) + } + + private upsertKeyForm(key: string, lang: string) { + let langControl = this.form.controls.translations.controls[lang]; + if (!langControl) { + langControl = new FormGroup>({}); + this.form.controls.translations.addControl(lang, langControl); + } + const control = langControl.controls[key]; + const controlValue = + this.stateService.localState().localizations?.[this.form.value.lang || '']?.[key] + || untracked(this.localizationService.localizationsMetadata).find((loc) => loc.key === key)?.value + || ''; + if (!control) { + const newControl = new FormControl(controlValue); + langControl.addControl(key, newControl); + this.subscription.add( + newControl.valueChanges.pipe( + throttleTime(THROTTLE_TIME, undefined, { trailing: true }) + ).subscribe((newValue) => { + this.onLocalizationChange(key, newValue ?? ''); + }) ); - }); + } else if (control.value !== controlValue) { + control.setValue(controlValue); + } } /** diff --git a/apps/chrome-devtools/src/app-devtools/localization-panel/localization-panel-pres.template.html b/apps/chrome-devtools/src/app-devtools/localization-panel/localization-panel-pres.template.html index 443befde03..9d8c5930a4 100644 --- a/apps/chrome-devtools/src/app-devtools/localization-panel/localization-panel-pres.template.html +++ b/apps/chrome-devtools/src/app-devtools/localization-panel/localization-panel-pres.template.html @@ -78,6 +78,9 @@

} @empty {

No localization found for your search.

} + @if (isTruncated()) { + Too many matches for this filter, please be more specific in your search. + } } @else {