From b9ab24224405d0d7cbbeed4ee2da842f645c364d Mon Sep 17 00:00:00 2001 From: Riley Jones <78179109+rileyajones@users.noreply.github.com> Date: Mon, 26 Aug 2024 20:03:32 -0700 Subject: [PATCH] Unblock LSC - Patch 2 - Fix initializer of instance members that reference identifiers declared in the constructor (#6901) ## Motivation for features / changes There is an ongoing LSC cl/652971829 which changes how instance methods are set. The change is blocked because of our split codebase. This PR is intended as a replacement for go/tbpr/6883 --------- Co-authored-by: Chinthoorie <73375917+frost-cy@users.noreply.github.com> --- .../execution_data_container.ts | 163 +++--- .../views/graph/graph_container.ts | 12 +- .../source_files/source_files_container.ts | 17 +- .../stack_trace/stack_trace_container.ts | 171 +++--- .../views/timeline/timeline_container.ts | 102 ++-- .../core/views/hash_storage_container.ts | 6 +- .../webapp/core/views/page_title_container.ts | 70 +-- .../feature_flag_modal_trigger_container.ts | 9 +- .../header/dark_mode_toggle_container.ts | 10 +- .../header/plugin_selector_container.ts | 14 +- tensorboard/webapp/header/reload_container.ts | 22 +- tensorboard/webapp/metrics/effects/index.ts | 526 +++++++++--------- .../card_renderer/histogram_card_container.ts | 16 +- .../card_renderer/image_card_container.ts | 16 +- .../card_renderer/scalar_card_container.ts | 95 ++-- .../webapp/reloader/reloader_component.ts | 17 +- .../runs_selector/runs_selector_container.ts | 31 +- .../views/runs_table/filterbar_container.ts | 8 +- .../runs_table/regex_edit_dialog_container.ts | 38 +- .../_views/polymer_interop_container.ts | 6 +- .../_views/settings_button_container.ts | 6 +- .../_views/settings_dialog_container.ts | 12 +- 22 files changed, 745 insertions(+), 622 deletions(-) diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/execution_data_container.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/execution_data_container.ts index 7bf3586bd50..ea605413d2b 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/execution_data_container.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/execution_data_container.ts @@ -37,87 +37,104 @@ export class ExecutionDataContainer { @Input() focusedExecutionIndex!: number; - readonly focusedExecutionData$ = this.store.pipe( - select(getFocusedExecutionData) - ); + readonly focusedExecutionData$; - readonly tensorDebugMode$ = this.store.pipe( - select( - createSelector(getFocusedExecutionData, (execution: Execution | null) => { - if (execution === null) { - return TensorDebugMode.UNSPECIFIED; - } else { - return execution.tensor_debug_mode; - } - }) - ) - ); + readonly tensorDebugMode$; - readonly hasDebugTensorValues$ = this.store.pipe( - select( - createSelector(getFocusedExecutionData, (execution: Execution | null) => { - if (execution === null || execution.debug_tensor_values === null) { - return false; - } else { - for (const singleDebugTensorValues of execution.debug_tensor_values) { - if ( - singleDebugTensorValues !== null && - singleDebugTensorValues.length > 0 - ) { - return true; - } - } - return false; - } - }) - ) - ); + readonly hasDebugTensorValues$; + + readonly debugTensorValues$; - readonly debugTensorValues$ = this.store.pipe( - select( - createSelector(getFocusedExecutionData, (execution: Execution | null) => { - if (execution === null) { - return null; - } else { - return execution.debug_tensor_values; - } - }) - ) - ); + readonly debugTensorDtypes$; - readonly debugTensorDtypes$ = this.store.pipe( - select( - createSelector( - getFocusedExecutionData, - (execution: Execution | null): string[] | null => { - if (execution === null || execution.debug_tensor_values === null) { - return null; + constructor(private readonly store: Store) { + this.focusedExecutionData$ = this.store.pipe( + select(getFocusedExecutionData) + ); + this.tensorDebugMode$ = this.store.pipe( + select( + createSelector( + getFocusedExecutionData, + (execution: Execution | null) => { + if (execution === null) { + return TensorDebugMode.UNSPECIFIED; + } else { + return execution.tensor_debug_mode; + } } - if ( - execution.tensor_debug_mode !== TensorDebugMode.FULL_HEALTH && - execution.tensor_debug_mode !== TensorDebugMode.SHAPE - ) { - // TODO(cais): Add logic for other TensorDebugModes with dtype info. - return null; + ) + ) + ); + this.hasDebugTensorValues$ = this.store.pipe( + select( + createSelector( + getFocusedExecutionData, + (execution: Execution | null) => { + if (execution === null || execution.debug_tensor_values === null) { + return false; + } else { + for (const singleDebugTensorValues of execution.debug_tensor_values) { + if ( + singleDebugTensorValues !== null && + singleDebugTensorValues.length > 0 + ) { + return true; + } + } + return false; + } } - const dtypes: string[] = []; - for (const tensorValue of execution.debug_tensor_values) { - if (tensorValue === null) { - dtypes.push(UNKNOWN_DTYPE_NAME); + ) + ) + ); + this.debugTensorValues$ = this.store.pipe( + select( + createSelector( + getFocusedExecutionData, + (execution: Execution | null) => { + if (execution === null) { + return null; } else { - const dtypeEnum = String( - execution.tensor_debug_mode === TensorDebugMode.FULL_HEALTH - ? tensorValue[2] // tensor_debug_mode: FULL_HEALTH - : tensorValue[1] // tensor_debug_mode: SHAPE - ); - dtypes.push(DTYPE_ENUM_TO_NAME[dtypeEnum] || UNKNOWN_DTYPE_NAME); + return execution.debug_tensor_values; } } - return dtypes; - } + ) ) - ) - ); - - constructor(private readonly store: Store) {} + ); + this.debugTensorDtypes$ = this.store.pipe( + select( + createSelector( + getFocusedExecutionData, + (execution: Execution | null): string[] | null => { + if (execution === null || execution.debug_tensor_values === null) { + return null; + } + if ( + execution.tensor_debug_mode !== TensorDebugMode.FULL_HEALTH && + execution.tensor_debug_mode !== TensorDebugMode.SHAPE + ) { + // TODO(cais): Add logic for other TensorDebugModes with dtype info. + return null; + } + const dtypes: string[] = []; + for (const tensorValue of execution.debug_tensor_values) { + if (tensorValue === null) { + dtypes.push(UNKNOWN_DTYPE_NAME); + } else { + const dtypeEnum = String( + execution.tensor_debug_mode === TensorDebugMode.FULL_HEALTH + ? tensorValue[2] // tensor_debug_mode: FULL_HEALTH + : tensorValue[1] // tensor_debug_mode: SHAPE + ); + dtypes.push( + DTYPE_ENUM_TO_NAME[dtypeEnum] || UNKNOWN_DTYPE_NAME + ); + } + } + return dtypes; + } + ) + ) + ); + } } diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/graph_container.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/graph_container.ts index dcf4c360b77..1bdbc328a7f 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/graph_container.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/graph_container.ts @@ -34,15 +34,19 @@ import {State} from '../../store/debugger_types'; `, }) export class GraphContainer { - readonly opInfo$ = this.store.pipe(select(getFocusedGraphOpInfo)); + readonly opInfo$; - readonly inputOps$ = this.store.pipe(select(getFocusedGraphOpInputs)); + readonly inputOps$; - readonly consumerOps$ = this.store.pipe(select(getFocusedGraphOpConsumers)); + readonly consumerOps$; onGraphOpNavigate(event: {graph_id: string; op_name: string}) { this.store.dispatch(graphOpFocused(event)); } - constructor(private readonly store: Store) {} + constructor(private readonly store: Store) { + this.opInfo$ = this.store.pipe(select(getFocusedGraphOpInfo)); + this.inputOps$ = this.store.pipe(select(getFocusedGraphOpInputs)); + this.consumerOps$ = this.store.pipe(select(getFocusedGraphOpConsumers)); + } } diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_container.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_container.ts index d26363d88f6..f83160c2ce6 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_container.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_container.ts @@ -34,14 +34,17 @@ import {State as DebuggerState} from '../../store/debugger_types'; `, }) export class SourceFilesContainer { - constructor(private readonly store: Store) {} + constructor(private readonly store: Store) { + this.focusedSourceFileContent$ = this.store.select( + getFocusedSourceFileContent + ); + this.focusedSourceLineSpec$ = this.store.select(getFocusedSourceLineSpec); + this.useDarkMode$ = this.store.select(getDarkModeEnabled); + } - readonly focusedSourceFileContent$ = this.store.select( - getFocusedSourceFileContent - ); + readonly focusedSourceFileContent$; - readonly focusedSourceLineSpec$ = this.store.select(getFocusedSourceLineSpec); + readonly focusedSourceLineSpec$; - readonly useDarkMode$: Observable = - this.store.select(getDarkModeEnabled); + readonly useDarkMode$: Observable; } diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_container.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_container.ts index 2e95ce46f06..33cbe347b69 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_container.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_container.ts @@ -41,95 +41,106 @@ import {StackFrameForDisplay} from './stack_trace_component'; `, }) export class StackTraceContainer { - readonly codeLocationType$ = this.store.pipe( - select( - createSelector( - getCodeLocationOrigin, - (originInfo): CodeLocationType | null => { - return originInfo === null ? null : originInfo.codeLocationType; - } - ) - ) - ); + readonly codeLocationType$; + + readonly opType$; - readonly opType$ = this.store.pipe( - select( - createSelector(getCodeLocationOrigin, (originInfo): string | null => { - return originInfo === null ? null : originInfo.opType; - }) - ) - ); + readonly opName$; - readonly opName$ = this.store.pipe( - select( - createSelector(getCodeLocationOrigin, (originInfo): string | null => { - if ( - originInfo === null || - originInfo.codeLocationType !== CodeLocationType.GRAPH_OP_CREATION - ) { - return null; - } - return originInfo.opName; - }) - ) - ); + readonly executionIndex$; - readonly executionIndex$ = this.store.pipe( - select( - createSelector(getCodeLocationOrigin, (originInfo): number | null => { - if ( - originInfo === null || - originInfo.codeLocationType !== CodeLocationType.EXECUTION - ) { - return null; - } - return originInfo.executionIndex; - }) - ) - ); + readonly stickToBottommostFrameInFocusedFile$; - readonly stickToBottommostFrameInFocusedFile$ = this.store.pipe( - select(getStickToBottommostFrameInFocusedFile) - ); + readonly stackFramesForDisplay$; - readonly stackFramesForDisplay$ = this.store.pipe( - select( - createSelector( - getFocusedStackFrames, - getFocusedSourceLineSpec, - (stackFrames, focusedSourceLineSpec): StackFrameForDisplay[] | null => { - if (stackFrames === null) { + constructor(private readonly store: Store) { + this.codeLocationType$ = this.store.pipe( + select( + createSelector( + getCodeLocationOrigin, + (originInfo): CodeLocationType | null => { + return originInfo === null ? null : originInfo.codeLocationType; + } + ) + ) + ); + this.opType$ = this.store.pipe( + select( + createSelector(getCodeLocationOrigin, (originInfo): string | null => { + return originInfo === null ? null : originInfo.opType; + }) + ) + ); + this.opName$ = this.store.pipe( + select( + createSelector(getCodeLocationOrigin, (originInfo): string | null => { + if ( + originInfo === null || + originInfo.codeLocationType !== CodeLocationType.GRAPH_OP_CREATION + ) { return null; } - const output: StackFrameForDisplay[] = []; - // Correctly label all the stack frames for display. - for (const stackFrame of stackFrames) { - const {host_name, file_path, lineno, function_name} = stackFrame; - const pathItems = file_path.split('/'); - const concise_file_path = pathItems[pathItems.length - 1]; - const belongsToFocusedFile = - focusedSourceLineSpec !== null && - host_name === focusedSourceLineSpec.host_name && - file_path === focusedSourceLineSpec.file_path; - const focused = - belongsToFocusedFile && lineno === focusedSourceLineSpec!.lineno; - output.push({ - host_name, - file_path, - concise_file_path, - lineno, - function_name, - belongsToFocusedFile, - focused, - }); + return originInfo.opName; + }) + ) + ); + this.executionIndex$ = this.store.pipe( + select( + createSelector(getCodeLocationOrigin, (originInfo): number | null => { + if ( + originInfo === null || + originInfo.codeLocationType !== CodeLocationType.EXECUTION + ) { + return null; } - return output; - } + return originInfo.executionIndex; + }) ) - ) - ); - - constructor(private readonly store: Store) {} + ); + this.stickToBottommostFrameInFocusedFile$ = this.store.pipe( + select(getStickToBottommostFrameInFocusedFile) + ); + this.stackFramesForDisplay$ = this.store.pipe( + select( + createSelector( + getFocusedStackFrames, + getFocusedSourceLineSpec, + ( + stackFrames, + focusedSourceLineSpec + ): StackFrameForDisplay[] | null => { + if (stackFrames === null) { + return null; + } + const output: StackFrameForDisplay[] = []; + // Correctly label all the stack frames for display. + for (const stackFrame of stackFrames) { + const {host_name, file_path, lineno, function_name} = stackFrame; + const pathItems = file_path.split('/'); + const concise_file_path = pathItems[pathItems.length - 1]; + const belongsToFocusedFile = + focusedSourceLineSpec !== null && + host_name === focusedSourceLineSpec.host_name && + file_path === focusedSourceLineSpec.file_path; + const focused = + belongsToFocusedFile && + lineno === focusedSourceLineSpec!.lineno; + output.push({ + host_name, + file_path, + concise_file_path, + lineno, + function_name, + belongsToFocusedFile, + focused, + }); + } + return output; + } + ) + ) + ); + } onSourceLineClicked(args: StackFrameForDisplay) { const {host_name, file_path, lineno, function_name} = args; diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/timeline/timeline_container.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/timeline/timeline_container.ts index 525bc52b180..c203f623d48 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/timeline/timeline_container.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/timeline/timeline_container.ts @@ -108,61 +108,73 @@ function getExecutionDigestForDisplay( changeDetection: ChangeDetectionStrategy.OnPush, }) export class TimelineContainer { - readonly activeRunId$ = this.store.pipe(select(getActiveRunId)); - - readonly loadingNumExecutions$ = this.store.pipe( - select( - createSelector(getNumExecutionsLoaded, (loaded) => { - return loaded.state == DataLoadState.LOADING; - }) - ) - ); + readonly activeRunId$; - readonly scrollBeginIndex$ = this.store.pipe( - select(getExecutionScrollBeginIndex) - ); + readonly loadingNumExecutions$; - readonly scrollBeginIndexUpperLimit$ = this.store.pipe( - select( - createSelector( - getNumExecutions, - getDisplayCount, - (numExecutions, displayCount) => { - return Math.max(0, numExecutions - displayCount); - } - ) - ) - ); + readonly scrollBeginIndex$; - readonly pageSize$ = this.store.pipe(select(getExecutionPageSize)); + readonly scrollBeginIndexUpperLimit$; - readonly displayCount$ = this.store.pipe(select(getDisplayCount)); + readonly pageSize$; - readonly displayExecutionDigests$ = this.store.pipe( - select( - createSelector(getVisibleExecutionDigests, (visibleDigests) => { - return visibleDigests.map((digest) => - getExecutionDigestForDisplay(digest) - ); - }) - ) - ); + readonly displayCount$; - readonly displayFocusedAlertTypes$ = this.store.pipe( - select(getFocusAlertTypesOfVisibleExecutionDigests) - ); + readonly displayExecutionDigests$; - readonly focusedExecutionIndex$ = this.store.pipe( - select(getFocusedExecutionIndex) - ); + readonly displayFocusedAlertTypes$; - readonly focusedExecutionDisplayIndex$ = this.store.pipe( - select(getFocusedExecutionDisplayIndex) - ); + readonly focusedExecutionIndex$; - readonly numExecutions$ = this.store.pipe(select(getNumExecutions)); + readonly focusedExecutionDisplayIndex$; - constructor(private readonly store: Store) {} + readonly numExecutions$; + + constructor(private readonly store: Store) { + this.activeRunId$ = this.store.pipe(select(getActiveRunId)); + this.loadingNumExecutions$ = this.store.pipe( + select( + createSelector(getNumExecutionsLoaded, (loaded) => { + return loaded.state == DataLoadState.LOADING; + }) + ) + ); + this.scrollBeginIndex$ = this.store.pipe( + select(getExecutionScrollBeginIndex) + ); + this.scrollBeginIndexUpperLimit$ = this.store.pipe( + select( + createSelector( + getNumExecutions, + getDisplayCount, + (numExecutions, displayCount) => { + return Math.max(0, numExecutions - displayCount); + } + ) + ) + ); + this.pageSize$ = this.store.pipe(select(getExecutionPageSize)); + this.displayCount$ = this.store.pipe(select(getDisplayCount)); + this.displayExecutionDigests$ = this.store.pipe( + select( + createSelector(getVisibleExecutionDigests, (visibleDigests) => { + return visibleDigests.map((digest) => + getExecutionDigestForDisplay(digest) + ); + }) + ) + ); + this.displayFocusedAlertTypes$ = this.store.pipe( + select(getFocusAlertTypesOfVisibleExecutionDigests) + ); + this.focusedExecutionIndex$ = this.store.pipe( + select(getFocusedExecutionIndex) + ); + this.focusedExecutionDisplayIndex$ = this.store.pipe( + select(getFocusedExecutionDisplayIndex) + ); + this.numExecutions$ = this.store.pipe(select(getNumExecutions)); + } onNavigateLeft() { this.store.dispatch(executionScrollLeft()); diff --git a/tensorboard/webapp/core/views/hash_storage_container.ts b/tensorboard/webapp/core/views/hash_storage_container.ts index a5dab2d5271..4b1439928b4 100644 --- a/tensorboard/webapp/core/views/hash_storage_container.ts +++ b/tensorboard/webapp/core/views/hash_storage_container.ts @@ -38,9 +38,11 @@ import {ChangedProp} from './hash_storage_component'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class HashStorageContainer { - readonly activePluginId$ = this.store.pipe(select(getActivePlugin)); + readonly activePluginId$; - constructor(private readonly store: Store) {} + constructor(private readonly store: Store) { + this.activePluginId$ = this.store.pipe(select(getActivePlugin)); + } onValueChanged(change: {prop: ChangedProp; value: string}) { switch (change.prop) { diff --git a/tensorboard/webapp/core/views/page_title_container.ts b/tensorboard/webapp/core/views/page_title_container.ts index c9300415b7c..8cf5927b0ca 100644 --- a/tensorboard/webapp/core/views/page_title_container.ts +++ b/tensorboard/webapp/core/views/page_title_container.ts @@ -57,46 +57,48 @@ const DEFAULT_BRAND_NAME = 'TensorBoard'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class PageTitleContainer { - private readonly getExperimentId$ = this.store - .select(getExperimentIdsFromRoute) - .pipe( - map((experimentIds) => { - return experimentIds?.[0]; - }) - ); + private readonly getExperimentId$; - private readonly experimentName$ = this.getExperimentId$.pipe( - filter(Boolean), - mergeMap((experimentId) => { - // Selectors with props are deprecated (getExperiment): - // https://github.com/ngrx/platform/issues/2980 - // tslint:disable-next-line:deprecation - return this.store.select(getExperiment, {experimentId}); - }), - map((experiment) => (experiment ? experiment.name : null)) - ); + private readonly experimentName$; - readonly title$ = this.store.select(getEnvironment).pipe( - combineLatestWith(this.store.select(getRouteKind), this.experimentName$), - map(([env, routeKind, experimentName]) => { - const tbBrandName = this.customBrandName || DEFAULT_BRAND_NAME; - if (env.window_title) { - // (it's an empty string when the `--window_title` flag is not set) - return env.window_title; - } - if (routeKind === RouteKind.EXPERIMENT && experimentName) { - return `${experimentName} - ${tbBrandName}`; - } - return tbBrandName; - }), - startWith(this.customBrandName || DEFAULT_BRAND_NAME), - distinctUntilChanged() - ); + readonly title$; constructor( private readonly store: Store, @Optional() @Inject(TB_BRAND_NAME) private readonly customBrandName: string | null - ) {} + ) { + this.getExperimentId$ = this.store.select(getExperimentIdsFromRoute).pipe( + map((experimentIds) => { + return experimentIds?.[0]; + }) + ); + this.experimentName$ = this.getExperimentId$.pipe( + filter(Boolean), + mergeMap((experimentId) => { + // Selectors with props are deprecated (getExperiment): + // https://github.com/ngrx/platform/issues/2980 + // tslint:disable-next-line:deprecation + return this.store.select(getExperiment, {experimentId}); + }), + map((experiment) => (experiment ? experiment.name : null)) + ); + this.title$ = this.store.select(getEnvironment).pipe( + combineLatestWith(this.store.select(getRouteKind), this.experimentName$), + map(([env, routeKind, experimentName]) => { + const tbBrandName = this.customBrandName || DEFAULT_BRAND_NAME; + if (env.window_title) { + // (it's an empty string when the `--window_title` flag is not set) + return env.window_title; + } + if (routeKind === RouteKind.EXPERIMENT && experimentName) { + return `${experimentName} - ${tbBrandName}`; + } + return tbBrandName; + }), + startWith(this.customBrandName || DEFAULT_BRAND_NAME), + distinctUntilChanged() + ); + } } diff --git a/tensorboard/webapp/feature_flag/views/feature_flag_modal_trigger_container.ts b/tensorboard/webapp/feature_flag/views/feature_flag_modal_trigger_container.ts index fba1f843ad6..e7376ce4062 100644 --- a/tensorboard/webapp/feature_flag/views/feature_flag_modal_trigger_container.ts +++ b/tensorboard/webapp/feature_flag/views/feature_flag_modal_trigger_container.ts @@ -38,14 +38,13 @@ export class FeatureFlagModalTriggerContainer implements OnInit, OnDestroy { // Allow the dialog component type to be overridden for testing purposes. featureFlagDialogType: ComponentType = FeatureFlagDialogContainer; - readonly showFeatureFlags$ = this.store.select(getShowFlagsEnabled); + readonly showFeatureFlags$; private featureFlagsDialog?: MatDialogRef; private ngUnsubscribe = new Subject(); - constructor( - private readonly store: Store, - private dialog: MatDialog - ) {} + constructor(private readonly store: Store, private dialog: MatDialog) { + this.showFeatureFlags$ = this.store.select(getShowFlagsEnabled); + } ngOnInit() { this.showFeatureFlags$ diff --git a/tensorboard/webapp/header/dark_mode_toggle_container.ts b/tensorboard/webapp/header/dark_mode_toggle_container.ts index 2107886c4eb..15d77ffda48 100644 --- a/tensorboard/webapp/header/dark_mode_toggle_container.ts +++ b/tensorboard/webapp/header/dark_mode_toggle_container.ts @@ -33,9 +33,10 @@ import {DarkModeOverride} from './dark_mode_toggle_component'; `, }) export class DarkModeToggleContainer { - readonly darkModeOverride$: Observable = this.store - .select(getEnableDarkModeOverride) - .pipe( + readonly darkModeOverride$: Observable; + + constructor(private readonly store: Store) { + this.darkModeOverride$ = this.store.select(getEnableDarkModeOverride).pipe( map((override: boolean | null): DarkModeOverride => { if (override === null) return DarkModeOverride.DEFAULT; return override @@ -43,8 +44,7 @@ export class DarkModeToggleContainer { : DarkModeOverride.DARK_MODE_OFF; }) ); - - constructor(private readonly store: Store) {} + } changeDarkMode(newOverride: DarkModeOverride) { let enableDarkMode: boolean | null = null; diff --git a/tensorboard/webapp/header/plugin_selector_container.ts b/tensorboard/webapp/header/plugin_selector_container.ts index d44c1318644..16a6b798167 100644 --- a/tensorboard/webapp/header/plugin_selector_container.ts +++ b/tensorboard/webapp/header/plugin_selector_container.ts @@ -40,11 +40,15 @@ const getDisabledPlugins = createSelector( `, }) export class PluginSelectorContainer { - readonly activePlugin$ = this.store.pipe(select(getActivePlugin)); - readonly plugins$ = this.store.pipe(select(getUiPlugins)); - readonly disabledPlugins$ = this.store.pipe(select(getDisabledPlugins)); - - constructor(private readonly store: Store) {} + readonly activePlugin$; + readonly plugins$; + readonly disabledPlugins$; + + constructor(private readonly store: Store) { + this.activePlugin$ = this.store.pipe(select(getActivePlugin)); + this.plugins$ = this.store.pipe(select(getUiPlugins)); + this.disabledPlugins$ = this.store.pipe(select(getDisabledPlugins)); + } onPluginSelectionChange(pluginId: PluginId) { this.store.dispatch(changePlugin({plugin: pluginId})); diff --git a/tensorboard/webapp/header/reload_container.ts b/tensorboard/webapp/header/reload_container.ts index 9f94d0b07d0..3199e937d17 100644 --- a/tensorboard/webapp/header/reload_container.ts +++ b/tensorboard/webapp/header/reload_container.ts @@ -77,24 +77,22 @@ const isReloadDisabledByPlugin = createSelector( ], }) export class ReloadContainer { - readonly reloadDisabled$: Observable = this.store.select( - isReloadDisabledByPlugin - ); + readonly reloadDisabled$: Observable; - isReloading$: Observable = this.store - .select(getCoreDataLoadedState) - .pipe( + isReloading$: Observable; + + lastLoadedTimeInMs$: Observable; + + constructor(private readonly store: Store) { + this.reloadDisabled$ = this.store.select(isReloadDisabledByPlugin); + this.isReloading$ = this.store.select(getCoreDataLoadedState).pipe( combineLatestWith(this.reloadDisabled$), map(([loadState, reloadDisabled]) => { return !reloadDisabled && loadState === DataLoadState.LOADING; }) ); - - lastLoadedTimeInMs$: Observable = this.store.select( - getAppLastLoadedTimeInMs - ); - - constructor(private readonly store: Store) {} + this.lastLoadedTimeInMs$ = this.store.select(getAppLastLoadedTimeInMs); + } triggerReload() { this.store.dispatch(manualReload()); diff --git a/tensorboard/webapp/metrics/effects/index.ts b/tensorboard/webapp/metrics/effects/index.ts index b76a2b0d57f..4ee3d22f973 100644 --- a/tensorboard/webapp/metrics/effects/index.ts +++ b/tensorboard/webapp/metrics/effects/index.ts @@ -72,13 +72,6 @@ const initAction = createAction('[Metrics Effects] Init'); @Injectable() export class MetricsEffects implements OnInitEffects { - constructor( - private readonly actions$: Actions, - private readonly store: Store, - private readonly metricsDataSource: MetricsDataSource, - private readonly savedPinsDataSource: SavedPinsDataSource - ) {} - /** @export */ ngrxOnInitEffects(): Action { return initAction(); @@ -95,66 +88,11 @@ export class MetricsEffects implements OnInitEffects { * first `activePlugin` set. * [App Routing] Navigated - experiment id updates. */ - private readonly dashboardShownWithoutData$ = this.actions$.pipe( - ofType( - initAction, - coreActions.changePlugin, - coreActions.pluginsListingLoaded, - routingActions.navigated - ), - withLatestFrom( - this.store.select(getActivePlugin), - this.store.select(getMetricsTagMetadataLoadState) - ), - filter(([, activePlugin, tagLoadState]) => { - return ( - activePlugin === METRICS_PLUGIN_ID && - tagLoadState.state === DataLoadState.NOT_LOADED - ); - }) - ); - - private readonly reloadRequestedWhileShown$ = this.actions$.pipe( - ofType(coreActions.reload, coreActions.manualReload), - withLatestFrom(this.store.select(getActivePlugin)), - filter(([, activePlugin]) => { - return activePlugin === METRICS_PLUGIN_ID; - }) - ); - - private readonly loadTagMetadata$ = merge( - this.dashboardShownWithoutData$, - this.reloadRequestedWhileShown$ - ).pipe( - withLatestFrom( - this.store.select(getMetricsTagMetadataLoadState), - this.store.select(selectors.getExperimentIdsFromRoute) - ), - filter(([, tagLoadState, experimentIds]) => { - /** - * When `experimentIds` is null, the actual ids have not - * appeared in the store yet. - */ - return ( - tagLoadState.state !== DataLoadState.LOADING && experimentIds !== null - ); - }), - throttleTime(10), - tap(() => { - this.store.dispatch(actions.metricsTagMetadataRequested()); - }), - switchMap(([, , experimentIds]) => { - return this.metricsDataSource.fetchTagMetadata(experimentIds!).pipe( - tap((tagMetadata: TagMetadata) => { - this.store.dispatch(actions.metricsTagMetadataLoaded({tagMetadata})); - }), - catchError(() => { - this.store.dispatch(actions.metricsTagMetadataFailed()); - return of(null); - }) - ); - }) - ); + private readonly dashboardShownWithoutData$; + + private readonly reloadRequestedWhileShown$; + + private readonly loadTagMetadata$; private getVisibleCardFetchInfos(): Observable { const visibleCardIds$ = this.store.select(selectors.getVisibleCardIdSet); @@ -227,161 +165,19 @@ export class MetricsEffects implements OnInitEffects { ); } - private readonly visibleCardsWithoutDataChanged$ = this.actions$.pipe( - ofType(actions.cardVisibilityChanged), - withLatestFrom(this.getVisibleCardFetchInfos()), - map(([, fetchInfos]) => { - return fetchInfos.filter((fetchInfo) => { - return fetchInfo.loadState === DataLoadState.NOT_LOADED; - }); - }) - ); - - private readonly visibleCardsReloaded$ = this.reloadRequestedWhileShown$.pipe( - withLatestFrom(this.getVisibleCardFetchInfos()), - map(([, fetchInfos]) => { - return fetchInfos.filter((fetchInfo) => { - return fetchInfo.loadState !== DataLoadState.LOADING; - }); - }) - ); - - private readonly loadTimeSeries$ = merge( - this.visibleCardsWithoutDataChanged$, - this.visibleCardsReloaded$ - ).pipe( - filter((fetchInfos) => fetchInfos.length > 0), - - // Ignore card visibility events until we have non-null - // experimentIds. - withLatestFrom( - this.store - .select(selectors.getExperimentIdsFromRoute) - .pipe(filter((experimentIds) => experimentIds !== null)) - ), - mergeMap(([fetchInfos, experimentIds]) => { - return this.fetchTimeSeriesForCards(fetchInfos, experimentIds!); - }) - ); - - private readonly addOrRemovePin$ = this.actions$.pipe( - ofType(actions.cardPinStateToggled), - withLatestFrom( - this.getVisibleCardFetchInfos(), - this.store.select(selectors.getEnableGlobalPins), - this.store.select(selectors.getShouldPersistSettings), - this.store.select(selectors.getMetricsSavingPinsEnabled) - ), - filter( - ([ - , - , - enableGlobalPinsFeature, - shouldPersistSettings, - isMetricsSavingPinsEnabled, - ]) => - enableGlobalPinsFeature && - shouldPersistSettings && - isMetricsSavingPinsEnabled - ), - tap(([{cardId, canCreateNewPins, wasPinned}, fetchInfos]) => { - const card = fetchInfos.find((value) => value.id === cardId); - // Saving only scalar pinned cards. - if (!card || card.plugin !== PluginType.SCALARS) { - return; - } - if (wasPinned) { - this.savedPinsDataSource.removeScalarPin(card.tag); - } else if (canCreateNewPins) { - this.savedPinsDataSource.saveScalarPin(card.tag); - } - }) - ); - - private readonly loadSavedPins$ = this.actions$.pipe( - // Should be dispatch before stateRehydratedFromUrl. - ofType(initAction), - withLatestFrom( - this.store.select(selectors.getEnableGlobalPins), - this.store.select(selectors.getShouldPersistSettings), - this.store.select(selectors.getMetricsSavingPinsEnabled) - ), - filter( - ([ - , - enableGlobalPinsFeature, - shouldPersistSettings, - isMetricsSavingPinsEnabled, - ]) => - enableGlobalPinsFeature && - shouldPersistSettings && - isMetricsSavingPinsEnabled - ), - tap(() => { - const tags = this.savedPinsDataSource.getSavedScalarPins(); - if (!tags || tags.length === 0) { - return; - } - const unresolvedPinnedCards = tags.map((tag) => ({ - plugin: PluginType.SCALARS, - tag: tag, - })); - this.store.dispatch( - actions.metricsUnresolvedPinnedCardsFromLocalStorageAdded({ - cards: unresolvedPinnedCards, - }) - ); - }) - ); - - private readonly removeAllPins$ = this.actions$.pipe( - ofType(actions.metricsClearAllPinnedCards), - withLatestFrom( - this.store.select(selectors.getEnableGlobalPins), - this.store.select(selectors.getShouldPersistSettings), - this.store.select(selectors.getMetricsSavingPinsEnabled) - ), - filter( - ([ - , - enableGlobalPinsFeature, - shouldPersistSettings, - isMetricsSavingPinsEnabled, - ]) => - enableGlobalPinsFeature && - shouldPersistSettings && - isMetricsSavingPinsEnabled - ), - tap(() => { - this.savedPinsDataSource.removeAllScalarPins(); - }) - ); - - private readonly addOrRemovePinsOnToggle$ = this.actions$.pipe( - ofType(actions.metricsEnableSavingPinsToggled), - withLatestFrom( - this.store.select(selectors.getPinnedCardsWithMetadata), - this.store.select(selectors.getEnableGlobalPins), - this.store.select(selectors.getShouldPersistSettings), - this.store.select(selectors.getMetricsSavingPinsEnabled) - ), - filter( - ([, , enableGlobalPins, getShouldPersistSettings]) => - enableGlobalPins && getShouldPersistSettings - ), - tap(([, pinnedCards, , , getMetricsSavingPinsEnabled]) => { - if (getMetricsSavingPinsEnabled) { - const tags: Tag[] = pinnedCards - .map((card) => { - return card.plugin === PluginType.SCALARS ? card.tag : null; - }) - .filter((v): v is Tag => v !== null); - this.savedPinsDataSource.saveScalarPins(tags); - } else { - this.savedPinsDataSource.removeAllScalarPins(); - } - }) - ); + private readonly visibleCardsWithoutDataChanged$; + + private readonly visibleCardsReloaded$; + + private readonly loadTimeSeries$; + + private readonly addOrRemovePin$; + + private readonly loadSavedPins$; + + private readonly removeAllPins$; + + private readonly addOrRemovePinsOnToggle$; /** * In general, this effect dispatch the following actions: @@ -403,39 +199,267 @@ export class MetricsEffects implements OnInitEffects { * - fetchTimeSeriesFailed */ /** @export */ - readonly dataEffects$ = createEffect( - () => { - return merge( - /** - * Subscribes to: dashboard shown, route navigation, reloads. - */ - this.loadTagMetadata$, + readonly dataEffects$; - /** - * Subscribes to: card visibility, reloads. - */ - this.loadTimeSeries$, + constructor( + private readonly actions$: Actions, + private readonly store: Store, + private readonly metricsDataSource: MetricsDataSource, + private readonly savedPinsDataSource: SavedPinsDataSource + ) { + this.dashboardShownWithoutData$ = actions$.pipe( + ofType( + initAction, + coreActions.changePlugin, + coreActions.pluginsListingLoaded, + routingActions.navigated + ), + withLatestFrom( + this.store.select(getActivePlugin), + this.store.select(getMetricsTagMetadataLoadState) + ), + filter(([, activePlugin, tagLoadState]) => { + return ( + activePlugin === METRICS_PLUGIN_ID && + tagLoadState.state === DataLoadState.NOT_LOADED + ); + }) + ); + this.reloadRequestedWhileShown$ = actions$.pipe( + ofType(coreActions.reload, coreActions.manualReload), + withLatestFrom(this.store.select(getActivePlugin)), + filter(([, activePlugin]) => { + return activePlugin === METRICS_PLUGIN_ID; + }) + ); + + this.loadTagMetadata$ = merge( + this.dashboardShownWithoutData$, + this.reloadRequestedWhileShown$ + ).pipe( + withLatestFrom( + this.store.select(getMetricsTagMetadataLoadState), + this.store.select(selectors.getExperimentIdsFromRoute) + ), + filter(([, tagLoadState, experimentIds]) => { /** - * Subscribes to: cardPinStateToggled. - */ - this.addOrRemovePin$, - /** - * Subscribes to: dashboard shown (initAction). - */ - this.loadSavedPins$, - /** - * Subscribes to: metricsClearAllPinnedCards. - */ - this.removeAllPins$, - /** - * Subscribes to: metricsEnableSavingPinsToggled. + * When `experimentIds` is null, the actual ids have not + * appeared in the store yet. */ - this.addOrRemovePinsOnToggle$ - ); - }, - {dispatch: false} - ); + return ( + tagLoadState.state !== DataLoadState.LOADING && experimentIds !== null + ); + }), + throttleTime(10), + tap(() => { + this.store.dispatch(actions.metricsTagMetadataRequested()); + }), + switchMap(([, , experimentIds]) => { + return this.metricsDataSource.fetchTagMetadata(experimentIds!).pipe( + tap((tagMetadata: TagMetadata) => { + this.store.dispatch( + actions.metricsTagMetadataLoaded({tagMetadata}) + ); + }), + catchError(() => { + this.store.dispatch(actions.metricsTagMetadataFailed()); + return of(null); + }) + ); + }) + ); + + this.visibleCardsWithoutDataChanged$ = this.actions$.pipe( + ofType(actions.cardVisibilityChanged), + withLatestFrom(this.getVisibleCardFetchInfos()), + map(([, fetchInfos]) => { + return fetchInfos.filter((fetchInfo) => { + return fetchInfo.loadState === DataLoadState.NOT_LOADED; + }); + }) + ); + + this.visibleCardsReloaded$ = this.reloadRequestedWhileShown$.pipe( + withLatestFrom(this.getVisibleCardFetchInfos()), + map(([, fetchInfos]) => { + return fetchInfos.filter((fetchInfo) => { + return fetchInfo.loadState !== DataLoadState.LOADING; + }); + }) + ); + + this.loadTimeSeries$ = merge( + this.visibleCardsWithoutDataChanged$, + this.visibleCardsReloaded$ + ).pipe( + filter((fetchInfos) => fetchInfos.length > 0), + + // Ignore card visibility events until we have non-null + // experimentIds. + withLatestFrom( + this.store + .select(selectors.getExperimentIdsFromRoute) + .pipe(filter((experimentIds) => experimentIds !== null)) + ), + mergeMap(([fetchInfos, experimentIds]) => { + return this.fetchTimeSeriesForCards(fetchInfos, experimentIds!); + }) + ); + + this.addOrRemovePin$ = this.actions$.pipe( + ofType(actions.cardPinStateToggled), + withLatestFrom( + this.getVisibleCardFetchInfos(), + this.store.select(selectors.getEnableGlobalPins), + this.store.select(selectors.getShouldPersistSettings), + this.store.select(selectors.getMetricsSavingPinsEnabled) + ), + filter( + ([ + , + , + enableGlobalPinsFeature, + shouldPersistSettings, + isMetricsSavingPinsEnabled, + ]) => + enableGlobalPinsFeature && + shouldPersistSettings && + isMetricsSavingPinsEnabled + ), + tap(([{cardId, canCreateNewPins, wasPinned}, fetchInfos]) => { + const card = fetchInfos.find((value) => value.id === cardId); + // Saving only scalar pinned cards. + if (!card || card.plugin !== PluginType.SCALARS) { + return; + } + if (wasPinned) { + this.savedPinsDataSource.removeScalarPin(card.tag); + } else if (canCreateNewPins) { + this.savedPinsDataSource.saveScalarPin(card.tag); + } + }) + ); + + this.loadSavedPins$ = this.actions$.pipe( + // Should be dispatch before stateRehydratedFromUrl. + ofType(initAction), + withLatestFrom( + this.store.select(selectors.getEnableGlobalPins), + this.store.select(selectors.getShouldPersistSettings), + this.store.select(selectors.getMetricsSavingPinsEnabled) + ), + filter( + ([ + , + enableGlobalPinsFeature, + shouldPersistSettings, + isMetricsSavingPinsEnabled, + ]) => + enableGlobalPinsFeature && + shouldPersistSettings && + isMetricsSavingPinsEnabled + ), + tap(() => { + const tags = this.savedPinsDataSource.getSavedScalarPins(); + if (!tags || tags.length === 0) { + return; + } + const unresolvedPinnedCards = tags.map((tag) => ({ + plugin: PluginType.SCALARS, + tag: tag, + })); + this.store.dispatch( + actions.metricsUnresolvedPinnedCardsFromLocalStorageAdded({ + cards: unresolvedPinnedCards, + }) + ); + }) + ); + + this.removeAllPins$ = this.actions$.pipe( + ofType(actions.metricsClearAllPinnedCards), + withLatestFrom( + this.store.select(selectors.getEnableGlobalPins), + this.store.select(selectors.getShouldPersistSettings), + this.store.select(selectors.getMetricsSavingPinsEnabled) + ), + filter( + ([ + , + enableGlobalPinsFeature, + shouldPersistSettings, + isMetricsSavingPinsEnabled, + ]) => + enableGlobalPinsFeature && + shouldPersistSettings && + isMetricsSavingPinsEnabled + ), + tap(() => { + this.savedPinsDataSource.removeAllScalarPins(); + }) + ); + + this.addOrRemovePinsOnToggle$ = this.actions$.pipe( + ofType(actions.metricsEnableSavingPinsToggled), + withLatestFrom( + this.store.select(selectors.getPinnedCardsWithMetadata), + this.store.select(selectors.getEnableGlobalPins), + this.store.select(selectors.getShouldPersistSettings), + this.store.select(selectors.getMetricsSavingPinsEnabled) + ), + filter( + ([, , enableGlobalPins, getShouldPersistSettings]) => + enableGlobalPins && getShouldPersistSettings + ), + tap(([, pinnedCards, , , getMetricsSavingPinsEnabled]) => { + if (getMetricsSavingPinsEnabled) { + const tags: Tag[] = pinnedCards + .map((card) => { + return card.plugin === PluginType.SCALARS ? card.tag : null; + }) + .filter((v): v is Tag => v !== null); + this.savedPinsDataSource.saveScalarPins(tags); + } else { + this.savedPinsDataSource.removeAllScalarPins(); + } + }) + ); + + this.dataEffects$ = createEffect( + () => { + return merge( + /** + * Subscribes to: dashboard shown, route navigation, reloads. + */ + this.loadTagMetadata$, + + /** + * Subscribes to: card visibility, reloads. + */ + this.loadTimeSeries$, + + /** + * Subscribes to: cardPinStateToggled. + */ + this.addOrRemovePin$, + /** + * Subscribes to: dashboard shown (initAction). + */ + this.loadSavedPins$, + /** + * Subscribes to: metricsClearAllPinnedCards. + */ + this.removeAllPins$, + /** + * Subscribes to: metricsEnableSavingPinsToggled. + */ + this.addOrRemovePinsOnToggle$ + ); + }, + {dispatch: false} + ); + } } export const TEST_ONLY = { diff --git a/tensorboard/webapp/metrics/views/card_renderer/histogram_card_container.ts b/tensorboard/webapp/metrics/views/card_renderer/histogram_card_container.ts index 5eb35a2e281..155f7d2f32c 100644 --- a/tensorboard/webapp/metrics/views/card_renderer/histogram_card_container.ts +++ b/tensorboard/webapp/metrics/views/card_renderer/histogram_card_container.ts @@ -98,7 +98,13 @@ type HistogramCardMetadata = CardMetadata & { changeDetection: ChangeDetectionStrategy.OnPush, }) export class HistogramCardContainer implements CardRenderer, OnInit { - constructor(private readonly store: Store) {} + constructor(private readonly store: Store) { + this.mode$ = this.store.select(getMetricsHistogramMode); + this.xAxisType$ = this.store.select(getMetricsXAxisType); + this.showFullWidth$ = this.store + .select(getCardStateMap) + .pipe(map((map) => map[this.cardId]?.fullWidth)); + } @Input() cardId!: CardId; @Input() groupName!: string | null; @@ -110,11 +116,9 @@ export class HistogramCardContainer implements CardRenderer, OnInit { tag$?: Observable; runId$?: Observable; data$?: Observable; - mode$ = this.store.select(getMetricsHistogramMode); - xAxisType$ = this.store.select(getMetricsXAxisType); - readonly showFullWidth$ = this.store - .select(getCardStateMap) - .pipe(map((map) => map[this.cardId]?.fullWidth)); + mode$; + xAxisType$; + readonly showFullWidth$; isPinned$?: Observable; linkedTimeSelection$?: Observable; isClosestStepHighlighted$?: Observable; diff --git a/tensorboard/webapp/metrics/views/card_renderer/image_card_container.ts b/tensorboard/webapp/metrics/views/card_renderer/image_card_container.ts index 228ced9badf..691fc352413 100644 --- a/tensorboard/webapp/metrics/views/card_renderer/image_card_container.ts +++ b/tensorboard/webapp/metrics/views/card_renderer/image_card_container.ts @@ -109,7 +109,15 @@ export class ImageCardContainer implements CardRenderer, OnInit, OnDestroy { constructor( private readonly store: Store, private readonly dataSource: MetricsDataSource - ) {} + ) { + this.brightnessInMilli$ = this.store.select( + getMetricsImageBrightnessInMilli + ); + this.contrastInMilli$ = this.store.select(getMetricsImageContrastInMilli); + this.actualSizeGlobalSetting$ = this.store.select( + getMetricsImageShowActualSize + ); + } @Input() cardId!: CardId; @Input() groupName!: string | null; @@ -139,9 +147,9 @@ export class ImageCardContainer implements CardRenderer, OnInit, OnDestroy { isPinned$?: Observable; linkedTimeSelection$?: Observable; selectedSteps$?: Observable; - brightnessInMilli$ = this.store.select(getMetricsImageBrightnessInMilli); - contrastInMilli$ = this.store.select(getMetricsImageContrastInMilli); - actualSizeGlobalSetting$ = this.store.select(getMetricsImageShowActualSize); + brightnessInMilli$; + contrastInMilli$; + actualSizeGlobalSetting$; showActualSize = false; // The UI toggle is overridden by the global setting. diff --git a/tensorboard/webapp/metrics/views/card_renderer/scalar_card_container.ts b/tensorboard/webapp/metrics/views/card_renderer/scalar_card_container.ts index 2a94e9fa316..7ed3e22d5e5 100644 --- a/tensorboard/webapp/metrics/views/card_renderer/scalar_card_container.ts +++ b/tensorboard/webapp/metrics/views/card_renderer/scalar_card_container.ts @@ -225,7 +225,47 @@ function areSeriesEqual( changeDetection: ChangeDetectionStrategy.OnPush, }) export class ScalarCardContainer implements CardRenderer, OnInit, OnDestroy { - constructor(private readonly store: Store) {} + constructor(private readonly store: Store) { + this.columnFilters$ = this.store.select(getCurrentColumnFilters); + this.numColumnsLoaded$ = this.store.select( + hparamsSelectors.getNumDashboardHparamsLoaded + ); + this.numColumnsToLoad$ = this.store.select( + hparamsSelectors.getNumDashboardHparamsToLoad + ); + this.useDarkMode$ = this.store.select(getDarkModeEnabled); + this.ignoreOutliers$ = this.store.select(getMetricsIgnoreOutliers); + this.tooltipSort$ = this.store.select(getMetricsTooltipSort); + this.xAxisType$ = this.store.select(getMetricsXAxisType); + this.forceSvg$ = this.store.select(getForceSvgFeatureFlag); + this.columnCustomizationEnabled$ = this.store.select( + getIsScalarColumnCustomizationEnabled + ); + this.columnContextMenusEnabled$ = this.store.select( + getIsScalarColumnContextMenusEnabled + ); + this.xScaleType$ = this.store.select(getMetricsXAxisType).pipe( + map((xAxisType) => { + switch (xAxisType) { + case XAxisType.STEP: + case XAxisType.RELATIVE: + return ScaleType.LINEAR; + case XAxisType.WALL_TIME: + return ScaleType.TIME; + default: + const neverType = xAxisType as never; + throw new Error(`Invalid xAxisType for line chart. ${neverType}`); + } + }) + ); + this.scalarSmoothing$ = this.store.select(getMetricsScalarSmoothing); + this.smoothingEnabled$ = this.store + .select(getMetricsScalarSmoothing) + .pipe(map((smoothing) => smoothing > 0)); + this.showFullWidth$ = this.store + .select(getCardStateMap) + .pipe(map((map) => map[this.cardId]?.fullWidth)); + } // Angular Component constructor for DataDownload dialog. It is customizable for // testability, without mocking out data for the component's internals, but defaults to @@ -251,54 +291,29 @@ export class ScalarCardContainer implements CardRenderer, OnInit, OnDestroy { cardState$?: Observable>; rangeEnabled$?: Observable; hparamsEnabled$?: Observable; - columnFilters$ = this.store.select(getCurrentColumnFilters); + columnFilters$; runToHparamMap$?: Observable; selectableColumns$?: Observable; - numColumnsLoaded$ = this.store.select( - hparamsSelectors.getNumDashboardHparamsLoaded - ); - numColumnsToLoad$ = this.store.select( - hparamsSelectors.getNumDashboardHparamsToLoad - ); + numColumnsLoaded$; + numColumnsToLoad$; onVisibilityChange({visible}: {visible: boolean}) { this.isVisible = visible; } - readonly useDarkMode$ = this.store.select(getDarkModeEnabled); - readonly ignoreOutliers$ = this.store.select(getMetricsIgnoreOutliers); - readonly tooltipSort$ = this.store.select(getMetricsTooltipSort); - readonly xAxisType$ = this.store.select(getMetricsXAxisType); - readonly forceSvg$ = this.store.select(getForceSvgFeatureFlag); - readonly columnCustomizationEnabled$ = this.store.select( - getIsScalarColumnCustomizationEnabled - ); - readonly columnContextMenusEnabled$ = this.store.select( - getIsScalarColumnContextMenusEnabled - ); - readonly xScaleType$ = this.store.select(getMetricsXAxisType).pipe( - map((xAxisType) => { - switch (xAxisType) { - case XAxisType.STEP: - case XAxisType.RELATIVE: - return ScaleType.LINEAR; - case XAxisType.WALL_TIME: - return ScaleType.TIME; - default: - const neverType = xAxisType as never; - throw new Error(`Invalid xAxisType for line chart. ${neverType}`); - } - }) - ); + readonly useDarkMode$; + readonly ignoreOutliers$; + readonly tooltipSort$; + readonly xAxisType$; + readonly forceSvg$; + readonly columnCustomizationEnabled$; + readonly columnContextMenusEnabled$; + readonly xScaleType$; - readonly scalarSmoothing$ = this.store.select(getMetricsScalarSmoothing); - readonly smoothingEnabled$ = this.store - .select(getMetricsScalarSmoothing) - .pipe(map((smoothing) => smoothing > 0)); + readonly scalarSmoothing$; + readonly smoothingEnabled$; - readonly showFullWidth$ = this.store - .select(getCardStateMap) - .pipe(map((map) => map[this.cardId]?.fullWidth)); + readonly showFullWidth$; private readonly ngUnsubscribe = new Subject(); diff --git a/tensorboard/webapp/reloader/reloader_component.ts b/tensorboard/webapp/reloader/reloader_component.ts index 8e0ee47efd6..b3671dd125d 100644 --- a/tensorboard/webapp/reloader/reloader_component.ts +++ b/tensorboard/webapp/reloader/reloader_component.ts @@ -27,12 +27,8 @@ import {selectors as settingsSelectors, State} from '../settings'; }) export class ReloaderComponent { private readonly onVisibilityChange = this.onVisibilityChangeImpl.bind(this); - private readonly reloadEnabled$ = this.store.pipe( - select(settingsSelectors.getReloadEnabled) - ); - private readonly reloadPeriodInMs$ = this.store.pipe( - select(settingsSelectors.getReloadPeriodInMs) - ); + private readonly reloadEnabled$; + private readonly reloadPeriodInMs$; private reloadTimerId: ReturnType | null = null; private missedAutoReload: boolean = false; private ngUnsubscribe = new Subject(); @@ -40,7 +36,14 @@ export class ReloaderComponent { constructor( private store: Store, @Inject(DOCUMENT) private readonly document: Document - ) {} + ) { + this.reloadEnabled$ = this.store.pipe( + select(settingsSelectors.getReloadEnabled) + ); + this.reloadPeriodInMs$ = this.store.pipe( + select(settingsSelectors.getReloadPeriodInMs) + ); + } ngOnInit() { this.document.addEventListener('visibilitychange', this.onVisibilityChange); diff --git a/tensorboard/webapp/runs/views/runs_selector/runs_selector_container.ts b/tensorboard/webapp/runs/views/runs_selector/runs_selector_container.ts index 66ca16c76cc..78414a21e20 100644 --- a/tensorboard/webapp/runs/views/runs_selector/runs_selector_container.ts +++ b/tensorboard/webapp/runs/views/runs_selector/runs_selector_container.ts @@ -30,19 +30,22 @@ import {RunsTableColumn} from '../runs_table/types'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class RunsSelectorContainer { - readonly experimentIds$ = this.store - .select(getExperimentIdsFromRoute) - .pipe(map((experimentIdsOrNull) => experimentIdsOrNull ?? [])); - readonly columns$ = this.store.select(getExperimentIdsFromRoute).pipe( - map((ids) => { - return [ - RunsTableColumn.CHECKBOX, - RunsTableColumn.RUN_NAME, - ids && ids.length > 1 ? RunsTableColumn.EXPERIMENT_NAME : null, - RunsTableColumn.RUN_COLOR, - ].filter((col) => col !== null) as RunsTableColumn[]; - }) - ); + readonly experimentIds$; + readonly columns$; - constructor(private readonly store: Store) {} + constructor(private readonly store: Store) { + this.experimentIds$ = this.store + .select(getExperimentIdsFromRoute) + .pipe(map((experimentIdsOrNull) => experimentIdsOrNull ?? [])); + this.columns$ = this.store.select(getExperimentIdsFromRoute).pipe( + map((ids) => { + return [ + RunsTableColumn.CHECKBOX, + RunsTableColumn.RUN_NAME, + ids && ids.length > 1 ? RunsTableColumn.EXPERIMENT_NAME : null, + RunsTableColumn.RUN_COLOR, + ].filter((col) => col !== null) as RunsTableColumn[]; + }) + ); + } } diff --git a/tensorboard/webapp/runs/views/runs_table/filterbar_container.ts b/tensorboard/webapp/runs/views/runs_table/filterbar_container.ts index 540064f42c2..2439dd53863 100644 --- a/tensorboard/webapp/runs/views/runs_table/filterbar_container.ts +++ b/tensorboard/webapp/runs/views/runs_table/filterbar_container.ts @@ -34,11 +34,15 @@ import {FilterAddedEvent} from '../../../widgets/data_table/types'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class FilterbarContainer implements OnDestroy { - filters$ = this.store.select(hparamsSelectors.getDashboardHparamFilterMap); + filters$; private readonly ngUnsubscribe = new Subject(); - constructor(private readonly store: Store) {} + constructor(private readonly store: Store) { + this.filters$ = this.store.select( + hparamsSelectors.getDashboardHparamFilterMap + ); + } addHparamFilter(event: FilterAddedEvent) { this.store.dispatch( diff --git a/tensorboard/webapp/runs/views/runs_table/regex_edit_dialog_container.ts b/tensorboard/webapp/runs/views/runs_table/regex_edit_dialog_container.ts index 98c7b6bb781..ff92d99092e 100644 --- a/tensorboard/webapp/runs/views/runs_table/regex_edit_dialog_container.ts +++ b/tensorboard/webapp/runs/views/runs_table/regex_edit_dialog_container.ts @@ -71,11 +71,8 @@ export class RegexEditDialogContainer { private readonly experimentIds: string[]; private readonly runIdToEid$: Observable>; private readonly allRuns$: Observable; - private readonly expNameByExpId$: Observable> = - this.store.select(getDashboardExperimentNames); - readonly enableColorByExperiment$: Observable = this.store.select( - getEnableColorByExperiment - ); + private readonly expNameByExpId$: Observable>; + readonly enableColorByExperiment$: Observable; // Tentative regex string and type are used because we don't want to change the state // every time we type in or select the dropdown option. @@ -91,19 +88,7 @@ export class RegexEditDialogContainer { ); }).pipe(startWith(''), shareReplay(1)); - readonly groupByRegexType$: Observable = merge( - this.store.select(getRunGroupBy).pipe( - take(1), - map((group) => group.key) - ), - this.tentativeRegexType$ - ).pipe( - startWith(GroupByKey.REGEX), - filter( - (key) => key === GroupByKey.REGEX || key === GroupByKey.REGEX_BY_EXP - ), - shareReplay(1) - ); + readonly groupByRegexType$: Observable; readonly colorRunPairList$: Observable = defer(() => { return this.groupByRegexString$.pipe( @@ -174,6 +159,23 @@ export class RegexEditDialogContainer { experimentIds: string[]; } ) { + this.expNameByExpId$ = this.store.select(getDashboardExperimentNames); + this.enableColorByExperiment$ = this.store.select( + getEnableColorByExperiment + ); + this.groupByRegexType$ = merge( + this.store.select(getRunGroupBy).pipe( + take(1), + map((group) => group.key) + ), + this.tentativeRegexType$ + ).pipe( + startWith(GroupByKey.REGEX), + filter( + (key) => key === GroupByKey.REGEX || key === GroupByKey.REGEX_BY_EXP + ), + shareReplay(1) + ); this.experimentIds = data.experimentIds; this.runIdToEid$ = combineLatest( diff --git a/tensorboard/webapp/settings/_views/polymer_interop_container.ts b/tensorboard/webapp/settings/_views/polymer_interop_container.ts index b5903951093..adfd3fc8508 100644 --- a/tensorboard/webapp/settings/_views/polymer_interop_container.ts +++ b/tensorboard/webapp/settings/_views/polymer_interop_container.ts @@ -36,12 +36,14 @@ import {State} from '../_redux/settings_types'; }) export class SettingsPolymerInteropContainer { private readonly ngUnsubscribe = new Subject(); - private readonly getPageSize$ = this.store.pipe(select(getPageSize)); + private readonly getPageSize$; private readonly paginatedViewStore = document.createElement( 'tf-paginated-view-store' ).tf_paginated_view; - constructor(private store: Store) {} + constructor(private store: Store) { + this.getPageSize$ = this.store.pipe(select(getPageSize)); + } ngOnInit() { this.getPageSize$ diff --git a/tensorboard/webapp/settings/_views/settings_button_container.ts b/tensorboard/webapp/settings/_views/settings_button_container.ts index 4c942324194..97e51a9cdcd 100644 --- a/tensorboard/webapp/settings/_views/settings_button_container.ts +++ b/tensorboard/webapp/settings/_views/settings_button_container.ts @@ -26,7 +26,9 @@ import {State} from '../_redux/settings_types'; `, }) export class SettingsButtonContainer { - readonly settingsLoadState$ = this.store.select(getSettingsLoadState); + readonly settingsLoadState$; - constructor(private store: Store) {} + constructor(private store: Store) { + this.settingsLoadState$ = this.store.select(getSettingsLoadState); + } } diff --git a/tensorboard/webapp/settings/_views/settings_dialog_container.ts b/tensorboard/webapp/settings/_views/settings_dialog_container.ts index 2bed7c47df5..daa13153611 100644 --- a/tensorboard/webapp/settings/_views/settings_dialog_container.ts +++ b/tensorboard/webapp/settings/_views/settings_dialog_container.ts @@ -40,11 +40,15 @@ import {State} from '../_redux/settings_types'; `, }) export class SettingsDialogContainer { - readonly reloadEnabled$ = this.store.select(getReloadEnabled); - readonly reloadPeriodInMs$ = this.store.select(getReloadPeriodInMs); - readonly pageSize$ = this.store.select(getPageSize); + readonly reloadEnabled$; + readonly reloadPeriodInMs$; + readonly pageSize$; - constructor(private store: Store) {} + constructor(private store: Store) { + this.reloadEnabled$ = this.store.select(getReloadEnabled); + this.reloadPeriodInMs$ = this.store.select(getReloadPeriodInMs); + this.pageSize$ = this.store.select(getPageSize); + } onReloadToggled(): void { this.store.dispatch(toggleReloadEnabled());