Graphite: Rollup Indicator (#22738)

* WIP: Rollup indiator progress

* Progress

* Progress, can now open inspector with right tab

* changed type and made inspect

* Showing stats

* Progress

* Progress

* Getting ready for v1

* Added option and fixed some strict nulls

* Updated

* Fixed test
This commit is contained in:
Torkel Ödegaard
2020-03-18 13:00:14 +01:00
committed by GitHub
parent 579abad9cc
commit 044ec40112
21 changed files with 631 additions and 226 deletions

View File

@@ -12,6 +12,7 @@ import { PanelChromeAngular } from './PanelChromeAngular';
// Actions
import { initDashboardPanel } from '../state/actions';
import { updateLocation } from 'app/core/reducers/location';
// Types
import { PanelModel, DashboardModel } from '../state';
@@ -33,6 +34,7 @@ export interface ConnectedProps {
export interface DispatchProps {
initDashboardPanel: typeof initDashboardPanel;
updateLocation: typeof updateLocation;
}
export type Props = OwnProps & ConnectedProps & DispatchProps;
@@ -72,7 +74,7 @@ export class DashboardPanelUnconnected extends PureComponent<Props, State> {
};
renderPanel(plugin: PanelPlugin) {
const { dashboard, panel, isFullscreen, isInView, isInEditMode } = this.props;
const { dashboard, panel, isFullscreen, isInView, isInEditMode, updateLocation } = this.props;
return (
<AutoSizer>
@@ -105,6 +107,7 @@ export class DashboardPanelUnconnected extends PureComponent<Props, State> {
isInEditMode={isInEditMode}
width={width}
height={height}
updateLocation={updateLocation}
/>
);
}}
@@ -170,6 +173,6 @@ const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (
};
};
const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = { initDashboardPanel };
const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = { initDashboardPanel, updateLocation };
export const DashboardPanel = connect(mapStateToProps, mapDispatchToProps)(DashboardPanelUnconnected);

View File

@@ -11,6 +11,7 @@ import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
import { profiler } from 'app/core/profiler';
import { getProcessedDataFrames } from '../state/runRequest';
import config from 'app/core/config';
import { updateLocation } from 'app/core/actions';
// Types
import { DashboardModel, PanelModel } from '../state';
import { PANEL_BORDER } from 'app/core/constants';
@@ -36,6 +37,7 @@ export interface Props {
isInEditMode?: boolean;
width: number;
height: number;
updateLocation: typeof updateLocation;
}
export interface State {
@@ -43,8 +45,6 @@ export interface State {
renderCounter: number;
errorMessage?: string;
refreshWhenInView: boolean;
// Current state of all events
data: PanelData;
}
@@ -312,7 +312,7 @@ export class PanelChrome extends PureComponent<Props, State> {
}
render() {
const { dashboard, panel, isFullscreen, width, height } = this.props;
const { dashboard, panel, isFullscreen, width, height, updateLocation } = this.props;
const { errorMessage, data } = this.state;
const { transparent } = panel;
@@ -328,14 +328,14 @@ export class PanelChrome extends PureComponent<Props, State> {
<PanelHeader
panel={panel}
dashboard={dashboard}
timeInfo={data.request ? data.request.timeInfo : undefined}
title={panel.title}
description={panel.description}
scopedVars={panel.scopedVars}
links={panel.links}
error={errorMessage}
isFullscreen={isFullscreen}
isLoading={data.state === LoadingState.Loading}
data={data}
updateLocation={updateLocation}
/>
<ErrorBoundary>
{({ error }) => {

View File

@@ -17,6 +17,7 @@ import config from 'app/core/config';
import { DashboardModel, PanelModel } from '../state';
import { StoreState } from 'app/types';
import { LoadingState, DefaultTimeRange, PanelData, PanelPlugin, PanelEvents } from '@grafana/data';
import { updateLocation } from 'app/core/actions';
import { PANEL_BORDER } from 'app/core/constants';
interface OwnProps {
@@ -35,6 +36,7 @@ interface ConnectedProps {
interface DispatchProps {
setPanelAngularComponent: typeof setPanelAngularComponent;
updateLocation: typeof updateLocation;
}
export type Props = OwnProps & ConnectedProps & DispatchProps;
@@ -215,7 +217,7 @@ export class PanelChromeAngularUnconnected extends PureComponent<Props, State> {
}
render() {
const { dashboard, panel, isFullscreen, plugin, angularComponent } = this.props;
const { dashboard, panel, isFullscreen, plugin, angularComponent, updateLocation } = this.props;
const { errorMessage, data, alertState } = this.state;
const { transparent } = panel;
@@ -238,7 +240,6 @@ export class PanelChromeAngularUnconnected extends PureComponent<Props, State> {
<PanelHeader
panel={panel}
dashboard={dashboard}
timeInfo={data.request ? data.request.timeInfo : undefined}
title={panel.title}
description={panel.description}
scopedVars={panel.scopedVars}
@@ -246,7 +247,8 @@ export class PanelChromeAngularUnconnected extends PureComponent<Props, State> {
links={panel.links}
error={errorMessage}
isFullscreen={isFullscreen}
isLoading={data.state === LoadingState.Loading}
data={data}
updateLocation={updateLocation}
/>
<div className={panelContentClassNames}>
<div ref={element => (this.element = element)} className="panel-height-helper" />
@@ -262,6 +264,6 @@ const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (
};
};
const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = { setPanelAngularComponent };
const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = { setPanelAngularComponent, updateLocation };
export const PanelChromeAngular = connect(mapStateToProps, mapDispatchToProps)(PanelChromeAngularUnconnected);

View File

@@ -1,9 +1,9 @@
import React, { Component } from 'react';
import classNames from 'classnames';
import { isEqual } from 'lodash';
import { DataLink, ScopedVars, PanelMenuItem } from '@grafana/data';
import { DataLink, ScopedVars, PanelMenuItem, PanelData, LoadingState, QueryResultMetaNotice } from '@grafana/data';
import { AngularComponent } from '@grafana/runtime';
import { ClickOutsideWrapper } from '@grafana/ui';
import { ClickOutsideWrapper, Tooltip } from '@grafana/ui';
import { e2e } from '@grafana/e2e';
import PanelHeaderCorner from './PanelHeaderCorner';
@@ -14,11 +14,11 @@ import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
import { getPanelLinksSupplier } from 'app/features/panel/panellinks/linkSuppliers';
import { getPanelMenu } from 'app/features/dashboard/utils/getPanelMenu';
import { updateLocation } from 'app/core/actions';
export interface Props {
panel: PanelModel;
dashboard: DashboardModel;
timeInfo?: string;
title?: string;
description?: string;
scopedVars?: ScopedVars;
@@ -26,7 +26,8 @@ export interface Props {
links?: DataLink[];
error?: string;
isFullscreen: boolean;
isLoading: boolean;
data: PanelData;
updateLocation: typeof updateLocation;
}
interface ClickCoordinates {
@@ -92,8 +93,35 @@ export class PanelHeader extends Component<Props, State> {
);
}
openInspect = (e: React.SyntheticEvent, tab: string) => {
const { updateLocation, panel } = this.props;
e.stopPropagation();
updateLocation({
query: { inspect: panel.id, tab },
partial: true,
});
};
renderNotice = (notice: QueryResultMetaNotice) => {
return (
<Tooltip content={notice.text} key={notice.severity}>
{notice.inspect ? (
<div className="panel-info-notice" onClick={e => this.openInspect(e, notice.inspect)}>
<span className="fa fa-info-circle" style={{ marginRight: '8px', cursor: 'pointer' }} />
</div>
) : (
<a className="panel-info-notice" href={notice.url} target="_blank">
<span className="fa fa-info-circle" style={{ marginRight: '8px', cursor: 'pointer' }} />
</a>
)}
</Tooltip>
);
};
render() {
const { panel, timeInfo, scopedVars, error, isFullscreen, isLoading } = this.props;
const { panel, scopedVars, error, isFullscreen, data } = this.props;
const { menuItems } = this.state;
const title = templateSrv.replaceWithText(panel.title, scopedVars);
@@ -102,9 +130,20 @@ export class PanelHeader extends Component<Props, State> {
'grid-drag-handle': !isFullscreen,
});
// dedupe on severity
const notices: Record<string, QueryResultMetaNotice> = {};
for (const series of data.series) {
if (series.meta && series.meta.notices) {
for (const notice of series.meta.notices) {
notices[notice.severity] = notice;
}
}
}
return (
<>
{isLoading && this.renderLoadingState()}
{data.state === LoadingState.Loading && this.renderLoadingState()}
<div className={panelHeaderClass}>
<PanelHeaderCorner
panel={panel}
@@ -121,6 +160,7 @@ export class PanelHeader extends Component<Props, State> {
aria-label={e2e.pages.Dashboard.Panels.Panel.selectors.title(title)}
>
<div className="panel-title">
{Object.values(notices).map(this.renderNotice)}
<span className="icon-gf panel-alert-icon" />
<span className="panel-title-text">
{title} <span className="fa fa-caret-down panel-menu-toggle" />
@@ -130,9 +170,9 @@ export class PanelHeader extends Component<Props, State> {
<PanelHeaderMenu items={menuItems} />
</ClickOutsideWrapper>
)}
{timeInfo && (
{data.request && data.request.timeInfo && (
<span className="panel-time-info">
<i className="fa fa-clock-o" /> {timeInfo}
<i className="fa fa-clock-o" /> {data.request.timeInfo}
</span>
)}
</div>