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={[]} - /> - - - - onPanelConfigChange('maxPerRow', value.value)} - /> - - )} - -
- ); -}; - -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 ? ( +
+ 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={[]} + /> + + + + onPanelConfigChange('maxPerRow', value.value)} + /> + + )} + + + ); + + 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; +}