mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Core: Move SplitPane layout from PanelEdit. (#29266)
* move split pane logic to its own component * fix update function typing * destruct updateuistate * updates after review * reword the rightpane to work for text panel
This commit is contained in:
parent
5773929953
commit
0b2a6ec7fe
177
public/app/core/components/ThreePaneSplit/SplitPaneWrapper.tsx
Normal file
177
public/app/core/components/ThreePaneSplit/SplitPaneWrapper.tsx
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
import React, { createRef, MutableRefObject, PureComponent, ReactNode } from 'react';
|
||||||
|
import SplitPane from 'react-split-pane';
|
||||||
|
import { css, cx } from 'emotion';
|
||||||
|
import { GrafanaTheme } from '@grafana/data';
|
||||||
|
import { stylesFactory } from '@grafana/ui';
|
||||||
|
import { config } from 'app/core/config';
|
||||||
|
|
||||||
|
enum Pane {
|
||||||
|
Right,
|
||||||
|
Top,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
leftPaneComponents: ReactNode[] | ReactNode;
|
||||||
|
rightPaneComponents: ReactNode;
|
||||||
|
uiState: { topPaneSize: number; rightPaneSize: number };
|
||||||
|
rightPaneVisible?: boolean;
|
||||||
|
updateUiState: (uiState: { topPaneSize?: number; rightPaneSize?: number }) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SplitPaneWrapper extends PureComponent<Props> {
|
||||||
|
rafToken = createRef<number>();
|
||||||
|
static defaultProps = {
|
||||||
|
rightPaneVisible: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
window.addEventListener('resize', this.updateSplitPaneSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener('resize', this.updateSplitPaneSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSplitPaneSize = () => {
|
||||||
|
if (this.rafToken.current !== undefined) {
|
||||||
|
window.cancelAnimationFrame(this.rafToken.current!);
|
||||||
|
}
|
||||||
|
(this.rafToken as MutableRefObject<number>).current = window.requestAnimationFrame(() => {
|
||||||
|
this.forceUpdate();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onDragFinished = (pane: Pane, size?: number) => {
|
||||||
|
document.body.style.cursor = 'auto';
|
||||||
|
|
||||||
|
// When the drag handle is just clicked size is undefined
|
||||||
|
if (!size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { updateUiState } = this.props;
|
||||||
|
if (pane === Pane.Top) {
|
||||||
|
updateUiState({
|
||||||
|
topPaneSize: size / window.innerHeight,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateUiState({
|
||||||
|
rightPaneSize: size / window.innerWidth,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onDragStarted = () => {
|
||||||
|
document.body.style.cursor = 'row-resize';
|
||||||
|
};
|
||||||
|
|
||||||
|
renderHorizontalSplit() {
|
||||||
|
const { leftPaneComponents, uiState } = this.props;
|
||||||
|
const styles = getStyles(config.theme);
|
||||||
|
const topPaneSize =
|
||||||
|
uiState.topPaneSize >= 1 ? (uiState.topPaneSize as number) : (uiState.topPaneSize as number) * window.innerHeight;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Guesstimate the height of the browser window minus
|
||||||
|
panel toolbar and editor toolbar (~120px). This is to prevent resizing
|
||||||
|
the preview window beyond the browser window.
|
||||||
|
*/
|
||||||
|
const maxHeight = window.innerHeight - 120;
|
||||||
|
|
||||||
|
if (Array.isArray(leftPaneComponents)) {
|
||||||
|
return (
|
||||||
|
<SplitPane
|
||||||
|
split="horizontal"
|
||||||
|
maxSize={maxHeight}
|
||||||
|
primary="first"
|
||||||
|
size={topPaneSize < 200 ? 200 : topPaneSize}
|
||||||
|
pane2Style={{ minHeight: 0 }}
|
||||||
|
resizerClassName={styles.resizerH}
|
||||||
|
onDragStarted={this.onDragStarted}
|
||||||
|
onDragFinished={size => this.onDragFinished(Pane.Top, size)}
|
||||||
|
>
|
||||||
|
{leftPaneComponents}
|
||||||
|
</SplitPane>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return leftPaneComponents;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { rightPaneVisible, rightPaneComponents, uiState } = this.props;
|
||||||
|
// Limit options pane width to 90% of screen.
|
||||||
|
const maxWidth = window.innerWidth * 0.9;
|
||||||
|
const styles = getStyles(config.theme);
|
||||||
|
|
||||||
|
// Need to handle when width is relative. ie a percentage of the viewport
|
||||||
|
const rightPaneSize =
|
||||||
|
uiState.rightPaneSize <= 1
|
||||||
|
? (uiState.rightPaneSize as number) * window.innerWidth
|
||||||
|
: (uiState.rightPaneSize as number);
|
||||||
|
|
||||||
|
if (!rightPaneVisible) {
|
||||||
|
return this.renderHorizontalSplit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SplitPane
|
||||||
|
split="vertical"
|
||||||
|
maxSize={maxWidth}
|
||||||
|
size={rightPaneSize >= 300 ? rightPaneSize : 300}
|
||||||
|
primary="second"
|
||||||
|
resizerClassName={styles.resizerV}
|
||||||
|
onDragStarted={() => (document.body.style.cursor = 'col-resize')}
|
||||||
|
onDragFinished={size => this.onDragFinished(Pane.Right, size)}
|
||||||
|
>
|
||||||
|
{this.renderHorizontalSplit()}
|
||||||
|
{rightPaneComponents}
|
||||||
|
</SplitPane>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||||
|
const handleColor = theme.palette.blue95;
|
||||||
|
const paneSpacing = theme.spacing.md;
|
||||||
|
|
||||||
|
const resizer = css`
|
||||||
|
font-style: italic;
|
||||||
|
background: transparent;
|
||||||
|
border-top: 0;
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
border-left: 0;
|
||||||
|
border-color: transparent;
|
||||||
|
border-style: solid;
|
||||||
|
transition: 0.2s border-color ease-in-out;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: ${handleColor};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
resizerV: cx(
|
||||||
|
resizer,
|
||||||
|
css`
|
||||||
|
cursor: col-resize;
|
||||||
|
width: ${paneSpacing};
|
||||||
|
border-right-width: 1px;
|
||||||
|
margin-top: 18px;
|
||||||
|
`
|
||||||
|
),
|
||||||
|
resizerH: cx(
|
||||||
|
resizer,
|
||||||
|
css`
|
||||||
|
height: ${paneSpacing};
|
||||||
|
cursor: row-resize;
|
||||||
|
position: relative;
|
||||||
|
top: 0px;
|
||||||
|
z-index: 1;
|
||||||
|
border-top-width: 1px;
|
||||||
|
margin-left: ${paneSpacing};
|
||||||
|
`
|
||||||
|
),
|
||||||
|
};
|
||||||
|
});
|
@ -1,7 +1,6 @@
|
|||||||
import React, { createRef, MutableRefObject, PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux';
|
import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux';
|
||||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||||
import SplitPane from 'react-split-pane';
|
|
||||||
import { css, cx } from 'emotion';
|
import { css, cx } from 'emotion';
|
||||||
import { Unsubscribable } from 'rxjs';
|
import { Unsubscribable } from 'rxjs';
|
||||||
|
|
||||||
@ -19,6 +18,7 @@ import { OptionsPaneContent } from './OptionsPaneContent';
|
|||||||
import { DashNavButton } from 'app/features/dashboard/components/DashNav/DashNavButton';
|
import { DashNavButton } from 'app/features/dashboard/components/DashNav/DashNavButton';
|
||||||
import { SubMenuItems } from 'app/features/dashboard/components/SubMenu/SubMenuItems';
|
import { SubMenuItems } from 'app/features/dashboard/components/SubMenu/SubMenuItems';
|
||||||
import { BackButton } from 'app/core/components/BackButton/BackButton';
|
import { BackButton } from 'app/core/components/BackButton/BackButton';
|
||||||
|
import { SplitPaneWrapper } from 'app/core/components/ThreePaneSplit/SplitPaneWrapper';
|
||||||
import { SaveDashboardModalProxy } from '../SaveDashboard/SaveDashboardModalProxy';
|
import { SaveDashboardModalProxy } from '../SaveDashboard/SaveDashboardModalProxy';
|
||||||
import { DashboardPanel } from '../../dashgrid/DashboardPanel';
|
import { DashboardPanel } from '../../dashgrid/DashboardPanel';
|
||||||
|
|
||||||
@ -65,28 +65,14 @@ type Props = OwnProps & ConnectedProps & DispatchProps;
|
|||||||
|
|
||||||
export class PanelEditorUnconnected extends PureComponent<Props> {
|
export class PanelEditorUnconnected extends PureComponent<Props> {
|
||||||
querySubscription: Unsubscribable;
|
querySubscription: Unsubscribable;
|
||||||
rafToken = createRef<number>();
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.initPanelEditor(this.props.sourcePanel, this.props.dashboard);
|
this.props.initPanelEditor(this.props.sourcePanel, this.props.dashboard);
|
||||||
|
|
||||||
window.addEventListener('resize', this.updateSplitPaneSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.props.panelEditorCleanUp();
|
this.props.panelEditorCleanUp();
|
||||||
window.removeEventListener('resize', this.updateSplitPaneSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSplitPaneSize = () => {
|
|
||||||
if (this.rafToken.current !== undefined) {
|
|
||||||
window.cancelAnimationFrame(this.rafToken.current!);
|
|
||||||
}
|
|
||||||
(this.rafToken as MutableRefObject<number>).current = window.requestAnimationFrame(() => {
|
|
||||||
this.forceUpdate();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onPanelExit = () => {
|
onPanelExit = () => {
|
||||||
this.props.updateLocation({
|
this.props.updateLocation({
|
||||||
query: { editPanel: null, tab: null },
|
query: { editPanel: null, tab: null },
|
||||||
@ -138,30 +124,6 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
|
|||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
};
|
};
|
||||||
|
|
||||||
onDragFinished = (pane: Pane, size?: number) => {
|
|
||||||
document.body.style.cursor = 'auto';
|
|
||||||
|
|
||||||
// When the drag handle is just clicked size is undefined
|
|
||||||
if (!size) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { updatePanelEditorUIState } = this.props;
|
|
||||||
if (pane === Pane.Top) {
|
|
||||||
updatePanelEditorUIState({
|
|
||||||
topPaneSize: size / window.innerHeight,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
updatePanelEditorUIState({
|
|
||||||
rightPaneSize: size / window.innerWidth,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onDragStarted = () => {
|
|
||||||
document.body.style.cursor = 'row-resize';
|
|
||||||
};
|
|
||||||
|
|
||||||
onDisplayModeChange = (mode: DisplayMode) => {
|
onDisplayModeChange = (mode: DisplayMode) => {
|
||||||
const { updatePanelEditorUIState } = this.props;
|
const { updatePanelEditorUIState } = this.props;
|
||||||
updatePanelEditorUIState({
|
updatePanelEditorUIState({
|
||||||
@ -177,7 +139,7 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
|
|||||||
renderPanel = (styles: EditorStyles) => {
|
renderPanel = (styles: EditorStyles) => {
|
||||||
const { dashboard, panel, tabs, uiState } = this.props;
|
const { dashboard, panel, tabs, uiState } = this.props;
|
||||||
return (
|
return (
|
||||||
<div className={cx(styles.mainPaneWrapper, tabs.length === 0 && styles.mainPaneWrapperNoTabs)}>
|
<div className={cx(styles.mainPaneWrapper, tabs.length === 0 && styles.mainPaneWrapperNoTabs)} key="panel">
|
||||||
{this.renderPanelToolbar(styles)}
|
{this.renderPanelToolbar(styles)}
|
||||||
<div className={styles.panelWrapper}>
|
<div className={styles.panelWrapper}>
|
||||||
<AutoSizer>
|
<AutoSizer>
|
||||||
@ -205,38 +167,22 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
renderHorizontalSplit(styles: EditorStyles) {
|
renderPanelAndEditor(styles: EditorStyles) {
|
||||||
const { dashboard, panel, tabs, uiState } = this.props;
|
const { panel, dashboard, tabs } = this.props;
|
||||||
/*
|
|
||||||
Guesstimate the height of the browser window minus
|
|
||||||
panel toolbar and editor toolbar (~120px). This is to prevent resizing
|
|
||||||
the preview window beyond the browser window.
|
|
||||||
*/
|
|
||||||
const windowHeight = window.innerHeight - 120;
|
|
||||||
const size = uiState.topPaneSize >= 1 ? uiState.topPaneSize : (uiState.topPaneSize as number) * window.innerHeight;
|
|
||||||
|
|
||||||
return tabs.length > 0 ? (
|
if (tabs.length > 0) {
|
||||||
<SplitPane
|
return [
|
||||||
split="horizontal"
|
this.renderPanel(styles),
|
||||||
minSize={200}
|
<div
|
||||||
maxSize={windowHeight}
|
className={styles.tabsWrapper}
|
||||||
primary="first"
|
aria-label={selectors.components.PanelEditor.DataPane.content}
|
||||||
size={size}
|
key="panel-editor-tabs"
|
||||||
/* Use persisted state for default size */
|
>
|
||||||
defaultSize={uiState.topPaneSize}
|
|
||||||
pane2Style={{ minHeight: 0 }}
|
|
||||||
resizerClassName={styles.resizerH}
|
|
||||||
onDragStarted={this.onDragStarted}
|
|
||||||
onDragFinished={size => this.onDragFinished(Pane.Top, size)}
|
|
||||||
>
|
|
||||||
{this.renderPanel(styles)}
|
|
||||||
<div className={styles.tabsWrapper} aria-label={selectors.components.PanelEditor.DataPane.content}>
|
|
||||||
<PanelEditorTabs panel={panel} dashboard={dashboard} tabs={tabs} onChangeTab={this.onChangeTab} />
|
<PanelEditorTabs panel={panel} dashboard={dashboard} tabs={tabs} onChangeTab={this.onChangeTab} />
|
||||||
</div>
|
</div>,
|
||||||
</SplitPane>
|
];
|
||||||
) : (
|
}
|
||||||
this.renderPanel(styles)
|
return this.renderPanel(styles);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTemplateVariables(styles: EditorStyles) {
|
renderTemplateVariables(styles: EditorStyles) {
|
||||||
@ -319,8 +265,13 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderOptionsPane(width: number) {
|
renderOptionsPane() {
|
||||||
const { plugin, dashboard, panel } = this.props;
|
const { plugin, dashboard, panel, uiState } = this.props;
|
||||||
|
|
||||||
|
const rightPaneSize =
|
||||||
|
uiState.rightPaneSize <= 1
|
||||||
|
? (uiState.rightPaneSize as number) * window.innerWidth
|
||||||
|
: (uiState.rightPaneSize as number);
|
||||||
|
|
||||||
if (!plugin) {
|
if (!plugin) {
|
||||||
return <div />;
|
return <div />;
|
||||||
@ -331,7 +282,7 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
|
|||||||
plugin={plugin}
|
plugin={plugin}
|
||||||
dashboard={dashboard}
|
dashboard={dashboard}
|
||||||
panel={panel}
|
panel={panel}
|
||||||
width={width}
|
width={rightPaneSize}
|
||||||
onClose={this.onTogglePanelOptions}
|
onClose={this.onTogglePanelOptions}
|
||||||
onFieldConfigsChange={this.onFieldConfigChange}
|
onFieldConfigsChange={this.onFieldConfigChange}
|
||||||
onPanelOptionsChanged={this.onPanelOptionsChanged}
|
onPanelOptionsChanged={this.onPanelOptionsChanged}
|
||||||
@ -340,39 +291,8 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderWithOptionsPane(styles: EditorStyles) {
|
|
||||||
const { uiState } = this.props;
|
|
||||||
|
|
||||||
// Limit options pane width to 90% of screen.
|
|
||||||
const maxWidth = window.innerWidth * 0.9;
|
|
||||||
|
|
||||||
// Need to handle when width is relative. ie a percentage of the viewport
|
|
||||||
const width =
|
|
||||||
uiState.rightPaneSize <= 1
|
|
||||||
? (uiState.rightPaneSize as number) * window.innerWidth
|
|
||||||
: (uiState.rightPaneSize as number);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SplitPane
|
|
||||||
split="vertical"
|
|
||||||
minSize={300}
|
|
||||||
maxSize={maxWidth}
|
|
||||||
size={width >= 300 ? width : 300}
|
|
||||||
primary="second"
|
|
||||||
/* Use persisted state for default size */
|
|
||||||
defaultSize={uiState.rightPaneSize}
|
|
||||||
resizerClassName={styles.resizerV}
|
|
||||||
onDragStarted={() => (document.body.style.cursor = 'col-resize')}
|
|
||||||
onDragFinished={size => this.onDragFinished(Pane.Right, size)}
|
|
||||||
>
|
|
||||||
{this.renderHorizontalSplit(styles)}
|
|
||||||
{this.renderOptionsPane(width)}
|
|
||||||
</SplitPane>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { initDone, uiState } = this.props;
|
const { initDone, updatePanelEditorUIState, uiState } = this.props;
|
||||||
const styles = getStyles(config.theme, this.props);
|
const styles = getStyles(config.theme, this.props);
|
||||||
|
|
||||||
if (!initDone) {
|
if (!initDone) {
|
||||||
@ -383,7 +303,13 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
|
|||||||
<div className={styles.wrapper} aria-label={selectors.components.PanelEditor.General.content}>
|
<div className={styles.wrapper} aria-label={selectors.components.PanelEditor.General.content}>
|
||||||
{this.editorToolbar(styles)}
|
{this.editorToolbar(styles)}
|
||||||
<div className={styles.verticalSplitPanesWrapper}>
|
<div className={styles.verticalSplitPanesWrapper}>
|
||||||
{uiState.isPanelOptionsVisible ? this.renderWithOptionsPane(styles) : this.renderHorizontalSplit(styles)}
|
<SplitPaneWrapper
|
||||||
|
leftPaneComponents={this.renderPanelAndEditor(styles)}
|
||||||
|
rightPaneComponents={this.renderOptionsPane()}
|
||||||
|
uiState={uiState}
|
||||||
|
updateUiState={updatePanelEditorUIState}
|
||||||
|
rightPaneVisible={uiState.isPanelOptionsVisible}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -416,35 +342,13 @@ const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = {
|
|||||||
|
|
||||||
export const PanelEditor = connect(mapStateToProps, mapDispatchToProps)(PanelEditorUnconnected);
|
export const PanelEditor = connect(mapStateToProps, mapDispatchToProps)(PanelEditorUnconnected);
|
||||||
|
|
||||||
enum Pane {
|
|
||||||
Right,
|
|
||||||
Top,
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Styles
|
* Styles
|
||||||
*/
|
*/
|
||||||
export const getStyles = stylesFactory((theme: GrafanaTheme, props: Props) => {
|
export const getStyles = stylesFactory((theme: GrafanaTheme, props: Props) => {
|
||||||
const { uiState } = props;
|
const { uiState } = props;
|
||||||
const handleColor = theme.palette.blue95;
|
|
||||||
const paneSpacing = theme.spacing.md;
|
const paneSpacing = theme.spacing.md;
|
||||||
|
|
||||||
const resizer = css`
|
|
||||||
font-style: italic;
|
|
||||||
background: transparent;
|
|
||||||
border-top: 0;
|
|
||||||
border-right: 0;
|
|
||||||
border-bottom: 0;
|
|
||||||
border-left: 0;
|
|
||||||
border-color: transparent;
|
|
||||||
border-style: solid;
|
|
||||||
transition: 0.2s border-color ease-in-out;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: ${handleColor};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
wrapper: css`
|
wrapper: css`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -488,27 +392,6 @@ export const getStyles = stylesFactory((theme: GrafanaTheme, props: Props) => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
padding-left: ${paneSpacing};
|
padding-left: ${paneSpacing};
|
||||||
`,
|
`,
|
||||||
resizerV: cx(
|
|
||||||
resizer,
|
|
||||||
css`
|
|
||||||
cursor: col-resize;
|
|
||||||
width: ${paneSpacing};
|
|
||||||
border-right-width: 1px;
|
|
||||||
margin-top: 18px;
|
|
||||||
`
|
|
||||||
),
|
|
||||||
resizerH: cx(
|
|
||||||
resizer,
|
|
||||||
css`
|
|
||||||
height: ${paneSpacing};
|
|
||||||
cursor: row-resize;
|
|
||||||
position: relative;
|
|
||||||
top: 0px;
|
|
||||||
z-index: 1;
|
|
||||||
border-top-width: 1px;
|
|
||||||
margin-left: ${paneSpacing};
|
|
||||||
`
|
|
||||||
),
|
|
||||||
tabsWrapper: css`
|
tabsWrapper: css`
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
updateEditorInitState,
|
updateEditorInitState,
|
||||||
} from './reducers';
|
} from './reducers';
|
||||||
import { cleanUpEditPanel, panelModelAndPluginReady } from '../../../state/reducers';
|
import { cleanUpEditPanel, panelModelAndPluginReady } from '../../../state/reducers';
|
||||||
import store from '../../../../../core/store';
|
import store from 'app/core/store';
|
||||||
|
|
||||||
export function initPanelEditor(sourcePanel: PanelModel, dashboard: DashboardModel): ThunkResult<void> {
|
export function initPanelEditor(sourcePanel: PanelModel, dashboard: DashboardModel): ThunkResult<void> {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
|
@ -17,9 +17,9 @@ export interface PanelEditorUIState {
|
|||||||
/* Visualization options pane visibility */
|
/* Visualization options pane visibility */
|
||||||
isPanelOptionsVisible: boolean;
|
isPanelOptionsVisible: boolean;
|
||||||
/* Pixels or percentage */
|
/* Pixels or percentage */
|
||||||
rightPaneSize: number | string;
|
rightPaneSize: number;
|
||||||
/* Pixels or percentage */
|
/* Pixels or percentage */
|
||||||
topPaneSize: number | string;
|
topPaneSize: number;
|
||||||
/* Visualization size mode */
|
/* Visualization size mode */
|
||||||
mode: DisplayMode;
|
mode: DisplayMode;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user