Procházet zdrojové kódy

feat(explore): make it possible to close left pane of split view (#16155)

* feat(explore): make it possible to close left pane of split view

* Use action's type prop instead of enum
Dominik Prokop před 6 roky
rodič
revize
a8c50ed6ba

+ 3 - 5
public/app/features/explore/ExploreToolbar.tsx

@@ -108,11 +108,9 @@ export class UnConnectedExploreToolbar extends PureComponent<Props, {}> {
                 </span>
               )}
             </div>
-            {exploreId === 'right' && (
-              <a className="explore-toolbar-header-close" onClick={this.props.closeSplit}>
-                <i className="fa fa-times fa-fw" />
-              </a>
-            )}
+            <a className="explore-toolbar-header-close" onClick={() => this.props.closeSplit(exploreId)}>
+              <i className="fa fa-times fa-fw" />
+            </a>
           </div>
         </div>
         <div className="explore-toolbar-item">

+ 10 - 9
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<SetQueriesPayload>('explore
 /**
  * Close the split view and save URL state.
  */
-export const splitCloseAction = noPayloadActionCreatorFactory('explore/SPLIT_CLOSE').create();
+export const splitCloseAction = actionCreatorFactory<SplitCloseActionPayload>('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<ToggleLogLevelPayload>(
 export const resetExploreAction = noPayloadActionCreatorFactory('explore/RESET_EXPLORE').create();
 export const queriesImportedAction = actionCreatorFactory<QueriesImportedPayload>('explore/QueriesImported').create();
 
-export type HigherOrderAction = SplitCloseAction | SplitOpenAction | ResetExploreAction | ActionOf<any>;
+export type HigherOrderAction =
+  | ActionOf<SplitCloseActionPayload>
+  | SplitOpenAction
+  | ResetExploreAction
+  | ActionOf<any>;
 
 export type Action =
   | ActionOf<AddQueryRowPayload>

+ 3 - 7
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<R> = ThunkAction<R, StoreState, undefined, Action>;
-
 /**
  * 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<void> {
+export function splitClose(itemId: ExploreId): ThunkResult<void> {
   return dispatch => {
-    dispatch(splitCloseAction());
+    dispatch(splitCloseAction({ itemId }));
     dispatch(stateSave());
   };
 }

+ 85 - 3
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<ExploreState, ActionOf<any>>, 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<ExploreState, ActionOf<any>>, 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<ExploreState, ActionOf<any>>, 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', () => {

+ 12 - 3
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: {