|
@@ -17,6 +17,7 @@ import { DataSourceSelectItem } from 'app/types/datasources';
|
|
|
import { DataQuery, StoreState } from 'app/types';
|
|
import { DataQuery, StoreState } from 'app/types';
|
|
|
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
|
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
|
|
import {
|
|
import {
|
|
|
|
|
+ ExploreId,
|
|
|
HistoryItem,
|
|
HistoryItem,
|
|
|
RangeScanner,
|
|
RangeScanner,
|
|
|
ResultType,
|
|
ResultType,
|
|
@@ -26,7 +27,7 @@ import {
|
|
|
QueryHintGetter,
|
|
QueryHintGetter,
|
|
|
} from 'app/types/explore';
|
|
} from 'app/types/explore';
|
|
|
import { Emitter } from 'app/core/core';
|
|
import { Emitter } from 'app/core/core';
|
|
|
-import { dispatch } from 'rxjs/internal/observable/pairs';
|
|
|
|
|
|
|
+import { ExploreItemState } from './reducers';
|
|
|
|
|
|
|
|
export enum ActionTypes {
|
|
export enum ActionTypes {
|
|
|
AddQueryRow = 'ADD_QUERY_ROW',
|
|
AddQueryRow = 'ADD_QUERY_ROW',
|
|
@@ -35,9 +36,11 @@ export enum ActionTypes {
|
|
|
ChangeSize = 'CHANGE_SIZE',
|
|
ChangeSize = 'CHANGE_SIZE',
|
|
|
ChangeTime = 'CHANGE_TIME',
|
|
ChangeTime = 'CHANGE_TIME',
|
|
|
ClickClear = 'CLICK_CLEAR',
|
|
ClickClear = 'CLICK_CLEAR',
|
|
|
|
|
+ ClickCloseSplit = 'CLICK_CLOSE_SPLIT',
|
|
|
ClickExample = 'CLICK_EXAMPLE',
|
|
ClickExample = 'CLICK_EXAMPLE',
|
|
|
ClickGraphButton = 'CLICK_GRAPH_BUTTON',
|
|
ClickGraphButton = 'CLICK_GRAPH_BUTTON',
|
|
|
ClickLogsButton = 'CLICK_LOGS_BUTTON',
|
|
ClickLogsButton = 'CLICK_LOGS_BUTTON',
|
|
|
|
|
+ ClickSplit = 'CLICK_SPLIT',
|
|
|
ClickTableButton = 'CLICK_TABLE_BUTTON',
|
|
ClickTableButton = 'CLICK_TABLE_BUTTON',
|
|
|
HighlightLogsExpression = 'HIGHLIGHT_LOGS_EXPRESSION',
|
|
HighlightLogsExpression = 'HIGHLIGHT_LOGS_EXPRESSION',
|
|
|
InitializeExplore = 'INITIALIZE_EXPLORE',
|
|
InitializeExplore = 'INITIALIZE_EXPLORE',
|
|
@@ -59,12 +62,14 @@ export enum ActionTypes {
|
|
|
|
|
|
|
|
export interface AddQueryRowAction {
|
|
export interface AddQueryRowAction {
|
|
|
type: ActionTypes.AddQueryRow;
|
|
type: ActionTypes.AddQueryRow;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
index: number;
|
|
index: number;
|
|
|
query: DataQuery;
|
|
query: DataQuery;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface ChangeQueryAction {
|
|
export interface ChangeQueryAction {
|
|
|
type: ActionTypes.ChangeQuery;
|
|
type: ActionTypes.ChangeQuery;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
query: DataQuery;
|
|
query: DataQuery;
|
|
|
index: number;
|
|
index: number;
|
|
|
override: boolean;
|
|
override: boolean;
|
|
@@ -72,38 +77,55 @@ export interface ChangeQueryAction {
|
|
|
|
|
|
|
|
export interface ChangeSizeAction {
|
|
export interface ChangeSizeAction {
|
|
|
type: ActionTypes.ChangeSize;
|
|
type: ActionTypes.ChangeSize;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
width: number;
|
|
width: number;
|
|
|
height: number;
|
|
height: number;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface ChangeTimeAction {
|
|
export interface ChangeTimeAction {
|
|
|
type: ActionTypes.ChangeTime;
|
|
type: ActionTypes.ChangeTime;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
range: TimeRange;
|
|
range: TimeRange;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface ClickClearAction {
|
|
export interface ClickClearAction {
|
|
|
type: ActionTypes.ClickClear;
|
|
type: ActionTypes.ClickClear;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export interface ClickCloseSplitAction {
|
|
|
|
|
+ type: ActionTypes.ClickCloseSplit;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface ClickExampleAction {
|
|
export interface ClickExampleAction {
|
|
|
type: ActionTypes.ClickExample;
|
|
type: ActionTypes.ClickExample;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
query: DataQuery;
|
|
query: DataQuery;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface ClickGraphButtonAction {
|
|
export interface ClickGraphButtonAction {
|
|
|
type: ActionTypes.ClickGraphButton;
|
|
type: ActionTypes.ClickGraphButton;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface ClickLogsButtonAction {
|
|
export interface ClickLogsButtonAction {
|
|
|
type: ActionTypes.ClickLogsButton;
|
|
type: ActionTypes.ClickLogsButton;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export interface ClickSplitAction {
|
|
|
|
|
+ type: ActionTypes.ClickSplit;
|
|
|
|
|
+ itemState: ExploreItemState;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface ClickTableButtonAction {
|
|
export interface ClickTableButtonAction {
|
|
|
type: ActionTypes.ClickTableButton;
|
|
type: ActionTypes.ClickTableButton;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface InitializeExploreAction {
|
|
export interface InitializeExploreAction {
|
|
|
type: ActionTypes.InitializeExplore;
|
|
type: ActionTypes.InitializeExplore;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
containerWidth: number;
|
|
containerWidth: number;
|
|
|
datasource: string;
|
|
datasource: string;
|
|
|
eventBridge: Emitter;
|
|
eventBridge: Emitter;
|
|
@@ -114,25 +136,30 @@ export interface InitializeExploreAction {
|
|
|
|
|
|
|
|
export interface HighlightLogsExpressionAction {
|
|
export interface HighlightLogsExpressionAction {
|
|
|
type: ActionTypes.HighlightLogsExpression;
|
|
type: ActionTypes.HighlightLogsExpression;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
expressions: string[];
|
|
expressions: string[];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface LoadDatasourceFailureAction {
|
|
export interface LoadDatasourceFailureAction {
|
|
|
type: ActionTypes.LoadDatasourceFailure;
|
|
type: ActionTypes.LoadDatasourceFailure;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
error: string;
|
|
error: string;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface LoadDatasourcePendingAction {
|
|
export interface LoadDatasourcePendingAction {
|
|
|
type: ActionTypes.LoadDatasourcePending;
|
|
type: ActionTypes.LoadDatasourcePending;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
datasourceId: number;
|
|
datasourceId: number;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface LoadDatasourceMissingAction {
|
|
export interface LoadDatasourceMissingAction {
|
|
|
type: ActionTypes.LoadDatasourceMissing;
|
|
type: ActionTypes.LoadDatasourceMissing;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface LoadDatasourceSuccessAction {
|
|
export interface LoadDatasourceSuccessAction {
|
|
|
type: ActionTypes.LoadDatasourceSuccess;
|
|
type: ActionTypes.LoadDatasourceSuccess;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
StartPage?: any;
|
|
StartPage?: any;
|
|
|
datasourceInstance: any;
|
|
datasourceInstance: any;
|
|
|
history: HistoryItem[];
|
|
history: HistoryItem[];
|
|
@@ -147,6 +174,7 @@ export interface LoadDatasourceSuccessAction {
|
|
|
|
|
|
|
|
export interface ModifyQueriesAction {
|
|
export interface ModifyQueriesAction {
|
|
|
type: ActionTypes.ModifyQueries;
|
|
type: ActionTypes.ModifyQueries;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
modification: any;
|
|
modification: any;
|
|
|
index: number;
|
|
index: number;
|
|
|
modifier: (queries: DataQuery[], modification: any) => DataQuery[];
|
|
modifier: (queries: DataQuery[], modification: any) => DataQuery[];
|
|
@@ -154,11 +182,13 @@ export interface ModifyQueriesAction {
|
|
|
|
|
|
|
|
export interface QueryTransactionFailureAction {
|
|
export interface QueryTransactionFailureAction {
|
|
|
type: ActionTypes.QueryTransactionFailure;
|
|
type: ActionTypes.QueryTransactionFailure;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
queryTransactions: QueryTransaction[];
|
|
queryTransactions: QueryTransaction[];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface QueryTransactionStartAction {
|
|
export interface QueryTransactionStartAction {
|
|
|
type: ActionTypes.QueryTransactionStart;
|
|
type: ActionTypes.QueryTransactionStart;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
resultType: ResultType;
|
|
resultType: ResultType;
|
|
|
rowIndex: number;
|
|
rowIndex: number;
|
|
|
transaction: QueryTransaction;
|
|
transaction: QueryTransaction;
|
|
@@ -166,27 +196,32 @@ export interface QueryTransactionStartAction {
|
|
|
|
|
|
|
|
export interface QueryTransactionSuccessAction {
|
|
export interface QueryTransactionSuccessAction {
|
|
|
type: ActionTypes.QueryTransactionSuccess;
|
|
type: ActionTypes.QueryTransactionSuccess;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
history: HistoryItem[];
|
|
history: HistoryItem[];
|
|
|
queryTransactions: QueryTransaction[];
|
|
queryTransactions: QueryTransaction[];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface RemoveQueryRowAction {
|
|
export interface RemoveQueryRowAction {
|
|
|
type: ActionTypes.RemoveQueryRow;
|
|
type: ActionTypes.RemoveQueryRow;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
index: number;
|
|
index: number;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface ScanStartAction {
|
|
export interface ScanStartAction {
|
|
|
type: ActionTypes.ScanStart;
|
|
type: ActionTypes.ScanStart;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
scanner: RangeScanner;
|
|
scanner: RangeScanner;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface ScanRangeAction {
|
|
export interface ScanRangeAction {
|
|
|
type: ActionTypes.ScanRange;
|
|
type: ActionTypes.ScanRange;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
range: RawTimeRange;
|
|
range: RawTimeRange;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface ScanStopAction {
|
|
export interface ScanStopAction {
|
|
|
type: ActionTypes.ScanStop;
|
|
type: ActionTypes.ScanStop;
|
|
|
|
|
+ exploreId: ExploreId;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export type Action =
|
|
export type Action =
|
|
@@ -195,9 +230,11 @@ export type Action =
|
|
|
| ChangeSizeAction
|
|
| ChangeSizeAction
|
|
|
| ChangeTimeAction
|
|
| ChangeTimeAction
|
|
|
| ClickClearAction
|
|
| ClickClearAction
|
|
|
|
|
+ | ClickCloseSplitAction
|
|
|
| ClickExampleAction
|
|
| ClickExampleAction
|
|
|
| ClickGraphButtonAction
|
|
| ClickGraphButtonAction
|
|
|
| ClickLogsButtonAction
|
|
| ClickLogsButtonAction
|
|
|
|
|
+ | ClickSplitAction
|
|
|
| ClickTableButtonAction
|
|
| ClickTableButtonAction
|
|
|
| HighlightLogsExpressionAction
|
|
| HighlightLogsExpressionAction
|
|
|
| InitializeExploreAction
|
|
| InitializeExploreAction
|
|
@@ -215,94 +252,126 @@ export type Action =
|
|
|
| ScanStopAction;
|
|
| ScanStopAction;
|
|
|
type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action>;
|
|
type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action>;
|
|
|
|
|
|
|
|
-export function addQueryRow(index: number): AddQueryRowAction {
|
|
|
|
|
|
|
+export function addQueryRow(exploreId: ExploreId, index: number): AddQueryRowAction {
|
|
|
const query = generateEmptyQuery(index + 1);
|
|
const query = generateEmptyQuery(index + 1);
|
|
|
- return { type: ActionTypes.AddQueryRow, index, query };
|
|
|
|
|
|
|
+ return { type: ActionTypes.AddQueryRow, exploreId, index, query };
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function changeDatasource(datasource: string): ThunkResult<void> {
|
|
|
|
|
|
|
+export function changeDatasource(exploreId: ExploreId, datasource: string): ThunkResult<void> {
|
|
|
return async dispatch => {
|
|
return async dispatch => {
|
|
|
const instance = await getDatasourceSrv().get(datasource);
|
|
const instance = await getDatasourceSrv().get(datasource);
|
|
|
- dispatch(loadDatasource(instance));
|
|
|
|
|
|
|
+ dispatch(loadDatasource(exploreId, instance));
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function changeQuery(query: DataQuery, index: number, override: boolean): ThunkResult<void> {
|
|
|
|
|
|
|
+export function changeQuery(
|
|
|
|
|
+ exploreId: ExploreId,
|
|
|
|
|
+ query: DataQuery,
|
|
|
|
|
+ index: number,
|
|
|
|
|
+ override: boolean
|
|
|
|
|
+): ThunkResult<void> {
|
|
|
return dispatch => {
|
|
return dispatch => {
|
|
|
// Null query means reset
|
|
// Null query means reset
|
|
|
if (query === null) {
|
|
if (query === null) {
|
|
|
query = { ...generateEmptyQuery(index) };
|
|
query = { ...generateEmptyQuery(index) };
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- dispatch({ type: ActionTypes.ChangeQuery, query, index, override });
|
|
|
|
|
|
|
+ dispatch({ type: ActionTypes.ChangeQuery, exploreId, query, index, override });
|
|
|
if (override) {
|
|
if (override) {
|
|
|
- dispatch(runQueries());
|
|
|
|
|
|
|
+ dispatch(runQueries(exploreId));
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function changeSize({ height, width }: { height: number; width: number }): ChangeSizeAction {
|
|
|
|
|
- return { type: ActionTypes.ChangeSize, height, width };
|
|
|
|
|
|
|
+export function changeSize(
|
|
|
|
|
+ exploreId: ExploreId,
|
|
|
|
|
+ { height, width }: { height: number; width: number }
|
|
|
|
|
+): ChangeSizeAction {
|
|
|
|
|
+ return { type: ActionTypes.ChangeSize, exploreId, height, width };
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export function changeTime(exploreId: ExploreId, range: TimeRange): ThunkResult<void> {
|
|
|
|
|
+ return dispatch => {
|
|
|
|
|
+ dispatch({ type: ActionTypes.ChangeTime, exploreId, range });
|
|
|
|
|
+ dispatch(runQueries(exploreId));
|
|
|
|
|
+ };
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function changeTime(range: TimeRange): ThunkResult<void> {
|
|
|
|
|
|
|
+export function clickClear(exploreId: ExploreId): ThunkResult<void> {
|
|
|
return dispatch => {
|
|
return dispatch => {
|
|
|
- dispatch({ type: ActionTypes.ChangeTime, range });
|
|
|
|
|
- dispatch(runQueries());
|
|
|
|
|
|
|
+ dispatch(scanStop(exploreId));
|
|
|
|
|
+ dispatch({ type: ActionTypes.ClickClear, exploreId });
|
|
|
|
|
+ // TODO save state
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function clickExample(rawQuery: DataQuery): ThunkResult<void> {
|
|
|
|
|
|
|
+export function clickCloseSplit(): ThunkResult<void> {
|
|
|
|
|
+ return dispatch => {
|
|
|
|
|
+ dispatch({ type: ActionTypes.ClickCloseSplit });
|
|
|
|
|
+ // When closing split, remove URL state for split part
|
|
|
|
|
+ // TODO save state
|
|
|
|
|
+ };
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export function clickExample(exploreId: ExploreId, rawQuery: DataQuery): ThunkResult<void> {
|
|
|
return dispatch => {
|
|
return dispatch => {
|
|
|
const query = { ...rawQuery, ...generateEmptyQuery() };
|
|
const query = { ...rawQuery, ...generateEmptyQuery() };
|
|
|
dispatch({
|
|
dispatch({
|
|
|
type: ActionTypes.ClickExample,
|
|
type: ActionTypes.ClickExample,
|
|
|
|
|
+ exploreId,
|
|
|
query,
|
|
query,
|
|
|
});
|
|
});
|
|
|
- dispatch(runQueries());
|
|
|
|
|
|
|
+ dispatch(runQueries(exploreId));
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function clickClear(): ThunkResult<void> {
|
|
|
|
|
- return dispatch => {
|
|
|
|
|
- dispatch(scanStop());
|
|
|
|
|
- dispatch({ type: ActionTypes.ClickClear });
|
|
|
|
|
- // TODO save state
|
|
|
|
|
|
|
+export function clickGraphButton(exploreId: ExploreId): ThunkResult<void> {
|
|
|
|
|
+ return (dispatch, getState) => {
|
|
|
|
|
+ dispatch({ type: ActionTypes.ClickGraphButton, exploreId });
|
|
|
|
|
+ if (getState().explore[exploreId].showingGraph) {
|
|
|
|
|
+ dispatch(runQueries(exploreId));
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function clickGraphButton(): ThunkResult<void> {
|
|
|
|
|
|
|
+export function clickLogsButton(exploreId: ExploreId): ThunkResult<void> {
|
|
|
return (dispatch, getState) => {
|
|
return (dispatch, getState) => {
|
|
|
- dispatch({ type: ActionTypes.ClickGraphButton });
|
|
|
|
|
- if (getState().explore.showingGraph) {
|
|
|
|
|
- dispatch(runQueries());
|
|
|
|
|
|
|
+ dispatch({ type: ActionTypes.ClickLogsButton, exploreId });
|
|
|
|
|
+ if (getState().explore[exploreId].showingLogs) {
|
|
|
|
|
+ dispatch(runQueries(exploreId));
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function clickLogsButton(): ThunkResult<void> {
|
|
|
|
|
|
|
+export function clickSplit(): ThunkResult<void> {
|
|
|
return (dispatch, getState) => {
|
|
return (dispatch, getState) => {
|
|
|
- dispatch({ type: ActionTypes.ClickLogsButton });
|
|
|
|
|
- if (getState().explore.showingLogs) {
|
|
|
|
|
- dispatch(runQueries());
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // Clone left state to become the right state
|
|
|
|
|
+ const leftState = getState().explore.left;
|
|
|
|
|
+ const itemState = {
|
|
|
|
|
+ ...leftState,
|
|
|
|
|
+ queryTransactions: [],
|
|
|
|
|
+ initialQueries: leftState.modifiedQueries.slice(),
|
|
|
|
|
+ };
|
|
|
|
|
+ dispatch({ type: ActionTypes.ClickSplit, itemState });
|
|
|
|
|
+ // TODO save state
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function clickTableButton(): ThunkResult<void> {
|
|
|
|
|
|
|
+export function clickTableButton(exploreId: ExploreId): ThunkResult<void> {
|
|
|
return (dispatch, getState) => {
|
|
return (dispatch, getState) => {
|
|
|
- dispatch({ type: ActionTypes.ClickTableButton });
|
|
|
|
|
- if (getState().explore.showingTable) {
|
|
|
|
|
- dispatch(runQueries());
|
|
|
|
|
|
|
+ dispatch({ type: ActionTypes.ClickTableButton, exploreId });
|
|
|
|
|
+ if (getState().explore[exploreId].showingTable) {
|
|
|
|
|
+ dispatch(runQueries(exploreId));
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function highlightLogsExpression(expressions: string[]): HighlightLogsExpressionAction {
|
|
|
|
|
- return { type: ActionTypes.HighlightLogsExpression, expressions };
|
|
|
|
|
|
|
+export function highlightLogsExpression(exploreId: ExploreId, expressions: string[]): HighlightLogsExpressionAction {
|
|
|
|
|
+ return { type: ActionTypes.HighlightLogsExpression, exploreId, expressions };
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export function initializeExplore(
|
|
export function initializeExplore(
|
|
|
|
|
+ exploreId: ExploreId,
|
|
|
datasource: string,
|
|
datasource: string,
|
|
|
queries: DataQuery[],
|
|
queries: DataQuery[],
|
|
|
range: RawTimeRange,
|
|
range: RawTimeRange,
|
|
@@ -320,6 +389,7 @@ export function initializeExplore(
|
|
|
|
|
|
|
|
dispatch({
|
|
dispatch({
|
|
|
type: ActionTypes.InitializeExplore,
|
|
type: ActionTypes.InitializeExplore,
|
|
|
|
|
+ exploreId,
|
|
|
containerWidth,
|
|
containerWidth,
|
|
|
datasource,
|
|
datasource,
|
|
|
eventBridge,
|
|
eventBridge,
|
|
@@ -335,26 +405,35 @@ export function initializeExplore(
|
|
|
} else {
|
|
} else {
|
|
|
instance = await getDatasourceSrv().get();
|
|
instance = await getDatasourceSrv().get();
|
|
|
}
|
|
}
|
|
|
- dispatch(loadDatasource(instance));
|
|
|
|
|
|
|
+ dispatch(loadDatasource(exploreId, instance));
|
|
|
} else {
|
|
} else {
|
|
|
- dispatch(loadDatasourceMissing);
|
|
|
|
|
|
|
+ dispatch(loadDatasourceMissing(exploreId));
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export const loadDatasourceFailure = (error: string): LoadDatasourceFailureAction => ({
|
|
|
|
|
|
|
+export const loadDatasourceFailure = (exploreId: ExploreId, error: string): LoadDatasourceFailureAction => ({
|
|
|
type: ActionTypes.LoadDatasourceFailure,
|
|
type: ActionTypes.LoadDatasourceFailure,
|
|
|
|
|
+ exploreId,
|
|
|
error,
|
|
error,
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-export const loadDatasourceMissing: LoadDatasourceMissingAction = { type: ActionTypes.LoadDatasourceMissing };
|
|
|
|
|
|
|
+export const loadDatasourceMissing = (exploreId: ExploreId): LoadDatasourceMissingAction => ({
|
|
|
|
|
+ type: ActionTypes.LoadDatasourceMissing,
|
|
|
|
|
+ exploreId,
|
|
|
|
|
+});
|
|
|
|
|
|
|
|
-export const loadDatasourcePending = (datasourceId: number): LoadDatasourcePendingAction => ({
|
|
|
|
|
|
|
+export const loadDatasourcePending = (exploreId: ExploreId, datasourceId: number): LoadDatasourcePendingAction => ({
|
|
|
type: ActionTypes.LoadDatasourcePending,
|
|
type: ActionTypes.LoadDatasourcePending,
|
|
|
|
|
+ exploreId,
|
|
|
datasourceId,
|
|
datasourceId,
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-export const loadDatasourceSuccess = (instance: any, queries: DataQuery[]): LoadDatasourceSuccessAction => {
|
|
|
|
|
|
|
+export const loadDatasourceSuccess = (
|
|
|
|
|
+ exploreId: ExploreId,
|
|
|
|
|
+ instance: any,
|
|
|
|
|
+ queries: DataQuery[]
|
|
|
|
|
+): LoadDatasourceSuccessAction => {
|
|
|
// Capabilities
|
|
// Capabilities
|
|
|
const supportsGraph = instance.meta.metrics;
|
|
const supportsGraph = instance.meta.metrics;
|
|
|
const supportsLogs = instance.meta.logs;
|
|
const supportsLogs = instance.meta.logs;
|
|
@@ -369,6 +448,7 @@ export const loadDatasourceSuccess = (instance: any, queries: DataQuery[]): Load
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
type: ActionTypes.LoadDatasourceSuccess,
|
|
type: ActionTypes.LoadDatasourceSuccess,
|
|
|
|
|
+ exploreId,
|
|
|
StartPage,
|
|
StartPage,
|
|
|
datasourceInstance: instance,
|
|
datasourceInstance: instance,
|
|
|
history,
|
|
history,
|
|
@@ -381,12 +461,12 @@ export const loadDatasourceSuccess = (instance: any, queries: DataQuery[]): Load
|
|
|
};
|
|
};
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-export function loadDatasource(instance: any): ThunkResult<void> {
|
|
|
|
|
|
|
+export function loadDatasource(exploreId: ExploreId, instance: any): ThunkResult<void> {
|
|
|
return async (dispatch, getState) => {
|
|
return async (dispatch, getState) => {
|
|
|
const datasourceId = instance.meta.id;
|
|
const datasourceId = instance.meta.id;
|
|
|
|
|
|
|
|
// Keep ID to track selection
|
|
// Keep ID to track selection
|
|
|
- dispatch(loadDatasourcePending(datasourceId));
|
|
|
|
|
|
|
+ dispatch(loadDatasourcePending(exploreId, datasourceId));
|
|
|
|
|
|
|
|
let datasourceError = null;
|
|
let datasourceError = null;
|
|
|
try {
|
|
try {
|
|
@@ -396,11 +476,11 @@ export function loadDatasource(instance: any): ThunkResult<void> {
|
|
|
datasourceError = (error && error.statusText) || 'Network error';
|
|
datasourceError = (error && error.statusText) || 'Network error';
|
|
|
}
|
|
}
|
|
|
if (datasourceError) {
|
|
if (datasourceError) {
|
|
|
- dispatch(loadDatasourceFailure(datasourceError));
|
|
|
|
|
|
|
+ dispatch(loadDatasourceFailure(exploreId, datasourceError));
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (datasourceId !== getState().explore.requestedDatasourceId) {
|
|
|
|
|
|
|
+ if (datasourceId !== getState().explore[exploreId].requestedDatasourceId) {
|
|
|
// User already changed datasource again, discard results
|
|
// User already changed datasource again, discard results
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
@@ -410,9 +490,9 @@ export function loadDatasource(instance: any): ThunkResult<void> {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Check if queries can be imported from previously selected datasource
|
|
// Check if queries can be imported from previously selected datasource
|
|
|
- const queries = getState().explore.modifiedQueries;
|
|
|
|
|
|
|
+ const queries = getState().explore[exploreId].modifiedQueries;
|
|
|
let importedQueries = queries;
|
|
let importedQueries = queries;
|
|
|
- const origin = getState().explore.datasourceInstance;
|
|
|
|
|
|
|
+ const origin = getState().explore[exploreId].datasourceInstance;
|
|
|
if (origin) {
|
|
if (origin) {
|
|
|
if (origin.meta.id === instance.meta.id) {
|
|
if (origin.meta.id === instance.meta.id) {
|
|
|
// Keep same queries if same type of datasource
|
|
// Keep same queries if same type of datasource
|
|
@@ -426,7 +506,7 @@ export function loadDatasource(instance: any): ThunkResult<void> {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (datasourceId !== getState().explore.requestedDatasourceId) {
|
|
|
|
|
|
|
+ if (datasourceId !== getState().explore[exploreId].requestedDatasourceId) {
|
|
|
// User already changed datasource again, discard results
|
|
// User already changed datasource again, discard results
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
@@ -437,23 +517,33 @@ export function loadDatasource(instance: any): ThunkResult<void> {
|
|
|
...generateEmptyQuery(i),
|
|
...generateEmptyQuery(i),
|
|
|
}));
|
|
}));
|
|
|
|
|
|
|
|
- dispatch(loadDatasourceSuccess(instance, nextQueries));
|
|
|
|
|
- dispatch(runQueries());
|
|
|
|
|
|
|
+ dispatch(loadDatasourceSuccess(exploreId, instance, nextQueries));
|
|
|
|
|
+ dispatch(runQueries(exploreId));
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function modifyQueries(modification: any, index: number, modifier: any): ThunkResult<void> {
|
|
|
|
|
|
|
+export function modifyQueries(
|
|
|
|
|
+ exploreId: ExploreId,
|
|
|
|
|
+ modification: any,
|
|
|
|
|
+ index: number,
|
|
|
|
|
+ modifier: any
|
|
|
|
|
+): ThunkResult<void> {
|
|
|
return dispatch => {
|
|
return dispatch => {
|
|
|
- dispatch({ type: ActionTypes.ModifyQueries, modification, index, modifier });
|
|
|
|
|
|
|
+ dispatch({ type: ActionTypes.ModifyQueries, exploreId, modification, index, modifier });
|
|
|
if (!modification.preventSubmit) {
|
|
if (!modification.preventSubmit) {
|
|
|
- dispatch(runQueries());
|
|
|
|
|
|
|
+ dispatch(runQueries(exploreId));
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function queryTransactionFailure(transactionId: string, response: any, datasourceId: string): ThunkResult<void> {
|
|
|
|
|
|
|
+export function queryTransactionFailure(
|
|
|
|
|
+ exploreId: ExploreId,
|
|
|
|
|
+ transactionId: string,
|
|
|
|
|
+ response: any,
|
|
|
|
|
+ datasourceId: string
|
|
|
|
|
+): ThunkResult<void> {
|
|
|
return (dispatch, getState) => {
|
|
return (dispatch, getState) => {
|
|
|
- const { datasourceInstance, queryTransactions } = getState().explore;
|
|
|
|
|
|
|
+ const { datasourceInstance, queryTransactions } = getState().explore[exploreId];
|
|
|
if (datasourceInstance.meta.id !== datasourceId || response.cancelled) {
|
|
if (datasourceInstance.meta.id !== datasourceId || response.cancelled) {
|
|
|
// Navigated away, queries did not matter
|
|
// Navigated away, queries did not matter
|
|
|
return;
|
|
return;
|
|
@@ -500,19 +590,21 @@ export function queryTransactionFailure(transactionId: string, response: any, da
|
|
|
return qt;
|
|
return qt;
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- dispatch({ type: ActionTypes.QueryTransactionFailure, queryTransactions: nextQueryTransactions });
|
|
|
|
|
|
|
+ dispatch({ type: ActionTypes.QueryTransactionFailure, exploreId, queryTransactions: nextQueryTransactions });
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export function queryTransactionStart(
|
|
export function queryTransactionStart(
|
|
|
|
|
+ exploreId: ExploreId,
|
|
|
transaction: QueryTransaction,
|
|
transaction: QueryTransaction,
|
|
|
resultType: ResultType,
|
|
resultType: ResultType,
|
|
|
rowIndex: number
|
|
rowIndex: number
|
|
|
): QueryTransactionStartAction {
|
|
): QueryTransactionStartAction {
|
|
|
- return { type: ActionTypes.QueryTransactionStart, resultType, rowIndex, transaction };
|
|
|
|
|
|
|
+ return { type: ActionTypes.QueryTransactionStart, exploreId, resultType, rowIndex, transaction };
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export function queryTransactionSuccess(
|
|
export function queryTransactionSuccess(
|
|
|
|
|
+ exploreId: ExploreId,
|
|
|
transactionId: string,
|
|
transactionId: string,
|
|
|
result: any,
|
|
result: any,
|
|
|
latency: number,
|
|
latency: number,
|
|
@@ -520,7 +612,7 @@ export function queryTransactionSuccess(
|
|
|
datasourceId: string
|
|
datasourceId: string
|
|
|
): ThunkResult<void> {
|
|
): ThunkResult<void> {
|
|
|
return (dispatch, getState) => {
|
|
return (dispatch, getState) => {
|
|
|
- const { datasourceInstance, history, queryTransactions, scanner, scanning } = getState().explore;
|
|
|
|
|
|
|
+ const { datasourceInstance, history, queryTransactions, scanner, scanning } = getState().explore[exploreId];
|
|
|
|
|
|
|
|
// If datasource already changed, results do not matter
|
|
// If datasource already changed, results do not matter
|
|
|
if (datasourceInstance.meta.id !== datasourceId) {
|
|
if (datasourceInstance.meta.id !== datasourceId) {
|
|
@@ -558,6 +650,7 @@ export function queryTransactionSuccess(
|
|
|
|
|
|
|
|
dispatch({
|
|
dispatch({
|
|
|
type: ActionTypes.QueryTransactionSuccess,
|
|
type: ActionTypes.QueryTransactionSuccess,
|
|
|
|
|
+ exploreId,
|
|
|
history: nextHistory,
|
|
history: nextHistory,
|
|
|
queryTransactions: nextQueryTransactions,
|
|
queryTransactions: nextQueryTransactions,
|
|
|
});
|
|
});
|
|
@@ -568,24 +661,24 @@ export function queryTransactionSuccess(
|
|
|
const other = nextQueryTransactions.find(qt => qt.scanning && !qt.done);
|
|
const other = nextQueryTransactions.find(qt => qt.scanning && !qt.done);
|
|
|
if (!other) {
|
|
if (!other) {
|
|
|
const range = scanner();
|
|
const range = scanner();
|
|
|
- dispatch({ type: ActionTypes.ScanRange, range });
|
|
|
|
|
|
|
+ dispatch({ type: ActionTypes.ScanRange, exploreId, range });
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
// We can stop scanning if we have a result
|
|
// We can stop scanning if we have a result
|
|
|
- dispatch(scanStop());
|
|
|
|
|
|
|
+ dispatch(scanStop(exploreId));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function removeQueryRow(index: number): ThunkResult<void> {
|
|
|
|
|
|
|
+export function removeQueryRow(exploreId: ExploreId, index: number): ThunkResult<void> {
|
|
|
return dispatch => {
|
|
return dispatch => {
|
|
|
- dispatch({ type: ActionTypes.RemoveQueryRow, index });
|
|
|
|
|
- dispatch(runQueries());
|
|
|
|
|
|
|
+ dispatch({ type: ActionTypes.RemoveQueryRow, exploreId, index });
|
|
|
|
|
+ dispatch(runQueries(exploreId));
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function runQueries() {
|
|
|
|
|
|
|
+export function runQueries(exploreId: ExploreId) {
|
|
|
return (dispatch, getState) => {
|
|
return (dispatch, getState) => {
|
|
|
const {
|
|
const {
|
|
|
datasourceInstance,
|
|
datasourceInstance,
|
|
@@ -596,10 +689,10 @@ export function runQueries() {
|
|
|
supportsGraph,
|
|
supportsGraph,
|
|
|
supportsLogs,
|
|
supportsLogs,
|
|
|
supportsTable,
|
|
supportsTable,
|
|
|
- } = getState().explore;
|
|
|
|
|
|
|
+ } = getState().explore[exploreId];
|
|
|
|
|
|
|
|
if (!hasNonEmptyQuery(modifiedQueries)) {
|
|
if (!hasNonEmptyQuery(modifiedQueries)) {
|
|
|
- dispatch({ type: ActionTypes.RunQueriesEmpty });
|
|
|
|
|
|
|
+ dispatch({ type: ActionTypes.RunQueriesEmpty, exploreId });
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -611,6 +704,7 @@ export function runQueries() {
|
|
|
if (showingTable && supportsTable) {
|
|
if (showingTable && supportsTable) {
|
|
|
dispatch(
|
|
dispatch(
|
|
|
runQueriesForType(
|
|
runQueriesForType(
|
|
|
|
|
+ exploreId,
|
|
|
'Table',
|
|
'Table',
|
|
|
{
|
|
{
|
|
|
interval,
|
|
interval,
|
|
@@ -625,6 +719,7 @@ export function runQueries() {
|
|
|
if (showingGraph && supportsGraph) {
|
|
if (showingGraph && supportsGraph) {
|
|
|
dispatch(
|
|
dispatch(
|
|
|
runQueriesForType(
|
|
runQueriesForType(
|
|
|
|
|
+ exploreId,
|
|
|
'Graph',
|
|
'Graph',
|
|
|
{
|
|
{
|
|
|
interval,
|
|
interval,
|
|
@@ -636,13 +731,18 @@ export function runQueries() {
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
if (showingLogs && supportsLogs) {
|
|
if (showingLogs && supportsLogs) {
|
|
|
- dispatch(runQueriesForType('Logs', { interval, format: 'logs' }));
|
|
|
|
|
|
|
+ dispatch(runQueriesForType(exploreId, 'Logs', { interval, format: 'logs' }));
|
|
|
}
|
|
}
|
|
|
// TODO save state
|
|
// TODO save state
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function runQueriesForType(resultType: ResultType, queryOptions: QueryOptions, resultGetter?: any) {
|
|
|
|
|
|
|
+function runQueriesForType(
|
|
|
|
|
+ exploreId: ExploreId,
|
|
|
|
|
+ resultType: ResultType,
|
|
|
|
|
+ queryOptions: QueryOptions,
|
|
|
|
|
+ resultGetter?: any
|
|
|
|
|
+) {
|
|
|
return async (dispatch, getState) => {
|
|
return async (dispatch, getState) => {
|
|
|
const {
|
|
const {
|
|
|
datasourceInstance,
|
|
datasourceInstance,
|
|
@@ -651,7 +751,7 @@ function runQueriesForType(resultType: ResultType, queryOptions: QueryOptions, r
|
|
|
queryIntervals,
|
|
queryIntervals,
|
|
|
range,
|
|
range,
|
|
|
scanning,
|
|
scanning,
|
|
|
- } = getState().explore;
|
|
|
|
|
|
|
+ } = getState().explore[exploreId];
|
|
|
const datasourceId = datasourceInstance.meta.id;
|
|
const datasourceId = datasourceInstance.meta.id;
|
|
|
|
|
|
|
|
// Run all queries concurrently
|
|
// Run all queries concurrently
|
|
@@ -665,30 +765,30 @@ function runQueriesForType(resultType: ResultType, queryOptions: QueryOptions, r
|
|
|
queryIntervals,
|
|
queryIntervals,
|
|
|
scanning
|
|
scanning
|
|
|
);
|
|
);
|
|
|
- dispatch(queryTransactionStart(transaction, resultType, rowIndex));
|
|
|
|
|
|
|
+ dispatch(queryTransactionStart(exploreId, transaction, resultType, rowIndex));
|
|
|
try {
|
|
try {
|
|
|
const now = Date.now();
|
|
const now = Date.now();
|
|
|
const res = await datasourceInstance.query(transaction.options);
|
|
const res = await datasourceInstance.query(transaction.options);
|
|
|
eventBridge.emit('data-received', res.data || []);
|
|
eventBridge.emit('data-received', res.data || []);
|
|
|
const latency = Date.now() - now;
|
|
const latency = Date.now() - now;
|
|
|
const results = resultGetter ? resultGetter(res.data) : res.data;
|
|
const results = resultGetter ? resultGetter(res.data) : res.data;
|
|
|
- dispatch(queryTransactionSuccess(transaction.id, results, latency, queries, datasourceId));
|
|
|
|
|
|
|
+ dispatch(queryTransactionSuccess(exploreId, transaction.id, results, latency, queries, datasourceId));
|
|
|
} catch (response) {
|
|
} catch (response) {
|
|
|
eventBridge.emit('data-error', response);
|
|
eventBridge.emit('data-error', response);
|
|
|
- dispatch(queryTransactionFailure(transaction.id, response, datasourceId));
|
|
|
|
|
|
|
+ dispatch(queryTransactionFailure(exploreId, transaction.id, response, datasourceId));
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function scanStart(scanner: RangeScanner): ThunkResult<void> {
|
|
|
|
|
|
|
+export function scanStart(exploreId: ExploreId, scanner: RangeScanner): ThunkResult<void> {
|
|
|
return dispatch => {
|
|
return dispatch => {
|
|
|
- dispatch({ type: ActionTypes.ScanStart, scanner });
|
|
|
|
|
|
|
+ dispatch({ type: ActionTypes.ScanStart, exploreId, scanner });
|
|
|
const range = scanner();
|
|
const range = scanner();
|
|
|
- dispatch({ type: ActionTypes.ScanRange, range });
|
|
|
|
|
|
|
+ dispatch({ type: ActionTypes.ScanRange, exploreId, range });
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function scanStop(): ScanStopAction {
|
|
|
|
|
- return { type: ActionTypes.ScanStop };
|
|
|
|
|
|
|
+export function scanStop(exploreId: ExploreId): ScanStopAction {
|
|
|
|
|
+ return { type: ActionTypes.ScanStop, exploreId };
|
|
|
}
|
|
}
|