Browse Source

wip: panel-header: Merge conflicts

Johannes Schill 7 years ago
parent
commit
ca4612af26

+ 2 - 1
public/app/features/dashboard/dashgrid/DashboardPanel.tsx

@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import React, { PureComponent } from 'react';
 import config from 'app/core/config';
 import config from 'app/core/config';
 import { PanelModel } from '../panel_model';
 import { PanelModel } from '../panel_model';
 import { DashboardModel } from '../dashboard_model';
 import { DashboardModel } from '../dashboard_model';
@@ -123,6 +123,7 @@ export class DashboardPanel extends PureComponent<Props, State> {
         <div className={panelWrapperClass}>
         <div className={panelWrapperClass}>
           <PanelChrome
           <PanelChrome
             component={pluginExports.PanelComponent}
             component={pluginExports.PanelComponent}
+            withMenuOptions={pluginExports.withMenuOptions}
             panel={this.props.panel}
             panel={this.props.panel}
             dashboard={this.props.dashboard}
             dashboard={this.props.dashboard}
           />
           />

+ 6 - 6
public/app/features/dashboard/dashgrid/PanelChrome.tsx

@@ -13,19 +13,20 @@ import { PanelModel } from '../panel_model';
 import { DashboardModel } from '../dashboard_model';
 import { DashboardModel } from '../dashboard_model';
 import { TimeRange, PanelProps } from 'app/types';
 import { TimeRange, PanelProps } from 'app/types';
 
 
-export interface Props {
+export interface PanelChromeProps {
   panel: PanelModel;
   panel: PanelModel;
   dashboard: DashboardModel;
   dashboard: DashboardModel;
   component: ComponentClass<PanelProps>;
   component: ComponentClass<PanelProps>;
+  withMenuOptions: any;
 }
 }
 
 
-export interface State {
+export interface PanelChromeState {
   refreshCounter: number;
   refreshCounter: number;
   renderCounter: number;
   renderCounter: number;
   timeRange?: TimeRange;
   timeRange?: TimeRange;
 }
 }
 
 
-export class PanelChrome extends PureComponent<Props, State> {
+export class PanelChrome extends PureComponent<PanelChromeProps, PanelChromeState> {
   constructor(props) {
   constructor(props) {
     super(props);
     super(props);
 
 
@@ -67,16 +68,15 @@ export class PanelChrome extends PureComponent<Props, State> {
   }
   }
 
 
   render() {
   render() {
-    const { panel, dashboard } = this.props;
+    const { panel, dashboard, withMenuOptions } = this.props;
     const { datasource, targets } = panel;
     const { datasource, targets } = panel;
     const { timeRange, renderCounter, refreshCounter } = this.state;
     const { timeRange, renderCounter, refreshCounter } = this.state;
     const PanelComponent = this.props.component;
     const PanelComponent = this.props.component;
-
     console.log('Panel chrome render');
     console.log('Panel chrome render');
 
 
     return (
     return (
       <div className="panel-container">
       <div className="panel-container">
-        <PanelHeader panel={panel} dashboard={dashboard} />
+        <PanelHeader panel={panel} dashboard={dashboard} withMenuOptions={withMenuOptions} />
         <div className="panel-content">
         <div className="panel-content">
           <DataPanel
           <DataPanel
             datasource={datasource}
             datasource={datasource}

+ 6 - 8
public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx

@@ -1,23 +1,21 @@
-import React from 'react';
+import React, { PureComponent } from 'react';
 import classNames from 'classnames';
 import classNames from 'classnames';
 import { PanelModel } from 'app/features/dashboard/panel_model';
 import { PanelModel } from 'app/features/dashboard/panel_model';
 import { DashboardModel } from 'app/features/dashboard/dashboard_model';
 import { DashboardModel } from 'app/features/dashboard/dashboard_model';
-// import { store } from 'app/store/configureStore';
-// import { updateLocation } from 'app/core/actions';
 import { PanelHeaderMenu } from './PanelHeaderMenu';
 import { PanelHeaderMenu } from './PanelHeaderMenu';
-// import appEvents from 'app/core/app_events';
 
 
 interface PanelHeaderProps {
 interface PanelHeaderProps {
   panel: PanelModel;
   panel: PanelModel;
   dashboard: DashboardModel;
   dashboard: DashboardModel;
+  withMenuOptions: any;
 }
 }
-
-export class PanelHeader extends React.Component<PanelHeaderProps, any> {
+export class PanelHeader extends PureComponent<PanelHeaderProps, any> {
   render() {
   render() {
-    const { dashboard } = this.props;
+    const { dashboard, withMenuOptions, panel } = this.props;
     const isFullscreen = false;
     const isFullscreen = false;
     const isLoading = false;
     const isLoading = false;
     const panelHeaderClass = classNames({ 'panel-header': true, 'grid-drag-handle': !isFullscreen });
     const panelHeaderClass = classNames({ 'panel-header': true, 'grid-drag-handle': !isFullscreen });
+    const PanelHeaderMenuComponent = withMenuOptions ? withMenuOptions(PanelHeaderMenu, panel) : PanelHeaderMenu;
 
 
     return (
     return (
       <div className={panelHeaderClass}>
       <div className={panelHeaderClass}>
@@ -39,7 +37,7 @@ export class PanelHeader extends React.Component<PanelHeaderProps, any> {
               {this.props.panel.title} <span className="fa fa-caret-down panel-menu-toggle" />
               {this.props.panel.title} <span className="fa fa-caret-down panel-menu-toggle" />
             </span>
             </span>
 
 
-            <PanelHeaderMenu panelId={this.props.panel.id} dashboard={dashboard} />
+            <PanelHeaderMenuComponent panelId={panel.id} dashboard={dashboard} />
             <span className="panel-time-info">
             <span className="panel-time-info">
               <i className="fa fa-clock-o" /> 4m
               <i className="fa fa-clock-o" /> 4m
             </span>
             </span>

+ 8 - 4
public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenu.tsx

@@ -6,6 +6,9 @@ import { getPanelMenu } from 'app/features/dashboard/utils/panel_menu';
 export interface PanelHeaderMenuProps {
 export interface PanelHeaderMenuProps {
   panelId: number;
   panelId: number;
   dashboard: DashboardModel;
   dashboard: DashboardModel;
+  datasource: any;
+  additionalMenuItems?: PanelHeaderMenuItemProps[];
+  additionalSubMenuItems?: PanelHeaderMenuItemProps[];
 }
 }
 
 
 export class PanelHeaderMenu extends PureComponent<PanelHeaderMenuProps, any> {
 export class PanelHeaderMenu extends PureComponent<PanelHeaderMenuProps, any> {
@@ -19,10 +22,10 @@ export class PanelHeaderMenu extends PureComponent<PanelHeaderMenuProps, any> {
   renderItems = (menu: PanelHeaderMenuItemProps[], isSubMenu = false) => {
   renderItems = (menu: PanelHeaderMenuItemProps[], isSubMenu = false) => {
     return (
     return (
       <ul className="dropdown-menu dropdown-menu--menu panel-menu" role={isSubMenu ? '' : 'menu'}>
       <ul className="dropdown-menu dropdown-menu--menu panel-menu" role={isSubMenu ? '' : 'menu'}>
-        {menu.map(menuItem => {
-          console.log(this);
+        {menu.map((menuItem, idx) => {
           return (
           return (
             <PanelHeaderMenuItem
             <PanelHeaderMenuItem
+              key={idx} // TODO: Fix proper key
               type={menuItem.type}
               type={menuItem.type}
               text={menuItem.text}
               text={menuItem.text}
               iconClassName={menuItem.iconClassName}
               iconClassName={menuItem.iconClassName}
@@ -38,8 +41,9 @@ export class PanelHeaderMenu extends PureComponent<PanelHeaderMenuProps, any> {
   };
   };
 
 
   render() {
   render() {
-    const { dashboard } = this.props;
-    const menu = getPanelMenu(dashboard, this.getPanel());
+    console.log('PanelHeaderMenu render');
+    const { dashboard, additionalMenuItems, additionalSubMenuItems } = this.props;
+    const menu = getPanelMenu(dashboard, this.getPanel(), additionalMenuItems, additionalSubMenuItems);
     return <div className="panel-menu-container dropdown">{this.renderItems(menu)}</div>;
     return <div className="panel-menu-container dropdown">{this.renderItems(menu)}</div>;
   }
   }
 }
 }

+ 4 - 6
public/app/features/dashboard/utils/panel_menu.ts

@@ -8,8 +8,8 @@ import { removePanel, duplicatePanel, copyPanel, editPanelJson, sharePanel } fro
 export const getPanelMenu = (
 export const getPanelMenu = (
   dashboard: DashboardModel,
   dashboard: DashboardModel,
   panel: PanelModel,
   panel: PanelModel,
-  extraMenuItems: PanelHeaderMenuItemProps[] = [],
-  extraSubMenuItems: PanelHeaderMenuItemProps[] = []
+  additionalMenuItems: PanelHeaderMenuItemProps[] = [],
+  additionalSubMenuItems: PanelHeaderMenuItemProps[] = []
 ) => {
 ) => {
   const onViewPanel = () => {
   const onViewPanel = () => {
     store.dispatch(
     store.dispatch(
@@ -80,9 +80,7 @@ export const getPanelMenu = (
       handleClick: onEditPanelJson,
       handleClick: onEditPanelJson,
     });
     });
 
 
-    // TODO: Handle this somehow
-    // this.events.emit('init-panel-actions', menu);
-    extraSubMenuItems.forEach(item => {
+    additionalSubMenuItems.forEach(item => {
       menu.push(item);
       menu.push(item);
     });
     });
     return menu;
     return menu;
@@ -117,7 +115,7 @@ export const getPanelMenu = (
     shortcut: 'p s',
     shortcut: 'p s',
   });
   });
 
 
-  extraMenuItems.forEach(item => {
+  additionalMenuItems.forEach(item => {
     menu.push(item);
     menu.push(item);
   });
   });
 
 

+ 1 - 0
public/app/plugins/panel/graph2/module.tsx

@@ -73,3 +73,4 @@ export class GraphOptions extends PureComponent<PanelOptionsProps<Options>> {
 }
 }
 
 
 export { Graph2 as PanelComponent, GraphOptions as PanelOptionsComponent };
 export { Graph2 as PanelComponent, GraphOptions as PanelOptionsComponent };
+export { withMenuOptions } from './withMenuOptions';

+ 94 - 0
public/app/plugins/panel/graph2/withMenuOptions.tsx

@@ -0,0 +1,94 @@
+// Libraries
+import React, { PureComponent } from 'react';
+
+// Services
+import { getTimeSrv } from 'app/features/dashboard/time_srv';
+import { contextSrv } from 'app/core/services/context_srv';
+import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
+import { store } from 'app/store/configureStore';
+
+// Components
+import { PanelHeaderMenu } from 'app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenu';
+import config from 'app/core/config';
+import { getExploreUrl } from 'app/core/utils/explore';
+import { updateLocation } from 'app/core/actions';
+
+// Types
+import { PanelModel } from 'app/features/dashboard/panel_model';
+import { PanelHeaderMenuProps } from 'app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenu';
+import {
+  PanelHeaderMenuItemProps,
+  PanelHeaderMenuItemTypes,
+} from 'app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuItem';
+
+interface LocalState {
+  datasource: any;
+}
+
+export const withMenuOptions = (WrappedPanelHeaderMenu: typeof PanelHeaderMenu, panel: PanelModel) => {
+  return class extends PureComponent<PanelHeaderMenuProps, LocalState> {
+    private datasourceSrv = getDatasourceSrv();
+    private timeSrv = getTimeSrv();
+
+    constructor(props) {
+      super(props);
+      this.state = {
+        datasource: undefined,
+      };
+    }
+
+    componentDidMount() {
+      const dsPromise = getDatasourceSrv().get(panel.datasource);
+      dsPromise.then((datasource: any) => {
+        this.setState(() => ({ datasource }));
+      });
+    }
+
+    onExploreClick = async () => {
+      const { datasource } = this.state;
+      const url = await getExploreUrl(panel, panel.targets, datasource, this.datasourceSrv, this.timeSrv);
+      if (url) {
+        store.dispatch(updateLocation({ path: url }));
+      }
+    };
+
+    getAdditionalMenuItems = () => {
+      const { datasource } = this.state;
+      const items = [];
+      if (
+        config.exploreEnabled &&
+        contextSrv.isEditor &&
+        datasource &&
+        (datasource.meta.explore || datasource.meta.id === 'mixed')
+      ) {
+        items.push({
+          type: PanelHeaderMenuItemTypes.Link,
+          text: 'Explore',
+          handleClick: this.onExploreClick,
+          iconClassName: 'fa fa-fw fa-rocket',
+          shortcut: 'x',
+        });
+      }
+      return items;
+    };
+
+    getAdditionalSubMenuItems = () => {
+      return [
+        {
+          type: PanelHeaderMenuItemTypes.Link,
+          text: 'Hello Sub Menu',
+          handleClick: () => {
+            alert('Hello world from HOC!');
+          },
+          shortcut: 's h w',
+        },
+      ] as PanelHeaderMenuItemProps[];
+    };
+
+    render() {
+      const menu: PanelHeaderMenuItemProps[] = this.getAdditionalMenuItems();
+      const subMenu: PanelHeaderMenuItemProps[] = this.getAdditionalSubMenuItems();
+      return <WrappedPanelHeaderMenu {...this.props} additionalMenuItems={menu} additionalSubMenuItems={subMenu} />;
+    }
+  };
+};

+ 1 - 0
public/app/types/plugins.ts

@@ -13,6 +13,7 @@ export interface PluginExports {
   PanelCtrl?;
   PanelCtrl?;
   PanelComponent?: ComponentClass<PanelProps>;
   PanelComponent?: ComponentClass<PanelProps>;
   PanelOptionsComponent: ComponentClass<PanelOptionsProps>;
   PanelOptionsComponent: ComponentClass<PanelOptionsProps>;
+  withMenuOptions?: any;
 }
 }
 
 
 export interface PanelPlugin {
 export interface PanelPlugin {