mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Annotations: fire an event when changing annotations (#37175)
This commit is contained in:
parent
3e35021f7e
commit
ffa0ef9b3d
@ -1,4 +1,4 @@
|
||||
import { DataFrame } from '../types';
|
||||
import { AnnotationEvent, DataFrame } from '../types';
|
||||
import { BusEventWithPayload } from './types';
|
||||
|
||||
/**
|
||||
@ -34,3 +34,8 @@ export class DataHoverClearEvent extends BusEventWithPayload<DataHoverPayload> {
|
||||
export class DataSelectEvent extends BusEventWithPayload<DataHoverPayload> {
|
||||
static type = 'data-select';
|
||||
}
|
||||
|
||||
/** @alpha */
|
||||
export class AnnotationChangeEvent extends BusEventWithPayload<Partial<AnnotationEvent>> {
|
||||
static type = 'annotation-event';
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import { DashboardModel, PanelModel } from '../state';
|
||||
import { PANEL_BORDER } from 'app/core/constants';
|
||||
import {
|
||||
AbsoluteTimeRange,
|
||||
AnnotationChangeEvent,
|
||||
AnnotationEventUIModel,
|
||||
DashboardCursorSync,
|
||||
EventFilterOptions,
|
||||
@ -278,7 +279,7 @@ export class PanelChrome extends Component<Props, State> {
|
||||
|
||||
onAnnotationCreate = async (event: AnnotationEventUIModel) => {
|
||||
const isRegion = event.from !== event.to;
|
||||
await saveAnnotation({
|
||||
const anno = {
|
||||
dashboardId: this.props.dashboard.id,
|
||||
panelId: this.props.panel.id,
|
||||
isRegion,
|
||||
@ -286,18 +287,21 @@ export class PanelChrome extends Component<Props, State> {
|
||||
timeEnd: isRegion ? event.to : 0,
|
||||
tags: event.tags,
|
||||
text: event.description,
|
||||
});
|
||||
};
|
||||
await saveAnnotation(anno);
|
||||
getDashboardQueryRunner().run({ dashboard: this.props.dashboard, range: this.timeSrv.timeRange() });
|
||||
this.state.context.eventBus.publish(new AnnotationChangeEvent(anno));
|
||||
};
|
||||
|
||||
onAnnotationDelete = async (id: string) => {
|
||||
await deleteAnnotation({ id });
|
||||
getDashboardQueryRunner().run({ dashboard: this.props.dashboard, range: this.timeSrv.timeRange() });
|
||||
this.state.context.eventBus.publish(new AnnotationChangeEvent({ id }));
|
||||
};
|
||||
|
||||
onAnnotationUpdate = async (event: AnnotationEventUIModel) => {
|
||||
const isRegion = event.from !== event.to;
|
||||
await updateAnnotation({
|
||||
const anno = {
|
||||
id: event.id,
|
||||
dashboardId: this.props.dashboard.id,
|
||||
panelId: this.props.panel.id,
|
||||
@ -306,9 +310,11 @@ export class PanelChrome extends Component<Props, State> {
|
||||
timeEnd: isRegion ? event.to : 0,
|
||||
tags: event.tags,
|
||||
text: event.description,
|
||||
});
|
||||
};
|
||||
await updateAnnotation(anno);
|
||||
|
||||
getDashboardQueryRunner().run({ dashboard: this.props.dashboard, range: this.timeSrv.timeRange() });
|
||||
this.state.context.eventBus.publish(new AnnotationChangeEvent(anno));
|
||||
};
|
||||
|
||||
get hasPanelSnapshot() {
|
||||
|
@ -56,7 +56,10 @@ async function setupTestContext({
|
||||
data: { state: LoadingState.Done, timeRange: getDefaultTimeRange(), series: [] },
|
||||
eventBus: {
|
||||
subscribe: jest.fn(),
|
||||
getStream: jest.fn(),
|
||||
getStream: () =>
|
||||
({
|
||||
subscribe: jest.fn(),
|
||||
} as any),
|
||||
publish: jest.fn(),
|
||||
removeAllListeners: jest.fn(),
|
||||
newScopedBus: jest.fn(),
|
||||
|
@ -2,14 +2,25 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
// Types
|
||||
import { AnnoOptions } from './types';
|
||||
import { AnnotationEvent, AppEvents, dateTime, DurationUnit, locationUtil, PanelProps } from '@grafana/data';
|
||||
import { getBackendSrv, locationService } from '@grafana/runtime';
|
||||
import {
|
||||
AnnotationChangeEvent,
|
||||
AnnotationEvent,
|
||||
AppEvents,
|
||||
dateTime,
|
||||
DurationUnit,
|
||||
GrafanaTheme,
|
||||
locationUtil,
|
||||
PanelProps,
|
||||
} from '@grafana/data';
|
||||
import { config, getBackendSrv, locationService } from '@grafana/runtime';
|
||||
import { AbstractList } from '@grafana/ui/src/components/List/AbstractList';
|
||||
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { AnnotationListItem } from './AnnotationListItem';
|
||||
import { AnnotationListItemTags } from './AnnotationListItemTags';
|
||||
import { CustomScrollbar } from '@grafana/ui';
|
||||
import { CustomScrollbar, stylesFactory } from '@grafana/ui';
|
||||
import { css } from '@emotion/css';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
interface UserInfo {
|
||||
id?: number;
|
||||
@ -25,8 +36,10 @@ interface State {
|
||||
queryUser?: UserInfo;
|
||||
queryTags: string[];
|
||||
}
|
||||
|
||||
export class AnnoListPanel extends PureComponent<Props, State> {
|
||||
style = getStyles(config.theme);
|
||||
subs = new Subscription();
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
@ -40,6 +53,19 @@ export class AnnoListPanel extends PureComponent<Props, State> {
|
||||
|
||||
componentDidMount() {
|
||||
this.doSearch();
|
||||
|
||||
// When an annotation on this dashboard changes, re-run the query
|
||||
this.subs.add(
|
||||
this.props.eventBus.getStream(AnnotationChangeEvent).subscribe({
|
||||
next: () => {
|
||||
this.doSearch();
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.subs.unsubscribe();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props, prevState: State) {
|
||||
@ -48,7 +74,7 @@ export class AnnoListPanel extends PureComponent<Props, State> {
|
||||
options !== prevProps.options ||
|
||||
this.state.queryTags !== prevState.queryTags ||
|
||||
this.state.queryUser !== prevState.queryUser ||
|
||||
timeRange !== prevProps.timeRange;
|
||||
(options.onlyInTimeRange && timeRange !== prevProps.timeRange);
|
||||
|
||||
if (needsQuery) {
|
||||
this.doSearch();
|
||||
@ -228,10 +254,20 @@ export class AnnoListPanel extends PureComponent<Props, State> {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{annotations.length < 1 && <div className="panel-alert-list__no-alerts">No Annotations Found</div>}
|
||||
{annotations.length < 1 && <div className={this.style.noneFound}>No Annotations Found</div>}
|
||||
|
||||
<AbstractList items={annotations} renderItem={this.renderItem} getItemKey={(item) => `${item.id}`} />
|
||||
</CustomScrollbar>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme) => ({
|
||||
noneFound: css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: calc(100% - 30px);
|
||||
`,
|
||||
}));
|
||||
|
@ -99,21 +99,17 @@ const TimeStamp: FC<TimeStampProps> = ({ time, formatDate }) => {
|
||||
function getStyles(theme: GrafanaTheme) {
|
||||
return {
|
||||
pointer: css`
|
||||
label: pointer;
|
||||
cursor: pointer;
|
||||
`,
|
||||
item: css`
|
||||
label: labelItem;
|
||||
margin: ${theme.spacing.xs};
|
||||
padding: ${theme.spacing.sm};
|
||||
${styleMixins.listItem(theme)}// display: flex;
|
||||
`,
|
||||
title: css`
|
||||
label: title;
|
||||
flex-basis: 80%;
|
||||
`,
|
||||
link: css`
|
||||
label: link;
|
||||
display: flex;
|
||||
|
||||
.fa {
|
||||
@ -125,7 +121,6 @@ function getStyles(theme: GrafanaTheme) {
|
||||
}
|
||||
`,
|
||||
login: css`
|
||||
label: login;
|
||||
align-self: center;
|
||||
flex: auto;
|
||||
display: flex;
|
||||
@ -133,13 +128,11 @@ function getStyles(theme: GrafanaTheme) {
|
||||
font-size: ${theme.typography.size.sm};
|
||||
`,
|
||||
time: css`
|
||||
label: time;
|
||||
margin-left: ${theme.spacing.sm};
|
||||
font-size: ${theme.typography.size.sm};
|
||||
color: ${theme.colors.textWeak};
|
||||
`,
|
||||
avatar: css`
|
||||
label: avatar;
|
||||
padding: ${theme.spacing.xs};
|
||||
img {
|
||||
border-radius: 50%;
|
||||
|
@ -27,7 +27,7 @@ export const AnnotationListItemTags: FC<Props> = ({ tags, remove, onClick }) =>
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
{tags.map((tag) => {
|
||||
return (
|
||||
<span key={tag} onClick={(e) => onTagClicked(e, tag)} className={styles.pointer}>
|
||||
@ -35,14 +35,13 @@ export const AnnotationListItemTags: FC<Props> = ({ tags, remove, onClick }) =>
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
function getStyles(theme: GrafanaTheme) {
|
||||
return {
|
||||
pointer: css`
|
||||
label: pointer;
|
||||
cursor: pointer;
|
||||
padding: ${theme.spacing.xxs};
|
||||
`,
|
||||
|
@ -42,7 +42,6 @@
|
||||
@import 'components/tags';
|
||||
@import 'components/panel_graph';
|
||||
@import 'components/submenu';
|
||||
@import 'components/panel_alertlist';
|
||||
@import 'components/panel_dashlist';
|
||||
@import 'components/panel_gettingstarted';
|
||||
@import 'components/panel_piechart';
|
||||
|
@ -1,11 +0,0 @@
|
||||
.panel-alert-list {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.panel-alert-list__no-alerts {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: calc(100% - 30px);
|
||||
}
|
Loading…
Reference in New Issue
Block a user