AnnotationList: Fix link for annotation with no panel or dashboard (#87048)

* Handle case for no associated panel or dashboard

* Convert to CSS object

* Add tests and extend type to cover null use case
This commit is contained in:
Tobias Skarhed 2024-05-02 10:30:19 +02:00 committed by GitHub
parent 6ddb8aeae3
commit a59e7e14b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 42 additions and 13 deletions

View File

@ -5474,8 +5474,7 @@ exports[`better eslint`] = {
[0, 0, 0, "Styles should be written using objects.", "6"]
],
"public/app/plugins/panel/annolist/AnnoListPanel.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Styles should be written using objects.", "1"]
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/plugins/panel/barchart/BarChartPanel.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],

View File

@ -26,7 +26,8 @@ export interface AnnotationEvent {
id?: string;
annotation?: any;
dashboardId?: number;
dashboardUID?: string;
/** May be null if it isn't set via the HTTP API */
dashboardUID?: string | null;
panelId?: number;
userId?: number;
login?: string;

View File

@ -59,6 +59,7 @@ async function setupTestContext({
const dashSrv = { getCurrent: () => dash } as DashboardSrv;
setDashboardSrv(dashSrv);
const pushSpy = jest.spyOn(locationService, 'push');
const partialSpy = jest.spyOn(locationService, 'partial');
const props: Props = {
data: { state: LoadingState.Done, timeRange: getDefaultTimeRange(), series: [] },
@ -89,7 +90,7 @@ async function setupTestContext({
const { rerender } = render(<AnnoListPanel {...props} />);
await waitFor(() => expect(getMock).toHaveBeenCalledTimes(1));
return { props, rerender, getMock, pushSpy };
return { props, rerender, getMock, pushSpy, partialSpy };
}
describe('AnnoListPanel', () => {
@ -220,6 +221,34 @@ describe('AnnoListPanel', () => {
expect(pushSpy).toHaveBeenCalledTimes(1);
expect(pushSpy).toHaveBeenCalledWith('/d/asdkjhajksd/some-dash?from=1609458600000&to=1609459800000');
});
it('should default to the current dashboard, if no dashboard is associated with the annotation', async () => {
const { getMock, partialSpy } = await setupTestContext({
results: [{ ...defaultResult, dashboardUID: null, panelId: 0 }],
});
getMock.mockClear();
expect(screen.getByRole('button', { name: /result text/i })).toBeInTheDocument();
await userEvent.click(screen.getByRole('button', { name: /result text/i }));
expect(getMock).not.toHaveBeenCalled();
expect(partialSpy).toHaveBeenCalledTimes(1);
expect(partialSpy).toHaveBeenCalledWith({ from: 1609458600000, to: 1609459800000, viewPanel: undefined });
});
it('should default to the current dashboard, if no dashboard is associated with the annotation and navigate to viewPanel', async () => {
const { getMock, partialSpy } = await setupTestContext({
results: [{ ...defaultResult, dashboardUID: null }],
});
getMock.mockClear();
expect(screen.getByRole('button', { name: /result text/i })).toBeInTheDocument();
await userEvent.click(screen.getByRole('button', { name: /result text/i }));
expect(getMock).not.toHaveBeenCalled();
expect(partialSpy).toHaveBeenCalledTimes(1);
expect(partialSpy).toHaveBeenCalledWith({ from: 1609458600000, to: 1609459800000, viewPanel: 13 });
});
});
describe('and the user clicks on a tag', () => {

View File

@ -146,10 +146,10 @@ export class AnnoListPanel extends PureComponent<Props, State> {
const params = {
from: this._timeOffset(anno.time, options.navigateBefore, true),
to: this._timeOffset(anno.timeEnd ?? anno.time, options.navigateAfter, false),
viewPanel: options.navigateToPanel ? anno.panelId : undefined,
viewPanel: options.navigateToPanel && anno.panelId ? anno.panelId : undefined,
};
if (current?.uid === anno.dashboardUID) {
if (!anno.dashboardUID || current?.uid === anno.dashboardUID) {
locationService.partial(params);
return;
}
@ -296,13 +296,13 @@ export class AnnoListPanel extends PureComponent<Props, State> {
}
const getStyles = stylesFactory((theme: GrafanaTheme2) => ({
noneFound: css`
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: calc(100% - 30px);
`,
noneFound: css({
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
height: 'calc(100% - 30px)',
}),
filter: css({
alignItems: 'center',
display: 'flex',