Commit e6001f57 by Marcus Efraimsson Committed by GitHub

Explore: Allow switching between metrics and logs (#16959)

Adds basic support for switching between Metrics and Logs in Explore. 
Currently only test datasource that supports both Metrics and Logs.
Summary of changes:
* Moves mode (Metric, Logs) selection to the left of datasource 
picker and add some quick styling.
* Only trigger change in ToggleButton if not selected
* Set correct mode if datasource only supports logs

Closes #16808
parent be66ed9d
...@@ -39,7 +39,7 @@ export const ToggleButton: FC<ToggleButtonProps> = ({ ...@@ -39,7 +39,7 @@ export const ToggleButton: FC<ToggleButtonProps> = ({
}) => { }) => {
const onClick = (event: React.SyntheticEvent) => { const onClick = (event: React.SyntheticEvent) => {
event.stopPropagation(); event.stopPropagation();
if (onChange) { if (!selected && onChange) {
onChange(value); onChange(value);
} }
}; };
......
...@@ -39,6 +39,7 @@ import { ...@@ -39,6 +39,7 @@ import {
ExploreId, ExploreId,
ExploreUpdateState, ExploreUpdateState,
ExploreUIState, ExploreUIState,
ExploreMode,
} from 'app/types/explore'; } from 'app/types/explore';
import { StoreState } from 'app/types'; import { StoreState } from 'app/types';
import { import {
...@@ -79,15 +80,13 @@ interface ExploreProps { ...@@ -79,15 +80,13 @@ interface ExploreProps {
setQueries: typeof setQueries; setQueries: typeof setQueries;
split: boolean; split: boolean;
showingStartPage?: boolean; showingStartPage?: boolean;
supportsGraph: boolean | null;
supportsLogs: boolean | null;
supportsTable: boolean | null;
queryKeys: string[]; queryKeys: string[];
initialDatasource: string; initialDatasource: string;
initialQueries: DataQuery[]; initialQueries: DataQuery[];
initialRange: RawTimeRange; initialRange: RawTimeRange;
initialUI: ExploreUIState; initialUI: ExploreUIState;
queryErrors: DataQueryError[]; queryErrors: DataQueryError[];
mode: ExploreMode;
} }
/** /**
...@@ -234,11 +233,9 @@ export class Explore extends React.PureComponent<ExploreProps> { ...@@ -234,11 +233,9 @@ export class Explore extends React.PureComponent<ExploreProps> {
exploreId, exploreId,
showingStartPage, showingStartPage,
split, split,
supportsGraph,
supportsLogs,
supportsTable,
queryKeys, queryKeys,
queryErrors, queryErrors,
mode,
} = this.props; } = this.props;
const exploreClass = split ? 'explore explore-split' : 'explore'; const exploreClass = split ? 'explore explore-split' : 'explore';
...@@ -273,9 +270,11 @@ export class Explore extends React.PureComponent<ExploreProps> { ...@@ -273,9 +270,11 @@ export class Explore extends React.PureComponent<ExploreProps> {
{showingStartPage && <StartPage onClickExample={this.onClickExample} />} {showingStartPage && <StartPage onClickExample={this.onClickExample} />}
{!showingStartPage && ( {!showingStartPage && (
<> <>
{supportsGraph && !supportsLogs && <GraphContainer width={width} exploreId={exploreId} />} {mode === ExploreMode.Metrics && <GraphContainer width={width} exploreId={exploreId} />}
{supportsTable && <TableContainer exploreId={exploreId} onClickCell={this.onClickLabel} />} {mode === ExploreMode.Metrics && (
{supportsLogs && ( <TableContainer exploreId={exploreId} onClickCell={this.onClickLabel} />
)}
{mode === ExploreMode.Logs && (
<LogsContainer <LogsContainer
width={width} width={width}
exploreId={exploreId} exploreId={exploreId}
...@@ -311,13 +310,11 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps) { ...@@ -311,13 +310,11 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps) {
datasourceMissing, datasourceMissing,
initialized, initialized,
showingStartPage, showingStartPage,
supportsGraph,
supportsLogs,
supportsTable,
queryKeys, queryKeys,
urlState, urlState,
update, update,
queryErrors, queryErrors,
mode,
} = item; } = item;
const { datasource, queries, range: urlRange, ui } = (urlState || {}) as ExploreUrlState; const { datasource, queries, range: urlRange, ui } = (urlState || {}) as ExploreUrlState;
...@@ -335,9 +332,6 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps) { ...@@ -335,9 +332,6 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps) {
initialized, initialized,
showingStartPage, showingStartPage,
split, split,
supportsGraph,
supportsLogs,
supportsTable,
queryKeys, queryKeys,
update, update,
initialDatasource, initialDatasource,
...@@ -345,6 +339,7 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps) { ...@@ -345,6 +339,7 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps) {
initialRange, initialRange,
initialUI, initialUI,
queryErrors, queryErrors,
mode,
}; };
} }
......
...@@ -2,8 +2,15 @@ import React, { PureComponent } from 'react'; ...@@ -2,8 +2,15 @@ import React, { PureComponent } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { hot } from 'react-hot-loader'; import { hot } from 'react-hot-loader';
import { ExploreId } from 'app/types/explore'; import { ExploreId, ExploreMode } from 'app/types/explore';
import { DataSourceSelectItem, RawTimeRange, ClickOutsideWrapper, TimeZone, TimeRange } from '@grafana/ui'; import {
DataSourceSelectItem,
RawTimeRange,
ClickOutsideWrapper,
TimeZone,
TimeRange,
SelectOptionItem,
} from '@grafana/ui';
import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker'; import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
import { StoreState } from 'app/types/store'; import { StoreState } from 'app/types/store';
import { import {
...@@ -13,10 +20,12 @@ import { ...@@ -13,10 +20,12 @@ import {
runQueries, runQueries,
splitOpen, splitOpen,
changeRefreshInterval, changeRefreshInterval,
changeMode,
} from './state/actions'; } from './state/actions';
import TimePicker from './TimePicker'; import TimePicker from './TimePicker';
import { getTimeZone } from '../profile/state/selectors'; import { getTimeZone } from '../profile/state/selectors';
import { RefreshPicker, SetInterval } from '@grafana/ui'; import { RefreshPicker, SetInterval } from '@grafana/ui';
import ToggleButtonGroup, { ToggleButton } from 'app/core/components/ToggleButtonGroup/ToggleButtonGroup';
enum IconSide { enum IconSide {
left = 'left', left = 'left',
...@@ -61,6 +70,8 @@ interface StateProps { ...@@ -61,6 +70,8 @@ interface StateProps {
selectedDatasource: DataSourceSelectItem; selectedDatasource: DataSourceSelectItem;
splitted: boolean; splitted: boolean;
refreshInterval: string; refreshInterval: string;
supportedModeOptions: Array<SelectOptionItem<ExploreMode>>;
selectedModeOption: SelectOptionItem<ExploreMode>;
} }
interface DispatchProps { interface DispatchProps {
...@@ -70,6 +81,7 @@ interface DispatchProps { ...@@ -70,6 +81,7 @@ interface DispatchProps {
closeSplit: typeof splitClose; closeSplit: typeof splitClose;
split: typeof splitOpen; split: typeof splitOpen;
changeRefreshInterval: typeof changeRefreshInterval; changeRefreshInterval: typeof changeRefreshInterval;
changeMode: typeof changeMode;
} }
type Props = StateProps & DispatchProps & OwnProps; type Props = StateProps & DispatchProps & OwnProps;
...@@ -100,6 +112,11 @@ export class UnConnectedExploreToolbar extends PureComponent<Props, {}> { ...@@ -100,6 +112,11 @@ export class UnConnectedExploreToolbar extends PureComponent<Props, {}> {
changeRefreshInterval(exploreId, item); changeRefreshInterval(exploreId, item);
}; };
onModeChange = (mode: ExploreMode) => {
const { changeMode, exploreId } = this.props;
changeMode(exploreId, mode);
};
render() { render() {
const { const {
datasourceMissing, datasourceMissing,
...@@ -115,6 +132,8 @@ export class UnConnectedExploreToolbar extends PureComponent<Props, {}> { ...@@ -115,6 +132,8 @@ export class UnConnectedExploreToolbar extends PureComponent<Props, {}> {
refreshInterval, refreshInterval,
onChangeTime, onChangeTime,
split, split,
supportedModeOptions,
selectedModeOption,
} = this.props; } = this.props;
return ( return (
...@@ -147,8 +166,31 @@ export class UnConnectedExploreToolbar extends PureComponent<Props, {}> { ...@@ -147,8 +166,31 @@ export class UnConnectedExploreToolbar extends PureComponent<Props, {}> {
current={selectedDatasource} current={selectedDatasource}
/> />
</div> </div>
{supportedModeOptions.length > 1 ? (
<div className="query-type-toggle">
<ToggleButtonGroup label="" transparent={true}>
<ToggleButton
key={ExploreMode.Metrics}
value={ExploreMode.Metrics}
onChange={this.onModeChange}
selected={selectedModeOption.value === ExploreMode.Metrics}
>
{'Metrics'}
</ToggleButton>
<ToggleButton
key={ExploreMode.Logs}
value={ExploreMode.Logs}
onChange={this.onModeChange}
selected={selectedModeOption.value === ExploreMode.Logs}
>
{'Logs'}
</ToggleButton>
</ToggleButtonGroup>
</div> </div>
) : null} ) : null}
</div>
) : null}
{exploreId === 'left' && !splitted ? ( {exploreId === 'left' && !splitted ? (
<div className="explore-toolbar-content-item"> <div className="explore-toolbar-content-item">
{createResponsiveButton({ {createResponsiveButton({
...@@ -208,12 +250,41 @@ const mapStateToProps = (state: StoreState, { exploreId }: OwnProps): StateProps ...@@ -208,12 +250,41 @@ const mapStateToProps = (state: StoreState, { exploreId }: OwnProps): StateProps
graphIsLoading, graphIsLoading,
logIsLoading, logIsLoading,
tableIsLoading, tableIsLoading,
supportedModes,
mode,
} = exploreItem; } = exploreItem;
const selectedDatasource = datasourceInstance const selectedDatasource = datasourceInstance
? exploreDatasources.find(datasource => datasource.name === datasourceInstance.name) ? exploreDatasources.find(datasource => datasource.name === datasourceInstance.name)
: undefined; : undefined;
const loading = graphIsLoading || logIsLoading || tableIsLoading; const loading = graphIsLoading || logIsLoading || tableIsLoading;
const supportedModeOptions: Array<SelectOptionItem<ExploreMode>> = [];
let selectedModeOption = null;
for (const supportedMode of supportedModes) {
switch (supportedMode) {
case ExploreMode.Metrics:
const option1 = {
value: ExploreMode.Metrics,
label: ExploreMode.Metrics,
};
supportedModeOptions.push(option1);
if (mode === ExploreMode.Metrics) {
selectedModeOption = option1;
}
break;
case ExploreMode.Logs:
const option2 = {
value: ExploreMode.Logs,
label: ExploreMode.Logs,
};
supportedModeOptions.push(option2);
if (mode === ExploreMode.Logs) {
selectedModeOption = option2;
}
break;
}
}
return { return {
datasourceMissing, datasourceMissing,
exploreDatasources, exploreDatasources,
...@@ -223,6 +294,8 @@ const mapStateToProps = (state: StoreState, { exploreId }: OwnProps): StateProps ...@@ -223,6 +294,8 @@ const mapStateToProps = (state: StoreState, { exploreId }: OwnProps): StateProps
selectedDatasource, selectedDatasource,
splitted, splitted,
refreshInterval, refreshInterval,
supportedModeOptions,
selectedModeOption,
}; };
}; };
...@@ -233,6 +306,7 @@ const mapDispatchToProps: DispatchProps = { ...@@ -233,6 +306,7 @@ const mapDispatchToProps: DispatchProps = {
runQueries, runQueries,
closeSplit: splitClose, closeSplit: splitClose,
split: splitOpen, split: splitOpen,
changeMode: changeMode,
}; };
export const ExploreToolbar = hot(module)( export const ExploreToolbar = hot(module)(
......
...@@ -35,7 +35,7 @@ export default class QueryEditor extends PureComponent<QueryEditorProps, any> { ...@@ -35,7 +35,7 @@ export default class QueryEditor extends PureComponent<QueryEditorProps, any> {
const loader = getAngularLoader(); const loader = getAngularLoader();
const template = '<plugin-component type="query-ctrl"> </plugin-component>'; const template = '<plugin-component type="query-ctrl"> </plugin-component>';
const target = { datasource: datasource.name, ...initialQuery }; const target = { ...initialQuery };
const scopeProps = { const scopeProps = {
ctrl: { ctrl: {
datasource, datasource,
...@@ -60,6 +60,7 @@ export default class QueryEditor extends PureComponent<QueryEditorProps, any> { ...@@ -60,6 +60,7 @@ export default class QueryEditor extends PureComponent<QueryEditorProps, any> {
this.component = loader.load(this.element, scopeProps, template); this.component = loader.load(this.element, scopeProps, template);
setTimeout(() => { setTimeout(() => {
this.props.onQueryChange(target); this.props.onQueryChange(target);
this.props.onExecuteQuery();
}, 1); }, 1);
} }
......
...@@ -38,6 +38,7 @@ interface QueryRowProps extends PropsFromParent { ...@@ -38,6 +38,7 @@ interface QueryRowProps extends PropsFromParent {
addQueryRow: typeof addQueryRow; addQueryRow: typeof addQueryRow;
changeQuery: typeof changeQuery; changeQuery: typeof changeQuery;
className?: string; className?: string;
exploreId: ExploreId;
datasourceInstance: ExploreDataSourceApi; datasourceInstance: ExploreDataSourceApi;
datasourceStatus: DataSourceStatus; datasourceStatus: DataSourceStatus;
highlightLogsExpressionAction: typeof highlightLogsExpressionAction; highlightLogsExpressionAction: typeof highlightLogsExpressionAction;
......
...@@ -18,6 +18,7 @@ import { ...@@ -18,6 +18,7 @@ import {
ResultType, ResultType,
QueryTransaction, QueryTransaction,
ExploreUIState, ExploreUIState,
ExploreMode,
} from 'app/types/explore'; } from 'app/types/explore';
import { actionCreatorFactory, noPayloadActionCreatorFactory, ActionOf } from 'app/core/redux/actionCreatorFactory'; import { actionCreatorFactory, noPayloadActionCreatorFactory, ActionOf } from 'app/core/redux/actionCreatorFactory';
...@@ -49,6 +50,11 @@ export interface AddQueryRowPayload { ...@@ -49,6 +50,11 @@ export interface AddQueryRowPayload {
query: DataQuery; query: DataQuery;
} }
export interface ChangeModePayload {
exploreId: ExploreId;
mode: ExploreMode;
}
export interface ChangeQueryPayload { export interface ChangeQueryPayload {
exploreId: ExploreId; exploreId: ExploreId;
query: DataQuery; query: DataQuery;
...@@ -246,6 +252,11 @@ export const addQueryRowAction = actionCreatorFactory<AddQueryRowPayload>('explo ...@@ -246,6 +252,11 @@ export const addQueryRowAction = actionCreatorFactory<AddQueryRowPayload>('explo
export const changeDatasourceAction = noPayloadActionCreatorFactory('explore/CHANGE_DATASOURCE').create(); export const changeDatasourceAction = noPayloadActionCreatorFactory('explore/CHANGE_DATASOURCE').create();
/** /**
* Change the mode of Explore.
*/
export const changeModeAction = actionCreatorFactory<ChangeModePayload>('explore/CHANGE_MODE').create();
/**
* Query change handler for the query row with the given index. * Query change handler for the query row with the given index.
* If `override` is reset the query modifications and run the queries. Use this to set queries via a link. * If `override` is reset the query modifications and run the queries. Use this to set queries via a link.
*/ */
......
...@@ -44,6 +44,7 @@ import { ...@@ -44,6 +44,7 @@ import {
QueryOptions, QueryOptions,
ExploreUIState, ExploreUIState,
QueryTransaction, QueryTransaction,
ExploreMode,
} from 'app/types/explore'; } from 'app/types/explore';
import { import {
updateDatasourceInstanceAction, updateDatasourceInstanceAction,
...@@ -85,6 +86,7 @@ import { ...@@ -85,6 +86,7 @@ import {
queryStartAction, queryStartAction,
historyUpdatedAction, historyUpdatedAction,
resetQueryErrorAction, resetQueryErrorAction,
changeModeAction,
} from './actionTypes'; } from './actionTypes';
import { ActionOf, ActionCreator } from 'app/core/redux/actionCreatorFactory'; import { ActionOf, ActionCreator } from 'app/core/redux/actionCreatorFactory';
import { LogsDedupStrategy } from 'app/core/logs_model'; import { LogsDedupStrategy } from 'app/core/logs_model';
...@@ -141,6 +143,16 @@ export function changeDatasource(exploreId: ExploreId, datasource: string): Thun ...@@ -141,6 +143,16 @@ export function changeDatasource(exploreId: ExploreId, datasource: string): Thun
} }
/** /**
* Change the display mode in Explore.
*/
export function changeMode(exploreId: ExploreId, mode: ExploreMode): ThunkResult<void> {
return dispatch => {
dispatch(changeModeAction({ exploreId, mode }));
dispatch(runQueries(exploreId));
};
}
/**
* Query change handler for the query row with the given index. * Query change handler for the query row with the given index.
* If `override` is reset the query modifications and run the queries. Use this to set queries via a link. * If `override` is reset the query modifications and run the queries. Use this to set queries via a link.
*/ */
...@@ -509,11 +521,9 @@ export function runQueries(exploreId: ExploreId, ignoreUIState = false): ThunkRe ...@@ -509,11 +521,9 @@ export function runQueries(exploreId: ExploreId, ignoreUIState = false): ThunkRe
showingLogs, showingLogs,
showingGraph, showingGraph,
showingTable, showingTable,
supportsGraph,
supportsLogs,
supportsTable,
datasourceError, datasourceError,
containerWidth, containerWidth,
mode,
} = getState().explore[exploreId]; } = getState().explore[exploreId];
if (datasourceError) { if (datasourceError) {
...@@ -533,7 +543,7 @@ export function runQueries(exploreId: ExploreId, ignoreUIState = false): ThunkRe ...@@ -533,7 +543,7 @@ export function runQueries(exploreId: ExploreId, ignoreUIState = false): ThunkRe
dispatch(runQueriesAction({ exploreId })); dispatch(runQueriesAction({ exploreId }));
// Keep table queries first since they need to return quickly // Keep table queries first since they need to return quickly
if ((ignoreUIState || showingTable) && supportsTable) { if ((ignoreUIState || showingTable) && mode === ExploreMode.Metrics) {
dispatch( dispatch(
runQueriesForType(exploreId, 'Table', { runQueriesForType(exploreId, 'Table', {
interval, interval,
...@@ -543,7 +553,7 @@ export function runQueries(exploreId: ExploreId, ignoreUIState = false): ThunkRe ...@@ -543,7 +553,7 @@ export function runQueries(exploreId: ExploreId, ignoreUIState = false): ThunkRe
}) })
); );
} }
if ((ignoreUIState || showingGraph) && supportsGraph) { if ((ignoreUIState || showingGraph) && mode === ExploreMode.Metrics) {
dispatch( dispatch(
runQueriesForType(exploreId, 'Graph', { runQueriesForType(exploreId, 'Graph', {
interval, interval,
...@@ -553,7 +563,7 @@ export function runQueries(exploreId: ExploreId, ignoreUIState = false): ThunkRe ...@@ -553,7 +563,7 @@ export function runQueries(exploreId: ExploreId, ignoreUIState = false): ThunkRe
}) })
); );
} }
if ((ignoreUIState || showingLogs) && supportsLogs) { if ((ignoreUIState || showingLogs) && mode === ExploreMode.Logs) {
dispatch(runQueriesForType(exploreId, 'Logs', { interval, format: 'logs' })); dispatch(runQueriesForType(exploreId, 'Logs', { interval, format: 'logs' }));
} }
......
...@@ -12,6 +12,7 @@ import { ...@@ -12,6 +12,7 @@ import {
ExploreState, ExploreState,
QueryTransaction, QueryTransaction,
RangeScanner, RangeScanner,
ExploreMode,
} from 'app/types/explore'; } from 'app/types/explore';
import { reducerTester } from 'test/core/redux/reducerTester'; import { reducerTester } from 'test/core/redux/reducerTester';
import { import {
...@@ -23,6 +24,7 @@ import { ...@@ -23,6 +24,7 @@ import {
updateDatasourceInstanceAction, updateDatasourceInstanceAction,
splitOpenAction, splitOpenAction,
splitCloseAction, splitCloseAction,
changeModeAction,
} from './actionTypes'; } from './actionTypes';
import { Reducer } from 'redux'; import { Reducer } from 'redux';
import { ActionOf } from 'app/core/redux/actionCreatorFactory'; import { ActionOf } from 'app/core/redux/actionCreatorFactory';
...@@ -122,6 +124,17 @@ describe('Explore item reducer', () => { ...@@ -122,6 +124,17 @@ describe('Explore item reducer', () => {
.thenStateShouldEqual(expectedState); .thenStateShouldEqual(expectedState);
}); });
}); });
describe('when changeDataType is dispatched', () => {
it('then it should set correct state', () => {
reducerTester()
.givenReducer(itemReducer, {})
.whenActionIsDispatched(changeModeAction({ exploreId: ExploreId.left, mode: ExploreMode.Logs }))
.thenStateShouldEqual({
mode: ExploreMode.Logs,
});
});
});
}); });
describe('changing datasource', () => { describe('changing datasource', () => {
...@@ -160,6 +173,8 @@ describe('Explore item reducer', () => { ...@@ -160,6 +173,8 @@ describe('Explore item reducer', () => {
showingStartPage: true, showingStartPage: true,
queries, queries,
queryKeys, queryKeys,
supportedModes: [ExploreMode.Metrics, ExploreMode.Logs],
mode: ExploreMode.Metrics,
}; };
reducerTester() reducerTester()
......
...@@ -8,7 +8,7 @@ import { ...@@ -8,7 +8,7 @@ import {
DEFAULT_UI_STATE, DEFAULT_UI_STATE,
generateNewKeyAndAddRefIdIfMissing, generateNewKeyAndAddRefIdIfMissing,
} from 'app/core/utils/explore'; } from 'app/core/utils/explore';
import { ExploreItemState, ExploreState, ExploreId, ExploreUpdateState } from 'app/types/explore'; import { ExploreItemState, ExploreState, ExploreId, ExploreUpdateState, ExploreMode } from 'app/types/explore';
import { DataQuery } from '@grafana/ui/src/types'; import { DataQuery } from '@grafana/ui/src/types';
import { import {
HigherOrderAction, HigherOrderAction,
...@@ -22,6 +22,7 @@ import { ...@@ -22,6 +22,7 @@ import {
runQueriesAction, runQueriesAction,
historyUpdatedAction, historyUpdatedAction,
resetQueryErrorAction, resetQueryErrorAction,
changeModeAction,
} from './actionTypes'; } from './actionTypes';
import { reducerFactory } from 'app/core/redux'; import { reducerFactory } from 'app/core/redux';
import { import {
...@@ -107,6 +108,8 @@ export const makeExploreItemState = (): ExploreItemState => ({ ...@@ -107,6 +108,8 @@ export const makeExploreItemState = (): ExploreItemState => ({
update: makeInitialUpdateState(), update: makeInitialUpdateState(),
queryErrors: [], queryErrors: [],
latency: 0, latency: 0,
supportedModes: [],
mode: null,
}); });
/** /**
...@@ -166,6 +169,13 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta ...@@ -166,6 +169,13 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta
}, },
}) })
.addMapper({ .addMapper({
filter: changeModeAction,
mapper: (state, action): ExploreItemState => {
const mode = action.payload.mode;
return { ...state, mode };
},
})
.addMapper({
filter: changeTimeAction, filter: changeTimeAction,
mapper: (state, action): ExploreItemState => { mapper: (state, action): ExploreItemState => {
return { ...state, range: action.payload.range }; return { ...state, range: action.payload.range };
...@@ -226,6 +236,21 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta ...@@ -226,6 +236,21 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta
const supportsLogs = datasourceInstance.meta.logs; const supportsLogs = datasourceInstance.meta.logs;
const supportsTable = datasourceInstance.meta.tables; const supportsTable = datasourceInstance.meta.tables;
let mode = ExploreMode.Metrics;
const supportedModes: ExploreMode[] = [];
if (supportsGraph) {
supportedModes.push(ExploreMode.Metrics);
}
if (supportsLogs) {
supportedModes.push(ExploreMode.Logs);
}
if (supportedModes.length === 1) {
mode = supportedModes[0];
}
// Custom components // Custom components
const StartPage = datasourceInstance.components.ExploreStartPage; const StartPage = datasourceInstance.components.ExploreStartPage;
...@@ -243,6 +268,8 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta ...@@ -243,6 +268,8 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta
StartPage, StartPage,
showingStartPage: Boolean(StartPage), showingStartPage: Boolean(StartPage),
queryKeys: getQueryKeys(state.queries, datasourceInstance), queryKeys: getQueryKeys(state.queries, datasourceInstance),
supportedModes,
mode,
}; };
}, },
}) })
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
"id": "testdata", "id": "testdata",
"metrics": true, "metrics": true,
"logs": true,
"alerting": true, "alerting": true,
"annotations": true, "annotations": true,
......
...@@ -17,6 +17,11 @@ import { Emitter, TimeSeries } from 'app/core/core'; ...@@ -17,6 +17,11 @@ import { Emitter, TimeSeries } from 'app/core/core';
import { LogsModel, LogsDedupStrategy } from 'app/core/logs_model'; import { LogsModel, LogsDedupStrategy } from 'app/core/logs_model';
import TableModel from 'app/core/table_model'; import TableModel from 'app/core/table_model';
export enum ExploreMode {
Metrics = 'Metrics',
Logs = 'Logs',
}
export interface CompletionItem { export interface CompletionItem {
/** /**
* The label of this completion item. By default * The label of this completion item. By default
...@@ -258,6 +263,8 @@ export interface ExploreItemState { ...@@ -258,6 +263,8 @@ export interface ExploreItemState {
queryErrors: DataQueryError[]; queryErrors: DataQueryError[];
latency: number; latency: number;
supportedModes: ExploreMode[];
mode: ExploreMode;
} }
export interface ExploreUpdateState { export interface ExploreUpdateState {
......
...@@ -92,6 +92,7 @@ ...@@ -92,6 +92,7 @@
.explore-toolbar-content-item:first-child { .explore-toolbar-content-item:first-child {
padding-left: $dashboard-padding; padding-left: $dashboard-padding;
margin-right: auto; margin-right: auto;
display: flex;
} }
@media only screen and (max-width: 1545px) { @media only screen and (max-width: 1545px) {
...@@ -413,3 +414,21 @@ ...@@ -413,3 +414,21 @@
margin: $space-xs 0; margin: $space-xs 0;
cursor: pointer; cursor: pointer;
} }
.query-type-toggle {
margin-left: 5px;
.toggle-button-group {
padding-top: 2px;
}
.btn.active {
background-color: $input-bg;
background-image: none;
background-clip: padding-box;
border: $input-border;
border-radius: $input-border-radius;
@include box-shadow($input-box-shadow);
color: $input-color;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment