diff --git a/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx b/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx
index 9123c31e243..c124a0d6f0b 100644
--- a/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx
+++ b/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx
@@ -82,11 +82,11 @@ const getQueryOperationRowStyles = stylesFactory((theme: GrafanaTheme) => {
margin-bottom: ${theme.spacing.md};
`,
header: css`
- padding: 0 ${theme.spacing.sm};
+ padding: ${theme.spacing.xs} ${theme.spacing.sm};
border-radius: ${theme.border.radius.sm};
background: ${theme.colors.bg2};
- height: ${theme.spacing.formInputHeight}px;
- line-height: ${theme.spacing.formInputHeight}px;
+ min-height: ${theme.spacing.formInputHeight}px;
+ line-height: ${theme.spacing.sm}px;
display: flex;
align-items: center;
justify-content: space-between;
diff --git a/public/app/features/dashboard/components/Inspector/DetailText.tsx b/public/app/features/dashboard/components/Inspector/DetailText.tsx
new file mode 100644
index 00000000000..26b55fc5974
--- /dev/null
+++ b/public/app/features/dashboard/components/Inspector/DetailText.tsx
@@ -0,0 +1,16 @@
+import React, { FC } from 'react';
+import { useStyles } from '@grafana/ui';
+import { GrafanaTheme } from '@grafana/data';
+import { css } from 'emotion';
+
+const getStyles = (theme: GrafanaTheme) => css`
+ margin: 0;
+ margin-left: ${theme.spacing.md};
+ font-size: ${theme.typography.size.sm};
+ color: ${theme.colors.textWeak};
+`;
+
+export const DetailText: FC = ({ children }) => {
+ const collapsedTextStyles = useStyles(getStyles);
+ return
{children}
;
+};
diff --git a/public/app/features/dashboard/components/Inspector/InspectDataTab.tsx b/public/app/features/dashboard/components/Inspector/InspectDataTab.tsx
index c0e097e1cb6..e7bc72afbcc 100644
--- a/public/app/features/dashboard/components/Inspector/InspectDataTab.tsx
+++ b/public/app/features/dashboard/components/Inspector/InspectDataTab.tsx
@@ -14,28 +14,18 @@ import {
DisplayProcessor,
getDisplayProcessor,
} from '@grafana/data';
-import {
- Button,
- Container,
- Field,
- HorizontalGroup,
- Icon,
- LegacyForms,
- Select,
- Table,
- VerticalGroup,
-} from '@grafana/ui';
+import { Button, Field, Icon, Switch, Select, Table, VerticalGroup, Container, HorizontalGroup } from '@grafana/ui';
import { selectors } from '@grafana/e2e-selectors';
import AutoSizer from 'react-virtualized-auto-sizer';
import { getPanelInspectorStyles } from './styles';
import { config } from 'app/core/config';
import { saveAs } from 'file-saver';
-import { css, cx } from 'emotion';
+import { css } from 'emotion';
import { GetDataOptions } from '../../state/PanelQueryRunner';
-import { QueryOperationRow } from '../../../../core/components/QueryOperationRow/QueryOperationRow';
-import { PanelModel } from '../../state';
-const { Switch } = LegacyForms;
+import { QueryOperationRow } from 'app/core/components/QueryOperationRow/QueryOperationRow';
+import { PanelModel } from 'app/features/dashboard/state';
+import { DetailText } from './DetailText';
interface Props {
panel: PanelModel;
@@ -46,9 +36,11 @@ interface Props {
}
interface State {
+ /** The string is seriesToColumns transformation. Otherwise it is a dataframe index */
+ selectedDataFrame: number | DataTransformerID;
transformId: DataTransformerID;
dataFrameIndex: number;
- transformationOptions: Array>;
+ transformationOptions: Array>;
}
export class InspectDataTab extends PureComponent {
@@ -56,8 +48,9 @@ export class InspectDataTab extends PureComponent {
super(props);
this.state = {
+ selectedDataFrame: DataTransformerID.seriesToColumns,
dataFrameIndex: 0,
- transformId: DataTransformerID.noop,
+ transformId: DataTransformerID.seriesToColumns,
transformationOptions: buildTransformationOptions(),
};
}
@@ -101,15 +94,15 @@ export class InspectDataTab extends PureComponent {
saveAs(blob, fileName);
};
- onSelectedFrameChanged = (item: SelectableValue) => {
- this.setState({ dataFrameIndex: item.value || 0 });
- };
-
- onTransformationChange = (value: SelectableValue) => {
- this.setState({ transformId: value.value, dataFrameIndex: 0 });
+ onDataFrameChange = (item: SelectableValue) => {
+ this.setState({
+ transformId:
+ item.value === DataTransformerID.seriesToColumns ? DataTransformerID.seriesToColumns : DataTransformerID.noop,
+ dataFrameIndex: typeof item.value === 'number' ? item.value : 0,
+ selectedDataFrame: item.value,
+ });
this.props.onOptionsChange({
...this.props.options,
- withTransforms: false,
});
};
@@ -149,9 +142,35 @@ export class InspectDataTab extends PureComponent {
});
}
- renderDataOptions = () => {
- const { options, onOptionsChange, panel } = this.props;
- const { transformId } = this.state;
+ getActiveString = () => {
+ const { selectedDataFrame } = this.state;
+ const { options, data } = this.props;
+ let activeString = '';
+ if (selectedDataFrame === DataTransformerID.seriesToColumns) {
+ activeString = 'series joined by time';
+ } else {
+ activeString = getFrameDisplayName(data[selectedDataFrame as number]);
+ }
+ if (options.withTransforms || options.withFieldConfig) {
+ activeString += ' - applied ';
+ if (options.withTransforms) {
+ activeString += 'panel transformations ';
+ }
+
+ if (options.withTransforms && options.withFieldConfig) {
+ activeString += 'and ';
+ }
+
+ if (options.withFieldConfig) {
+ activeString += 'field configuration';
+ }
+ }
+ return activeString;
+ };
+
+ renderDataOptions = (dataFrames: DataFrame[]) => {
+ const { options, onOptionsChange, panel, data } = this.props;
+ const { transformId, transformationOptions, selectedDataFrame } = this.state;
const styles = getPanelInspectorStyles();
const panelTransformations = panel.getTransformations();
@@ -160,43 +179,80 @@ export class InspectDataTab extends PureComponent {
const showFieldConfigsOption = !panel.plugin?.fieldConfigRegistry.isEmpty();
const showDataOptions = showPanelTransformationsOption || showFieldConfigsOption;
+ let dataSelect = dataFrames;
+ if (selectedDataFrame === DataTransformerID.seriesToColumns) {
+ dataSelect = data;
+ }
+
+ const choices = dataSelect.map((frame, index) => {
+ return {
+ value: index,
+ label: `${getFrameDisplayName(frame)} (${index})`,
+ } as SelectableValue;
+ });
+
+ const selectableOptions = [...transformationOptions, ...choices];
+
if (!showDataOptions) {
return null;
}
return (
-
-
- {showPanelTransformationsOption && (
-
- onOptionsChange({ ...options, withTransforms: !options.withTransforms })}
- />
-
- )}
- {showFieldConfigsOption && (
-
- onOptionsChange({ ...options, withFieldConfig: !options.withFieldConfig })}
- />
-
- )}
-
-
+ {this.getActiveString()}}
+ isOpen={false}
+ >
+
+
+ {data.length > 1 && (
+
+
+
+ )}
+
+ {showPanelTransformationsOption && (
+
+ onOptionsChange({ ...options, withTransforms: !options.withTransforms })}
+ />
+
+ )}
+ {showFieldConfigsOption && (
+
+ onOptionsChange({ ...options, withFieldConfig: !options.withFieldConfig })}
+ />
+
+ )}
+
+
+
+
);
};
render() {
- const { isLoading, data, options, onOptionsChange } = this.props;
- const { dataFrameIndex, transformId, transformationOptions } = this.state;
+ const { isLoading } = this.props;
+ const { dataFrameIndex } = this.state;
const styles = getPanelInspectorStyles();
if (isLoading) {
@@ -213,83 +269,20 @@ export class InspectDataTab extends PureComponent {
return No Data
;
}
- const choices = dataFrames.map((frame, index) => {
- return {
- value: index,
- label: `${getFrameDisplayName(frame)} (${index})`,
- };
- });
-
- const panelTransformations = this.props.panel.getTransformations();
-
return (
-
-
-
-
- {data.length > 1 && (
-
-
-
-
-
- )}
- {choices.length > 1 && (
-
-
-
-
-
- )}
-
-
-
-
-
-
- {panelTransformations && panelTransformations.length > 0 && (
-
- onOptionsChange({ ...options, withTransforms: !options.withTransforms })}
- />
-
- )}
-
- onOptionsChange({ ...options, withFieldConfig: !options.withFieldConfig })}
- />
-
-
-
-
-
-
+
+
{this.renderDataOptions(dataFrames)}
+
+
{({ width, height }) => {
@@ -311,17 +304,10 @@ export class InspectDataTab extends PureComponent {
}
function buildTransformationOptions() {
- const transformations: Array> = [
+ const transformations: Array> = [
{
- value: 'Do nothing',
- label: 'None',
- transformer: {
- id: DataTransformerID.noop,
- },
- },
- {
- value: 'join by time',
- label: 'Join by time',
+ value: DataTransformerID.seriesToColumns,
+ label: 'Series joined by time',
transformer: {
id: DataTransformerID.seriesToColumns,
options: { byField: 'Time' },
diff --git a/public/app/features/dashboard/components/Inspector/styles.ts b/public/app/features/dashboard/components/Inspector/styles.ts
index 6a5e007ccce..9ce1bcd14c5 100644
--- a/public/app/features/dashboard/components/Inspector/styles.ts
+++ b/public/app/features/dashboard/components/Inspector/styles.ts
@@ -54,14 +54,18 @@ export const getPanelInspectorStyles = stylesFactory(() => {
`,
actionsWrapper: css`
display: flex;
- flex-wrap: wrap;
`,
leftActions: css`
display: flex;
flex-grow: 1;
+
+ max-width: 85%;
+ @media (max-width: 1345px) {
+ max-width: 75%;
+ }
`,
options: css`
- margin-top: 19px;
+ padding-top: ${config.theme.spacing.sm};
`,
dataDisplayOptions: css`
flex-grow: 1;