diff --git a/packages/grafana-ui/src/types/datasource.ts b/packages/grafana-ui/src/types/datasource.ts index 40c89e43850..0f056c610e4 100644 --- a/packages/grafana-ui/src/types/datasource.ts +++ b/packages/grafana-ui/src/types/datasource.ts @@ -295,7 +295,6 @@ export interface ExploreQueryFieldProps< TQuery extends DataQuery = DataQuery, TOptions extends DataSourceJsonData = DataSourceJsonData > extends QueryEditorProps { - datasourceStatus: DataSourceStatus; history: any[]; onHint?: (action: QueryFixAction) => void; } diff --git a/public/app/features/explore/Explore.tsx b/public/app/features/explore/Explore.tsx index 00232704e72..2eb7a04d339 100644 --- a/public/app/features/explore/Explore.tsx +++ b/public/app/features/explore/Explore.tsx @@ -9,7 +9,7 @@ import memoizeOne from 'memoize-one'; // Services & Utils import store from 'app/core/store'; // Components -import { Alert, ErrorBoundaryAlert, DataQuery, ExploreStartPageProps, DataSourceApi, PanelData } from '@grafana/ui'; +import { ErrorBoundaryAlert, DataQuery, ExploreStartPageProps, DataSourceApi, PanelData } from '@grafana/ui'; import LogsContainer from './LogsContainer'; import QueryRows from './QueryRows'; import TableContainer from './TableContainer'; @@ -21,7 +21,6 @@ import { scanStart, setQueries, refreshExplore, - reconnectDatasource, updateTimeRange, toggleGraph, } from './state/actions'; @@ -46,7 +45,6 @@ import { import { Emitter } from 'app/core/utils/emitter'; import { ExploreToolbar } from './ExploreToolbar'; import { NoDataSourceCallToAction } from './NoDataSourceCallToAction'; -import { FadeIn } from 'app/core/components/Animations/FadeIn'; import { getTimeZone } from '../profile/state/selectors'; import { ErrorContainer } from './ErrorContainer'; import { scanStopAction } from './state/actionTypes'; @@ -65,7 +63,6 @@ const getStyles = memoizeOne(() => { interface ExploreProps { StartPage?: ComponentType; changeSize: typeof changeSize; - datasourceError: string; datasourceInstance: DataSourceApi; datasourceMissing: boolean; exploreId: ExploreId; @@ -73,7 +70,6 @@ interface ExploreProps { initialized: boolean; modifyQueries: typeof modifyQueries; update: ExploreUpdateState; - reconnectDatasource: typeof reconnectDatasource; refreshExplore: typeof refreshExplore; scanning?: boolean; scanRange?: RawTimeRange; @@ -238,18 +234,10 @@ export class Explore extends React.PureComponent { ); }; - onReconnect = (event: React.MouseEvent) => { - const { exploreId, reconnectDatasource } = this.props; - - event.preventDefault(); - reconnectDatasource(exploreId); - }; - render() { const { StartPage, datasourceInstance, - datasourceError, datasourceMissing, exploreId, showingStartPage, @@ -272,17 +260,6 @@ export class Explore extends React.PureComponent {
{datasourceMissing ? this.renderEmptyState() : null} - - -
- -
-
- {datasourceInstance && (
@@ -357,7 +334,6 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps): Partia const timeZone = getTimeZone(state.user); const { StartPage, - datasourceError, datasourceInstance, datasourceMissing, initialized, @@ -402,7 +378,6 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps): Partia return { StartPage, - datasourceError, datasourceInstance, datasourceMissing, initialized, @@ -431,7 +406,6 @@ const mapDispatchToProps: Partial = { changeSize, initializeExplore, modifyQueries, - reconnectDatasource, refreshExplore, scanStart, scanStopAction, diff --git a/public/app/features/explore/QueryRow.tsx b/public/app/features/explore/QueryRow.tsx index d5c278e9b00..d9fb09a8f40 100644 --- a/public/app/features/explore/QueryRow.tsx +++ b/public/app/features/explore/QueryRow.tsx @@ -13,7 +13,7 @@ import { changeQuery, modifyQueries, runQueries, addQueryRow } from './state/act // Types import { StoreState } from 'app/types'; import { TimeRange, AbsoluteTimeRange, LoadingState } from '@grafana/data'; -import { DataQuery, DataSourceApi, QueryFixAction, DataSourceStatus, PanelData } from '@grafana/ui'; +import { DataQuery, DataSourceApi, QueryFixAction, PanelData } from '@grafana/ui'; import { HistoryItem, ExploreItemState, ExploreId, ExploreMode } from 'app/types/explore'; import { Emitter } from 'app/core/utils/emitter'; import { highlightLogsExpressionAction, removeQueryRowAction } from './state/actionTypes'; @@ -31,7 +31,6 @@ interface QueryRowProps extends PropsFromParent { className?: string; exploreId: ExploreId; datasourceInstance: DataSourceApi; - datasourceStatus: DataSourceStatus; highlightLogsExpressionAction: typeof highlightLogsExpressionAction; history: HistoryItem[]; query: DataQuery; @@ -121,7 +120,6 @@ export class QueryRow extends PureComponent { exploreEvents, range, absoluteRange, - datasourceStatus, queryResponse, latency, mode, @@ -148,7 +146,6 @@ export class QueryRow extends PureComponent { //@ts-ignore { function mapStateToProps(state: StoreState, { exploreId, index }: QueryRowProps) { const explore = state.explore; const item: ExploreItemState = explore[exploreId]; - const { - datasourceInstance, - history, - queries, - range, - absoluteRange, - datasourceError, - latency, - mode, - queryResponse, - } = item; + const { datasourceInstance, history, queries, range, absoluteRange, latency, mode, queryResponse } = item; const query = queries[index]; - const datasourceStatus = datasourceError ? DataSourceStatus.Disconnected : DataSourceStatus.Connected; return { datasourceInstance, @@ -210,7 +196,6 @@ function mapStateToProps(state: StoreState, { exploreId, index }: QueryRowProps) query, range, absoluteRange, - datasourceStatus, queryResponse, latency, mode, diff --git a/public/app/features/explore/state/actionTypes.ts b/public/app/features/explore/state/actionTypes.ts index 1d821be3e82..180c7474f09 100644 --- a/public/app/features/explore/state/actionTypes.ts +++ b/public/app/features/explore/state/actionTypes.ts @@ -105,19 +105,6 @@ export interface LoadDatasourceReadyPayload { history: HistoryItem[]; } -export interface TestDatasourcePendingPayload { - exploreId: ExploreId; -} - -export interface TestDatasourceFailurePayload { - exploreId: ExploreId; - error: string; -} - -export interface TestDatasourceSuccessPayload { - exploreId: ExploreId; -} - export interface ModifyQueriesPayload { exploreId: ExploreId; modification: QueryFixAction; @@ -391,15 +378,6 @@ export const toggleLogLevelAction = actionCreatorFactory( */ export const resetExploreAction = actionCreatorFactory('explore/RESET_EXPLORE').create(); export const queriesImportedAction = actionCreatorFactory('explore/QueriesImported').create(); -export const testDataSourcePendingAction = actionCreatorFactory( - 'explore/TEST_DATASOURCE_PENDING' -).create(); -export const testDataSourceSuccessAction = actionCreatorFactory( - 'explore/TEST_DATASOURCE_SUCCESS' -).create(); -export const testDataSourceFailureAction = actionCreatorFactory( - 'explore/TEST_DATASOURCE_FAILURE' -).create(); export const loadExploreDatasources = actionCreatorFactory( 'explore/LOAD_EXPLORE_DATASOURCES' ).create(); diff --git a/public/app/features/explore/state/actions.test.ts b/public/app/features/explore/state/actions.test.ts index 6cd3e03379e..6b8771f5df5 100644 --- a/public/app/features/explore/state/actions.test.ts +++ b/public/app/features/explore/state/actions.test.ts @@ -1,4 +1,4 @@ -import { refreshExplore, testDatasource, loadDatasource } from './actions'; +import { refreshExplore, loadDatasource } from './actions'; import { ExploreId, ExploreUrlState, ExploreUpdateState, ExploreMode } from 'app/types'; import { thunkTester } from 'test/core/thunk/thunkTester'; import { @@ -6,9 +6,6 @@ import { InitializeExplorePayload, updateUIStateAction, setQueriesAction, - testDataSourcePendingAction, - testDataSourceSuccessAction, - testDataSourceFailureAction, loadDatasourcePendingAction, loadDatasourceReadyAction, } from './actionTypes'; @@ -164,72 +161,6 @@ describe('refreshExplore', () => { }); }); -describe('test datasource', () => { - describe('when testDatasource thunk is dispatched', () => { - describe('and testDatasource call on instance is successful', () => { - it('then it should dispatch testDataSourceSuccessAction', async () => { - const exploreId = ExploreId.left; - const mockDatasourceInstance = { - testDatasource: () => { - return Promise.resolve({ status: 'success' }); - }, - }; - - const dispatchedActions = await thunkTester({}) - .givenThunk(testDatasource) - .whenThunkIsDispatched(exploreId, mockDatasourceInstance); - - expect(dispatchedActions).toEqual([ - testDataSourcePendingAction({ exploreId }), - testDataSourceSuccessAction({ exploreId }), - ]); - }); - }); - - describe('and testDatasource call on instance is not successful', () => { - it('then it should dispatch testDataSourceFailureAction', async () => { - const exploreId = ExploreId.left; - const error = 'something went wrong'; - const mockDatasourceInstance = { - testDatasource: () => { - return Promise.resolve({ status: 'fail', message: error }); - }, - }; - - const dispatchedActions = await thunkTester({}) - .givenThunk(testDatasource) - .whenThunkIsDispatched(exploreId, mockDatasourceInstance); - - expect(dispatchedActions).toEqual([ - testDataSourcePendingAction({ exploreId }), - testDataSourceFailureAction({ exploreId, error }), - ]); - }); - }); - - describe('and testDatasource call on instance throws', () => { - it('then it should dispatch testDataSourceFailureAction', async () => { - const exploreId = ExploreId.left; - const error = 'something went wrong'; - const mockDatasourceInstance = { - testDatasource: () => { - throw { statusText: error }; - }, - }; - - const dispatchedActions = await thunkTester({}) - .givenThunk(testDatasource) - .whenThunkIsDispatched(exploreId, mockDatasourceInstance); - - expect(dispatchedActions).toEqual([ - testDataSourcePendingAction({ exploreId }), - testDataSourceFailureAction({ exploreId, error }), - ]); - }); - }); - }); -}); - describe('loading datasource', () => { describe('when loadDatasource thunk is dispatched', () => { describe('and all goes fine', () => { @@ -255,8 +186,6 @@ describe('loading datasource', () => { exploreId, requestedDatasourceName: mockDatasourceInstance.name, }), - testDataSourcePendingAction({ exploreId }), - testDataSourceSuccessAction({ exploreId }), loadDatasourceReadyAction({ exploreId, history: [] }), ]); }); @@ -285,8 +214,6 @@ describe('loading datasource', () => { exploreId, requestedDatasourceName: mockDatasourceInstance.name, }), - testDataSourcePendingAction({ exploreId }), - testDataSourceSuccessAction({ exploreId }), ]); }); }); diff --git a/public/app/features/explore/state/actions.ts b/public/app/features/explore/state/actions.ts index 951a2512b4d..3de226e7c6a 100644 --- a/public/app/features/explore/state/actions.ts +++ b/public/app/features/explore/state/actions.ts @@ -59,9 +59,6 @@ import { ToggleGraphPayload, ToggleTablePayload, updateUIStateAction, - testDataSourcePendingAction, - testDataSourceSuccessAction, - testDataSourceFailureAction, loadExploreDatasources, changeModeAction, scanStopAction, @@ -340,41 +337,6 @@ export function importQueries( }; } -/** - * Tests datasource. - */ -export const testDatasource = (exploreId: ExploreId, instance: DataSourceApi): ThunkResult => { - return async dispatch => { - let datasourceError = null; - - dispatch(testDataSourcePendingAction({ exploreId })); - - try { - const testResult = await instance.testDatasource(); - datasourceError = testResult.status === 'success' ? null : testResult.message; - } catch (error) { - datasourceError = (error && error.statusText) || 'Network error'; - } - - if (datasourceError) { - dispatch(testDataSourceFailureAction({ exploreId, error: datasourceError })); - return; - } - - dispatch(testDataSourceSuccessAction({ exploreId })); - }; -}; - -/** - * Reconnects datasource when there is a connection failure. - */ -export const reconnectDatasource = (exploreId: ExploreId): ThunkResult => { - return async (dispatch, getState) => { - const instance = getState().explore[exploreId].datasourceInstance; - dispatch(changeDatasource(exploreId, instance.name)); - }; -}; - /** * Main action to asynchronously load a datasource. Dispatches lots of smaller actions for feedback. */ @@ -385,13 +347,6 @@ export function loadDatasource(exploreId: ExploreId, instance: DataSourceApi, or // Keep ID to track selection dispatch(loadDatasourcePendingAction({ exploreId, requestedDatasourceName: datasourceName })); - await dispatch(testDatasource(exploreId, instance)); - - if (datasourceName !== getState().explore[exploreId].requestedDatasourceName) { - // User already changed datasource again, discard results - return; - } - if (instance.init) { try { instance.init(); @@ -401,7 +356,7 @@ export function loadDatasource(exploreId: ExploreId, instance: DataSourceApi, or } if (datasourceName !== getState().explore[exploreId].requestedDatasourceName) { - // User already changed datasource again, discard results + // User already changed datasource, discard results return; } @@ -441,7 +396,6 @@ export function runQueries(exploreId: ExploreId): ThunkResult { const { datasourceInstance, queries, - datasourceError, containerWidth, isLive: live, range, @@ -454,11 +408,6 @@ export function runQueries(exploreId: ExploreId): ThunkResult { showingTable, } = exploreItemState; - if (datasourceError) { - // let's not run any queries if data source is in a faulty state - return; - } - if (!hasNonEmptyQuery(queries)) { dispatch(clearQueriesAction({ exploreId })); dispatch(stateSave()); // Remember to save to state and update location diff --git a/public/app/features/explore/state/reducers.test.ts b/public/app/features/explore/state/reducers.test.ts index 59840ed81c1..7ab3f3d5dff 100644 --- a/public/app/features/explore/state/reducers.test.ts +++ b/public/app/features/explore/state/reducers.test.ts @@ -10,9 +10,6 @@ import { ExploreId, ExploreItemState, ExploreUrlState, ExploreState, ExploreMode import { reducerTester } from 'test/core/redux/reducerTester'; import { scanStartAction, - testDataSourcePendingAction, - testDataSourceSuccessAction, - testDataSourceFailureAction, updateDatasourceInstanceAction, splitOpenAction, splitCloseAction, @@ -29,7 +26,7 @@ import { updateLocation } from 'app/core/actions/location'; import { serializeStateToUrlParam } from 'app/core/utils/explore'; import TableModel from 'app/core/table_model'; import { DataSourceApi, DataQuery } from '@grafana/ui'; -import { LogsModel, LogsDedupStrategy, dateTime, LoadingState } from '@grafana/data'; +import { LogsDedupStrategy, dateTime, LoadingState } from '@grafana/data'; describe('Explore item reducer', () => { describe('scanning', () => { @@ -65,56 +62,7 @@ describe('Explore item reducer', () => { }); }); - describe('testing datasource', () => { - describe('when testDataSourcePendingAction is dispatched', () => { - it('then it should set datasourceError', () => { - reducerTester() - .givenReducer(itemReducer, { datasourceError: {} }) - .whenActionIsDispatched(testDataSourcePendingAction({ exploreId: ExploreId.left })) - .thenStateShouldEqual({ datasourceError: null }); - }); - }); - - describe('when testDataSourceSuccessAction is dispatched', () => { - it('then it should set datasourceError', () => { - reducerTester() - .givenReducer(itemReducer, { datasourceError: {} }) - .whenActionIsDispatched(testDataSourceSuccessAction({ exploreId: ExploreId.left })) - .thenStateShouldEqual({ datasourceError: null }); - }); - }); - - describe('when testDataSourceFailureAction is dispatched', () => { - it('then it should set correct state', () => { - const error = 'some error'; - const initalState: Partial = { - datasourceError: null, - graphResult: [], - tableResult: {} as TableModel, - logsResult: {} as LogsModel, - update: { - datasource: true, - queries: true, - range: true, - mode: true, - ui: true, - }, - }; - const expectedState = { - datasourceError: error, - graphResult: undefined as any[], - tableResult: undefined as TableModel, - logsResult: undefined as LogsModel, - update: makeInitialUpdateState(), - }; - - reducerTester() - .givenReducer(itemReducer, initalState) - .whenActionIsDispatched(testDataSourceFailureAction({ exploreId: ExploreId.left, error })) - .thenStateShouldEqual(expectedState); - }); - }); - + describe('changing datasource', () => { describe('when changeDataType is dispatched', () => { it('then it should set correct state', () => { reducerTester() @@ -125,9 +73,7 @@ describe('Explore item reducer', () => { }); }); }); - }); - describe('changing datasource', () => { describe('when updateDatasourceInstanceAction is dispatched', () => { describe('and datasourceInstance supports graph, logs, table and has a startpage', () => { it('then it should set correct state', () => { diff --git a/public/app/features/explore/state/reducers.ts b/public/app/features/explore/state/reducers.ts index 0ea13e943fb..bea72733ea1 100644 --- a/public/app/features/explore/state/reducers.ts +++ b/public/app/features/explore/state/reducers.ts @@ -15,9 +15,6 @@ import { DataQuery, DataSourceApi, PanelData, DataQueryRequest, RefreshPicker, P import { HigherOrderAction, ActionTypes, - testDataSourcePendingAction, - testDataSourceSuccessAction, - testDataSourceFailureAction, splitCloseAction, SplitCloseActionPayload, loadExploreDatasources, @@ -82,7 +79,6 @@ export const makeExploreItemState = (): ExploreItemState => ({ containerWidth: 0, datasourceInstance: null, requestedDatasourceName: null, - datasourceError: null, datasourceLoading: null, datasourceMissing: false, exploreDatasources: [], @@ -475,37 +471,6 @@ export const itemReducer = reducerFactory({} as ExploreItemSta }; }, }) - .addMapper({ - filter: testDataSourcePendingAction, - mapper: (state): ExploreItemState => { - return { - ...state, - datasourceError: null, - }; - }, - }) - .addMapper({ - filter: testDataSourceSuccessAction, - mapper: (state): ExploreItemState => { - return { - ...state, - datasourceError: null, - }; - }, - }) - .addMapper({ - filter: testDataSourceFailureAction, - mapper: (state, action): ExploreItemState => { - return { - ...state, - datasourceError: action.payload.error, - graphResult: undefined, - tableResult: undefined, - logsResult: undefined, - update: makeInitialUpdateState(), - }; - }, - }) .addMapper({ filter: loadExploreDatasources, mapper: (state, action): ExploreItemState => { diff --git a/public/app/plugins/datasource/influxdb/components/InfluxLogsQueryField.tsx b/public/app/plugins/datasource/influxdb/components/InfluxLogsQueryField.tsx index 18df8a43069..a6adf99afd1 100644 --- a/public/app/plugins/datasource/influxdb/components/InfluxLogsQueryField.tsx +++ b/public/app/plugins/datasource/influxdb/components/InfluxLogsQueryField.tsx @@ -17,6 +17,13 @@ export interface State { measurements: CascaderOption[]; measurement: string; field: string; + error: string; +} + +interface ChooserOptions { + measurement: string; + field: string; + error: string; } // Helper function for determining if a collection of pairs are valid @@ -32,37 +39,54 @@ export function pairsAreValid(pairs: KeyValuePair[]) { ); } +function getChooserText({ measurement, field, error }: ChooserOptions): string { + if (error) { + return '(No measurement found)'; + } + if (measurement) { + return `Measurements (${measurement}/${field})`; + } + return 'Measurements'; +} + export class InfluxLogsQueryField extends React.PureComponent { templateSrv: TemplateSrv = new TemplateSrv(); - state: State = { measurements: [], measurement: null, field: null }; + state: State = { measurements: [], measurement: null, field: null, error: null }; async componentDidMount() { const { datasource } = this.props; - const queryBuilder = new InfluxQueryBuilder({ measurement: '', tags: [] }, datasource.database); - const measureMentsQuery = queryBuilder.buildExploreQuery('MEASUREMENTS'); - const influxMeasurements = await datasource.metricFindQuery(measureMentsQuery); + try { + const queryBuilder = new InfluxQueryBuilder({ measurement: '', tags: [] }, datasource.database); + const measureMentsQuery = queryBuilder.buildExploreQuery('MEASUREMENTS'); + const influxMeasurements = await datasource.metricFindQuery(measureMentsQuery); - const measurements = []; - for (let index = 0; index < influxMeasurements.length; index++) { - const measurementObj = influxMeasurements[index]; - const queryBuilder = new InfluxQueryBuilder({ measurement: measurementObj.text, tags: [] }, datasource.database); - const fieldsQuery = queryBuilder.buildExploreQuery('FIELDS'); - const influxFields = await datasource.metricFindQuery(fieldsQuery); - const fields: any[] = influxFields.map( - (field: any): any => ({ - label: field.text, - value: field.text, - children: [], - }) - ); - measurements.push({ - label: measurementObj.text, - value: measurementObj.text, - children: fields, - }); + const measurements = []; + for (let index = 0; index < influxMeasurements.length; index++) { + const measurementObj = influxMeasurements[index]; + const queryBuilder = new InfluxQueryBuilder( + { measurement: measurementObj.text, tags: [] }, + datasource.database + ); + const fieldsQuery = queryBuilder.buildExploreQuery('FIELDS'); + const influxFields = await datasource.metricFindQuery(fieldsQuery); + const fields: any[] = influxFields.map( + (field: any): any => ({ + label: field.text, + value: field.text, + children: [], + }) + ); + measurements.push({ + label: measurementObj.text, + value: measurementObj.text, + children: fields, + }); + } + this.setState({ measurements }); + } catch (error) { + const message = error && error.message ? error.message : error; + this.setState({ error: message }); } - - this.setState({ measurements }); } componentDidUpdate(prevProps: Props) { @@ -107,8 +131,8 @@ export class InfluxLogsQueryField extends React.PureComponent { render() { const { datasource } = this.props; - const { measurements, measurement, field } = this.state; - const cascadeText = measurement ? `Measurements (${measurement}/${field})` : 'Measurements'; + const { measurements, measurement, field, error } = this.state; + const cascadeText = getChooserText({ measurement, field, error }); return (
@@ -119,7 +143,7 @@ export class InfluxLogsQueryField extends React.PureComponent { onChange={this.onMeasurementsChange} expandIcon={null} > - @@ -132,6 +156,9 @@ export class InfluxLogsQueryField extends React.PureComponent { extendedOptions={{ measurement }} /> )} + {error ? ( + {error} + ) : null}
); diff --git a/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx b/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx index 030da96e5ad..0bd81cd46b9 100644 --- a/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx +++ b/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx @@ -2,7 +2,6 @@ import React, { memo } from 'react'; // Types -import { DataSourceStatus } from '@grafana/ui'; import { LokiQuery } from '../types'; import { useLokiSyntax } from './useLokiSyntax'; import { LokiQueryFieldForm } from './LokiQueryFieldForm'; @@ -25,7 +24,6 @@ export const LokiAnnotationsQueryEditor = memo(function LokiAnnotationQueryEdito const { isSyntaxReady, setActiveOption, refreshLabels, ...syntaxProps } = useLokiSyntax( datasource.languageProvider, - DataSourceStatus.Connected, absolute ); @@ -38,7 +36,6 @@ export const LokiAnnotationsQueryEditor = memo(function LokiAnnotationQueryEdito
onChange(query.expr)} onRunQuery={() => {}} diff --git a/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx b/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx index 538136e4b6c..66f0bd50312 100644 --- a/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx +++ b/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx @@ -3,7 +3,7 @@ import React, { memo } from 'react'; // Types import { AbsoluteTimeRange } from '@grafana/data'; -import { QueryEditorProps, DataSourceStatus } from '@grafana/ui'; +import { QueryEditorProps } from '@grafana/ui'; import { LokiDatasource } from '../datasource'; import { LokiQuery } from '../types'; import { LokiQueryField } from './LokiQueryField'; @@ -30,8 +30,6 @@ export const LokiQueryEditor = memo(function LokiQueryEditor(props: Props) { const { isSyntaxReady, setActiveOption, refreshLabels, ...syntaxProps } = useLokiSyntax( datasource.languageProvider, - // TODO maybe use real status - DataSourceStatus.Connected, absolute ); @@ -39,7 +37,6 @@ export const LokiQueryEditor = memo(function LokiQueryEditor(props: Props) {
= ({ - datasource, - datasourceStatus, - ...otherProps -}) => { +export const LokiQueryField: FunctionComponent = ({ datasource, ...otherProps }) => { const { isSyntaxReady, setActiveOption, refreshLabels, ...syntaxProps } = useLokiSyntax( datasource.languageProvider as LokiLanguageProvider, - datasourceStatus, otherProps.absoluteRange ); return ( 0; - const chooserText = getChooserText(syntaxLoaded, hasLogLabels, datasourceStatus); - const buttonDisabled = !syntaxLoaded || datasourceStatus === DataSourceStatus.Disconnected; + const chooserText = getChooserText(syntaxLoaded, hasLogLabels); + const buttonDisabled = !(syntaxLoaded && hasLogLabels); const showError = data && data.error && data.error.refId === query.refId; return ( @@ -166,7 +154,7 @@ export class LokiQueryFieldForm extends React.PureComponent
{ return Promise.resolve(); }; - const { result, waitForNextUpdate } = renderHook(() => - useLokiLabels(languageProvider, true, [], rangeMock, DataSourceStatus.Connected, DataSourceStatus.Connected) - ); + const { result, waitForNextUpdate } = renderHook(() => useLokiLabels(languageProvider, true, [], rangeMock)); act(() => result.current.refreshLabels()); expect(result.current.logLabelOptions).toEqual([]); await waitForNextUpdate(); expect(result.current.logLabelOptions).toEqual(logLabelOptionsMock); }); - - it('should force refresh labels after a disconnect', () => { - const datasource = makeMockLokiDatasource({}); - - const rangeMock: AbsoluteTimeRange = { - from: 1560153109000, - to: 1560153109000, - }; - - const languageProvider = new LanguageProvider(datasource); - languageProvider.refreshLogLabels = jest.fn(); - - renderHook(() => - useLokiLabels(languageProvider, true, [], rangeMock, DataSourceStatus.Connected, DataSourceStatus.Disconnected) - ); - - expect(languageProvider.refreshLogLabels).toBeCalledTimes(1); - expect(languageProvider.refreshLogLabels).toBeCalledWith(rangeMock, true); - }); - - it('should not force refresh labels after a connect', () => { - const datasource = makeMockLokiDatasource({}); - - const rangeMock: AbsoluteTimeRange = { - from: 1560153109000, - to: 1560153109000, - }; - - const languageProvider = new LanguageProvider(datasource); - languageProvider.refreshLogLabels = jest.fn(); - - renderHook(() => - useLokiLabels(languageProvider, true, [], rangeMock, DataSourceStatus.Disconnected, DataSourceStatus.Connected) - ); - - expect(languageProvider.refreshLogLabels).not.toBeCalled(); - }); }); diff --git a/public/app/plugins/datasource/loki/components/useLokiLabels.ts b/public/app/plugins/datasource/loki/components/useLokiLabels.ts index 487814501d1..4076e2c979c 100644 --- a/public/app/plugins/datasource/loki/components/useLokiLabels.ts +++ b/public/app/plugins/datasource/loki/components/useLokiLabels.ts @@ -1,5 +1,4 @@ import { useState, useEffect } from 'react'; -import { DataSourceStatus } from '@grafana/ui/src/types/datasource'; import { AbsoluteTimeRange } from '@grafana/data'; import LokiLanguageProvider from 'app/plugins/datasource/loki/language_provider'; @@ -18,18 +17,13 @@ export const useLokiLabels = ( languageProvider: LokiLanguageProvider, languageProviderInitialised: boolean, activeOption: CascaderOption[], - absoluteRange: AbsoluteTimeRange, - datasourceStatus: DataSourceStatus, - initialDatasourceStatus?: DataSourceStatus // used for test purposes + absoluteRange: AbsoluteTimeRange ) => { const mounted = useRefMounted(); // State const [logLabelOptions, setLogLabelOptions] = useState([]); const [shouldTryRefreshLabels, setRefreshLabels] = useState(false); - const [prevDatasourceStatus, setPrevDatasourceStatus] = useState( - initialDatasourceStatus || DataSourceStatus.Connected - ); const [shouldForceRefreshLabels, setForceRefreshLabels] = useState(false); // Async @@ -83,15 +77,6 @@ export const useLokiLabels = ( } }, [shouldTryRefreshLabels, shouldForceRefreshLabels]); - // This effect is performed on datasourceStatus state change only. - // We want to make sure to only force refresh AFTER a disconnected state thats why we store the previous datasourceStatus in state - useEffect(() => { - if (datasourceStatus === DataSourceStatus.Connected && prevDatasourceStatus === DataSourceStatus.Disconnected) { - setForceRefreshLabels(true); - } - setPrevDatasourceStatus(datasourceStatus); - }, [datasourceStatus]); - return { logLabelOptions, setLogLabelOptions, diff --git a/public/app/plugins/datasource/loki/components/useLokiSyntax.test.ts b/public/app/plugins/datasource/loki/components/useLokiSyntax.test.ts index 07c98cc476c..88908600270 100644 --- a/public/app/plugins/datasource/loki/components/useLokiSyntax.test.ts +++ b/public/app/plugins/datasource/loki/components/useLokiSyntax.test.ts @@ -1,5 +1,4 @@ import { renderHook, act } from 'react-hooks-testing-library'; -import { DataSourceStatus } from '@grafana/ui/src/types/datasource'; import { AbsoluteTimeRange } from '@grafana/data'; import LanguageProvider from 'app/plugins/datasource/loki/language_provider'; @@ -36,9 +35,7 @@ describe('useLokiSyntax hook', () => { }; it('should provide Loki syntax when used', async () => { - const { result, waitForNextUpdate } = renderHook(() => - useLokiSyntax(languageProvider, DataSourceStatus.Connected, rangeMock) - ); + const { result, waitForNextUpdate } = renderHook(() => useLokiSyntax(languageProvider, rangeMock)); expect(result.current.syntax).toEqual(null); await waitForNextUpdate(); @@ -47,9 +44,7 @@ describe('useLokiSyntax hook', () => { }); it('should fetch labels on first call', async () => { - const { result, waitForNextUpdate } = renderHook(() => - useLokiSyntax(languageProvider, DataSourceStatus.Connected, rangeMock) - ); + const { result, waitForNextUpdate } = renderHook(() => useLokiSyntax(languageProvider, rangeMock)); expect(result.current.isSyntaxReady).toBeFalsy(); expect(result.current.logLabelOptions).toEqual([]); @@ -60,9 +55,7 @@ describe('useLokiSyntax hook', () => { }); it('should try to fetch missing options when active option changes', async () => { - const { result, waitForNextUpdate } = renderHook(() => - useLokiSyntax(languageProvider, DataSourceStatus.Connected, rangeMock) - ); + const { result, waitForNextUpdate } = renderHook(() => useLokiSyntax(languageProvider, rangeMock)); await waitForNextUpdate(); expect(result.current.logLabelOptions).toEqual(logLabelOptionsMock2); diff --git a/public/app/plugins/datasource/loki/components/useLokiSyntax.ts b/public/app/plugins/datasource/loki/components/useLokiSyntax.ts index f4ae3652e4d..a8e92bde3ac 100644 --- a/public/app/plugins/datasource/loki/components/useLokiSyntax.ts +++ b/public/app/plugins/datasource/loki/components/useLokiSyntax.ts @@ -1,6 +1,5 @@ import { useState, useEffect } from 'react'; import Prism from 'prismjs'; -import { DataSourceStatus } from '@grafana/ui/src/types/datasource'; import { AbsoluteTimeRange } from '@grafana/data'; import LokiLanguageProvider from 'app/plugins/datasource/loki/language_provider'; import { useLokiLabels } from 'app/plugins/datasource/loki/components/useLokiLabels'; @@ -14,11 +13,7 @@ const PRISM_SYNTAX = 'promql'; * @param languageProvider * @description Initializes given language provider, exposes Loki syntax and enables loading label option values */ -export const useLokiSyntax = ( - languageProvider: LokiLanguageProvider, - datasourceStatus: DataSourceStatus, - absoluteRange: AbsoluteTimeRange -) => { +export const useLokiSyntax = (languageProvider: LokiLanguageProvider, absoluteRange: AbsoluteTimeRange) => { const mounted = useRefMounted(); // State const [languageProviderInitialized, setLanguageProviderInitilized] = useState(false); @@ -35,8 +30,7 @@ export const useLokiSyntax = ( languageProvider, languageProviderInitialized, activeOption, - absoluteRange, - datasourceStatus + absoluteRange ); // Async diff --git a/public/app/plugins/datasource/loki/datasource.ts b/public/app/plugins/datasource/loki/datasource.ts index 3a212853e12..a17dee3a8cb 100644 --- a/public/app/plugins/datasource/loki/datasource.ts +++ b/public/app/plugins/datasource/loki/datasource.ts @@ -121,7 +121,7 @@ export class LokiDatasource extends DataSourceApi { processError = (err: any, target: any): DataQueryError => { const error: DataQueryError = { - message: 'Unknown error during query transaction. Please check JS console logs.', + message: (err && err.statusText) || 'Unknown error during query transaction. Please check JS console logs.', refId: target.refId, }; diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx index eee711fa0e1..e8e06a82303 100644 --- a/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx @@ -2,7 +2,7 @@ import _ from 'lodash'; import React, { PureComponent } from 'react'; // Types -import { FormLabel, Select, Switch, QueryEditorProps, DataSourceStatus } from '@grafana/ui'; +import { FormLabel, Select, Switch, QueryEditorProps } from '@grafana/ui'; import { SelectableValue } from '@grafana/data'; import { PrometheusDatasource } from '../datasource'; @@ -104,7 +104,6 @@ export class PromQueryEditor extends PureComponent { onChange={this.onFieldChange} history={[]} data={data} - datasourceStatus={DataSourceStatus.Connected} // TODO: replace with real DataSourceStatus />
diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx index fdc4d799b09..65b5f784177 100644 --- a/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx @@ -13,7 +13,7 @@ import BracesPlugin from 'app/features/explore/slate-plugins/braces'; import QueryField, { TypeaheadInput } from 'app/features/explore/QueryField'; import { PromQuery, PromContext, PromOptions } from '../types'; import { CancelablePromise, makePromiseCancelable } from 'app/core/utils/CancelablePromise'; -import { ExploreQueryFieldProps, DataSourceStatus, QueryHint, DOMUtil } from '@grafana/ui'; +import { ExploreQueryFieldProps, QueryHint, DOMUtil } from '@grafana/ui'; import { isDataFrame, toLegacyResponseData } from '@grafana/data'; import { PrometheusDatasource } from '../datasource'; import PromQlLanguageProvider from '../language_provider'; @@ -24,13 +24,13 @@ const METRIC_MARK = 'metric'; const PRISM_SYNTAX = 'promql'; export const RECORDING_RULES_GROUP = '__recording_rules__'; -function getChooserText(hasSyntax: boolean, datasourceStatus: DataSourceStatus) { - if (datasourceStatus === DataSourceStatus.Disconnected) { - return '(Disconnected)'; - } +function getChooserText(hasSyntax: boolean, metrics: string[]) { if (!hasSyntax) { return 'Loading metrics...'; } + if (metrics && metrics.length === 0) { + return '(No metrics found)'; + } return 'Metrics'; } @@ -159,21 +159,6 @@ class PromQueryField extends React.PureComponent { @@ -291,11 +276,11 @@ class PromQueryField extends React.PureComponent 0); const showError = data && data.error && data.error.refId === query.refId; return ( diff --git a/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap b/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap index 11c80d4023e..d2dedc0392e 100644 --- a/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap +++ b/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap @@ -9,7 +9,6 @@ exports[`Render PromQueryEditor with basic options should render 1`] = ` "getPrometheusTime": [MockFunction], } } - datasourceStatus={0} history={Array []} onChange={[Function]} onRunQuery={[Function]} diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index 27f214bd496..654aa279fa1 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -447,7 +447,7 @@ export class PrometheusDatasource extends DataSourceApi handleErrors = (err: any, target: PromQuery) => { const error: DataQueryError = { - message: 'Unknown error during query transaction. Please check JS console logs.', + message: (err && err.statusText) || 'Unknown error during query transaction. Please check JS console logs.', refId: target.refId, }; diff --git a/public/app/types/explore.ts b/public/app/types/explore.ts index 63ef0ad03d0..92ec9194606 100644 --- a/public/app/types/explore.ts +++ b/public/app/types/explore.ts @@ -161,10 +161,6 @@ export interface ExploreItemState { * Current data source name or null if default */ requestedDatasourceName: string | null; - /** - * Error to be shown when datasource loading or testing failed. - */ - datasourceError: string; /** * True if the datasource is loading. `null` if the loading has not started yet. */