diff --git a/public/app/features/dashboard/components/PanelEditor/GeneralPanelOptions.tsx b/public/app/features/dashboard/components/PanelEditor/GeneralPanelOptions.tsx
deleted file mode 100644
index 7fb337a8cea..00000000000
--- a/public/app/features/dashboard/components/PanelEditor/GeneralPanelOptions.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-import React, { FC, useMemo } from 'react';
-import { PanelModel } from '../../state';
-import { SelectableValue } from '@grafana/data';
-import { Forms, Select, DataLinksInlineEditor, Input } from '@grafana/ui';
-import { OptionsGroup } from './OptionsGroup';
-import { getPanelLinksVariableSuggestions } from '../../../panel/panellinks/link_srv';
-import { getVariables } from '../../../variables/state/selectors';
-
-export const GeneralPanelOptions: FC<{
- panel: PanelModel;
- onPanelConfigChange: (configKey: string, value: any) => void;
-}> = ({ panel, onPanelConfigChange }) => {
- const linkVariablesSuggestions = useMemo(() => getPanelLinksVariableSuggestions(), []);
-
- const variableOptions = getVariableOptions();
- const directionOptions = [
- { label: 'Horizontal', value: 'h' },
- { label: 'Vertical', value: 'v' },
- ];
-
- const maxPerRowOptions = [2, 3, 4, 6, 8, 12].map(value => ({ label: value.toString(), value }));
-
- return (
-
-
-
- onPanelConfigChange('title', e.currentTarget.value)} />
-
-
- onPanelConfigChange('description', e.currentTarget.value)}
- />
-
-
- onPanelConfigChange('transparent', e.currentTarget.checked)}
- />
-
-
-
- onPanelConfigChange('links', links)}
- suggestions={linkVariablesSuggestions}
- data={[]}
- />
-
-
-
-
- {panel.repeat && (
-
- onPanelConfigChange('repeatDirection', value)}
- />
-
- )}
-
- {panel.repeat && panel.repeatDirection === 'h' && (
-
-
- )}
-
-
- );
-};
-
-function getVariableOptions(): Array> {
- const options = getVariables().map((item: any) => {
- return { label: item.name, value: item.name };
- });
-
- if (options.length === 0) {
- options.unshift({
- label: 'No template variables found',
- value: null,
- });
- }
-
- options.unshift({
- label: 'Disable repeating',
- value: null,
- });
-
- return options;
-}
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsGroup.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsGroup.tsx
index 106e98a35ac..f31ebb8a83f 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsGroup.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsGroup.tsx
@@ -5,10 +5,11 @@ import { useTheme, Icon, stylesFactory } from '@grafana/ui';
interface Props {
title: string;
+ defaultToClosed?: boolean;
}
-export const OptionsGroup: FC = ({ title, children }) => {
- const [isExpanded, toggleExpand] = useState(true);
+export const OptionsGroup: FC = ({ title, children, defaultToClosed }) => {
+ const [isExpanded, toggleExpand] = useState(defaultToClosed ? false : true);
const theme = useTheme();
const styles = getStyles(theme);
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneContent.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneContent.tsx
index 3370b9fcec2..43987d2b441 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneContent.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneContent.tsx
@@ -1,6 +1,6 @@
import React, { useCallback, useState, CSSProperties } from 'react';
import Transition from 'react-transition-group/Transition';
-import { FieldConfigSource, GrafanaTheme, PanelData, PanelPlugin } from '@grafana/data';
+import { FieldConfigSource, GrafanaTheme, PanelData, PanelPlugin, SelectableValue } from '@grafana/data';
import { DashboardModel, PanelModel } from '../../state';
import {
CustomScrollbar,
@@ -8,22 +8,22 @@ import {
Tab,
TabContent,
TabsBar,
+ Select,
useTheme,
Container,
Icon,
Input,
} from '@grafana/ui';
import { DefaultFieldConfigEditor, OverrideFieldConfigEditor } from './FieldConfigEditor';
-import { AngularPanelOptions } from './AngularPanelOptions';
import { css } from 'emotion';
-import { GeneralPanelOptions } from './GeneralPanelOptions';
-import { PanelOptionsEditor } from './PanelOptionsEditor';
+import { PanelOptionsTab } from './PanelOptionsTab';
import { DashNavButton } from 'app/features/dashboard/components/DashNav/DashNavButton';
export const OptionsPaneContent: React.FC<{
- plugin?: PanelPlugin;
+ plugin: PanelPlugin;
panel: PanelModel;
data: PanelData;
+ width: number;
dashboard: DashboardModel;
onClose: () => void;
onFieldConfigsChange: (config: FieldConfigSource) => void;
@@ -33,6 +33,7 @@ export const OptionsPaneContent: React.FC<{
plugin,
panel,
data,
+ width,
onFieldConfigsChange,
onPanelOptionsChanged,
onPanelConfigChange,
@@ -41,7 +42,7 @@ export const OptionsPaneContent: React.FC<{
}) => {
const theme = useTheme();
const styles = getStyles(theme);
- const [activeTab, setActiveTab] = useState('defaults');
+ const [activeTab, setActiveTab] = useState('options');
const [isSearching, setSearchMode] = useState(false);
const renderFieldOptions = useCallback(
@@ -54,7 +55,6 @@ export const OptionsPaneContent: React.FC<{
return (
- {renderCustomPanelSettings(plugin)}
{
- const editors: JSX.Element[] = [];
- if (plugin.editor && panel) {
- editors.push(
-
-
+ {plugin && (
+
+
+
-
- );
- }
-
- // When editor created declaratively
- if (plugin.optionEditors && panel) {
- editors.push(
-
- );
- }
-
- if (editors.length > 0) {
- return editors;
- }
-
- return (
-
-
+
+
+
+ {activeTab === 'options' && (
+
+ )}
+ {activeTab === 'defaults' && renderFieldOptions(plugin)}
+ {activeTab === 'overrides' && renderFieldOverrideOptions(plugin)}
+
+
- );
- },
- [data, plugin, panel, onFieldConfigsChange]
+ )}
+
);
+};
- const renderSearchInput = useCallback(() => {
+export const TabsBarContent: React.FC<{
+ width: number;
+ isSearching: boolean;
+ activeTab: string;
+ styles: OptionsPaneStyles;
+ onClose: () => void;
+ setSearchMode: (mode: boolean) => void;
+ setActiveTab: (tab: string) => void;
+}> = ({ width, isSearching, activeTab, onClose, setSearchMode, setActiveTab, styles }) => {
+ if (isSearching) {
const defaultStyles = {
transition: 'width 50ms ease-in-out',
width: '50%',
@@ -163,56 +168,66 @@ export const OptionsPaneContent: React.FC<{
}}
);
- }, []);
+ }
return (
-
- {plugin && (
-
-
- {isSearching && renderSearchInput()}
- {!isSearching && (
- <>
- setActiveTab('defaults')} />
- setActiveTab('overrides')}
- />
- setActiveTab('panel')} />
-
-
- setSearchMode(true)}
- />
-
-
-
-
- >
- )}
-
-
-
- {activeTab === 'defaults' && renderFieldOptions(plugin)}
- {activeTab === 'overrides' && renderFieldOverrideOptions(plugin)}
- {activeTab === 'panel' && }
-
-
+ <>
+ {width < 377 ? (
+
+
+ ) : (
+ <>
+ {tabSelections.map(item => {
+ return (
+
setActiveTab(item.value)} />
+ );
+ })}
+
+ >
)}
-
+
+
+ setSearchMode(true)}
+ />
+
+
+
+
+ >
);
};
+const tabSelections: Array
> = [
+ {
+ label: 'Panel',
+ value: 'options',
+ },
+ {
+ label: 'Data',
+ value: 'defaults',
+ },
+ {
+ label: 'Overrides',
+ value: 'overrides',
+ },
+];
+
const getStyles = stylesFactory((theme: GrafanaTheme) => {
return {
wrapper: css`
@@ -274,3 +289,5 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
`,
};
});
+
+type OptionsPaneStyles = ReturnType;
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx
index 7705979b6c0..eda0c4a9af8 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx
@@ -30,11 +30,6 @@ import { VariableModel } from 'app/features/templating/types';
import { getVariables } from 'app/features/variables/state/selectors';
import { SubMenuItems } from 'app/features/dashboard/components/SubMenu/SubMenuItems';
-enum Pane {
- Right,
- Top,
-}
-
interface OwnProps {
dashboard: DashboardModel;
sourcePanel: PanelModel;
@@ -255,7 +250,7 @@ export class PanelEditorUnconnected extends PureComponent {
}
renderOptionsPane() {
- const { plugin, dashboard, data, panel } = this.props;
+ const { plugin, dashboard, data, panel, uiState } = this.props;
if (!plugin) {
return ;
@@ -267,6 +262,7 @@ export class PanelEditorUnconnected extends PureComponent {
dashboard={dashboard}
data={data}
panel={panel}
+ width={uiState.rightPaneSize as number}
onClose={this.onTogglePanelOptions}
onFieldConfigsChange={this.onFieldConfigChange}
onPanelOptionsChanged={this.onPanelOptionsChanged}
@@ -342,6 +338,11 @@ const mapDispatchToProps: MapDispatchToProps = {
export const PanelEditor = connect(mapStateToProps, mapDispatchToProps)(PanelEditorUnconnected);
+enum Pane {
+ Right,
+ Top,
+}
+
/*
* Styles
*/
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelOptionsTab.tsx b/public/app/features/dashboard/components/PanelEditor/PanelOptionsTab.tsx
new file mode 100644
index 00000000000..ecb4867df1e
--- /dev/null
+++ b/public/app/features/dashboard/components/PanelEditor/PanelOptionsTab.tsx
@@ -0,0 +1,165 @@
+import React, { FC, useMemo } from 'react';
+import { PanelModel, DashboardModel } from '../../state';
+import { SelectableValue, PanelPlugin, FieldConfigSource, PanelData } from '@grafana/data';
+import { Forms, Select, DataLinksInlineEditor, Input } from '@grafana/ui';
+import { OptionsGroup } from './OptionsGroup';
+import { getPanelLinksVariableSuggestions } from '../../../panel/panellinks/link_srv';
+import { getVariables } from '../../../variables/state/selectors';
+import { PanelOptionsEditor } from './PanelOptionsEditor';
+import { AngularPanelOptions } from '../../panel_editor/AngularPanelOptions';
+
+interface Props {
+ panel: PanelModel;
+ plugin: PanelPlugin;
+ data: PanelData;
+ dashboard: DashboardModel;
+ onPanelConfigChange: (configKey: string, value: any) => void;
+ onPanelOptionsChanged: (options: any) => void;
+ onFieldConfigsChange: (config: FieldConfigSource) => void;
+}
+
+export const PanelOptionsTab: FC = ({
+ panel,
+ plugin,
+ data,
+ dashboard,
+ onPanelConfigChange,
+ onPanelOptionsChanged,
+ onFieldConfigsChange,
+}) => {
+ const elements: JSX.Element[] = [];
+ const linkVariablesSuggestions = useMemo(() => getPanelLinksVariableSuggestions(), []);
+
+ const variableOptions = getVariableOptions();
+ const directionOptions = [
+ { label: 'Horizontal', value: 'h' },
+ { label: 'Vertical', value: 'v' },
+ ];
+
+ const maxPerRowOptions = [2, 3, 4, 6, 8, 12].map(value => ({ label: value.toString(), value }));
+
+ // Fist common panel settings Title, description
+ elements.push(
+
+
+ onPanelConfigChange('title', e.currentTarget.value)} />
+
+
+ onPanelConfigChange('description', e.currentTarget.value)}
+ />
+
+
+ onPanelConfigChange('transparent', e.currentTarget.checked)}
+ />
+
+
+ );
+
+ // Old legacy react editor
+ if (plugin.editor && panel && !plugin.optionEditors) {
+ elements.push(
+
+
+
+ );
+ }
+
+ if (plugin.optionEditors && panel) {
+ elements.push(
+
+
+
+ );
+ }
+
+ if (plugin.angularPanelCtrl) {
+ elements.push(
+
+
+
+ );
+ }
+
+ elements.push(
+ <>
+
+ onPanelConfigChange('links', links)}
+ suggestions={linkVariablesSuggestions}
+ data={[]}
+ />
+
+
+
+
+ {panel.repeat && (
+
+ onPanelConfigChange('repeatDirection', value)}
+ />
+
+ )}
+
+ {panel.repeat && panel.repeatDirection === 'h' && (
+
+
+ )}
+
+ >
+ );
+
+ return <>{elements}>;
+};
+
+function getVariableOptions(): Array> {
+ const options = getVariables().map((item: any) => {
+ return { label: item.name, value: item.name };
+ });
+
+ if (options.length === 0) {
+ options.unshift({
+ label: 'No template variables found',
+ value: null,
+ });
+ }
+
+ options.unshift({
+ label: 'Disable repeating',
+ value: null,
+ });
+
+ return options;
+}