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 { GrafanaTheme } from '@grafana/data';
import { selectThemeVariant } from '../../themes/selectThemeVariant';
import { ThemeContext } from '../../themes/ThemeContext';
import { stylesFactory } from '../../themes/stylesFactory';
import { Icon } from '../Icon/Icon';
const getStyles = stylesFactory((theme: GrafanaTheme) => ({
collapse: css`
label: collapse;
margin-top: ${theme.spacing.sm};
margin-bottom: ${theme.spacing.sm};
`,
collapseBody: css`
label: collapse__body;
@ -51,7 +51,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
`,
header: css`
label: collapse__header;
padding: ${theme.spacing.sm} ${theme.spacing.md} 0 ${theme.spacing.md};
padding: ${theme.spacing.sm} ${theme.spacing.md};
display: flex;
cursor: inherit;
transition: all 0.1s linear;
@ -60,7 +60,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
headerCollapsed: css`
label: collapse__header--collapsed;
cursor: pointer;
padding: ${theme.spacing.sm} ${theme.spacing.md} 0 ${theme.spacing.md};
padding: ${theme.spacing.sm} ${theme.spacing.md};
`,
headerButtons: css`
label: collapse__header-buttons;
@ -78,7 +78,6 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
font-weight: ${theme.typography.weight.semibold};
margin-right: ${theme.spacing.sm};
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;
}
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 }) => {
const theme = useContext(ThemeContext);
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 iconClass = isOpen ? 'fa fa-caret-up' : 'fa fa-caret-down';
const loaderClass = loading ? cx([style.loader, style.loaderActive]) : cx([style.loader]);
const headerClass = collapsible ? cx([style.header]) : cx([style.headerCollapsed]);
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={headerClass} onClick={onClickToggle}>
<div className={headerButtonsClass}>
<span className={iconClass} />
<Icon name={isOpen ? 'caret-up' : 'caret-down'} />
</div>
<div className={cx([style.headerLabel])}>{label}</div>
</div>

View File

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

View File

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

View File

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

View File

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