diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index 6b49d7dcd91..18e2a6b58aa 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -108,11 +108,9 @@ export class UnConnectedExploreToolbar extends PureComponent { )} - {exploreId === 'right' && ( - - - - )} + this.props.closeSplit(exploreId)}> + +
diff --git a/public/app/features/explore/state/actionTypes.ts b/public/app/features/explore/state/actionTypes.ts index 8f3e1dbcf80..360e509aab4 100644 --- a/public/app/features/explore/state/actionTypes.ts +++ b/public/app/features/explore/state/actionTypes.ts @@ -24,16 +24,9 @@ import { LogLevel } from 'app/core/logs_model'; * */ export enum ActionTypes { - SplitClose = 'explore/SPLIT_CLOSE', SplitOpen = 'explore/SPLIT_OPEN', ResetExplore = 'explore/RESET_EXPLORE', } - -export interface SplitCloseAction { - type: ActionTypes.SplitClose; - payload: {}; -} - export interface SplitOpenAction { type: ActionTypes.SplitOpen; payload: { @@ -167,6 +160,10 @@ export interface SetQueriesPayload { queries: DataQuery[]; } +export interface SplitCloseActionPayload { + itemId: ExploreId; +} + export interface SplitOpenPayload { itemState: ExploreItemState; } @@ -350,7 +347,7 @@ export const setQueriesAction = actionCreatorFactory('explore /** * Close the split view and save URL state. */ -export const splitCloseAction = noPayloadActionCreatorFactory('explore/SPLIT_CLOSE').create(); +export const splitCloseAction = actionCreatorFactory('explore/SPLIT_CLOSE').create(); /** * Open the split view and copy the left state to be the right state. @@ -395,7 +392,11 @@ export const toggleLogLevelAction = actionCreatorFactory( export const resetExploreAction = noPayloadActionCreatorFactory('explore/RESET_EXPLORE').create(); export const queriesImportedAction = actionCreatorFactory('explore/QueriesImported').create(); -export type HigherOrderAction = SplitCloseAction | SplitOpenAction | ResetExploreAction | ActionOf; +export type HigherOrderAction = + | ActionOf + | SplitOpenAction + | ResetExploreAction + | ActionOf; export type Action = | ActionOf diff --git a/public/app/features/explore/state/actions.ts b/public/app/features/explore/state/actions.ts index a674404569e..2b8c13b0185 100644 --- a/public/app/features/explore/state/actions.ts +++ b/public/app/features/explore/state/actions.ts @@ -1,6 +1,5 @@ // Libraries import _ from 'lodash'; -import { ThunkAction } from 'redux-thunk'; // Services & Utils import store from 'app/core/store'; @@ -23,7 +22,6 @@ import { import { updateLocation } from 'app/core/actions'; // Types -import { StoreState } from 'app/types'; import { RawTimeRange, TimeRange, @@ -35,7 +33,6 @@ import { } from '@grafana/ui/src/types'; import { ExploreId, ExploreUrlState, RangeScanner, ResultType, QueryOptions, ExploreUIState } from 'app/types/explore'; import { - Action, updateDatasourceInstanceAction, changeQueryAction, changeSizeAction, @@ -71,10 +68,9 @@ import { } from './actionTypes'; import { ActionOf, ActionCreator } from 'app/core/redux/actionCreatorFactory'; import { LogsDedupStrategy } from 'app/core/logs_model'; +import { ThunkResult } from 'app/types'; import { parseTime } from '../TimePicker'; -type ThunkResult = ThunkAction; - /** * Updates UI state and save it to the URL */ @@ -645,9 +641,9 @@ export function setQueries(exploreId: ExploreId, rawQueries: DataQuery[]): Thunk /** * Close the split view and save URL state. */ -export function splitClose(): ThunkResult { +export function splitClose(itemId: ExploreId): ThunkResult { return dispatch => { - dispatch(splitCloseAction()); + dispatch(splitCloseAction({ itemId })); dispatch(stateSave()); }; } diff --git a/public/app/features/explore/state/reducers.test.ts b/public/app/features/explore/state/reducers.test.ts index e0853cd3a11..0a7aa2766e0 100644 --- a/public/app/features/explore/state/reducers.test.ts +++ b/public/app/features/explore/state/reducers.test.ts @@ -1,7 +1,13 @@ -import { itemReducer, makeExploreItemState, exploreReducer, makeInitialUpdateState } from './reducers'; -import { ExploreId, ExploreItemState, ExploreUrlState } from 'app/types/explore'; +import { + itemReducer, + makeExploreItemState, + exploreReducer, + makeInitialUpdateState, + initialExploreState, +} from './reducers'; +import { ExploreId, ExploreItemState, ExploreUrlState, ExploreState } from 'app/types/explore'; import { reducerTester } from 'test/core/redux/reducerTester'; -import { scanStartAction, scanStopAction } from './actionTypes'; +import { scanStartAction, scanStopAction, splitOpenAction, splitCloseAction } from './actionTypes'; import { Reducer } from 'redux'; import { ActionOf } from 'app/core/redux/actionCreatorFactory'; import { updateLocation } from 'app/core/actions/location'; @@ -76,6 +82,82 @@ export const setup = (urlStateOverrides?: any) => { }; describe('Explore reducer', () => { + describe('split view', () => { + it("should make right pane a duplicate of the given item's state on split open", () => { + const leftItemMock = { + containerWidth: 100, + } as ExploreItemState; + + const initalState = { + split: null, + left: leftItemMock as ExploreItemState, + right: makeExploreItemState(), + } as ExploreState; + + reducerTester() + .givenReducer(exploreReducer as Reducer>, initalState) + .whenActionIsDispatched(splitOpenAction({ itemState: leftItemMock })) + .thenStateShouldEqual({ + split: true, + left: leftItemMock, + right: leftItemMock, + }); + }); + + describe('split close', () => { + it('should keep right pane as left when left is closed', () => { + const leftItemMock = { + containerWidth: 100, + } as ExploreItemState; + + const rightItemMock = { + containerWidth: 200, + } as ExploreItemState; + + const initalState = { + split: null, + left: leftItemMock, + right: rightItemMock, + } as ExploreState; + + // closing left item + reducerTester() + .givenReducer(exploreReducer as Reducer>, initalState) + .whenActionIsDispatched(splitCloseAction({ itemId: ExploreId.left })) + .thenStateShouldEqual({ + split: false, + left: rightItemMock, + right: initialExploreState.right, + }); + }); + it('should reset right pane when it is closed ', () => { + const leftItemMock = { + containerWidth: 100, + } as ExploreItemState; + + const rightItemMock = { + containerWidth: 200, + } as ExploreItemState; + + const initalState = { + split: null, + left: leftItemMock, + right: rightItemMock, + } as ExploreState; + + // closing left item + reducerTester() + .givenReducer(exploreReducer as Reducer>, initalState) + .whenActionIsDispatched(splitCloseAction({ itemId: ExploreId.right })) + .thenStateShouldEqual({ + split: false, + left: leftItemMock, + right: initialExploreState.right, + }); + }); + }); + }); + describe('when updateLocation is dispatched', () => { describe('and payload does not contain a query', () => { it('then it should just return state', () => { diff --git a/public/app/features/explore/state/reducers.ts b/public/app/features/explore/state/reducers.ts index 14aa5d61363..4eae1a55440 100644 --- a/public/app/features/explore/state/reducers.ts +++ b/public/app/features/explore/state/reducers.ts @@ -12,7 +12,7 @@ import { import { ExploreItemState, ExploreState, QueryTransaction, ExploreId, ExploreUpdateState } from 'app/types/explore'; import { DataQuery } from '@grafana/ui/src/types'; -import { HigherOrderAction, ActionTypes } from './actionTypes'; +import { HigherOrderAction, ActionTypes, SplitCloseActionPayload, splitCloseAction } from './actionTypes'; import { reducerFactory } from 'app/core/redux'; import { addQueryRowAction, @@ -560,8 +560,17 @@ export const updateChildRefreshState = ( */ export const exploreReducer = (state = initialExploreState, action: HigherOrderAction): ExploreState => { switch (action.type) { - case ActionTypes.SplitClose: { - return { ...state, split: false }; + case splitCloseAction.type: { + const { itemId } = action.payload as SplitCloseActionPayload; + const targetSplit = { + left: itemId === ExploreId.left ? state.right : state.left, + right: initialExploreState.right, + }; + return { + ...state, + ...targetSplit, + split: false, + }; } case ActionTypes.SplitOpen: {