mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
wip: panel-header: Merge conflicts
This commit is contained in:
parent
f471482569
commit
ca4612af26
@ -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}
|
||||||
/>
|
/>
|
||||||
|
@ -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}
|
||||||
|
@ -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 PureComponent<PanelHeaderProps, any> {
|
||||||
export class PanelHeader extends React.Component<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>
|
||||||
|
@ -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 => {
|
{menu.map((menuItem, idx) => {
|
||||||
console.log(this);
|
|
||||||
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;
|
console.log('PanelHeaderMenu render');
|
||||||
const menu = getPanelMenu(dashboard, this.getPanel());
|
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>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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[] = [],
|
additionalMenuItems: PanelHeaderMenuItemProps[] = [],
|
||||||
extraSubMenuItems: 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
|
additionalSubMenuItems.forEach(item => {
|
||||||
// this.events.emit('init-panel-actions', menu);
|
|
||||||
extraSubMenuItems.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);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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
public/app/plugins/panel/graph2/withMenuOptions.tsx
Normal file
94
public/app/plugins/panel/graph2/withMenuOptions.tsx
Normal file
@ -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} />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user