mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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
This commit is contained in:
parent
be66ed9dab
commit
e6001f57a2
@ -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 {
|
|||||||
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 {
|
|||||||
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> {
|
|||||||
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> {
|
|||||||
{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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
initialRange,
|
initialRange,
|
||||||
initialUI,
|
initialUI,
|
||||||
queryErrors,
|
queryErrors,
|
||||||
|
mode,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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, {}> {
|
|||||||
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, {}> {
|
|||||||
refreshInterval,
|
refreshInterval,
|
||||||
onChangeTime,
|
onChangeTime,
|
||||||
split,
|
split,
|
||||||
|
supportedModeOptions,
|
||||||
|
selectedModeOption,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -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>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : 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
|
|||||||
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
|
|||||||
selectedDatasource,
|
selectedDatasource,
|
||||||
splitted,
|
splitted,
|
||||||
refreshInterval,
|
refreshInterval,
|
||||||
|
supportedModeOptions,
|
||||||
|
selectedModeOption,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -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> {
|
|||||||
|
|
||||||
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> {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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;
|
||||||
@ -245,6 +251,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 {
|
|||||||
QueryOptions,
|
QueryOptions,
|
||||||
ExploreUIState,
|
ExploreUIState,
|
||||||
QueryTransaction,
|
QueryTransaction,
|
||||||
|
ExploreMode,
|
||||||
} from 'app/types/explore';
|
} from 'app/types/explore';
|
||||||
import {
|
import {
|
||||||
updateDatasourceInstanceAction,
|
updateDatasourceInstanceAction,
|
||||||
@ -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';
|
||||||
@ -140,6 +142,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
|
|||||||
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
|
|||||||
|
|
||||||
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
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
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
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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', () => {
|
|||||||
.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', () => {
|
|||||||
showingStartPage: true,
|
showingStartPage: true,
|
||||||
queries,
|
queries,
|
||||||
queryKeys,
|
queryKeys,
|
||||||
|
supportedModes: [ExploreMode.Metrics, ExploreMode.Logs],
|
||||||
|
mode: ExploreMode.Metrics,
|
||||||
};
|
};
|
||||||
|
|
||||||
reducerTester()
|
reducerTester()
|
||||||
|
@ -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 {
|
|||||||
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 => ({
|
|||||||
update: makeInitialUpdateState(),
|
update: makeInitialUpdateState(),
|
||||||
queryErrors: [],
|
queryErrors: [],
|
||||||
latency: 0,
|
latency: 0,
|
||||||
|
supportedModes: [],
|
||||||
|
mode: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -165,6 +168,13 @@ export const itemReducer = reducerFactory<ExploreItemState>({} as ExploreItemSta
|
|||||||
return { ...state, containerWidth };
|
return { ...state, containerWidth };
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
.addMapper({
|
||||||
|
filter: changeModeAction,
|
||||||
|
mapper: (state, action): ExploreItemState => {
|
||||||
|
const mode = action.payload.mode;
|
||||||
|
return { ...state, mode };
|
||||||
|
},
|
||||||
|
})
|
||||||
.addMapper({
|
.addMapper({
|
||||||
filter: changeTimeAction,
|
filter: changeTimeAction,
|
||||||
mapper: (state, action): ExploreItemState => {
|
mapper: (state, action): ExploreItemState => {
|
||||||
@ -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
|
|||||||
StartPage,
|
StartPage,
|
||||||
showingStartPage: Boolean(StartPage),
|
showingStartPage: Boolean(StartPage),
|
||||||
queryKeys: getQueryKeys(state.queries, datasourceInstance),
|
queryKeys: getQueryKeys(state.queries, datasourceInstance),
|
||||||
|
supportedModes,
|
||||||
|
mode,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -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';
|
|||||||
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 {
|
|||||||
|
|
||||||
queryErrors: DataQueryError[];
|
queryErrors: DataQueryError[];
|
||||||
latency: number;
|
latency: number;
|
||||||
|
supportedModes: ExploreMode[];
|
||||||
|
mode: ExploreMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExploreUpdateState {
|
export interface ExploreUpdateState {
|
||||||
|
@ -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 @@
|
|||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user