瀏覽代碼

Persis deduplication strategy in url

Dominik Prokop 6 年之前
父節點
當前提交
229d646bfc

+ 4 - 2
public/app/core/utils/explore.test.ts

@@ -8,6 +8,7 @@ import {
 } from './explore';
 import { ExploreUrlState } from 'app/types/explore';
 import store from 'app/core/store';
+import { LogsDedupStrategy } from 'app/core/logs_model';
 
 const DEFAULT_EXPLORE_STATE: ExploreUrlState = {
   datasource: null,
@@ -17,6 +18,7 @@ const DEFAULT_EXPLORE_STATE: ExploreUrlState = {
     showingGraph: true,
     showingTable: true,
     showingLogs: true,
+    dedupStrategy: LogsDedupStrategy.none,
   }
 };
 
@@ -78,7 +80,7 @@ describe('state functions', () => {
       expect(serializeStateToUrlParam(state)).toBe(
         '{"datasource":"foo","queries":[{"expr":"metric{test=\\"a/b\\"}"},' +
           '{"expr":"super{foo=\\"x/z\\"}"}],"range":{"from":"now-5h","to":"now"},' +
-          '"ui":{"showingGraph":true,"showingTable":true,"showingLogs":true}}'
+          '"ui":{"showingGraph":true,"showingTable":true,"showingLogs":true,"dedupStrategy":"none"}}'
       );
     });
 
@@ -100,7 +102,7 @@ describe('state functions', () => {
         },
       };
       expect(serializeStateToUrlParam(state, true)).toBe(
-        '["now-5h","now","foo",{"expr":"metric{test=\\"a/b\\"}"},{"expr":"super{foo=\\"x/z\\"}"},{"ui":[true,true,true]}]'
+        '["now-5h","now","foo",{"expr":"metric{test=\\"a/b\\"}"},{"expr":"super{foo=\\"x/z\\"}"},{"ui":[true,true,true,"none"]}]'
       );
     });
   });

+ 4 - 1
public/app/core/utils/explore.ts

@@ -21,6 +21,7 @@ import {
   QueryIntervals,
   QueryOptions,
 } from 'app/types/explore';
+import { LogsDedupStrategy } from 'app/core/logs_model';
 
 export const DEFAULT_RANGE = {
   from: 'now-6h',
@@ -31,6 +32,7 @@ export const DEFAULT_UI_STATE = {
   showingTable: true,
   showingGraph: true,
   showingLogs: true,
+  dedupStrategy: LogsDedupStrategy.none,
 };
 
 const MAX_HISTORY_ITEMS = 100;
@@ -183,6 +185,7 @@ export function parseUrlState(initial: string | undefined): ExploreUrlState {
               showingGraph: segment.ui[0],
               showingLogs: segment.ui[1],
               showingTable: segment.ui[2],
+              dedupStrategy: segment.ui[3],
             };
           }
         });
@@ -204,7 +207,7 @@ export function serializeStateToUrlParam(urlState: ExploreUrlState, compact?: bo
       urlState.range.to,
       urlState.datasource,
       ...urlState.queries,
-      { ui: [!!urlState.ui.showingGraph, !!urlState.ui.showingLogs, !!urlState.ui.showingTable] },
+      { ui: [!!urlState.ui.showingGraph, !!urlState.ui.showingLogs, !!urlState.ui.showingTable, urlState.ui.dedupStrategy] },
     ]);
   }
   return JSON.stringify(urlState);

+ 14 - 13
public/app/features/explore/Logs.tsx

