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 7bf3586bd5..4839cc6424 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; - } - 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); + 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 { - 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.tensor_debug_mode; } - } - return dtypes; - } - ) - ) - ); - - constructor(private readonly store: Store) {} + }, + ), + ), + ); + 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; + } + }, + ), + ), + ); + this.debugTensorValues$ = this.store.pipe( + select( + createSelector( + getFocusedExecutionData, + (execution: Execution | null) => { + if (execution === null) { + return null; + } else { + return execution.debug_tensor_values; + } + }, + ), + ), + ); + 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 dcf4c360b7..1bdbc328a7 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 d26363d88f..a66c78a292 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 2e95ce46f0..242edaf6bb 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 @@ -52,84 +52,104 @@ export class StackTraceContainer { ) ); - readonly opType$ = this.store.pipe( - select( - createSelector(getCodeLocationOrigin, (originInfo): string | null => { - return originInfo === null ? null : originInfo.opType; - }) - ) - ); + readonly opType$; - 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 opName$; - readonly executionIndex$ = this.store.pipe( - select( - createSelector(getCodeLocationOrigin, (originInfo): number | null => { - if ( - originInfo === null || - originInfo.codeLocationType !== CodeLocationType.EXECUTION - ) { - return null; - } - return originInfo.executionIndex; - }) - ) - ); + readonly executionIndex$; - readonly stickToBottommostFrameInFocusedFile$ = this.store.pipe( - select(getStickToBottommostFrameInFocusedFile) - ); + readonly stickToBottommostFrameInFocusedFile$; - readonly stackFramesForDisplay$ = this.store.pipe( - select( - createSelector( - getFocusedStackFrames, - getFocusedSourceLineSpec, - (stackFrames, focusedSourceLineSpec): StackFrameForDisplay[] | null => { - if (stackFrames === null) { + readonly stackFramesForDisplay$; + + 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; - } - ) - ) - ); - - constructor(private readonly store: Store) {} + return originInfo.executionIndex; + }), + ), + ); + 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 525bc52b18..0956d57720 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 focusedExecutionDisplayIndex$; - readonly numExecutions$ = this.store.pipe(select(getNumExecutions)); + readonly numExecutions$; - constructor(private readonly store: Store) {} + 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 a5dab2d527..4b1439928b 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 c9300415b7..72155ac9fd 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 fba1f843ad..25167c2862 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,16 @@ 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 - ) {} + ) { + 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 2107886c4e..83cb65381e 100644 --- a/tensorboard/webapp/header/dark_mode_toggle_container.ts +++ b/tensorboard/webapp/header/dark_mode_toggle_container.ts @@ -33,18 +33,18 @@ 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 ? DarkModeOverride.DARK_MODE_ON : 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 d44c131864..16a6b79816 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 9f94d0b07d..7c80187ee6 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 b76a2b0d57..1e7bafcbc5 100644 --- a/tensorboard/webapp/metrics/effects/index.ts +++ b/tensorboard/webapp/metrics/effects/index.ts @@ -77,7 +77,217 @@ export class MetricsEffects implements OnInitEffects { private readonly store: Store, private readonly metricsDataSource: MetricsDataSource, private readonly savedPinsDataSource: SavedPinsDataSource - ) {} + ) { + this.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 + ); + }), + ); + this.reloadRequestedWhileShown$ = this.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]) => { + /** + * 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); + }), + ); + }), + ); + 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(); + } + }), + ); + } /** @export */ ngrxOnInitEffects(): Action { @@ -95,66 +305,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 dashboardShownWithoutData$; - 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 reloadRequestedWhileShown$; - 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 loadTagMetadata$; private getVisibleCardFetchInfos(): Observable { const visibleCardIds$ = this.store.select(selectors.getVisibleCardIdSet); @@ -227,161 +382,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 visibleCardsWithoutDataChanged$; - private readonly loadTimeSeries$ = merge( - this.visibleCardsWithoutDataChanged$, - this.visibleCardsReloaded$ - ).pipe( - filter((fetchInfos) => fetchInfos.length > 0), + private readonly visibleCardsReloaded$; - // 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 loadTimeSeries$; - 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 addOrRemovePin$; - 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 loadSavedPins$; - 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 removeAllPins$; - 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 addOrRemovePinsOnToggle$; /** * In general, this effect dispatch the following actions: 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 5eb35a2e28..155f7d2f32 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 228ced9bad..4a35211f5e 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 2a94e9fa31..cd6fadf780 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 8e0ee47efd..62bb8d4d61 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 66ca16c76c..90b058f29a 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 540064f42c..aaeaaf93e8 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 98c7b6bb78..7bc1a6a8cf 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 b590395109..adfd3fc850 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 4c94232419..97e51a9cdc 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 2bed7c47df..daa1315361 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());