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 1179d7a6d1..76fb23d622 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 @@ -84,17 +84,6 @@ export class LocalizationPanelPresComponent implements OnDestroy { 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); diff --git a/apps/chrome-devtools/src/components/app-connection/app-connection.component.ts b/apps/chrome-devtools/src/components/app-connection/app-connection.component.ts index fb09ede3f7..e9a14c5c34 100644 --- a/apps/chrome-devtools/src/components/app-connection/app-connection.component.ts +++ b/apps/chrome-devtools/src/components/app-connection/app-connection.component.ts @@ -1,11 +1,8 @@ import { AsyncPipe } from '@angular/common'; -import { ChangeDetectionStrategy, Component, OnDestroy } from '@angular/core'; -import { Observable, of, Subscription } from 'rxjs'; -import { catchError, map, startWith, take, timeout } from 'rxjs/operators'; -import { ChromeExtensionConnectionService, isRuleEngineEventsMessage } from '../../services/connection.service'; -import { RulesetHistoryService } from '../../services/ruleset-history.service'; +import {ChangeDetectionStrategy, Component, inject, OnDestroy} from '@angular/core'; +import { Observable, Subscription } from 'rxjs'; +import { AppState, ChromeExtensionConnectionService } from '../../services/connection.service'; -type AppState = 'loading' | 'timeout' | 'connected'; @Component({ selector: 'app-connection', @@ -17,32 +14,14 @@ type AppState = 'loading' | 'timeout' | 'connected'; ] }) export class AppConnectionComponent implements OnDestroy { - /** Stream of application's state */ - public appState$: Observable; - private readonly subscription = new Subscription(); + private readonly connectionService = inject(ChromeExtensionConnectionService); - constructor( - connectionService: ChromeExtensionConnectionService, - rulesetHistoryService: RulesetHistoryService - ) { - this.subscription.add( - connectionService.message$.subscribe((message) => { - if (isRuleEngineEventsMessage(message)) { - rulesetHistoryService.update(message); - } - }) - ); - - this.appState$ = connectionService.message$.pipe( - map(() => 'connected' as AppState), - take(1), - startWith('loading' as AppState), - timeout(3000), - catchError(() => of('timeout' as AppState)) - ); + /** Stream of application's state */ + public appState$: Observable = this.connectionService.appState$; - connectionService.activate(); + constructor() { + this.connectionService.activate(); } /** @inheritDoc */ diff --git a/apps/chrome-devtools/src/services/connection.service.ts b/apps/chrome-devtools/src/services/connection.service.ts index c2de597a59..9f3653dbf2 100644 --- a/apps/chrome-devtools/src/services/connection.service.ts +++ b/apps/chrome-devtools/src/services/connection.service.ts @@ -2,8 +2,18 @@ import { ApplicationRef, Injectable, OnDestroy } from '@angular/core'; import type { Dictionary } from '@ngrx/entity'; import type { ConfigurationModel } from '@o3r/configuration'; import { otterMessageType } from '@o3r/core'; -import { type Observable, ReplaySubject, Subscription } from 'rxjs'; -import { debounceTime, distinctUntilChanged, filter, map, shareReplay } from 'rxjs/operators'; +import {type Observable, of, ReplaySubject, Subscription} from 'rxjs'; +import { + catchError, + debounceTime, + distinctUntilChanged, + filter, + map, + shareReplay, + startWith, + take, + timeout +} from 'rxjs/operators'; import type { AvailableMessageContents } from './message.interface'; import type { ApplicationInformationContentMessage } from '@o3r/application'; @@ -59,6 +69,8 @@ export const filterAndMapMessage = ( shareReplay({ refCount: true, bufferSize: 1 }) ); +export type AppState = 'loading' | 'timeout' | 'connected'; + /** * Service to communicate with the current tab */ @@ -71,6 +83,15 @@ export class ChromeExtensionConnectionService implements OnDestroy { /** Stream of messages received from the service worker */ public message$ = this.messageSubject.asObservable(); + /** Stream the state of the extension connection to the Otter application*/ + public appState$ = this.message$.pipe( + map(() => 'connected' as AppState), + take(1), + startWith('loading' as AppState), + timeout(3000), + catchError(() => of('timeout' as AppState)) + ); + private readonly configurations = new ReplaySubject>(1); public configurations$ = this.configurations.asObservable(); diff --git a/apps/chrome-devtools/src/services/localization.service.ts b/apps/chrome-devtools/src/services/localization.service.ts index a01808770b..66295b0500 100644 --- a/apps/chrome-devtools/src/services/localization.service.ts +++ b/apps/chrome-devtools/src/services/localization.service.ts @@ -55,6 +55,23 @@ export class LocalizationService { ); constructor() { + const activated = toSignal(this.connectionService.appState$); + effect(() => { + if (activated() === 'connected') { + this.connectionService.sendMessage( + 'requestMessages', + { + only: [ + 'localizations', + 'languages', + 'switchLanguage', + 'isTranslationDeactivationEnabled' + ] + } + ); + } + }); + effect(() => { const currentLanguage = this.currentLanguage(); if (currentLanguage) { diff --git a/apps/chrome-devtools/src/services/ruleset-history.service.ts b/apps/chrome-devtools/src/services/ruleset-history.service.ts index d4a6cc596e..e1cac9cdb5 100644 --- a/apps/chrome-devtools/src/services/ruleset-history.service.ts +++ b/apps/chrome-devtools/src/services/ruleset-history.service.ts @@ -1,14 +1,17 @@ -import { Injectable } from '@angular/core'; +import {effect, inject, Injectable} from '@angular/core'; import type { RulesEngineDebugEventsContentMessage, RulesetExecutionDebug } from '@o3r/rules-engine'; import { rulesetReportToHistory } from '@o3r/rules-engine'; -import { map, Observable, ReplaySubject } from 'rxjs'; +import {filter, map, Observable, ReplaySubject} from 'rxjs'; import {shareReplay} from 'rxjs/operators'; +import {ChromeExtensionConnectionService, isRuleEngineEventsMessage} from './connection.service'; +import {toSignal} from '@angular/core/rxjs-interop'; @Injectable({ providedIn: 'root' }) export class RulesetHistoryService { private readonly ruleEngineDebugEventsSubject = new ReplaySubject(1); + private readonly connectionService = inject(ChromeExtensionConnectionService); /** Ruleset history stream */ public readonly ruleEngineDebugEvents$ = this.ruleEngineDebugEventsSubject.asObservable(); @@ -21,6 +24,16 @@ export class RulesetHistoryService { shareReplay({bufferSize: 1, refCount: true}) ); + constructor() { + const extensionMessage = toSignal(this.connectionService.message$.pipe(filter(isRuleEngineEventsMessage))); + effect(() => { + const message = extensionMessage(); + if (message) { + this.update(message); + } + }); + } + /** * Update the ruleset history * @param message Message from the background service @@ -28,4 +41,5 @@ export class RulesetHistoryService { public update(message: RulesEngineDebugEventsContentMessage) { this.ruleEngineDebugEventsSubject.next(message); } + } diff --git a/apps/chrome-devtools/src/services/state.service.ts b/apps/chrome-devtools/src/services/state.service.ts index 5a0de49c9d..f7964bb0c4 100644 --- a/apps/chrome-devtools/src/services/state.service.ts +++ b/apps/chrome-devtools/src/services/state.service.ts @@ -1,4 +1,4 @@ -import { computed, effect, inject, Injectable, signal, type Signal, untracked } from '@angular/core'; +import { computed, effect, inject, Injectable, signal, type Signal } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { ChromeExtensionConnectionService, filterAndMapMessage, isApplicationInformationMessage } from './connection.service'; import { ACTIVE_STATE_NAME_KEY, type State, type StateOverride, STATES_KEY } from '../extension/interface'; @@ -75,7 +75,7 @@ export class StateService { effect(() => { const state = this.activeState(); - const languages = untracked(this.languages); + const languages = this.languages(); this.updateLocalState(state || {}, true); // TODO reset configuration (is it possible? based on default value from metadata if present?) // Reset all styling variables before applying override of the new state