Merge pull request #15119 from grafana/explore/queries-import-changes

Fix queries being imported incorrectly on datasource change
This commit is contained in:
Torkel Ödegaard 2019-01-30 16:11:36 +01:00 committed by GitHub
commit bd688449f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 75 additions and 37 deletions

View File

@ -43,6 +43,7 @@ export enum ActionTypes {
ToggleTable = 'explore/TOGGLE_TABLE', ToggleTable = 'explore/TOGGLE_TABLE',
UpdateDatasourceInstance = 'explore/UPDATE_DATASOURCE_INSTANCE', UpdateDatasourceInstance = 'explore/UPDATE_DATASOURCE_INSTANCE',
ResetExplore = 'explore/RESET_EXPLORE', ResetExplore = 'explore/RESET_EXPLORE',
QueriesImported = 'explore/QueriesImported',
} }
export interface AddQueryRowAction { export interface AddQueryRowAction {
@ -142,7 +143,6 @@ export interface LoadDatasourceSuccessAction {
StartPage?: any; StartPage?: any;
datasourceInstance: any; datasourceInstance: any;
history: HistoryItem[]; history: HistoryItem[];
initialQueries: DataQuery[];
logsHighlighterExpressions?: any[]; logsHighlighterExpressions?: any[];
showingStartPage: boolean; showingStartPage: boolean;
supportsGraph: boolean; supportsGraph: boolean;
@ -283,6 +283,14 @@ export interface ResetExploreAction {
payload: {}; payload: {};
} }
export interface QueriesImported {
type: ActionTypes.QueriesImported;
payload: {
exploreId: ExploreId;
queries: DataQuery[];
};
}
export type Action = export type Action =
| AddQueryRowAction | AddQueryRowAction
| ChangeQueryAction | ChangeQueryAction
@ -312,4 +320,5 @@ export type Action =
| ToggleLogsAction | ToggleLogsAction
| ToggleTableAction | ToggleTableAction
| UpdateDatasourceInstanceAction | UpdateDatasourceInstanceAction
| ResetExploreAction; | ResetExploreAction
| QueriesImported;

View File

@ -53,6 +53,7 @@ import {
QueryTransactionStartAction, QueryTransactionStartAction,
ScanStopAction, ScanStopAction,
UpdateDatasourceInstanceAction, UpdateDatasourceInstanceAction,
QueriesImported,
} from './actionTypes'; } from './actionTypes';
type ThunkResult<R> = ThunkAction<R, StoreState, undefined, ThunkableAction>; type ThunkResult<R> = ThunkAction<R, StoreState, undefined, ThunkableAction>;
@ -69,10 +70,15 @@ export function addQueryRow(exploreId: ExploreId, index: number): AddQueryRowAct
* Loads a new datasource identified by the given name. * Loads a new datasource identified by the given name.
*/ */
export function changeDatasource(exploreId: ExploreId, datasource: string): ThunkResult<void> { export function changeDatasource(exploreId: ExploreId, datasource: string): ThunkResult<void> {
return async dispatch => { return async (dispatch, getState) => {
const instance = await getDatasourceSrv().get(datasource); const newDataSourceInstance = await getDatasourceSrv().get(datasource);
dispatch(updateDatasourceInstance(exploreId, instance)); const currentDataSourceInstance = getState().explore[exploreId].datasourceInstance;
dispatch(loadDatasource(exploreId, instance)); const modifiedQueries = getState().explore[exploreId].modifiedQueries;
await dispatch(importQueries(exploreId, modifiedQueries, currentDataSourceInstance, newDataSourceInstance));
dispatch(updateDatasourceInstance(exploreId, newDataSourceInstance));
dispatch(loadDatasource(exploreId, newDataSourceInstance));
}; };
} }
@ -174,6 +180,7 @@ export function initializeExplore(
if (exploreDatasources.length >= 1) { if (exploreDatasources.length >= 1) {
let instance; let instance;
if (datasourceName) { if (datasourceName) {
try { try {
instance = await getDatasourceSrv().get(datasourceName); instance = await getDatasourceSrv().get(datasourceName);
@ -185,6 +192,7 @@ export function initializeExplore(
if (!instance) { if (!instance) {
instance = await getDatasourceSrv().get(); instance = await getDatasourceSrv().get();
} }
dispatch(updateDatasourceInstance(exploreId, instance)); dispatch(updateDatasourceInstance(exploreId, instance));
dispatch(loadDatasource(exploreId, instance)); dispatch(loadDatasource(exploreId, instance));
} else { } else {
@ -224,7 +232,10 @@ export const loadDatasourceMissing = (exploreId: ExploreId): LoadDatasourceMissi
/** /**
* Start the async process of loading a datasource to display a loading indicator * Start the async process of loading a datasource to display a loading indicator
*/ */
export const loadDatasourcePending = (exploreId: ExploreId, requestedDatasourceName: string): LoadDatasourcePendingAction => ({ export const loadDatasourcePending = (
exploreId: ExploreId,
requestedDatasourceName: string
): LoadDatasourcePendingAction => ({
type: ActionTypes.LoadDatasourcePending, type: ActionTypes.LoadDatasourcePending,
payload: { payload: {
exploreId, exploreId,
@ -232,6 +243,16 @@ export const loadDatasourcePending = (exploreId: ExploreId, requestedDatasourceN
}, },
}); });
export const queriesImported = (exploreId: ExploreId, queries: DataQuery[]): QueriesImported => {
return {
type: ActionTypes.QueriesImported,
payload: {
exploreId,
queries,
},
};
};
/** /**
* Datasource loading was successfully completed. The instance is stored in the state as well in case we need to * Datasource loading was successfully completed. The instance is stored in the state as well in case we need to
* run datasource-specific code. Existing queries are imported to the new datasource if an importer exists, * run datasource-specific code. Existing queries are imported to the new datasource if an importer exists,
@ -240,7 +261,6 @@ export const loadDatasourcePending = (exploreId: ExploreId, requestedDatasourceN
export const loadDatasourceSuccess = ( export const loadDatasourceSuccess = (
exploreId: ExploreId, exploreId: ExploreId,
instance: any, instance: any,
queries: DataQuery[]
): LoadDatasourceSuccessAction => { ): LoadDatasourceSuccessAction => {
// Capabilities // Capabilities
const supportsGraph = instance.meta.metrics; const supportsGraph = instance.meta.metrics;
@ -261,7 +281,6 @@ export const loadDatasourceSuccess = (
StartPage, StartPage,
datasourceInstance: instance, datasourceInstance: instance,
history, history,
initialQueries: queries,
showingStartPage: Boolean(StartPage), showingStartPage: Boolean(StartPage),
supportsGraph, supportsGraph,
supportsLogs, supportsLogs,
@ -286,6 +305,35 @@ export function updateDatasourceInstance(
}; };
} }
export function importQueries(
exploreId: ExploreId,
queries: DataQuery[],
sourceDataSource: DataSourceApi,
targetDataSource: DataSourceApi
) {
return async dispatch => {
let importedQueries = queries;
// Check if queries can be imported from previously selected datasource
if (sourceDataSource.meta.id === targetDataSource.meta.id) {
// Keep same queries if same type of datasource
importedQueries = [...queries];
} else if (targetDataSource.importQueries) {
// Datasource-specific importers
importedQueries = await targetDataSource.importQueries(queries, sourceDataSource.meta);
} else {
// Default is blank queries
importedQueries = ensureQueries();
}
const nextQueries = importedQueries.map((q, i) => ({
...importedQueries[i],
...generateEmptyQuery(i),
}));
dispatch(queriesImported(exploreId, nextQueries));
};
}
/** /**
* Main action to asynchronously load a datasource. Dispatches lots of smaller actions for feedback. * Main action to asynchronously load a datasource. Dispatches lots of smaller actions for feedback.
*/ */
@ -318,35 +366,12 @@ export function loadDatasource(exploreId: ExploreId, instance: DataSourceApi): T
instance.init(); instance.init();
} }
// Check if queries can be imported from previously selected datasource
const queries = getState().explore[exploreId].modifiedQueries;
let importedQueries = queries;
const origin = getState().explore[exploreId].datasourceInstance;
if (origin) {
if (origin.meta.id === instance.meta.id) {
// Keep same queries if same type of datasource
importedQueries = [...queries];
} else if (instance.importQueries) {
// Datasource-specific importers
importedQueries = await instance.importQueries(queries, origin.meta);
} else {
// Default is blank queries
importedQueries = ensureQueries();
}
}
if (datasourceName !== getState().explore[exploreId].requestedDatasourceName) { if (datasourceName !== getState().explore[exploreId].requestedDatasourceName) {
// User already changed datasource again, discard results // User already changed datasource again, discard results
return; return;
} }
// Reset edit state with new queries dispatch(loadDatasourceSuccess(exploreId, instance));
const nextQueries = importedQueries.map((q, i) => ({
...importedQueries[i],
...generateEmptyQuery(i),
}));
dispatch(loadDatasourceSuccess(exploreId, instance, nextQueries));
dispatch(runQueries(exploreId)); dispatch(runQueries(exploreId));
}; };
} }

View File

@ -203,7 +203,6 @@ export const itemReducer = (state, action: Action): ExploreItemState => {
StartPage, StartPage,
datasourceInstance, datasourceInstance,
history, history,
initialQueries,
showingStartPage, showingStartPage,
supportsGraph, supportsGraph,
supportsLogs, supportsLogs,
@ -217,7 +216,6 @@ export const itemReducer = (state, action: Action): ExploreItemState => {
StartPage, StartPage,
datasourceInstance, datasourceInstance,
history, history,
initialQueries,
showingStartPage, showingStartPage,
supportsGraph, supportsGraph,
supportsLogs, supportsLogs,
@ -226,7 +224,6 @@ export const itemReducer = (state, action: Action): ExploreItemState => {
datasourceMissing: false, datasourceMissing: false,
datasourceError: null, datasourceError: null,
logsHighlighterExpressions: undefined, logsHighlighterExpressions: undefined,
modifiedQueries: initialQueries.slice(),
queryTransactions: [], queryTransactions: [],
}; };
} }
@ -295,7 +292,6 @@ export const itemReducer = (state, action: Action): ExploreItemState => {
// Append new transaction // Append new transaction
const nextQueryTransactions: QueryTransaction[] = [...remainingTransactions, transaction]; const nextQueryTransactions: QueryTransaction[] = [...remainingTransactions, transaction];
return { return {
...state, ...state,
queryTransactions: nextQueryTransactions, queryTransactions: nextQueryTransactions,
@ -417,6 +413,14 @@ export const itemReducer = (state, action: Action): ExploreItemState => {
return { ...state, ...results, queryTransactions: nextQueryTransactions, showingTable }; return { ...state, ...results, queryTransactions: nextQueryTransactions, showingTable };
} }
case ActionTypes.QueriesImported: {
return {
...state,
initialQueries: action.payload.queries,
modifiedQueries: action.payload.queries.slice(),
};
}
} }
return state; return state;