diff --git a/devtools/projects/ng-devtools/src/BUILD.bazel b/devtools/projects/ng-devtools/src/BUILD.bazel index 8c0ddfe56cf..f08bbab5525 100644 --- a/devtools/projects/ng-devtools/src/BUILD.bazel +++ b/devtools/projects/ng-devtools/src/BUILD.bazel @@ -9,5 +9,6 @@ ng_project( "//devtools/projects/ng-devtools/src/lib", "//devtools/projects/ng-devtools/src/lib/application-environment", "//devtools/projects/ng-devtools/src/lib/application-operations", + "//devtools/projects/ng-devtools/src/lib/application-providers:settings", ], ) diff --git a/devtools/projects/ng-devtools/src/lib/application-services/BUILD.bazel b/devtools/projects/ng-devtools/src/lib/application-services/BUILD.bazel index 156855e0f9d..fc277d32aef 100644 --- a/devtools/projects/ng-devtools/src/lib/application-services/BUILD.bazel +++ b/devtools/projects/ng-devtools/src/lib/application-services/BUILD.bazel @@ -66,7 +66,7 @@ ts_test_library( "//devtools/projects/ng-devtools/src/lib/application-environment", "//devtools/projects/ng-devtools/src/lib/application-providers:window", "//devtools/projects/ng-devtools/src/lib/application-services/test-utils:app_operations_mock", - "//devtools/projects/ng-devtools/src/lib/application-services/test-utils:settings_store_mock", + "//devtools/projects/ng-devtools/src/lib/application-services/test-utils:settings_mock", "//devtools/projects/protocol", ], ) diff --git a/devtools/projects/ng-devtools/src/lib/application-services/settings.ts b/devtools/projects/ng-devtools/src/lib/application-services/settings.ts index 334226820c0..b7140860692 100644 --- a/devtools/projects/ng-devtools/src/lib/application-services/settings.ts +++ b/devtools/projects/ng-devtools/src/lib/application-services/settings.ts @@ -12,9 +12,27 @@ import {SettingsStore} from './settings_store'; export class Settings { private readonly settingsStore = inject(SettingsStore); - readonly dummy = this.settingsStore.create({ - key: 'dummy', + readonly showCommentNodes = this.settingsStore.create({ + key: 'show_comment_nodes', category: 'general', - initialValue: true, + initialValue: false, + }); + + readonly routerGraphEnabled = this.settingsStore.create({ + key: 'router_graph_enabled', + category: 'general', + initialValue: false, + }); + + readonly timingAPIEnabled = this.settingsStore.create({ + key: 'timing_api_enabled', + category: 'general', + initialValue: false, + }); + + readonly signalGraphEnabled = this.settingsStore.create({ + key: 'signal_graph_enabled', + category: 'general', + initialValue: false, }); } diff --git a/devtools/projects/ng-devtools/src/lib/application-services/test-utils/BUILD.bazel b/devtools/projects/ng-devtools/src/lib/application-services/test-utils/BUILD.bazel index 5510dab0501..31bf0abb742 100644 --- a/devtools/projects/ng-devtools/src/lib/application-services/test-utils/BUILD.bazel +++ b/devtools/projects/ng-devtools/src/lib/application-services/test-utils/BUILD.bazel @@ -3,12 +3,13 @@ load("//devtools/tools:defaults.bzl", "ts_project") package(default_visibility = ["//devtools:__subpackages__"]) ts_project( - name = "settings_store_mock", + name = "settings_mock", srcs = [ - "settings_store_mock.ts", + "settings_mock.ts", ], deps = [ "//:node_modules/@angular/core", + "//devtools/projects/ng-devtools/src/lib/application-services:settings", "//devtools/projects/ng-devtools/src/lib/application-services:settings_store", ], ) diff --git a/devtools/projects/ng-devtools/src/lib/application-services/test-utils/settings_mock.ts b/devtools/projects/ng-devtools/src/lib/application-services/test-utils/settings_mock.ts new file mode 100644 index 00000000000..c91e3f5ad9e --- /dev/null +++ b/devtools/projects/ng-devtools/src/lib/application-services/test-utils/settings_mock.ts @@ -0,0 +1,33 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {Provider, signal, WritableSignal} from '@angular/core'; +import {Settings} from '../settings'; +import {SettingsStore} from '../settings_store'; + +export class SettingsMock extends Settings { + routerGraphEnabled = signal(false); + showCommentNodes = signal(false); + signalGraphEnabled = signal(false); + timingAPIEnabled = signal(false); +} + +export const SETTINGS_MOCK: Provider[] = [ + { + provide: SettingsStore, + useClass: class { + create(config: unknown): WritableSignal { + return signal(null); + } + }, + }, + { + provide: Settings, + useClass: SettingsMock, + }, +]; diff --git a/devtools/projects/ng-devtools/src/lib/application-services/test-utils/settings_store_mock.ts b/devtools/projects/ng-devtools/src/lib/application-services/test-utils/settings_store_mock.ts deleted file mode 100644 index eb2f9f59c2f..00000000000 --- a/devtools/projects/ng-devtools/src/lib/application-services/test-utils/settings_store_mock.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {Provider, signal} from '@angular/core'; -import {SettingsStore} from '../settings_store'; - -export class SettingsStoreMock { - private readonly signals = new Map(); - - get(key: string, initialValue: unknown) { - const value = this.signals.get(key) ?? signal(initialValue); - this.signals.set(key, value); - return value; - } -} - -export const SETTINGS_STORE_MOCK: Provider = { - provide: SettingsStore, - useClass: SettingsStoreMock, -}; diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/BUILD.bazel b/devtools/projects/ng-devtools/src/lib/devtools-tabs/BUILD.bazel index 0c9b151e19c..b7d31a2f6d7 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/BUILD.bazel +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/BUILD.bazel @@ -27,6 +27,7 @@ ng_project( "//:node_modules/rxjs", "//devtools/projects/ng-devtools/src/lib/application-environment", "//devtools/projects/ng-devtools/src/lib/application-services:frame_manager", + "//devtools/projects/ng-devtools/src/lib/application-services:settings", "//devtools/projects/ng-devtools/src/lib/application-services:theme", "//devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer", "//devtools/projects/ng-devtools/src/lib/devtools-tabs/injector-tree:injector_tree", @@ -51,6 +52,7 @@ ts_test_library( "//devtools/projects/ng-devtools/src/lib/application-environment", "//devtools/projects/ng-devtools/src/lib/application-services:frame_manager", "//devtools/projects/ng-devtools/src/lib/application-services:theme", + "//devtools/projects/ng-devtools/src/lib/application-services/test-utils:settings_mock", "//devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer", "//devtools/projects/ng-devtools/src/lib/devtools-tabs/tab-update", "//devtools/projects/protocol", diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/devtools-tabs.component.html b/devtools/projects/ng-devtools/src/lib/devtools-tabs/devtools-tabs.component.html index eb5095657da..709e1736867 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/devtools-tabs.component.html +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/devtools-tabs.component.html @@ -130,7 +130,7 @@ [checked]="routerGraphEnabled()" (change)="setRouterGraph($event.checked)" /> - Enable Router Graph + Enable Router Tree } @if (supportedApis().signals) { diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/devtools-tabs.component.ts b/devtools/projects/ng-devtools/src/lib/devtools-tabs/devtools-tabs.component.ts index 22167eaeb1c..8ef301c8e1d 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/devtools-tabs.component.ts +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/devtools-tabs.component.ts @@ -40,6 +40,7 @@ import {ProfilerComponent} from './profiler/profiler.component'; import {RouterTreeComponent} from './router-tree/router-tree.component'; import {TransferStateComponent} from './transfer-state/transfer-state.component'; import {TabUpdate} from './tab-update/index'; +import {Settings} from '../application-services/settings'; type Tab = 'Components' | 'Profiler' | 'Router Tree' | 'Injector Tree' | 'Transfer State'; @@ -67,23 +68,29 @@ type Tab = 'Components' | 'Profiler' | 'Router Tree' | 'Injector Tree' | 'Transf changeDetection: ChangeDetectionStrategy.OnPush, }) export class DevToolsTabsComponent { + readonly applicationEnvironment = inject(ApplicationEnvironment); + readonly frameManager = inject(FrameManager); + readonly themeService = inject(ThemeService); + private readonly tabUpdate = inject(TabUpdate); + private readonly messageBus = inject>(MessageBus); + private readonly settings = inject(Settings); + readonly isHydrationEnabled = input(false); readonly supportedApis = input.required(); readonly frameSelected = output(); - readonly applicationEnvironment = inject(ApplicationEnvironment); readonly activeTab = signal('Components'); readonly inspectorRunning = signal(false); - readonly showCommentNodes = signal(false); - readonly routerGraphEnabled = signal(false); - readonly timingAPIEnabled = signal(false); - readonly signalGraphEnabled = signal(false); + + protected readonly showCommentNodes = this.settings.showCommentNodes; + protected readonly routerGraphEnabled = this.settings.routerGraphEnabled; + protected readonly timingAPIEnabled = this.settings.timingAPIEnabled; + protected readonly signalGraphEnabled = this.settings.signalGraphEnabled; readonly transferStateTabEnabled = signal(false); readonly componentExplorerView = signal(null); readonly providers = signal([]); readonly routes = signal([]); - readonly frameManager = inject(FrameManager); readonly snapToRoot = signal(false); @@ -123,27 +130,23 @@ export class DevToolsTabsComponent { readonly extensionVersion = signal('dev-build'); - public tabUpdate = inject(TabUpdate); - public themeService = inject(ThemeService); - private _messageBus = inject>(MessageBus); - constructor() { - this._messageBus.on('updateRouterTree', (routes: any[]) => { + this.messageBus.on('updateRouterTree', (routes: any[]) => { this.routes.set(routes || []); }); // Change the tab to Components, if an element is selected via the inspector. - this._messageBus.on('selectComponent', () => { + this.messageBus.on('selectComponent', () => { if (this.activeTab() !== 'Components') { this.changeTab('Components'); } }); - this._messageBus.on('latestComponentExplorerView', (view: ComponentExplorerView) => { + this.messageBus.on('latestComponentExplorerView', (view: ComponentExplorerView) => { this.componentExplorerView.set(view); }); - this._messageBus.on( + this.messageBus.on( 'latestInjectorProviders', (_: SerializedInjector, providers: SerializedProviderRecord[]) => { this.providers.set(providers); @@ -165,7 +168,7 @@ export class DevToolsTabsComponent { this.activeTab.set(tab); this.tabUpdate.notify(tab); if (tab === 'Router Tree') { - this._messageBus.emit('getRoutes'); + this.messageBus.emit('getRoutes'); this.snapToRoot.set(true); } } @@ -177,10 +180,10 @@ export class DevToolsTabsComponent { emitInspectorEvent(): void { if (this.inspectorRunning()) { - this._messageBus.emit('inspectorStart'); + this.messageBus.emit('inspectorStart'); } else { - this._messageBus.emit('inspectorEnd'); - this._messageBus.emit('removeHighlightOverlay'); + this.messageBus.emit('inspectorEnd'); + this.messageBus.emit('removeHighlightOverlay'); } } @@ -191,8 +194,8 @@ export class DevToolsTabsComponent { toggleTimingAPI(): void { this.timingAPIEnabled.update((state) => !state); this.timingAPIEnabled() - ? this._messageBus.emit('enableTimingAPI') - : this._messageBus.emit('disableTimingAPI'); + ? this.messageBus.emit('enableTimingAPI') + : this.messageBus.emit('disableTimingAPI'); } protected setRouterGraph(enabled: boolean): void { diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/devtools-tabs.spec.ts b/devtools/projects/ng-devtools/src/lib/devtools-tabs/devtools-tabs.spec.ts index 47907fbddfa..8a954ecd315 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/devtools-tabs.spec.ts +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/devtools-tabs.spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {Component} from '@angular/core'; +import {Component, signal} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {MatMenuModule} from '@angular/material/menu'; import {MatTooltip} from '@angular/material/tooltip'; @@ -20,6 +20,7 @@ import {DevToolsTabsComponent} from './devtools-tabs.component'; import {TabUpdate} from './tab-update/index'; import {DirectiveExplorerComponent} from './directive-explorer/directive-explorer.component'; import {FrameManager} from '../application-services/frame_manager'; +import {SETTINGS_MOCK} from '../application-services/test-utils/settings_mock'; @Component({ selector: 'ng-directive-explorer', @@ -41,6 +42,7 @@ describe('DevtoolsTabsComponent', () => { imports: [MatTooltip, MatMenuModule, DevToolsTabsComponent], providers: [ TabUpdate, + SETTINGS_MOCK, {provide: ThemeService, useFactory: () => ({currentTheme: new Subject()})}, {provide: MessageBus, useValue: messageBusMock}, {provide: ApplicationEnvironment, useValue: applicationEnvironmentMock}, diff --git a/devtools/projects/ng-devtools/src/public-api.ts b/devtools/projects/ng-devtools/src/public-api.ts index 918a5bb8480..f2d747a10df 100644 --- a/devtools/projects/ng-devtools/src/public-api.ts +++ b/devtools/projects/ng-devtools/src/public-api.ts @@ -13,3 +13,4 @@ export {DevToolsComponent} from './lib/devtools.component'; export * from './lib/application-operations'; export * from './lib/application-environment'; +export * from './lib/application-providers/settings_provider'; diff --git a/devtools/projects/shell-browser/src/app/app.config.ts b/devtools/projects/shell-browser/src/app/app.config.ts index 049ab3b0580..d1c27d07cf3 100644 --- a/devtools/projects/shell-browser/src/app/app.config.ts +++ b/devtools/projects/shell-browser/src/app/app.config.ts @@ -7,7 +7,7 @@ */ import {ApplicationConfig, provideZonelessChangeDetection} from '@angular/core'; -import {ApplicationEnvironment, ApplicationOperations} from '../../../ng-devtools'; +import {ApplicationEnvironment, ApplicationOperations, provideSettings} from '../../../ng-devtools'; import {ChromeApplicationEnvironment} from './chrome-application-environment'; import {ChromeApplicationOperations} from './chrome-application-operations'; @@ -39,5 +39,6 @@ export const appConfig: ApplicationConfig = { return new PriorityAwareMessageBus(new ChromeMessageBus(port)); }, }, + provideSettings(), ], }; diff --git a/devtools/src/app/app.config.ts b/devtools/src/app/app.config.ts index 23d50863852..35fb67f12fd 100644 --- a/devtools/src/app/app.config.ts +++ b/devtools/src/app/app.config.ts @@ -12,7 +12,11 @@ import { provideAppInitializer, } from '@angular/core'; import {provideRouter} from '@angular/router'; -import {ApplicationEnvironment, ApplicationOperations} from '../../projects/ng-devtools'; +import { + ApplicationEnvironment, + ApplicationOperations, + provideSettings, +} from '../../projects/ng-devtools'; import {DemoApplicationEnvironment} from '../demo-application-environment'; import {DemoApplicationOperations} from '../demo-application-operations'; @@ -45,5 +49,6 @@ export const appConfig: ApplicationConfig = { }, // We simulate a transfer state created by the server-side rendering. provideAppInitializer(async () => serializeTransferState()), + provideSettings(), ], };