Collapse: add a controlled collapse (#22046)

This commit is contained in:
Ryan McKinley
2020-02-09 17:39:26 +01:00
committed by GitHub
parent 1554dcee0d
commit bedc708dfa
5 changed files with 55 additions and 25 deletions

View File

@@ -1,15 +1,15 @@
import React, { FunctionComponent, useContext } from 'react'; import React, { FunctionComponent, useContext, useState } from 'react';
import { css, cx } from 'emotion'; import { css, cx } from 'emotion';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaTheme } from '@grafana/data';
import { selectThemeVariant } from '../../themes/selectThemeVariant';
import { ThemeContext } from '../../themes/ThemeContext'; import { ThemeContext } from '../../themes/ThemeContext';
import { stylesFactory } from '../../themes/stylesFactory'; import { stylesFactory } from '../../themes/stylesFactory';
import { Icon } from '../Icon/Icon';
const getStyles = stylesFactory((theme: GrafanaTheme) => ({ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
collapse: css` collapse: css`
label: collapse; label: collapse;
margin-top: ${theme.spacing.sm}; margin-bottom: ${theme.spacing.sm};
`, `,
collapseBody: css` collapseBody: css`
label: collapse__body; label: collapse__body;
@@ -51,7 +51,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
`, `,
header: css` header: css`
label: collapse__header; label: collapse__header;
padding: ${theme.spacing.sm} ${theme.spacing.md} 0 ${theme.spacing.md}; padding: ${theme.spacing.sm} ${theme.spacing.md};
display: flex; display: flex;
cursor: inherit; cursor: inherit;
transition: all 0.1s linear; transition: all 0.1s linear;
@@ -60,7 +60,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
headerCollapsed: css` headerCollapsed: css`
label: collapse__header--collapsed; label: collapse__header--collapsed;
cursor: pointer; cursor: pointer;
padding: ${theme.spacing.sm} ${theme.spacing.md} 0 ${theme.spacing.md}; padding: ${theme.spacing.sm} ${theme.spacing.md};
`, `,
headerButtons: css` headerButtons: css`
label: collapse__header-buttons; label: collapse__header-buttons;
@@ -78,7 +78,6 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
font-weight: ${theme.typography.weight.semibold}; font-weight: ${theme.typography.weight.semibold};
margin-right: ${theme.spacing.sm}; margin-right: ${theme.spacing.sm};
font-size: ${theme.typography.heading.h6}; font-size: ${theme.typography.heading.h6};
box-shadow: ${selectThemeVariant({ light: 'none', dark: '1px 1px 4px rgb(45, 45, 45)' }, theme.type)};
`, `,
})); }));
@@ -90,6 +89,22 @@ interface Props {
onToggle?: (isOpen: boolean) => void; onToggle?: (isOpen: boolean) => void;
} }
export const ControlledCollapse: FunctionComponent<Props> = ({ isOpen, onToggle, ...otherProps }) => {
const [open, setOpen] = useState(isOpen);
return (
<Collapse
isOpen={open}
{...otherProps}
onToggle={() => {
setOpen(!open);
if (onToggle) {
onToggle(!open);
}
}}
/>
);
};
export const Collapse: FunctionComponent<Props> = ({ isOpen, label, loading, collapsible, onToggle, children }) => { export const Collapse: FunctionComponent<Props> = ({ isOpen, label, loading, collapsible, onToggle, children }) => {
const theme = useContext(ThemeContext); const theme = useContext(ThemeContext);
const style = getStyles(theme); const style = getStyles(theme);
@@ -100,7 +115,6 @@ export const Collapse: FunctionComponent<Props> = ({ isOpen, label, loading, col
}; };
const panelClass = cx([style.collapse, 'panel-container']); const panelClass = cx([style.collapse, 'panel-container']);
const iconClass = isOpen ? 'fa fa-caret-up' : 'fa fa-caret-down';
const loaderClass = loading ? cx([style.loader, style.loaderActive]) : cx([style.loader]); const loaderClass = loading ? cx([style.loader, style.loaderActive]) : cx([style.loader]);
const headerClass = collapsible ? cx([style.header]) : cx([style.headerCollapsed]); const headerClass = collapsible ? cx([style.header]) : cx([style.headerCollapsed]);
const headerButtonsClass = collapsible ? cx([style.headerButtons]) : cx([style.headerButtonsCollapsed]); const headerButtonsClass = collapsible ? cx([style.headerButtons]) : cx([style.headerButtonsCollapsed]);
@@ -109,7 +123,7 @@ export const Collapse: FunctionComponent<Props> = ({ isOpen, label, loading, col
<div className={panelClass}> <div className={panelClass}>
<div className={headerClass} onClick={onClickToggle}> <div className={headerClass} onClick={onClickToggle}>
<div className={headerButtonsClass}> <div className={headerButtonsClass}>
<span className={iconClass} /> <Icon name={isOpen ? 'caret-up' : 'caret-down'} />
</div> </div>
<div className={cx([style.headerLabel])}>{label}</div> <div className={cx([style.headerLabel])}>{label}</div>
</div> </div>

View File

@@ -10,6 +10,7 @@ import {
import { standardFieldConfigEditorRegistry } from './standardFieldConfigEditorRegistry'; import { standardFieldConfigEditorRegistry } from './standardFieldConfigEditorRegistry';
import Forms from '../Forms'; import Forms from '../Forms';
import { fieldMatchersUI } from '../MatchersUI/fieldMatchersUI'; import { fieldMatchersUI } from '../MatchersUI/fieldMatchersUI';
import { ControlledCollapse } from '../Collapse/Collapse';
interface Props { interface Props {
config: FieldConfigSource; config: FieldConfigSource;
@@ -214,10 +215,17 @@ export class FieldConfigEditor extends React.PureComponent<Props> {
render() { render() {
return ( return (
<div> <div>
{this.renderStandardConfigs()} <ControlledCollapse label="Standard Field Configuration" collapsible>
{this.renderCustomConfigs()} {this.renderStandardConfigs()}
{this.renderAddOverride()} </ControlledCollapse>
{this.renderOverrides()} {this.props.custom && (
<ControlledCollapse label="Standard Field Configuration">{this.renderCustomConfigs()}</ControlledCollapse>
)}
<ControlledCollapse label="Field Overrides" collapsible>
{this.renderAddOverride()}
{this.renderOverrides()}
</ControlledCollapse>
</div> </div>
); );
} }

View File

@@ -84,7 +84,7 @@ export {
export { Alert, AlertVariant } from './Alert/Alert'; export { Alert, AlertVariant } from './Alert/Alert';
export { GraphSeriesToggler, GraphSeriesTogglerAPI } from './Graph/GraphSeriesToggler'; export { GraphSeriesToggler, GraphSeriesTogglerAPI } from './Graph/GraphSeriesToggler';
export { Collapse } from './Collapse/Collapse'; export { Collapse, ControlledCollapse } from './Collapse/Collapse';
export { LogLabels } from './Logs/LogLabels'; export { LogLabels } from './Logs/LogLabels';
export { LogRows } from './Logs/LogRows'; export { LogRows } from './Logs/LogRows';
export { getLogRowStyles } from './Logs/getLogRowStyles'; export { getLogRowStyles } from './Logs/getLogRowStyles';

View File

@@ -8,7 +8,14 @@ import {
PanelEvents, PanelEvents,
SelectableValue, SelectableValue,
} from '@grafana/data'; } from '@grafana/data';
import { stylesFactory, Forms, FieldConfigEditor, CustomScrollbar, selectThemeVariant } from '@grafana/ui'; import {
stylesFactory,
Forms,
FieldConfigEditor,
CustomScrollbar,
selectThemeVariant,
ControlledCollapse,
} from '@grafana/ui';
import { css, cx } from 'emotion'; import { css, cx } from 'emotion';
import config from 'app/core/config'; import config from 'app/core/config';
import AutoSizer from 'react-virtualized-auto-sizer'; import AutoSizer from 'react-virtualized-auto-sizer';
@@ -211,14 +218,12 @@ export class PanelEditor extends PureComponent<Props, State> {
} }
return ( return (
<div> <FieldConfigEditor
<FieldConfigEditor config={fieldOptions}
config={fieldOptions} custom={plugin.customFieldConfigs}
custom={plugin.customFieldConfigs} onChange={this.onFieldConfigsChange}
onChange={this.onFieldConfigsChange} data={data.series}
data={data.series} />
/>
</div>
); );
} }
@@ -239,7 +244,7 @@ export class PanelEditor extends PureComponent<Props, State> {
if (plugin.editor && panel) { if (plugin.editor && panel) {
return ( return (
<div style={{ marginTop: '40px' }}> <div style={{ marginTop: '10px' }}>
<plugin.editor data={data} options={panel.getOptions()} onOptionsChange={this.onPanelOptionsChanged} /> <plugin.editor data={data} options={panel.getOptions()} onOptionsChange={this.onPanelOptionsChanged} />
</div> </div>
); );
@@ -359,7 +364,9 @@ export class PanelEditor extends PureComponent<Props, State> {
<CustomScrollbar> <CustomScrollbar>
<div style={{ padding: '10px' }}> <div style={{ padding: '10px' }}>
{this.renderFieldOptions()} {this.renderFieldOptions()}
{this.renderVisSettings()} <ControlledCollapse label="Visualization Settings" collapsible>
{this.renderVisSettings()}
</ControlledCollapse>
</div> </div>
</CustomScrollbar> </CustomScrollbar>
</div> </div>

View File

@@ -7,6 +7,7 @@ import { EditorTab, allTabs } from './types';
import { DashboardModel } from '../../state'; import { DashboardModel } from '../../state';
import { QueriesTab } from '../../panel_editor/QueriesTab'; import { QueriesTab } from '../../panel_editor/QueriesTab';
import { PanelModel } from '../../state/PanelModel'; import { PanelModel } from '../../state/PanelModel';
import { AlertTab } from 'app/features/alerting/AlertTab';
interface PanelEditorTabsProps { interface PanelEditorTabsProps {
panel: PanelModel; panel: PanelModel;
@@ -57,7 +58,7 @@ export const PanelEditorTabs: React.FC<PanelEditorTabsProps> = ({ panel, dashboa
return ( return (
<div style={{ width, height }}> <div style={{ width, height }}>
{activeTab === EditorTab.Query && <QueriesTab panel={panel} dashboard={dashboard} />} {activeTab === EditorTab.Query && <QueriesTab panel={panel} dashboard={dashboard} />}
{activeTab === EditorTab.Alerts && <div>TODO: Show Alerts</div>} {activeTab === EditorTab.Alerts && <AlertTab panel={panel} dashboard={dashboard} />}
{activeTab === EditorTab.Transform && <div>TODO: Show Transform</div>} {activeTab === EditorTab.Transform && <div>TODO: Show Transform</div>}
</div> </div>
); );