mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
refactor(devtools): save user settings in the settings store (#62429)
Save user settings in the `SettingsStore`. NOTE: The theme is omitted since the change is not trivial and it will be handled in a separate PR. PR Close #62429
This commit is contained in:
committed by
Kristiyan Kostadinov
parent
1cdb54559d
commit
cb8d30a293
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
+33
@@ -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<unknown> {
|
||||
return signal<unknown>(null);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: Settings,
|
||||
useClass: SettingsMock,
|
||||
},
|
||||
];
|
||||
-25
@@ -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<string, unknown>();
|
||||
|
||||
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,
|
||||
};
|
||||
@@ -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",
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
[checked]="routerGraphEnabled()"
|
||||
(change)="setRouterGraph($event.checked)"
|
||||
/>
|
||||
<span class="ng-mat-menu-label-text">Enable Router Graph</span>
|
||||
<span class="ng-mat-menu-label-text">Enable Router Tree</span>
|
||||
</label>
|
||||
}
|
||||
@if (supportedApis().signals) {
|
||||
|
||||
@@ -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<Events>>(MessageBus);
|
||||
private readonly settings = inject(Settings);
|
||||
|
||||
readonly isHydrationEnabled = input(false);
|
||||
readonly supportedApis = input.required<SupportedApis>();
|
||||
readonly frameSelected = output<Frame>();
|
||||
|
||||
readonly applicationEnvironment = inject(ApplicationEnvironment);
|
||||
readonly activeTab = signal<Tab>('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<ComponentExplorerView | null>(null);
|
||||
readonly providers = signal<SerializedProviderRecord[]>([]);
|
||||
readonly routes = signal<Route[]>([]);
|
||||
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<Events>>(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 {
|
||||
|
||||
@@ -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<Theme>()})},
|
||||
{provide: MessageBus, useValue: messageBusMock},
|
||||
{provide: ApplicationEnvironment, useValue: applicationEnvironmentMock},
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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(),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -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(),
|
||||
],
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user