diff --git a/public/app/features/explore/state/actionTypes.ts b/public/app/features/explore/state/actionTypes.ts index 757f946f37a..be7d5754bbe 100644 --- a/public/app/features/explore/state/actionTypes.ts +++ b/public/app/features/explore/state/actionTypes.ts @@ -43,6 +43,7 @@ export enum ActionTypes { ToggleTable = 'explore/TOGGLE_TABLE', UpdateDatasourceInstance = 'explore/UPDATE_DATASOURCE_INSTANCE', ResetExplore = 'explore/RESET_EXPLORE', + QueriesImported = 'explore/QueriesImported', } export interface AddQueryRowAction { @@ -142,7 +143,6 @@ export interface LoadDatasourceSuccessAction { StartPage?: any; datasourceInstance: any; history: HistoryItem[]; - initialQueries: DataQuery[]; logsHighlighterExpressions?: any[]; showingStartPage: boolean; supportsGraph: boolean; @@ -283,6 +283,14 @@ export interface ResetExploreAction { payload: {}; } +export interface QueriesImported { + type: ActionTypes.QueriesImported; + payload: { + exploreId: ExploreId; + queries: DataQuery[]; + }; +} + export type Action = | AddQueryRowAction | ChangeQueryAction @@ -312,4 +320,5 @@ export type Action = | ToggleLogsAction | ToggleTableAction | UpdateDatasourceInstanceAction - | ResetExploreAction; + | ResetExploreAction + | QueriesImported; diff --git a/public/app/features/explore/state/actions.ts b/public/app/features/explore/state/actions.ts index 40a8f367672..1a11b7fcac9 100644 --- a/public/app/features/explore/state/actions.ts +++ b/public/app/features/explore/state/actions.ts @@ -53,6 +53,7 @@ import { QueryTransactionStartAction, ScanStopAction, UpdateDatasourceInstanceAction, + QueriesImported, } from './actionTypes'; type ThunkResult = ThunkAction; @@ -69,10 +70,15 @@ export function addQueryRow(exploreId: ExploreId, index: number): AddQueryRowAct * Loads a new datasource identified by the given name. */ export function changeDatasource(exploreId: ExploreId, datasource: string): ThunkResult { - return async dispatch => { - const instance = await getDatasourceSrv().get(datasource); - dispatch(updateDatasourceInstance(exploreId, instance)); - dispatch(loadDatasource(exploreId, instance)); + return async (dispatch, getState) => { + const newDataSourceInstance = await getDatasourceSrv().get(datasource); + const currentDataSourceInstance = getState().explore[exploreId].datasourceInstance; + 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) { let instance; + if (datasourceName) { try { instance = await getDatasourceSrv().get(datasourceName); @@ -185,6 +192,7 @@ export function initializeExplore( if (!instance) { instance = await getDatasourceSrv().get(); } + dispatch(updateDatasourceInstance(exploreId, instance)); dispatch(loadDatasource(exploreId, instance)); } else { @@ -224,7 +232,10 @@ export const loadDatasourceMissing = (exploreId: ExploreId): LoadDatasourceMissi /** * 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, payload: { 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 * 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 = ( exploreId: ExploreId, instance: any, - queries: DataQuery[] ): LoadDatasourceSuccessAction => { // Capabilities const supportsGraph = instance.meta.metrics; @@ -261,7 +281,6 @@ export const loadDatasourceSuccess = ( StartPage, datasourceInstance: instance, history, - initialQueries: queries, showingStartPage: Boolean(StartPage), supportsGraph, 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. */ @@ -318,35 +366,12 @@ export function loadDatasource(exploreId: ExploreId, instance: DataSourceApi): T 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) { // User already changed datasource again, discard results return; } - // Reset edit state with new queries - const nextQueries = importedQueries.map((q, i) => ({ - ...importedQueries[i], - ...generateEmptyQuery(i), - })); - - dispatch(loadDatasourceSuccess(exploreId, instance, nextQueries)); + dispatch(loadDatasourceSuccess(exploreId, instance)); dispatch(runQueries(exploreId)); }; } diff --git a/public/app/features/explore/state/reducers.ts b/public/app/features/explore/state/reducers.ts index ad5ef8b5a71..eb67beee3b3 100644 --- a/public/app/features/explore/state/reducers.ts +++ b/public/app/features/explore/state/reducers.ts @@ -203,7 +203,6 @@ export const itemReducer = (state, action: Action): ExploreItemState => { StartPage, datasourceInstance, history, - initialQueries, showingStartPage, supportsGraph, supportsLogs, @@ -217,7 +216,6 @@ export const itemReducer = (state, action: Action): ExploreItemState => { StartPage, datasourceInstance, history, - initialQueries, showingStartPage, supportsGraph, supportsLogs, @@ -226,7 +224,6 @@ export const itemReducer = (state, action: Action): ExploreItemState => { datasourceMissing: false, datasourceError: null, logsHighlighterExpressions: undefined, - modifiedQueries: initialQueries.slice(), queryTransactions: [], }; } @@ -295,7 +292,6 @@ export const itemReducer = (state, action: Action): ExploreItemState => { // Append new transaction const nextQueryTransactions: QueryTransaction[] = [...remainingTransactions, transaction]; - return { ...state, queryTransactions: nextQueryTransactions, @@ -417,6 +413,14 @@ export const itemReducer = (state, action: Action): ExploreItemState => { return { ...state, ...results, queryTransactions: nextQueryTransactions, showingTable }; } + + case ActionTypes.QueriesImported: { + return { + ...state, + initialQueries: action.payload.queries, + modifiedQueries: action.payload.queries.slice(), + }; + } } return state;