diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx index 477e800bea2..ab009e4e7ca 100644 --- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx +++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx @@ -87,10 +87,16 @@ export class PanelHeader extends Component { }); }; + onCancelQuery = () => { + this.props.panel.getQueryRunner().cancelQuery(); + }; + private renderLoadingState(): JSX.Element { return ( -
- +
+ + +
); } diff --git a/public/app/features/dashboard/state/PanelQueryRunner.ts b/public/app/features/dashboard/state/PanelQueryRunner.ts index a5536bbee8d..1c6ae39e762 100644 --- a/public/app/features/dashboard/state/PanelQueryRunner.ts +++ b/public/app/features/dashboard/state/PanelQueryRunner.ts @@ -25,6 +25,7 @@ import { applyFieldOverrides, DataConfigSource, TimeZone, + LoadingState, } from '@grafana/data'; export interface QueryRunnerOptions< @@ -198,6 +199,22 @@ export class PanelQueryRunner { }); } + cancelQuery() { + if (!this.subscription) { + return; + } + + this.subscription.unsubscribe(); + + // If we have an old result with loading state, send it with done state + if (this.lastResult && this.lastResult.state === LoadingState.Loading) { + this.subject.next({ + ...this.lastResult, + state: LoadingState.Done, + }); + } + } + resendLastResult = () => { if (this.lastResult) { this.subject.next(this.lastResult); diff --git a/public/sass/components/_panel_header.scss b/public/sass/components/_panel_header.scss index bf6f1d8c94d..4a96298da6b 100644 --- a/public/sass/components/_panel_header.scss +++ b/public/sass/components/_panel_header.scss @@ -78,6 +78,10 @@ $panel-header-no-title-zindex: 1; z-index: $panel-header-z-index + 1; font-size: $font-size-lg; color: $text-color-weak; + + &:hover { + cursor: pointer; + } } .panel-empty { diff --git a/public/sass/mixins/_animations.scss b/public/sass/mixins/_animations.scss index 18d9b6db456..7104303400c 100644 --- a/public/sass/mixins/_animations.scss +++ b/public/sass/mixins/_animations.scss @@ -34,3 +34,16 @@ transition: max-height 250ms ease-in-out; } } + +@keyframes spin-counter-clock { + 0% { + transform: rotate(359deg); + } + 100% { + transform: rotate(0deg); + } +} + +.spin-counter-clock { + animation: spin-counter-clock 3s infinite linear; +}