mirror of
https://github.com/grafana/grafana.git
synced 2024-12-28 18:01:40 -06:00
PanelHeader: show streaming indicator (and allow unsubscribe) (#28682)
This commit is contained in:
parent
f39a8d630b
commit
7308028a90
@ -13,7 +13,7 @@ export interface PopoverContentProps {
|
||||
|
||||
export type PopoverContent = string | React.ReactElement<any> | ((props: PopoverContentProps) => JSX.Element);
|
||||
|
||||
export const Tooltip: FC<TooltipProps> = ({ children, theme, ...controllerProps }: TooltipProps) => {
|
||||
export const Tooltip: FC<TooltipProps> = React.memo(({ children, theme, ...controllerProps }: TooltipProps) => {
|
||||
const tooltipTriggerRef = createRef<PopperJS.ReferenceObject>();
|
||||
const popperBackgroundClassName = 'popper__background' + (theme ? ' popper__background--' + theme : '');
|
||||
|
||||
@ -52,4 +52,4 @@ export const Tooltip: FC<TooltipProps> = ({ children, theme, ...controllerProps
|
||||
}}
|
||||
</PopoverController>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React, { Component } from 'react';
|
||||
import React, { PureComponent } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { isEqual } from 'lodash';
|
||||
import { DataLink, LoadingState, PanelData, PanelMenuItem, QueryResultMetaNotice, ScopedVars } from '@grafana/data';
|
||||
import { AngularComponent, getTemplateSrv } from '@grafana/runtime';
|
||||
import { ClickOutsideWrapper, Icon, IconName, Tooltip } from '@grafana/ui';
|
||||
import { AngularComponent, config, getTemplateSrv } from '@grafana/runtime';
|
||||
import { ClickOutsideWrapper, Icon, IconName, Tooltip, stylesFactory } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import PanelHeaderCorner from './PanelHeaderCorner';
|
||||
@ -14,6 +14,7 @@ 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';
|
||||
import { css } from 'emotion';
|
||||
|
||||
export interface Props {
|
||||
panel: PanelModel;
|
||||
@ -41,7 +42,7 @@ interface State {
|
||||
menuItems: PanelMenuItem[];
|
||||
}
|
||||
|
||||
export class PanelHeader extends Component<Props, State> {
|
||||
export class PanelHeader extends PureComponent<Props, State> {
|
||||
clickCoordinates: ClickCoordinates = { x: 0, y: 0 };
|
||||
|
||||
state: State = {
|
||||
@ -90,14 +91,28 @@ export class PanelHeader extends Component<Props, State> {
|
||||
this.props.panel.getQueryRunner().cancelQuery();
|
||||
};
|
||||
|
||||
private renderLoadingState(): JSX.Element {
|
||||
return (
|
||||
<div className="panel-loading" onClick={this.onCancelQuery}>
|
||||
<Tooltip content="Cancel query">
|
||||
<Icon className="panel-loading__spinner spin-clockwise" name="sync" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
renderLoadingState(state: LoadingState): JSX.Element | null {
|
||||
if (state === LoadingState.Loading) {
|
||||
return (
|
||||
<div className="panel-loading" onClick={this.onCancelQuery}>
|
||||
<Tooltip content="Cancel query">
|
||||
<Icon className="panel-loading__spinner spin-clockwise" name="sync" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (state === LoadingState.Streaming) {
|
||||
const styles = getStyles();
|
||||
|
||||
return (
|
||||
<div className="panel-loading" onClick={this.onCancelQuery}>
|
||||
<div title="Streaming (click to stop)" className={styles.streamIndicator} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
openInspect = (e: React.SyntheticEvent, tab: string) => {
|
||||
@ -156,7 +171,7 @@ export class PanelHeader extends Component<Props, State> {
|
||||
|
||||
return (
|
||||
<>
|
||||
{data.state === LoadingState.Loading && this.renderLoadingState()}
|
||||
{this.renderLoadingState(data.state)}
|
||||
<div className={panelHeaderClass}>
|
||||
<PanelHeaderCorner
|
||||
panel={panel}
|
||||
@ -201,3 +216,21 @@ export class PanelHeader extends Component<Props, State> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Styles
|
||||
*/
|
||||
export const getStyles = stylesFactory(() => {
|
||||
return {
|
||||
streamIndicator: css`
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: ${config.theme.colors.textFaint};
|
||||
box-shadow: 0 0 2px ${config.theme.colors.textFaint};
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
top: 6px;
|
||||
right: 1px;
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ exports[`Render should render component 1`] = `
|
||||
>
|
||||
External group sync
|
||||
</h3>
|
||||
<Component
|
||||
<Memo()
|
||||
content="Sync LDAP or OAuth groups with your Grafana teams."
|
||||
placement="auto"
|
||||
>
|
||||
@ -18,7 +18,7 @@ exports[`Render should render component 1`] = `
|
||||
className="icon--has-hover page-sub-heading-icon"
|
||||
name="question-circle"
|
||||
/>
|
||||
</Component>
|
||||
</Memo()>
|
||||
<div
|
||||
className="page-action-bar__spacer"
|
||||
/>
|
||||
@ -92,7 +92,7 @@ exports[`Render should render groups table 1`] = `
|
||||
>
|
||||
External group sync
|
||||
</h3>
|
||||
<Component
|
||||
<Memo()
|
||||
content="Sync LDAP or OAuth groups with your Grafana teams."
|
||||
placement="auto"
|
||||
>
|
||||
@ -100,7 +100,7 @@ exports[`Render should render groups table 1`] = `
|
||||
className="icon--has-hover page-sub-heading-icon"
|
||||
name="question-circle"
|
||||
/>
|
||||
</Component>
|
||||
</Memo()>
|
||||
<div
|
||||
className="page-action-bar__spacer"
|
||||
/>
|
||||
|
@ -98,6 +98,7 @@ export function runSignalStream(
|
||||
subscriber.next({
|
||||
data: [data],
|
||||
key: streamId,
|
||||
state: LoadingState.Streaming,
|
||||
});
|
||||
|
||||
timeoutId = setTimeout(pushNextEvent, speed);
|
||||
|
Loading…
Reference in New Issue
Block a user