diff --git a/public/app/core/components/Animations/FadeIn.tsx b/public/app/core/components/Animations/FadeIn.tsx new file mode 100644 index 00000000000..98eb3b682c0 --- /dev/null +++ b/public/app/core/components/Animations/FadeIn.tsx @@ -0,0 +1,37 @@ +import React, { SFC } from 'react'; +import Transition from 'react-transition-group/Transition'; + +interface Props { + duration: number; + children: JSX.Element; + in: boolean; +} + +export const FadeIn: SFC = props => { + const defaultStyle = { + transition: `opacity ${props.duration}ms linear`, + opacity: 0, + }; + + const transitionStyles = { + exited: { opacity: 0, display: 'none' }, + entering: { opacity: 0 }, + entered: { opacity: 1 }, + exiting: { opacity: 0 }, + }; + + return ( + + {state => ( +
+ {props.children} +
+ )} +
+ ); +}; diff --git a/public/app/core/components/Animations/SlideDown.tsx b/public/app/core/components/Animations/SlideDown.tsx index 70dacd73849..6e8995298dc 100644 --- a/public/app/core/components/Animations/SlideDown.tsx +++ b/public/app/core/components/Animations/SlideDown.tsx @@ -23,7 +23,7 @@ export default ({ children, in: inProp, maxHeight = defaultMaxHeight, style = de const transitionStyles = { exited: { maxHeight: 0 }, entering: { maxHeight: maxHeight }, - entered: { maxHeight: maxHeight, overflow: 'visible' }, + entered: { maxHeight: 'unset', overflow: 'visible' }, exiting: { maxHeight: 0 }, }; diff --git a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx index 4f73a50f138..9205814a291 100644 --- a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx +++ b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx @@ -1,15 +1,18 @@ import React from 'react'; import config from 'app/core/config'; -import { PanelModel } from '../panel_model'; -import { DashboardModel } from '../dashboard_model'; + import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader'; -import { DashboardRow } from './DashboardRow'; -import { AddPanelPanel } from './AddPanelPanel'; import { importPluginModule } from 'app/features/plugins/plugin_loader'; -import { PluginExports, PanelPlugin } from 'app/types/plugins'; + +import { AddPanelPanel } from './AddPanelPanel'; +import { DashboardRow } from './DashboardRow'; +import { PanelPlugin } from 'app/types/plugins'; import { PanelChrome } from './PanelChrome'; import { PanelEditor } from './PanelEditor'; +import { PanelModel } from '../panel_model'; +import { DashboardModel } from '../dashboard_model'; + export interface Props { panelType: string; panel: PanelModel; @@ -17,20 +20,19 @@ export interface Props { } export interface State { - pluginExports: PluginExports; + plugin: PanelPlugin; } export class DashboardPanel extends React.Component { element: any; angularPanel: AngularComponent; - pluginInfo: any; specialPanels = {}; constructor(props) { super(props); this.state = { - pluginExports: null, + plugin: null, }; this.specialPanels['row'] = this.renderRow.bind(this); @@ -63,20 +65,22 @@ export class DashboardPanel extends React.Component { return; } - // handle plugin loading & changing of plugin type - if (!this.pluginInfo || this.pluginInfo.id !== this.props.panel.type) { - this.pluginInfo = config.panels[this.props.panel.type]; + const { panel } = this.props; - if (this.pluginInfo.exports) { + // handle plugin loading & changing of plugin type + if (!this.state.plugin || this.state.plugin.id !== panel.type) { + const plugin = config.panels[panel.type]; + + if (plugin.exports) { this.cleanUpAngularPanel(); - this.setState({ pluginExports: this.pluginInfo.exports }); + this.setState({ plugin: plugin }); } else { - importPluginModule(this.pluginInfo.module).then(pluginExports => { + importPluginModule(plugin.module).then(pluginExports => { this.cleanUpAngularPanel(); // cache plugin exports (saves a promise async cycle next time) - this.pluginInfo.exports = pluginExports; + plugin.exports = pluginExports; // update panel state - this.setState({ pluginExports: pluginExports }); + this.setState({ plugin: plugin }); }); } } @@ -112,44 +116,41 @@ export class DashboardPanel extends React.Component { } renderReactPanel() { - const { pluginExports } = this.state; - const containerClass = this.props.panel.isEditing ? 'panel-editor-container' : 'panel-height-helper'; - const panelWrapperClass = this.props.panel.isEditing ? 'panel-editor-container__panel' : 'panel-height-helper'; + const { dashboard, panel } = this.props; + const { plugin } = this.state; + + const containerClass = panel.isEditing ? 'panel-editor-container' : 'panel-height-helper'; + const panelWrapperClass = panel.isEditing ? 'panel-editor-container__panel' : 'panel-height-helper'; // this might look strange with these classes that change when edit, but // I want to try to keep markup (parents) for panel the same in edit mode to avoide unmount / new mount of panel return (
- +
- {this.props.panel.isEditing && ( - + {panel.isEditing && ( + )}
); } render() { + const { panel } = this.props; + const { plugin } = this.state; + if (this.isSpecial()) { - return this.specialPanels[this.props.panel.type](); + return this.specialPanels[panel.type](); } - if (!this.state.pluginExports) { + // if we have not loaded plugin exports yet, wait + if (!plugin || !plugin.exports) { return null; } - if (this.state.pluginExports.PanelComponent) { + // if exporting PanelComponent it must be a react panel + if (plugin.exports.PanelComponent) { return this.renderReactPanel(); } diff --git a/public/app/features/dashboard/dashgrid/PanelEditor.tsx b/public/app/features/dashboard/dashgrid/PanelEditor.tsx index a8df7de1d5c..1e41fd7ee0e 100644 --- a/public/app/features/dashboard/dashgrid/PanelEditor.tsx +++ b/public/app/features/dashboard/dashgrid/PanelEditor.tsx @@ -10,13 +10,12 @@ import { updateLocation } from 'app/core/actions'; import { PanelModel } from '../panel_model'; import { DashboardModel } from '../dashboard_model'; -import { PanelPlugin, PluginExports } from 'app/types/plugins'; +import { PanelPlugin } from 'app/types/plugins'; interface PanelEditorProps { panel: PanelModel; dashboard: DashboardModel; - panelType: string; - pluginExports: PluginExports; + plugin: PanelPlugin; onTypeChanged: (newType: PanelPlugin) => void; } @@ -44,11 +43,11 @@ export class PanelEditor extends PureComponent { } renderPanelOptions() { - const { pluginExports, panel } = this.props; + const { plugin, panel } = this.props; + const { PanelOptionsComponent } = plugin.exports; - if (pluginExports.PanelOptionsComponent) { - const OptionsComponent = pluginExports.PanelOptionsComponent; - return ; + if (PanelOptionsComponent) { + return ; } else { return

Visualization has no options

; } @@ -62,7 +61,7 @@ export class PanelEditor extends PureComponent { renderVizTab() { return (
- + {this.renderPanelOptions()}
); diff --git a/public/app/features/dashboard/dashgrid/VizTypePicker.tsx b/public/app/features/dashboard/dashgrid/VizTypePicker.tsx index 9f8b26b8635..e3bc9cd0a04 100644 --- a/public/app/features/dashboard/dashgrid/VizTypePicker.tsx +++ b/public/app/features/dashboard/dashgrid/VizTypePicker.tsx @@ -1,18 +1,19 @@ import React, { PureComponent } from 'react'; import classNames from 'classnames'; - -import config from 'app/core/config'; -import { PanelPlugin } from 'app/types/plugins'; -import CustomScrollbar from 'app/core/components/CustomScrollbar/CustomScrollbar'; import _ from 'lodash'; +import { FadeIn } from 'app/core/components/Animations/FadeIn'; +import config from 'app/core/config'; +import { PanelPlugin } from 'app/types/plugins'; + interface Props { - currentType: string; + current: PanelPlugin; onTypeChanged: (newType: PanelPlugin) => void; } interface State { pluginList: PanelPlugin[]; + isOpen: boolean; } export class VizTypePicker extends PureComponent { @@ -21,6 +22,7 @@ export class VizTypePicker extends PureComponent { this.state = { pluginList: this.getPanelPlugins(''), + isOpen: false, }; } @@ -37,7 +39,7 @@ export class VizTypePicker extends PureComponent { renderVizPlugin = (plugin, index) => { const cssClass = classNames({ 'viz-picker__item': true, - 'viz-picker__item--selected': plugin.id === this.props.currentType, + 'viz-picker__item--selected': plugin.id === this.props.current.id, }); return ( @@ -55,7 +57,7 @@ export class VizTypePicker extends PureComponent { -
+
@@ -63,24 +65,52 @@ export class VizTypePicker extends PureComponent { ); } + onToggleOpen = () => { + this.setState({ isOpen: !this.state.isOpen }); + }; + render() { - const { currentType } = this.props; - const { pluginList } = this.state; + const { current } = this.props; + const { pluginList, isOpen } = this.state; return (
- - -
- {this.renderFilters()} +
+
+ + +
+
+
+
+ +
+
- -
{pluginList.map(this.renderVizPlugin)}
-
+ +
+ + +
+
Select visualization
+ {this.renderFilters()} +
+
+ +
{pluginList.map(this.renderVizPlugin)}
+
+
); } diff --git a/public/sass/components/_gf-form.scss b/public/sass/components/_gf-form.scss index 0de386f3f68..8ec697326be 100644 --- a/public/sass/components/_gf-form.scss +++ b/public/sass/components/_gf-form.scss @@ -410,7 +410,27 @@ select.gf-form-input ~ .gf-form-help-icon { } .cta-form__close { + background: transparent; + padding: 4px 8px 4px 9px; + border: none; position: absolute; right: 0; - top: 0; + top: -2px; + font-size: $font-size-lg; + + &:hover { + color: $text-color-strong; + } +} + +.cta-form__bar { + display: flex; + align-items: center; + align-content: center; + margin-bottom: 20px; +} + +.cta-form__bar-header { + font-size: $font-size-h4; + padding-right: 20px; } diff --git a/public/sass/components/_viz_editor.scss b/public/sass/components/_viz_editor.scss index 8eac117d2a4..e109c8840e0 100644 --- a/public/sass/components/_viz_editor.scss +++ b/public/sass/components/_viz_editor.scss @@ -59,6 +59,7 @@ .viz-picker__items { display: flex; + flex-wrap: wrap; // for scrollbar margin-bottom: 13px; } @@ -68,14 +69,15 @@ box-shadow: $card-shadow; border-radius: 3px; - height: 70px; - width: 130px; + height: 90px; + width: 150px; flex-shrink: 0; flex-direction: column; text-align: center; cursor: pointer; display: flex; - margin-right: 6px; + margin-right: 10px; + margin-bottom: 10px; border: 1px solid transparent; align-items: center; @@ -98,11 +100,11 @@ display: flex; flex-direction: column; align-self: center; - height: 20px; + height: 23px; } .viz-picker__item-img { - height: 40px; + height: 55px; } .panel-editor__aside { @@ -162,7 +164,6 @@ } .viz-picker__bar { - display: flex; margin-bottom: $spacer; }