Skip to content

Commit

Permalink
fix: localization panel freeze if too many translations
Browse files Browse the repository at this point in the history
Only create form for inputs to be displayed and limit the
number of translation shown on the panel.

Encourage the user to use the search bar to find their translation.
  • Loading branch information
cpaulve-1A committed Jun 14, 2024
1 parent 6bdd008 commit 82622e0
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 62 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
import { AsyncPipe } from '@angular/common';
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';
import { NgbAccordionDirective, NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap';
import {AsyncPipe} from '@angular/common';
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';
import {NgbAccordionDirective, NgbAccordionModule} from '@ng-bootstrap/ng-bootstrap';
import type {
JSONLocalization,
LocalizationMetadata
} 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 {Subscription} from 'rxjs';
import {map, throttleTime} from 'rxjs/operators';
import {ChromeExtensionConnectionService} from '../../services/connection.service';
import {LocalizationService, StateService} from '../../services';

const THROTTLE_TIME = 100;

Expand Down Expand Up @@ -44,6 +55,7 @@ export class LocalizationPanelPresComponent implements OnDestroy {
public readonly filteredLocalizations: Signal<LocalizationMetadata>;
public readonly languages = this.localizationService.languages;
public readonly hasSeveralLanguages: Signal<boolean>;
public readonly isTruncated: Signal<boolean>;
public readonly localizationActiveStateOverridesForCurrentLang = computed(() => {
const lang = this.currentLanguage();
if (!lang) {
Expand Down Expand Up @@ -89,18 +101,23 @@ export class LocalizationPanelPresComponent implements OnDestroy {
const search = toSignal(
this.form.controls.search.valueChanges.pipe(
map((text) => text?.toLowerCase() || ''),
throttleTime(THROTTLE_TIME, undefined, { trailing: true })
throttleTime(THROTTLE_TIME, undefined, {trailing: true})
),
{ initialValue: '' }
{initialValue: ''}
);
const searchMatch = computed(() => {
return search() ?
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, 20);
});

this.isTruncated = computed(() => this.filteredLocalizations().length < searchMatch().length);

effect(() => {
const lang = this.currentLanguage();
if (lang) {
Expand All @@ -120,34 +137,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<Record<string, TranslationControl>>({});
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<string>(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(() => {
Expand All @@ -166,14 +162,33 @@ 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<Record<string, TranslationControl>>({});
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<string>(controlValue);
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(controlValue);
}

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ <h3 ngbAccordionHeader>
} @empty {
<h3>No localization found for your search.</h3>
}
@if (isTruncated()) {
<span>Too many matches for this filter, please be more specific in your search.</span>
}
</div>
</ng-container>
} @else {
Expand Down
7 changes: 5 additions & 2 deletions apps/chrome-devtools/src/services/localization.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,11 @@ export class LocalizationService {

constructor() {
effect(() => {
this.connectionService.sendMessage('switchLanguage', { language: this.currentLanguage() });
this.connectionService.sendMessage('requestMessages', { only: ['getTranslationValuesContentMessage'] });
const currentLanguage = this.currentLanguage();
if (currentLanguage) {
this.connectionService.sendMessage('switchLanguage', { language: this.currentLanguage() });
this.connectionService.sendMessage('requestMessages', { only: ['getTranslationValuesContentMessage'] });
}
});
const externalSwitchLanguage = toSignal(
this.connectionService.message$.pipe(
Expand Down
14 changes: 1 addition & 13 deletions apps/showcase/src/style/dark-theme/dark-theme.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
@import "highlight.js/styles/a11y-dark.css";

:root {
/* --- BEGIN THEME Auto-generated --- */
Expand Down Expand Up @@ -97,15 +96,4 @@
.card { --bs-card-color: #ffffff; }
.card { --bs-card-bg: #000000; }
/* --- END THEME Auto-generated --- */

.nav.nav-pills .nav-link {
--bs-scrollspy-color: #ffffff;
--bs-nav-pills-link-active-bg: transparent;
}
.input-group-text {
background-color: var(--bs-tertiary-bg);
}
.form-select {
--bs-form-select-bg-img: url("data:image/svg+xml;charset=utf8,%3Csvg version='1.1' viewBox='0 0 1792 1792' style='fill%3a%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m1408 704q0 26-19 45l-448 448q-19 19-45 19t-45-19l-448-448q-19-19-19-45t19-45 45-19h896q26 0 45 19t19 45z'/%3E%3C/svg%3E");
}
}
}

0 comments on commit 82622e0

Please sign in to comment.