diff --git a/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.test.tsx b/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.test.tsx new file mode 100644 index 00000000000..91da066e4cc --- /dev/null +++ b/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.test.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { AddPanelWidget, Props } from './AddPanelWidget'; +import { DashboardModel, PanelModel } from '../../state'; + +const setup = (propOverrides?: object) => { + const props: Props = { + dashboard: {} as DashboardModel, + panel: {} as PanelModel, + }; + + Object.assign(props, propOverrides); + + return shallow(); +}; + +describe('Render', () => { + it('should render component', () => { + const wrapper = setup(); + + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.tsx b/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.tsx index 8c1ab93cec1..135b04a8ac5 100644 --- a/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.tsx +++ b/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.tsx @@ -1,12 +1,20 @@ +// Libraries import React from 'react'; import _ from 'lodash'; + +// Utils import config from 'app/core/config'; -import { PanelModel } from '../../state/PanelModel'; -import { DashboardModel } from '../../state/DashboardModel'; import store from 'app/core/store'; -import { LS_PANEL_COPY_KEY } from 'app/core/constants'; -import { updateLocation } from 'app/core/actions'; + +// Store import { store as reduxStore } from 'app/store/store'; +import { updateLocation } from 'app/core/actions'; + +// Types +import { PanelModel } from '../../state'; +import { DashboardModel } from '../../state'; +import { LS_PANEL_COPY_KEY } from 'app/core/constants'; +import { LocationUpdate } from 'app/types'; export interface Props { panel: PanelModel; @@ -46,6 +54,7 @@ export class AddPanelWidget extends React.Component { copiedPanels.push(pluginCopy); } } + return _.sortBy(copiedPanels, 'sort'); } @@ -54,28 +63,7 @@ export class AddPanelWidget extends React.Component { this.props.dashboard.removePanel(this.props.dashboard.panels[0]); } - copyButton(panel) { - return ( - - ); - } - - moveToEdit(panel) { - reduxStore.dispatch( - updateLocation({ - query: { - panelId: panel.id, - edit: true, - fullscreen: true, - }, - partial: true, - }) - ); - } - - onCreateNewPanel = () => { + onCreateNewPanel = (tab = 'queries') => { const dashboard = this.props.dashboard; const { gridPos } = this.props.panel; @@ -88,7 +76,21 @@ export class AddPanelWidget extends React.Component { dashboard.addPanel(newPanel); dashboard.removePanel(this.props.panel); - this.moveToEdit(newPanel); + const location: LocationUpdate = { + query: { + panelId: newPanel.id, + edit: true, + fullscreen: true, + }, + partial: true, + }; + + if (tab === 'visualization') { + location.query.tab = 'visualization'; + location.query.openVizPicker = true; + } + + reduxStore.dispatch(updateLocation(location)); }; onPasteCopiedPanel = panelPluginInfo => { @@ -125,30 +127,50 @@ export class AddPanelWidget extends React.Component { dashboard.removePanel(this.props.panel); }; - render() { - let addCopyButton; + renderOptionLink = (icon, text, onClick) => { + return ( + + ); + }; - if (this.state.copiedPanelPlugins.length === 1) { - addCopyButton = this.copyButton(this.state.copiedPanelPlugins[0]); - } + render() { + const { copiedPanelPlugins } = this.state; return (
+ New Panel
- - {addCopyButton} - +
+ {this.renderOptionLink('queries', 'Add Query', this.onCreateNewPanel)} + {this.renderOptionLink('visualization', 'Choose Visualization', () => + this.onCreateNewPanel('visualization') + )} +
+
+ + {copiedPanelPlugins.length === 1 && ( + + )} +
diff --git a/public/app/features/dashboard/components/AddPanelWidget/_AddPanelWidget.scss b/public/app/features/dashboard/components/AddPanelWidget/_AddPanelWidget.scss index 5a1cbee4b44..288b2e7a410 100644 --- a/public/app/features/dashboard/components/AddPanelWidget/_AddPanelWidget.scss +++ b/public/app/features/dashboard/components/AddPanelWidget/_AddPanelWidget.scss @@ -14,6 +14,9 @@ align-items: center; width: 100%; cursor: move; + background: $page-header-bg; + box-shadow: $page-header-shadow; + border-bottom: 1px solid $page-header-border-color; .gicon { font-size: 30px; @@ -26,6 +29,29 @@ } } +.add-panel-widget__title { + font-size: $font-size-md; + font-weight: $font-weight-semi-bold; + margin-right: $spacer*2; +} + +.add-panel-widget__link { + margin: 0 8px; + width: 154px; +} + +.add-panel-widget__icon { + margin-bottom: 8px; + + .gicon { + color: white; + height: 44px; + width: 53px; + position: relative; + left: 5px; + } +} + .add-panel-widget__close { margin-left: auto; background-color: transparent; @@ -34,14 +60,25 @@ margin-right: -10px; } +.add-panel-widget__create { + display: inherit; + margin-bottom: 24px; + // this is to have the big button appear centered + margin-top: 55px; +} + +.add-panel-widget__actions { + display: inherit; +} + +.add-panel-widget__action { + margin: 0 4px; +} + .add-panel-widget__btn-container { + height: 100%; display: flex; justify-content: center; align-items: center; - height: 100%; flex-direction: column; - - .btn { - margin-bottom: 10px; - } } diff --git a/public/app/features/dashboard/components/AddPanelWidget/__snapshots__/AddPanelWidget.test.tsx.snap b/public/app/features/dashboard/components/AddPanelWidget/__snapshots__/AddPanelWidget.test.tsx.snap new file mode 100644 index 00000000000..00faf48d8df --- /dev/null +++ b/public/app/features/dashboard/components/AddPanelWidget/__snapshots__/AddPanelWidget.test.tsx.snap @@ -0,0 +1,86 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Render should render component 1`] = ` +
+
+
+ + + New Panel + + +
+
+ +
+ +
+
+
+
+`; diff --git a/public/app/features/dashboard/panel_editor/PanelEditor.tsx b/public/app/features/dashboard/panel_editor/PanelEditor.tsx index d7aafb89e55..bfdc13bc8f2 100644 --- a/public/app/features/dashboard/panel_editor/PanelEditor.tsx +++ b/public/app/features/dashboard/panel_editor/PanelEditor.tsx @@ -2,7 +2,7 @@ import React, { PureComponent } from 'react'; import classNames from 'classnames'; import { QueriesTab } from './QueriesTab'; -import { VisualizationTab } from './VisualizationTab'; +import VisualizationTab from './VisualizationTab'; import { GeneralTab } from './GeneralTab'; import { AlertTab } from '../../alerting/AlertTab'; @@ -38,7 +38,7 @@ export class PanelEditor extends PureComponent { onChangeTab = (tab: PanelEditorTab) => { store.dispatch( updateLocation({ - query: { tab: tab.id }, + query: { tab: tab.id, openVizPicker: null }, partial: true, }) ); diff --git a/public/app/features/dashboard/panel_editor/VisualizationTab.tsx b/public/app/features/dashboard/panel_editor/VisualizationTab.tsx index 35b9b71112a..94a403c11bf 100644 --- a/public/app/features/dashboard/panel_editor/VisualizationTab.tsx +++ b/public/app/features/dashboard/panel_editor/VisualizationTab.tsx @@ -3,6 +3,9 @@ import React, { PureComponent } from 'react'; // Utils & Services import { AngularComponent, getAngularLoader } from 'app/core/services/AngularLoader'; +import { connectWithStore } from 'app/core/utils/connectWithReduxStore'; +import { StoreState } from 'app/types'; +import { updateLocation } from 'app/core/actions'; // Components import { EditorTabBody, EditorToolbarView } from './EditorTabBody'; @@ -21,6 +24,8 @@ interface Props { plugin: PanelPlugin; angularPanel?: AngularComponent; onTypeChanged: (newType: PanelPlugin) => void; + updateLocation: typeof updateLocation; + urlOpenVizPicker: boolean; } interface State { @@ -38,7 +43,7 @@ export class VisualizationTab extends PureComponent { super(props); this.state = { - isVizPickerOpen: false, + isVizPickerOpen: this.props.urlOpenVizPicker, searchQuery: '', scrollTop: 0, }; @@ -149,6 +154,10 @@ export class VisualizationTab extends PureComponent { }; onCloseVizPicker = () => { + if (this.props.urlOpenVizPicker) { + this.props.updateLocation({ query: { openVizPicker: null }, partial: true }); + } + this.setState({ isVizPickerOpen: false }); }; @@ -236,3 +245,13 @@ export class VisualizationTab extends PureComponent { ); } } + +const mapStateToProps = (state: StoreState) => ({ + urlOpenVizPicker: !!state.location.query.openVizPicker +}); + +const mapDispatchToProps = { + updateLocation +}; + +export default connectWithStore(VisualizationTab, mapStateToProps, mapDispatchToProps); diff --git a/public/img/icons_dark_theme/icon_advanced.svg b/public/img/icons_dark_theme/icon_advanced.svg index 5fd18a86dd5..dea3ddff685 100644 --- a/public/img/icons_dark_theme/icon_advanced.svg +++ b/public/img/icons_dark_theme/icon_advanced.svg @@ -4,7 +4,7 @@ diff --git a/public/img/icons_dark_theme/icon_advanced_active.svg b/public/img/icons_dark_theme/icon_advanced_active.svg index 80672a2595b..1227ddc868c 100644 --- a/public/img/icons_dark_theme/icon_advanced_active.svg +++ b/public/img/icons_dark_theme/icon_advanced_active.svg @@ -5,7 +5,7 @@ width="121px" height="100px" viewBox="0 0 121 100" style="enable-background:new 0 0 121 100;" xml:space="preserve">