@@ -57,14 +57,15 @@ interface Props {
   range?: RawTimeRange;
   scanning?: boolean;
   scanRange?: RawTimeRange;
+  dedupStrategy: LogsDedupStrategy;
   onChangeTime?: (range: RawTimeRange) => void;
   onClickLabel?: (label: string, value: string) => void;
   onStartScanning?: () => void;
   onStopScanning?: () => void;
+  onDedupStrategyChange: (dedupStrategy: LogsDedupStrategy) => void;
 }
 
 interface State {
-  dedup: LogsDedupStrategy;
   deferLogs: boolean;
   hiddenLogLevels: Set<LogLevel>;
   renderAll: boolean;
@@ -78,7 +79,6 @@ export default class Logs extends PureComponent<Props, State> {
   renderAllTimer: NodeJS.Timer;
 
   state = {
-    dedup: LogsDedupStrategy.none,
     deferLogs: true,
     hiddenLogLevels: new Set(),
     renderAll: false,
@@ -111,12 +111,11 @@ export default class Logs extends PureComponent<Props, State> {
   }
 
   onChangeDedup = (dedup: LogsDedupStrategy) => {
-    this.setState(prevState => {
-      if (prevState.dedup === dedup) {
-        return { dedup: LogsDedupStrategy.none };
-      }
-      return { dedup };
-    });
+    const { onDedupStrategyChange } = this.props;
+    if (this.props.dedupStrategy === dedup) {
+      return onDedupStrategyChange(LogsDedupStrategy.none);
+    }
+    return onDedupStrategyChange(dedup);
   };
 
   onChangeLabels = (event: React.SyntheticEvent) => {
@@ -171,17 +170,19 @@ export default class Logs extends PureComponent<Props, State> {
       return null;
     }
 
-    const { dedup, deferLogs, hiddenLogLevels, renderAll, showLocalTime, showUtc } = this.state;
+    const { deferLogs, hiddenLogLevels, renderAll, showLocalTime, showUtc,  } = this.state;
     let { showLabels } = this.state;
+    const { dedupStrategy } = this.props;
     const hasData = data && data.rows && data.rows.length > 0;
-    const showDuplicates = dedup !== LogsDedupStrategy.none;
+    const showDuplicates = dedupStrategy !== LogsDedupStrategy.none;
 
     // Filtering
     const filteredData = filterLogLevels(data, hiddenLogLevels);
-    const dedupedData = dedupLogRows(filteredData, dedup);
+    const dedupedData = dedupLogRows(filteredData, dedupStrategy);
     const dedupCount = dedupedData.rows.reduce((sum, row) => sum + row.duplicates, 0);
     const meta = [...data.meta];
-    if (dedup !== LogsDedupStrategy.none) {
+
+    if (dedupStrategy !== LogsDedupStrategy.none) {
       meta.push({
         label: 'Dedup count',
         value: dedupCount,
@@ -233,7 +234,7 @@ export default class Logs extends PureComponent<Props, State> {
                   key={i}
                   value={dedupType}
                   onChange={this.onChangeDedup}
-                  selected={dedup === dedupType}
+                  selected={dedupStrategy === dedupType}
                   tooltip={LogsDedupDescription[dedupType]}
                 >
                   {dedupType}

+ 26 - 4
public/app/features/explore/LogsContainer.tsx

@@ -4,10 +4,10 @@ import { connect } from 'react-redux';
 import { RawTimeRange, TimeRange } from '@grafana/ui';
 
 import { ExploreId, ExploreItemState } from 'app/types/explore';
-import { LogsModel } from 'app/core/logs_model';
+import { LogsModel, LogsDedupStrategy } from 'app/core/logs_model';
 import { StoreState } from 'app/types';
 
-import { toggleLogs } from './state/actions';
+import { toggleLogs, changeDedupStrategy } from './state/actions';
 import Logs from './Logs';
 import Panel from './Panel';
 
@@ -25,6 +25,8 @@ interface LogsContainerProps {
   scanRange?: RawTimeRange;
   showingLogs: boolean;
   toggleLogs: typeof toggleLogs;
+  changeDedupStrategy: typeof changeDedupStrategy;
+  dedupStrategy: LogsDedupStrategy;
 }
 
 export class LogsContainer extends PureComponent<LogsContainerProps> {
@@ -32,6 +34,10 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
     this.props.toggleLogs(this.props.exploreId);
   };
 
+  handleDedupStrategyChange = (dedupStrategy: LogsDedupStrategy) => {
+    this.props.changeDedupStrategy(this.props.exploreId, dedupStrategy);
+  };
+
   render() {
     const {
       exploreId,
@@ -45,12 +51,13 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
       range,
       showingLogs,
       scanning,
-      scanRange,
+      scanRange
     } = this.props;
 
     return (
       <Panel label="Logs" loading={loading} isOpen={showingLogs} onToggle={this.onClickLogsButton}>
         <Logs
+          dedupStrategy={this.props.dedupStrategy || LogsDedupStrategy.none}
           data={logsResult}
           exploreId={exploreId}
           key={logsResult && logsResult.id}
@@ -60,6 +67,7 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
           onClickLabel={onClickLabel}
           onStartScanning={onStartScanning}
           onStopScanning={onStopScanning}
+          onDedupStrategyChange={this.handleDedupStrategyChange}
           range={range}
           scanning={scanning}
           scanRange={scanRange}
@@ -69,11 +77,23 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
   }
 }
 
+const selectItemUIState = (itemState: ExploreItemState) => {
+  const { showingGraph, showingLogs, showingTable, showingStartPage, dedupStrategy } = itemState;
+  return {
+    showingGraph,
+    showingLogs,
+    showingTable,
+    showingStartPage,
+    dedupStrategy,
+  };
+};
 function mapStateToProps(state: StoreState, { exploreId }) {
   const explore = state.explore;
   const item: ExploreItemState = explore[exploreId];
-  const { logsHighlighterExpressions, logsResult, queryTransactions, scanning, scanRange, showingLogs, range } = item;
+  const { logsHighlighterExpressions, logsResult, queryTransactions, scanning, scanRange, range } = item;
   const loading = queryTransactions.some(qt => qt.resultType === 'Logs' && !qt.done);
+  const {showingLogs, dedupStrategy} = selectItemUIState(item);
+  // const dedup = item.dedup;
   return {
     loading,
     logsHighlighterExpressions,
@@ -82,11 +102,13 @@ function mapStateToProps(state: StoreState, { exploreId }) {
     scanRange,
     showingLogs,
     range,
+    dedupStrategy,
   };
 }
 
 const mapDispatchToProps = {
   toggleLogs,
+  changeDedupStrategy,
 };
 
 export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(LogsContainer));

+ 11 - 0
public/app/features/explore/state/actionTypes.ts

@@ -180,6 +180,8 @@ export interface SplitOpenPayload {
   itemState: ExploreItemState;
 }
 
+//
+
 export interface ToggleTablePayload {
   exploreId: ExploreId;
 }
@@ -192,6 +194,10 @@ export interface ToggleLogsPayload {
   exploreId: ExploreId;
 }
 
+export interface UpdateUIStatePayload extends Partial<ExploreUIState>{
+  exploreId: ExploreId;
+}
+
 export interface UpdateDatasourceInstancePayload {
   exploreId: ExploreId;
   datasourceInstance: DataSourceApi;
@@ -366,6 +372,11 @@ export const splitCloseAction = noPayloadActionCreatorFactory('explore/SPLIT_CLO
 export const splitOpenAction = actionCreatorFactory<SplitOpenPayload>('explore/SPLIT_OPEN').create();
 export const stateSaveAction = noPayloadActionCreatorFactory('explore/STATE_SAVE').create();
 
+/**
+ * Update state of Explores UI
+ */
+export const updateUIStateAction = actionCreatorFactory<UpdateUIStatePayload>('explore/UPDATE_UI_STATE').create();
+
 /**
  * Expand/collapse the table result viewer. When collapsed, table queries won't be run.
  */

+ 44 - 10
public/app/features/explore/state/actions.ts

@@ -67,14 +67,26 @@ import {
   ToggleGraphPayload,
   ToggleLogsPayload,
   ToggleTablePayload,
+  updateUIStateAction,
 } from './actionTypes';
 import { ActionOf, ActionCreator } from 'app/core/redux/actionCreatorFactory';
+import { LogsDedupStrategy } from 'app/core/logs_model';
 
 type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action>;
 
-// /**
-//  * Adds a query row after the row with the given index.
-//  */
+/**
+ * Updates UI state and save it to the URL
+ */
+const updateExploreUIState = (exploreId, uiStateFragment: Partial<ExploreUIState>) => {
+  return dispatch => {
+    dispatch(updateUIStateAction({ exploreId, ...uiStateFragment }));
+    dispatch(stateSave());
+  };
+};
+
+/**
+ * Adds a query row after the row with the given index.
+ */
 export function addQueryRow(exploreId: ExploreId, index: number): ActionOf<AddQueryRowPayload> {
   const query = generateEmptyQuery(index + 1);
   return addQueryRowAction({ exploreId, index, query });
@@ -669,6 +681,7 @@ export function stateSave() {
         showingGraph: left.showingGraph,
         showingLogs: left.showingLogs,
         showingTable: left.showingTable,
+        dedupStrategy: left.dedupStrategy,
       },
     };
     urlStates.left = serializeStateToUrlParam(leftUrlState, true);
@@ -677,7 +690,12 @@ export function stateSave() {
         datasource: right.datasourceInstance.name,
         queries: right.queries.map(clearQueryKeys),
         range: right.range,
-        ui: { showingGraph: right.showingGraph, showingLogs: right.showingLogs, showingTable: right.showingTable },
+        ui: {
+          showingGraph: right.showingGraph,
+          showingLogs: right.showingLogs,
+          showingTable: right.showingTable,
+          dedupStrategy: right.dedupStrategy,
+        },
       };
 
       urlStates.right = serializeStateToUrlParam(rightUrlState, true);
@@ -698,22 +716,29 @@ const togglePanelActionCreator = (
     | ActionCreator<ToggleTablePayload>
 ) => (exploreId: ExploreId) => {
   return (dispatch, getState) => {
-    let shouldRunQueries;
-    dispatch(actionCreator({ exploreId }));
-    dispatch(stateSave());
+    let shouldRunQueries, uiFragmentStateUpdate: Partial<ExploreUIState>;
 
     switch (actionCreator.type) {
       case toggleGraphAction.type:
-        shouldRunQueries = getState().explore[exploreId].showingGraph;
+        const isShowingGraph = getState().explore[exploreId].showingGraph;
+        shouldRunQueries = !isShowingGraph;
+        uiFragmentStateUpdate = { showingGraph: !isShowingGraph };
         break;
       case toggleLogsAction.type:
-        shouldRunQueries = getState().explore[exploreId].showingLogs;
+        const isShowingLogs = getState().explore[exploreId].showingLogs;
+        shouldRunQueries = !isShowingLogs;
+        uiFragmentStateUpdate = { showingLogs: !isShowingLogs };
         break;
       case toggleTableAction.type:
-        shouldRunQueries = getState().explore[exploreId].showingTable;
+        const isShowingTable = getState().explore[exploreId].showingTable;
+        shouldRunQueries = !isShowingTable;
+        uiFragmentStateUpdate = { showingTable: !isShowingTable };
         break;
     }
 
+    dispatch(actionCreator({ exploreId }));
+    dispatch(updateExploreUIState(exploreId, uiFragmentStateUpdate));
+
     if (shouldRunQueries) {
       dispatch(runQueries(exploreId));
     }
@@ -734,3 +759,12 @@ export const toggleLogs = togglePanelActionCreator(toggleLogsAction);
  * Expand/collapse the table result viewer. When collapsed, table queries won't be run.
  */
 export const toggleTable = togglePanelActionCreator(toggleTableAction);
+
+/**
+ * Change logs deduplication strategy and update URL.
+ */
+export const changeDedupStrategy = (exploreId, dedupStrategy: LogsDedupStrategy) => {
+  return dispatch => {
+    dispatch(updateExploreUIState(exploreId, { dedupStrategy }));
+  };
+};

+ 11 - 4
public/app/features/explore/state/reducers.ts

@@ -37,6 +37,7 @@ import {
   toggleLogsAction,
   toggleTableAction,
   queriesImportedAction,
+  updateUIStateAction,
 } from './actionTypes';
 
 export const DEFAULT_RANGE = {
@@ -406,6 +407,12 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta
       };
     },
   })
+  .addMapper({
+    filter: updateUIStateAction,
+    mapper: (state, action): ExploreItemState => {
+      return { ...state, ...action.payload };
+    },
+  })
   .addMapper({
     filter: toggleGraphAction,
     mapper: (state): ExploreItemState => {
@@ -415,7 +422,7 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta
         // Discard transactions related to Graph query
         nextQueryTransactions = state.queryTransactions.filter(qt => qt.resultType !== 'Graph');
       }
-      return { ...state, queryTransactions: nextQueryTransactions, showingGraph };
+      return { ...state, queryTransactions: nextQueryTransactions };
     },
   })
   .addMapper({
@@ -427,7 +434,7 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta
         // Discard transactions related to Logs query
         nextQueryTransactions = state.queryTransactions.filter(qt => qt.resultType !== 'Logs');
       }
-      return { ...state, queryTransactions: nextQueryTransactions, showingLogs };
+      return { ...state, queryTransactions: nextQueryTransactions };
     },
   })
   .addMapper({
@@ -435,7 +442,7 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta
     mapper: (state): ExploreItemState => {
       const showingTable = !state.showingTable;
       if (showingTable) {
-        return { ...state, showingTable, queryTransactions: state.queryTransactions };
+        return { ...state, queryTransactions: state.queryTransactions };
       }
 
       // Toggle off needs discarding of table queries and results
@@ -446,7 +453,7 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta
         state.queryIntervals.intervalMs
       );
 
-      return { ...state, ...results, queryTransactions: nextQueryTransactions, showingTable };
+      return { ...state, ...results, queryTransactions: nextQueryTransactions };
     },
   })
   .addMapper({

+ 7 - 1
public/app/types/explore.ts

@@ -11,7 +11,7 @@ import {
 } from '@grafana/ui';
 
 import { Emitter } from 'app/core/core';
-import { LogsModel } from 'app/core/logs_model';
+import { LogsModel, LogsDedupStrategy } from 'app/core/logs_model';
 import TableModel from 'app/core/table_model';
 
 export interface CompletionItem {
@@ -237,12 +237,18 @@ export interface ExploreItemState {
    * React keys for rendering of QueryRows
    */
   queryKeys: string[];
+
+  /**
+   * Current logs deduplication strategy
+   */
+  dedupStrategy?: LogsDedupStrategy;
 }
 
 export interface ExploreUIState {
   showingTable: boolean;
   showingGraph: boolean;
   showingLogs: boolean;
+  dedupStrategy?: LogsDedupStrategy;
 }
 
 export interface ExploreUrlState {