Skip to content

Commit

Permalink
[Vis: Default editor] EUIficate and Reactify the sidebar (#49864)
Browse files Browse the repository at this point in the history
* EUIficate the sidebar

* Create a state reducer and a state context

* Create an editor context and actions

* Improve types

* Apply aggs reordering

* Fix functionality

* Improve types

* Fix sub_agg changes

* Remove legacy dependencies

* Watch dirty state

* Fix dirty state changes

* Update actions and reducers

* Handle keyboard submit

* Apply editor form validation

* Remove fancy forms

* Update validation

* Use embeddable instead of visualize loader

* Add auto apply behavior

* Remove legacy styles

* Remove the sidebar

* Restrict responsive to the bottom_bar

* Upgrade @elastic/eui to v14.10.0

* Replace EuiBottomBar with EuiControlBar

* Get rid of mutations in control vis

* Revert "Upgrade @elastic/eui to v14.10.0"

This reverts commit 2cd86c5.

* Replace bottom bar with a control panel for sidebar

* Replace selectors

* Use editor resizer

* Apply selectors

* Change selectors

* Fix sub agg change values

* Add collapse button

* Fix tests

* Get rid of editor editor_state_context, simplify the code

* Fix jest tests, update snapshots

* Fix types

* Moving collapse button to right of index pattern

* Tweaks bottom buttons

* Moved Vega buttons so they don’t scroll away

* Fix responsiveness

* Resolve UI comments

* Fix console resizer

* Update dev docs

* Bail out of additional render in metrics and axes

* Apply performance optimizations for metrics and axis panel

* Remove unused translations

* Use debounce when autoapply enabled

Co-authored-by: Caroline Horn <[email protected]>
Co-authored-by: Elastic Machine <[email protected]>
3 people authored Jan 17, 2020
1 parent 92b5f78 commit 3e46060
Showing 115 changed files with 2,218 additions and 2,206 deletions.
Original file line number Diff line number Diff line change
@@ -208,8 +208,8 @@ This is the sidebar editor you see in many of the Kibana visualizations. You can

[[development-default-editor]]
==== `default` editor controller
The default editor controller receives an `optionsTemplate` or `optionsTabs` parameter.
These can be either an AngularJS template or React component.
The default editor controller receives an `optionsTemplate` or `optionTabs` parameter.
These tabs should be React components.

["source","js"]
-----------
@@ -220,12 +220,9 @@ These can be either an AngularJS template or React component.
description: 'Cool new chart',
editor: 'default',
editorConfig: {
optionsTemplate: '<my-custom-options-directive></my-custom-options-directive>' // or
optionsTemplate: MyReactComponent // or if multiple tabs are required:
optionsTabs: [
{ title: 'tab 1', template: '<div>....</div> },
{ title: 'tab 2', template: '<my-custom-options-directive></my-custom-options-directive>' },
{ title: 'tab 3', template: MyReactComponent }
optionTabs: [
{ title: 'tab 3', editor: MyReactComponent }
]
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -18,20 +18,28 @@
*/

import React from 'react';
import { EuiIcon } from '@elastic/eui';
import { i18n } from '@kbn/i18n';

type ResizerMouseEvent = React.MouseEvent<HTMLDivElement, MouseEvent>;
export type ResizerMouseEvent = React.MouseEvent<HTMLButtonElement, MouseEvent>;
export type ResizerKeyDownEvent = React.KeyboardEvent<HTMLButtonElement>;

export interface Props {
onKeyDown: (eve: ResizerKeyDownEvent) => void;
onMouseDown: (eve: ResizerMouseEvent) => void;
className?: string;
}

/**
* TODO: This component uses styling constants from public UI - should be removed, next iteration should incl. horizontal and vertical resizers.
*/
export function Resizer(props: Props) {
return (
<div {...props} className="conApp__resizer" data-test-subj="splitPanelResizer">
&#xFE19;
</div>
<button
{...props}
data-test-subj="splitPanelResizer"
aria-label={i18n.translate('console.splitPanel.adjustPanelSizeAriaLabel', {
defaultMessage: 'Press left/right to adjust panels size',
})}
>
<EuiIcon type="grabHorizontal" />
</button>
);
}
Original file line number Diff line number Diff line change
@@ -22,20 +22,26 @@ import { usePanelContext } from '../context';

export interface Props {
children: ReactNode[] | ReactNode;
initialWidth?: string;
className?: string;

/**
* initial width of the panel in percents
*/
initialWidth?: number;
style?: CSSProperties;
}

export function Panel({ children, initialWidth = '100%', style = {} }: Props) {
const [width, setWidth] = useState(initialWidth);
export function Panel({ children, className, initialWidth = 100, style = {} }: Props) {
const [width, setWidth] = useState(`${initialWidth}%`);
const { registry } = usePanelContext();
const divRef = useRef<HTMLDivElement>(null);

useEffect(() => {
registry.registerPanel({
initialWidth,
width: initialWidth,
setWidth(value) {
setWidth(value + '%');
this.width = value;
},
getWidth() {
return divRef.current!.getBoundingClientRect().width;
@@ -44,7 +50,7 @@ export function Panel({ children, initialWidth = '100%', style = {} }: Props) {
}, [initialWidth, registry]);

return (
<div ref={divRef} style={{ ...style, width, display: 'flex' }}>
<div className={className} ref={divRef} style={{ ...style, width, display: 'flex' }}>
{children}
</div>
);
Original file line number Diff line number Diff line change
@@ -17,14 +17,17 @@
* under the License.
*/

import React, { Children, ReactNode, useRef, useState } from 'react';
import React, { Children, ReactNode, useRef, useState, useCallback } from 'react';

import { keyCodes } from '@elastic/eui';
import { PanelContextProvider } from '../context';
import { Resizer } from '../components/resizer';
import { Resizer, ResizerMouseEvent, ResizerKeyDownEvent } from '../components/resizer';
import { PanelRegistry } from '../registry';

export interface Props {
children: ReactNode;
className?: string;
resizerClassName?: string;
onPanelWidthChange?: (arrayOfPanelWidths: number[]) => any;
}

@@ -37,7 +40,12 @@ const initialState: State = { isDragging: false, currentResizerPos: -1 };

const pxToPercent = (proportion: number, whole: number) => (proportion / whole) * 100;

export function PanelsContainer({ children, onPanelWidthChange }: Props) {
export function PanelsContainer({
children,
className,
onPanelWidthChange,
resizerClassName,
}: Props) {
const [firstChild, secondChild] = Children.toArray(children);

const registryRef = useRef(new PanelRegistry());
@@ -48,25 +56,56 @@ export function PanelsContainer({ children, onPanelWidthChange }: Props) {
return containerRef.current!.getBoundingClientRect().width;
};

const handleMouseDown = useCallback(
(event: ResizerMouseEvent) => {
setState({
...state,
isDragging: true,
currentResizerPos: event.clientX,
});
},
[state]
);

const handleKeyDown = useCallback(
(ev: ResizerKeyDownEvent) => {
const { keyCode } = ev;

if (keyCode === keyCodes.LEFT || keyCode === keyCodes.RIGHT) {
ev.preventDefault();

const { current: registry } = registryRef;
const [left, right] = registry.getPanels();

const leftPercent = left.width - (keyCode === keyCodes.LEFT ? 1 : -1);
const rightPercent = right.width - (keyCode === keyCodes.RIGHT ? 1 : -1);

left.setWidth(leftPercent);
right.setWidth(rightPercent);

if (onPanelWidthChange) {
onPanelWidthChange([leftPercent, rightPercent]);
}
}
},
[onPanelWidthChange]
);

const childrenWithResizer = [
firstChild,
<Resizer
key={'resizer'}
onMouseDown={event => {
event.preventDefault();
setState({
...state,
isDragging: true,
currentResizerPos: event.clientX,
});
}}
className={resizerClassName}
onKeyDown={handleKeyDown}
onMouseDown={handleMouseDown}
/>,
secondChild,
];

return (
<PanelContextProvider registry={registryRef.current}>
<div
className={className}
ref={containerRef}
style={{ display: 'flex', height: '100%', width: '100%' }}
onMouseMove={event => {
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@
export interface PanelController {
setWidth: (percent: number) => void;
getWidth: () => number;
initialWidth: string;
width: number;
}

export class PanelRegistry {
@@ -35,6 +35,6 @@ export class PanelRegistry {
}

getPanels() {
return this.panels.map(panel => ({ ...panel }));
return this.panels;
}
}
Original file line number Diff line number Diff line change
@@ -65,8 +65,8 @@ describe('Split panel', () => {

const panelContainer = mount(
<PanelsContainer onPanelWidthChange={onWidthChange}>
<Panel initialWidth={'50%'}>{testComponentA}</Panel>
<Panel initialWidth={'50%'}>{testComponentB}</Panel>
<Panel initialWidth={50}>{testComponentA}</Panel>
<Panel initialWidth={50}>{testComponentB}</Panel>
</PanelsContainer>
);

Original file line number Diff line number Diff line change
@@ -55,10 +55,10 @@ export const Editor = ({ loading }: Props) => {
if (!currentTextObject) return null;

return (
<PanelsContainer onPanelWidthChange={onPanelWidthChange}>
<PanelsContainer onPanelWidthChange={onPanelWidthChange} resizerClassName="conApp__resizer">
<Panel
style={{ height: '100%', position: 'relative', minWidth: PANEL_MIN_WIDTH }}
initialWidth={firstPanelWidth + '%'}
initialWidth={firstPanelWidth}
>
{loading ? (
<EditorContentSpinner />
@@ -68,7 +68,7 @@ export const Editor = ({ loading }: Props) => {
</Panel>
<Panel
style={{ height: '100%', position: 'relative', minWidth: PANEL_MIN_WIDTH }}
initialWidth={secondPanelWidth + '%'}
initialWidth={secondPanelWidth}
>
{loading ? <EditorContentSpinner /> : <EditorOutput />}
</Panel>

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3e46060

Please sign in to comment.