diff --git a/public/app/features/dashboard/panel_editor/PanelEditor.tsx b/public/app/features/dashboard/panel_editor/PanelEditor.tsx index 539810d4ad3..299942d2fbf 100644 --- a/public/app/features/dashboard/panel_editor/PanelEditor.tsx +++ b/public/app/features/dashboard/panel_editor/PanelEditor.tsx @@ -2,7 +2,7 @@ import React, { PureComponent } from 'react'; import classNames from 'classnames'; import { hot } from 'react-hot-loader'; import { connect } from 'react-redux'; -import { Tooltip, PanelPlugin, PanelPluginMeta } from '@grafana/ui'; +import { PanelPlugin, PanelPluginMeta, Tooltip } from '@grafana/ui'; import { AngularComponent, config } from '@grafana/runtime'; import { QueriesTab } from './QueriesTab'; @@ -12,8 +12,9 @@ import { AlertTab } from '../../alerting/AlertTab'; import { PanelModel } from '../state/PanelModel'; import { DashboardModel } from '../state/DashboardModel'; import { StoreState } from '../../../types'; -import { PanelEditorTabIds, PanelEditorTab } from './state/reducers'; -import { refreshPanelEditor, changePanelEditorTab, panelEditorCleanUp } from './state/actions'; +import { PanelEditorTab, PanelEditorTabIds } from './state/reducers'; +import { changePanelEditorTab, panelEditorCleanUp, refreshPanelEditor } from './state/actions'; +import { getActiveTabAndTabs } from './state/selectors'; interface PanelEditorProps { panel: PanelModel; @@ -108,10 +109,7 @@ class UnConnectedPanelEditor extends PureComponent { } } -export const mapStateToProps = (state: StoreState) => ({ - activeTab: state.location.query.tab || PanelEditorTabIds.Queries, - tabs: state.panelEditor.tabs, -}); +export const mapStateToProps = (state: StoreState) => getActiveTabAndTabs(state.location, state.panelEditor); const mapDispatchToProps = { refreshPanelEditor, panelEditorCleanUp, changePanelEditorTab }; diff --git a/public/app/features/dashboard/panel_editor/state/selectors.test.ts b/public/app/features/dashboard/panel_editor/state/selectors.test.ts new file mode 100644 index 00000000000..0fe19983b9a --- /dev/null +++ b/public/app/features/dashboard/panel_editor/state/selectors.test.ts @@ -0,0 +1,88 @@ +import { getActiveTabAndTabs } from './selectors'; +import { LocationState } from '../../../../types'; +import { getPanelEditorTab, PanelEditorState, PanelEditorTab, PanelEditorTabIds } from './reducers'; + +describe('getActiveTabAndTabs', () => { + describe('when called and location state contains tab', () => { + it('then it should return location state', () => { + const activeTabId = 1337; + const location: LocationState = { + path: 'a path', + lastUpdated: 1, + replace: false, + routeParams: {}, + query: { + tab: activeTabId, + }, + url: 'an url', + }; + const panelEditor: PanelEditorState = { + activeTab: PanelEditorTabIds.Queries, + tabs: [], + }; + + const result = getActiveTabAndTabs(location, panelEditor); + + expect(result).toEqual({ + activeTab: activeTabId, + tabs: [], + }); + }); + }); + + describe('when called without location state and PanelEditor state contains tabs', () => { + it('then it should return the id for the first tab in PanelEditor state', () => { + const activeTabId = PanelEditorTabIds.Visualization; + const tabs = [getPanelEditorTab(PanelEditorTabIds.Visualization), getPanelEditorTab(PanelEditorTabIds.Advanced)]; + const location: LocationState = { + path: 'a path', + lastUpdated: 1, + replace: false, + routeParams: {}, + query: { + tab: undefined, + }, + url: 'an url', + }; + const panelEditor: PanelEditorState = { + activeTab: PanelEditorTabIds.Advanced, + tabs, + }; + + const result = getActiveTabAndTabs(location, panelEditor); + + expect(result).toEqual({ + activeTab: activeTabId, + tabs, + }); + }); + }); + + describe('when called without location state and PanelEditor state does not contain tabs', () => { + it('then it should return PanelEditorTabIds.Queries', () => { + const activeTabId = PanelEditorTabIds.Queries; + const tabs: PanelEditorTab[] = []; + const location: LocationState = { + path: 'a path', + lastUpdated: 1, + replace: false, + routeParams: {}, + query: { + tab: undefined, + }, + url: 'an url', + }; + const panelEditor: PanelEditorState = { + activeTab: PanelEditorTabIds.Advanced, + tabs, + }; + + const result = getActiveTabAndTabs(location, panelEditor); + + expect(result).toEqual({ + activeTab: activeTabId, + tabs, + }); + }); + }); +}); diff --git a/public/app/features/dashboard/panel_editor/state/selectors.ts b/public/app/features/dashboard/panel_editor/state/selectors.ts new file mode 100644 index 00000000000..f6e6e80ecf9 --- /dev/null +++ b/public/app/features/dashboard/panel_editor/state/selectors.ts @@ -0,0 +1,11 @@ +import memoizeOne from 'memoize-one'; +import { LocationState } from '../../../../types'; +import { PanelEditorState, PanelEditorTabIds } from './reducers'; + +export const getActiveTabAndTabs = memoizeOne((location: LocationState, panelEditor: PanelEditorState) => { + const panelEditorTab = panelEditor.tabs.length > 0 ? panelEditor.tabs[0].id : PanelEditorTabIds.Queries; + return { + activeTab: location.query.tab || panelEditorTab, + tabs: panelEditor.tabs, + }; +});