mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Annotations: Migrate dashboardId to dashboardUID (#52588)
* Annotations: replaced dashboardId with dashboardUID when fetching annotations * Annotations: Replaced dashboardID with dashboardUID when adding and updating annotations * Annotations: Used dashboardUID for PanelChrome related methods * Annotations: Used dashboarduid in annolistpanel * Annotations: Used dashboardUID in graph plugin * used boolean in canEditDashboard
This commit is contained in:
parent
046a2602ff
commit
1fc9f6f1c6
@ -33,6 +33,7 @@ export interface AnnotationEvent {
|
|||||||
id?: string;
|
id?: string;
|
||||||
annotation?: any;
|
annotation?: any;
|
||||||
dashboardId?: number;
|
dashboardId?: number;
|
||||||
|
dashboardUID?: string;
|
||||||
panelId?: number;
|
panelId?: number;
|
||||||
userId?: number;
|
userId?: number;
|
||||||
login?: string;
|
login?: string;
|
||||||
|
@ -32,8 +32,8 @@ export interface PanelContext {
|
|||||||
onToggleSeriesVisibility?: (label: string, mode: SeriesVisibilityChangeMode) => void;
|
onToggleSeriesVisibility?: (label: string, mode: SeriesVisibilityChangeMode) => void;
|
||||||
|
|
||||||
canAddAnnotations?: () => boolean;
|
canAddAnnotations?: () => boolean;
|
||||||
canEditAnnotations?: (dashboardId: number) => boolean;
|
canEditAnnotations?: (dashboardUID?: string) => boolean;
|
||||||
canDeleteAnnotations?: (dashboardId: number) => boolean;
|
canDeleteAnnotations?: (dashboardUID?: string) => boolean;
|
||||||
onAnnotationCreate?: (annotation: AnnotationEventUIModel) => void;
|
onAnnotationCreate?: (annotation: AnnotationEventUIModel) => void;
|
||||||
onAnnotationUpdate?: (annotation: AnnotationEventUIModel) => void;
|
onAnnotationUpdate?: (annotation: AnnotationEventUIModel) => void;
|
||||||
onAnnotationDelete?: (id: string) => void;
|
onAnnotationDelete?: (id: string) => void;
|
||||||
|
@ -125,6 +125,7 @@ const alertEventAndAnnotationFields: AnnotationFieldInfo[] = [
|
|||||||
{ key: 'panelId' },
|
{ key: 'panelId' },
|
||||||
{ key: 'alertId' },
|
{ key: 'alertId' },
|
||||||
{ key: 'dashboardId' },
|
{ key: 'dashboardId' },
|
||||||
|
{ key: 'dashboardUID' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export function getAnnotationsFromData(
|
export function getAnnotationsFromData(
|
||||||
|
@ -47,6 +47,9 @@ function setupTestContext(options: Partial<Props>) {
|
|||||||
panelInitialized: jest.fn(),
|
panelInitialized: jest.fn(),
|
||||||
getTimezone: () => 'browser',
|
getTimezone: () => 'browser',
|
||||||
events: new EventBusSrv(),
|
events: new EventBusSrv(),
|
||||||
|
canAddAnnotations: jest.fn(),
|
||||||
|
canEditAnnotations: jest.fn(),
|
||||||
|
canDeleteAnnotations: jest.fn(),
|
||||||
meta: {
|
meta: {
|
||||||
isPublic: false,
|
isPublic: false,
|
||||||
},
|
},
|
||||||
|
@ -29,7 +29,6 @@ import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
|
|||||||
import { changeSeriesColorConfigFactory } from 'app/plugins/panel/timeseries/overrides/colorSeriesConfigFactory';
|
import { changeSeriesColorConfigFactory } from 'app/plugins/panel/timeseries/overrides/colorSeriesConfigFactory';
|
||||||
import { RenderEvent } from 'app/types/events';
|
import { RenderEvent } from 'app/types/events';
|
||||||
|
|
||||||
import { contextSrv } from '../../../core/services/context_srv';
|
|
||||||
import { isSoloRoute } from '../../../routes/utils';
|
import { isSoloRoute } from '../../../routes/utils';
|
||||||
import { deleteAnnotation, saveAnnotation, updateAnnotation } from '../../annotations/api';
|
import { deleteAnnotation, saveAnnotation, updateAnnotation } from '../../annotations/api';
|
||||||
import { getDashboardQueryRunner } from '../../query/state/DashboardQueryRunner/DashboardQueryRunner';
|
import { getDashboardQueryRunner } from '../../query/state/DashboardQueryRunner/DashboardQueryRunner';
|
||||||
@ -89,53 +88,16 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
onAnnotationCreate: this.onAnnotationCreate,
|
onAnnotationCreate: this.onAnnotationCreate,
|
||||||
onAnnotationUpdate: this.onAnnotationUpdate,
|
onAnnotationUpdate: this.onAnnotationUpdate,
|
||||||
onAnnotationDelete: this.onAnnotationDelete,
|
onAnnotationDelete: this.onAnnotationDelete,
|
||||||
canAddAnnotations: this.canAddAnnotation,
|
|
||||||
onInstanceStateChange: this.onInstanceStateChange,
|
onInstanceStateChange: this.onInstanceStateChange,
|
||||||
onToggleLegendSort: this.onToggleLegendSort,
|
onToggleLegendSort: this.onToggleLegendSort,
|
||||||
canEditAnnotations: this.canEditAnnotation,
|
canAddAnnotations: props.dashboard.canAddAnnotations.bind(props.dashboard),
|
||||||
canDeleteAnnotations: this.canDeleteAnnotation,
|
canEditAnnotations: props.dashboard.canEditAnnotations.bind(props.dashboard),
|
||||||
|
canDeleteAnnotations: props.dashboard.canDeleteAnnotations.bind(props.dashboard),
|
||||||
},
|
},
|
||||||
data: this.getInitialPanelDataState(),
|
data: this.getInitialPanelDataState(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
canEditDashboard = () => Boolean(this.props.dashboard.meta.canEdit || this.props.dashboard.meta.canMakeEditable);
|
|
||||||
|
|
||||||
canAddAnnotation = () => {
|
|
||||||
let canAdd = true;
|
|
||||||
|
|
||||||
if (contextSrv.accessControlEnabled()) {
|
|
||||||
canAdd = !!this.props.dashboard.meta.annotationsPermissions?.dashboard.canAdd;
|
|
||||||
}
|
|
||||||
return canAdd && this.canEditDashboard();
|
|
||||||
};
|
|
||||||
|
|
||||||
canEditAnnotation = (dashboardId: number) => {
|
|
||||||
let canEdit = true;
|
|
||||||
|
|
||||||
if (contextSrv.accessControlEnabled()) {
|
|
||||||
if (dashboardId !== 0) {
|
|
||||||
canEdit = !!this.props.dashboard.meta.annotationsPermissions?.dashboard.canEdit;
|
|
||||||
} else {
|
|
||||||
canEdit = !!this.props.dashboard.meta.annotationsPermissions?.organization.canEdit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return canEdit && this.canEditDashboard();
|
|
||||||
};
|
|
||||||
|
|
||||||
canDeleteAnnotation = (dashboardId: number) => {
|
|
||||||
let canDelete = true;
|
|
||||||
|
|
||||||
if (contextSrv.accessControlEnabled()) {
|
|
||||||
if (dashboardId !== 0) {
|
|
||||||
canDelete = !!this.props.dashboard.meta.annotationsPermissions?.dashboard.canDelete;
|
|
||||||
} else {
|
|
||||||
canDelete = !!this.props.dashboard.meta.annotationsPermissions?.organization.canDelete;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return canDelete && this.canEditDashboard();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Due to a mutable panel model we get the sync settings via function that proactively reads from the model
|
// Due to a mutable panel model we get the sync settings via function that proactively reads from the model
|
||||||
getSync = () => (this.props.isEditing ? DashboardCursorSync.Off : this.props.dashboard.graphTooltip);
|
getSync = () => (this.props.isEditing ? DashboardCursorSync.Off : this.props.dashboard.graphTooltip);
|
||||||
|
|
||||||
@ -400,7 +362,7 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
onAnnotationCreate = async (event: AnnotationEventUIModel) => {
|
onAnnotationCreate = async (event: AnnotationEventUIModel) => {
|
||||||
const isRegion = event.from !== event.to;
|
const isRegion = event.from !== event.to;
|
||||||
const anno = {
|
const anno = {
|
||||||
dashboardId: this.props.dashboard.id,
|
dashboardUID: this.props.dashboard.uid,
|
||||||
panelId: this.props.panel.id,
|
panelId: this.props.panel.id,
|
||||||
isRegion,
|
isRegion,
|
||||||
time: event.from,
|
time: event.from,
|
||||||
@ -423,7 +385,7 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
const isRegion = event.from !== event.to;
|
const isRegion = event.from !== event.to;
|
||||||
const anno = {
|
const anno = {
|
||||||
id: event.id,
|
id: event.id,
|
||||||
dashboardId: this.props.dashboard.id,
|
dashboardUID: this.props.dashboard.uid,
|
||||||
panelId: this.props.panel.id,
|
panelId: this.props.panel.id,
|
||||||
isRegion,
|
isRegion,
|
||||||
time: event.from,
|
time: event.from,
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { keys as _keys } from 'lodash';
|
import { keys as _keys } from 'lodash';
|
||||||
|
|
||||||
|
import { contextSrv } from 'app/core/services/context_srv';
|
||||||
|
|
||||||
import { getDashboardModel } from '../../../../test/helpers/getDashboardModel';
|
import { getDashboardModel } from '../../../../test/helpers/getDashboardModel';
|
||||||
import { variableAdapters } from '../../variables/adapters';
|
import { variableAdapters } from '../../variables/adapters';
|
||||||
import { createAdHocVariableAdapter } from '../../variables/adhoc/adapter';
|
import { createAdHocVariableAdapter } from '../../variables/adhoc/adapter';
|
||||||
@ -9,7 +11,9 @@ import { setTimeSrv, TimeSrv } from '../services/TimeSrv';
|
|||||||
import { DashboardModel } from '../state/DashboardModel';
|
import { DashboardModel } from '../state/DashboardModel';
|
||||||
import { PanelModel } from '../state/PanelModel';
|
import { PanelModel } from '../state/PanelModel';
|
||||||
|
|
||||||
jest.mock('app/core/services/context_srv', () => ({}));
|
jest.mock('app/core/services/context_srv');
|
||||||
|
|
||||||
|
const mockContextSrv = jest.mocked(contextSrv, true);
|
||||||
|
|
||||||
variableAdapters.setInit(() => [
|
variableAdapters.setInit(() => [
|
||||||
createQueryVariableAdapter(),
|
createQueryVariableAdapter(),
|
||||||
@ -860,20 +864,160 @@ describe('DashboardModel', () => {
|
|||||||
|
|
||||||
describe('canAddAnnotations', () => {
|
describe('canAddAnnotations', () => {
|
||||||
it.each`
|
it.each`
|
||||||
canEdit | canMakeEditable | expected
|
canEdit | canMakeEditable | canAdd | expected
|
||||||
${false} | ${false} | ${false}
|
${false} | ${true} | ${true} | ${true}
|
||||||
${false} | ${true} | ${true}
|
${true} | ${false} | ${true} | ${true}
|
||||||
${true} | ${false} | ${true}
|
${true} | ${true} | ${true} | ${true}
|
||||||
${true} | ${true} | ${true}
|
${false} | ${false} | ${true} | ${false}
|
||||||
|
${false} | ${true} | ${false} | ${false}
|
||||||
|
${true} | ${false} | ${false} | ${false}
|
||||||
|
${true} | ${true} | ${false} | ${false}
|
||||||
|
${false} | ${false} | ${false} | ${false}
|
||||||
`(
|
`(
|
||||||
'when called with canEdit:{$canEdit}, canMakeEditable:{$canMakeEditable} and expected:{$expected}',
|
'when called with canEdit:{$canEdit}, canMakeEditable:{$canMakeEditable}, canAdd:{$canAdd} and expected:{$expected}',
|
||||||
({ canEdit, canMakeEditable, expected }) => {
|
({ canEdit, canMakeEditable, canAdd, expected }) => {
|
||||||
const dashboard = new DashboardModel({});
|
const dashboard = new DashboardModel(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
annotationsPermissions: {
|
||||||
|
dashboard: { canAdd, canEdit: true, canDelete: true },
|
||||||
|
organization: { canAdd: false, canEdit: false, canDelete: false },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
dashboard.meta.canEdit = canEdit;
|
dashboard.meta.canEdit = canEdit;
|
||||||
dashboard.meta.canMakeEditable = canMakeEditable;
|
dashboard.meta.canMakeEditable = canMakeEditable;
|
||||||
|
mockContextSrv.accessControlEnabled.mockReturnValue(true);
|
||||||
|
const result = dashboard.canAddAnnotations();
|
||||||
|
expect(result).toBe(expected);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const result = dashboard.canEditDashboard();
|
describe('canEditAnnotations', () => {
|
||||||
|
it.each`
|
||||||
|
canEdit | canMakeEditable | canEditWithOrgPermission | expected
|
||||||
|
${false} | ${true} | ${true} | ${true}
|
||||||
|
${true} | ${false} | ${true} | ${true}
|
||||||
|
${true} | ${true} | ${true} | ${true}
|
||||||
|
${false} | ${false} | ${true} | ${false}
|
||||||
|
${false} | ${true} | ${false} | ${false}
|
||||||
|
${true} | ${false} | ${false} | ${false}
|
||||||
|
${true} | ${true} | ${false} | ${false}
|
||||||
|
${false} | ${false} | ${false} | ${false}
|
||||||
|
`(
|
||||||
|
'when called with canEdit:{$canEdit}, canMakeEditable:{$canMakeEditable}, canEditWithOrgPermission:{$canEditWithOrgPermission} and expected:{$expected}',
|
||||||
|
({ canEdit, canMakeEditable, canEditWithOrgPermission, expected }) => {
|
||||||
|
const dashboard = new DashboardModel(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
annotationsPermissions: {
|
||||||
|
dashboard: { canAdd: false, canEdit: false, canDelete: true },
|
||||||
|
organization: { canAdd: false, canEdit: canEditWithOrgPermission, canDelete: false },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
dashboard.meta.canEdit = canEdit;
|
||||||
|
dashboard.meta.canMakeEditable = canMakeEditable;
|
||||||
|
mockContextSrv.accessControlEnabled.mockReturnValue(true);
|
||||||
|
const result = dashboard.canEditAnnotations();
|
||||||
|
expect(result).toBe(expected);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each`
|
||||||
|
canEdit | canMakeEditable | canEditWithDashboardPermission | expected
|
||||||
|
${false} | ${true} | ${true} | ${true}
|
||||||
|
${true} | ${false} | ${true} | ${true}
|
||||||
|
${true} | ${true} | ${true} | ${true}
|
||||||
|
${false} | ${false} | ${true} | ${false}
|
||||||
|
${false} | ${true} | ${false} | ${false}
|
||||||
|
${true} | ${false} | ${false} | ${false}
|
||||||
|
${true} | ${true} | ${false} | ${false}
|
||||||
|
${false} | ${false} | ${false} | ${false}
|
||||||
|
`(
|
||||||
|
'when called with canEdit:{$canEdit}, canMakeEditable:{$canMakeEditable}, canEditWithDashboardPermission:{$canEditWithDashboardPermission} and expected:{$expected}',
|
||||||
|
({ canEdit, canMakeEditable, canEditWithDashboardPermission, expected }) => {
|
||||||
|
const dashboard = new DashboardModel(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
annotationsPermissions: {
|
||||||
|
dashboard: { canAdd: false, canEdit: canEditWithDashboardPermission, canDelete: true },
|
||||||
|
organization: { canAdd: false, canEdit: false, canDelete: false },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
dashboard.meta.canEdit = canEdit;
|
||||||
|
dashboard.meta.canMakeEditable = canMakeEditable;
|
||||||
|
mockContextSrv.accessControlEnabled.mockReturnValue(true);
|
||||||
|
const result = dashboard.canEditAnnotations('testDashboardUID');
|
||||||
|
expect(result).toBe(expected);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('canDeleteAnnotations', () => {
|
||||||
|
it.each`
|
||||||
|
canEdit | canMakeEditable | canDeleteWithOrgPermission | expected
|
||||||
|
${false} | ${true} | ${true} | ${true}
|
||||||
|
${true} | ${false} | ${true} | ${true}
|
||||||
|
${true} | ${true} | ${true} | ${true}
|
||||||
|
${false} | ${false} | ${true} | ${false}
|
||||||
|
${false} | ${true} | ${false} | ${false}
|
||||||
|
${true} | ${false} | ${false} | ${false}
|
||||||
|
${true} | ${true} | ${false} | ${false}
|
||||||
|
${false} | ${false} | ${false} | ${false}
|
||||||
|
`(
|
||||||
|
'when called with canEdit:{$canEdit}, canMakeEditable:{$canMakeEditable}, canDeleteWithOrgPermission:{$canDeleteWithOrgPermission} and expected:{$expected}',
|
||||||
|
({ canEdit, canMakeEditable, canDeleteWithOrgPermission, expected }) => {
|
||||||
|
const dashboard = new DashboardModel(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
annotationsPermissions: {
|
||||||
|
dashboard: { canAdd: false, canEdit: false, canDelete: false },
|
||||||
|
organization: { canAdd: false, canEdit: false, canDelete: canDeleteWithOrgPermission },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
dashboard.meta.canEdit = canEdit;
|
||||||
|
dashboard.meta.canMakeEditable = canMakeEditable;
|
||||||
|
mockContextSrv.accessControlEnabled.mockReturnValue(true);
|
||||||
|
const result = dashboard.canDeleteAnnotations();
|
||||||
|
expect(result).toBe(expected);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each`
|
||||||
|
canEdit | canMakeEditable | canDeleteWithDashboardPermission | expected
|
||||||
|
${false} | ${true} | ${true} | ${true}
|
||||||
|
${true} | ${false} | ${true} | ${true}
|
||||||
|
${true} | ${true} | ${true} | ${true}
|
||||||
|
${false} | ${false} | ${true} | ${false}
|
||||||
|
${false} | ${true} | ${false} | ${false}
|
||||||
|
${true} | ${false} | ${false} | ${false}
|
||||||
|
${true} | ${true} | ${false} | ${false}
|
||||||
|
${false} | ${false} | ${false} | ${false}
|
||||||
|
`(
|
||||||
|
'when called with canEdit:{$canEdit}, canMakeEditable:{$canMakeEditable}, canDeleteWithDashboardPermission:{$canDeleteWithDashboardPermission} and expected:{$expected}',
|
||||||
|
({ canEdit, canMakeEditable, canDeleteWithDashboardPermission, expected }) => {
|
||||||
|
const dashboard = new DashboardModel(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
annotationsPermissions: {
|
||||||
|
dashboard: { canAdd: false, canEdit: false, canDelete: canDeleteWithDashboardPermission },
|
||||||
|
organization: { canAdd: false, canEdit: false, canDelete: false },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
dashboard.meta.canEdit = canEdit;
|
||||||
|
dashboard.meta.canMakeEditable = canMakeEditable;
|
||||||
|
mockContextSrv.accessControlEnabled.mockReturnValue(true);
|
||||||
|
const result = dashboard.canDeleteAnnotations('testDashboardUID');
|
||||||
expect(result).toBe(expected);
|
expect(result).toBe(expected);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1073,12 +1073,13 @@ export class DashboardModel implements TimeModel {
|
|||||||
return this.getVariablesFromState(this.uid);
|
return this.getVariablesFromState(this.uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
canEditAnnotations(dashboardId: number) {
|
canEditAnnotations(dashboardUID?: string) {
|
||||||
let canEdit = true;
|
let canEdit = true;
|
||||||
|
|
||||||
// if RBAC is enabled there are additional conditions to check
|
// if RBAC is enabled there are additional conditions to check
|
||||||
if (contextSrv.accessControlEnabled()) {
|
if (contextSrv.accessControlEnabled()) {
|
||||||
if (dashboardId === 0) {
|
// dashboardUID is falsy when it is an organizational annotation
|
||||||
|
if (!dashboardUID) {
|
||||||
canEdit = !!this.meta.annotationsPermissions?.organization.canEdit;
|
canEdit = !!this.meta.annotationsPermissions?.organization.canEdit;
|
||||||
} else {
|
} else {
|
||||||
canEdit = !!this.meta.annotationsPermissions?.dashboard.canEdit;
|
canEdit = !!this.meta.annotationsPermissions?.dashboard.canEdit;
|
||||||
@ -1087,14 +1088,29 @@ export class DashboardModel implements TimeModel {
|
|||||||
return this.canEditDashboard() && canEdit;
|
return this.canEditDashboard() && canEdit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canDeleteAnnotations(dashboardUID?: string) {
|
||||||
|
let canDelete = true;
|
||||||
|
|
||||||
|
if (contextSrv.accessControlEnabled()) {
|
||||||
|
// dashboardUID is falsy when it is an organizational annotation
|
||||||
|
if (!dashboardUID) {
|
||||||
|
canDelete = !!this.meta.annotationsPermissions?.organization.canDelete;
|
||||||
|
} else {
|
||||||
|
canDelete = !!this.meta.annotationsPermissions?.dashboard.canDelete;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return canDelete && this.canEditDashboard();
|
||||||
|
}
|
||||||
|
|
||||||
canAddAnnotations() {
|
canAddAnnotations() {
|
||||||
// If RBAC is enabled there are additional conditions to check
|
// If RBAC is enabled there are additional conditions to check.
|
||||||
const canAdd = !contextSrv.accessControlEnabled() || this.meta.annotationsPermissions?.dashboard.canAdd;
|
const canAdd = !contextSrv.accessControlEnabled() || Boolean(this.meta.annotationsPermissions?.dashboard.canAdd);
|
||||||
|
|
||||||
return this.canEditDashboard() && canAdd;
|
return this.canEditDashboard() && canAdd;
|
||||||
}
|
}
|
||||||
|
|
||||||
canEditDashboard() {
|
canEditDashboard() {
|
||||||
return this.meta.canEdit || this.meta.canMakeEditable;
|
return Boolean(this.meta.canEdit || this.meta.canMakeEditable);
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldUpdateDashboardPanelFromJSON(updatedPanel: PanelModel, panel: PanelModel) {
|
shouldUpdateDashboardPanelFromJSON(updatedPanel: PanelModel, panel: PanelModel) {
|
||||||
|
@ -64,7 +64,7 @@ describe('grafana data source', () => {
|
|||||||
type: GrafanaAnnotationType.Dashboard,
|
type: GrafanaAnnotationType.Dashboard,
|
||||||
tags: ['tag1'],
|
tags: ['tag1'],
|
||||||
},
|
},
|
||||||
{ id: 1 }
|
{ uid: 'DSNdW0gVk' }
|
||||||
);
|
);
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -78,7 +78,7 @@ describe('grafana data source', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function setupAnnotationQueryOptions(annotation: Partial<GrafanaAnnotationQuery>, dashboard?: { id: number }) {
|
function setupAnnotationQueryOptions(annotation: Partial<GrafanaAnnotationQuery>, dashboard?: { uid: string }) {
|
||||||
return {
|
return {
|
||||||
annotation: {
|
annotation: {
|
||||||
target: annotation,
|
target: annotation,
|
||||||
|
@ -170,11 +170,11 @@ export class GrafanaDatasource extends DataSourceWithBackend<GrafanaQuery> {
|
|||||||
|
|
||||||
if (target.type === GrafanaAnnotationType.Dashboard) {
|
if (target.type === GrafanaAnnotationType.Dashboard) {
|
||||||
// if no dashboard id yet return
|
// if no dashboard id yet return
|
||||||
if (!options.dashboard.id) {
|
if (!options.dashboard.uid) {
|
||||||
return Promise.resolve({ data: [] });
|
return Promise.resolve({ data: [] });
|
||||||
}
|
}
|
||||||
// filter by dashboard id
|
// filter by dashboard id
|
||||||
params.dashboardId = options.dashboard.id;
|
params.dashboardUID = options.dashboard.uid;
|
||||||
// remove tags filter if any
|
// remove tags filter if any
|
||||||
delete params.tags;
|
delete params.tags;
|
||||||
} else {
|
} else {
|
||||||
@ -202,7 +202,7 @@ export class GrafanaDatasource extends DataSourceWithBackend<GrafanaQuery> {
|
|||||||
const annotations = await getBackendSrv().get(
|
const annotations = await getBackendSrv().get(
|
||||||
'/api/annotations',
|
'/api/annotations',
|
||||||
params,
|
params,
|
||||||
`grafana-data-source-annotations-${annotation.name}-${options.dashboard?.id}`
|
`grafana-data-source-annotations-${annotation.name}-${options.dashboard?.uid}`
|
||||||
);
|
);
|
||||||
return { data: [toDataFrame(annotations)] };
|
return { data: [toDataFrame(annotations)] };
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,8 @@ const defaultResult: any = {
|
|||||||
panelId: 13,
|
panelId: 13,
|
||||||
dashboardId: 14, // deliberately different from panelId
|
dashboardId: 14, // deliberately different from panelId
|
||||||
id: 14,
|
id: 14,
|
||||||
|
uid: '7MeksYbmk',
|
||||||
|
dashboardUID: '7MeksYbmk',
|
||||||
url: '/d/asdkjhajksd/some-dash',
|
url: '/d/asdkjhajksd/some-dash',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,7 +55,7 @@ async function setupTestContext({
|
|||||||
const getMock = jest.spyOn(backendSrv, 'get');
|
const getMock = jest.spyOn(backendSrv, 'get');
|
||||||
getMock.mockResolvedValue(results);
|
getMock.mockResolvedValue(results);
|
||||||
|
|
||||||
const dash: any = { id: 1, formatDate: (time: number) => new Date(time).toISOString() };
|
const dash: any = { uid: 'srx16xR4z', formatDate: (time: number) => new Date(time).toISOString() };
|
||||||
const dashSrv: any = { getCurrent: () => dash };
|
const dashSrv: any = { getCurrent: () => dash };
|
||||||
setDashboardSrv(dashSrv);
|
setDashboardSrv(dashSrv);
|
||||||
const pushSpy = jest.spyOn(locationService, 'push');
|
const pushSpy = jest.spyOn(locationService, 'push');
|
||||||
@ -99,7 +101,7 @@ describe('AnnoListPanel', () => {
|
|||||||
expect(getMock).toHaveBeenCalledWith(
|
expect(getMock).toHaveBeenCalledWith(
|
||||||
'/api/annotations',
|
'/api/annotations',
|
||||||
{
|
{
|
||||||
dashboardId: 1,
|
dashboardUID: 'srx16xR4z',
|
||||||
limit: 10,
|
limit: 10,
|
||||||
tags: ['tag A', 'tag B'],
|
tags: ['tag A', 'tag B'],
|
||||||
type: 'annotation',
|
type: 'annotation',
|
||||||
@ -205,7 +207,7 @@ describe('AnnoListPanel', () => {
|
|||||||
await userEvent.click(screen.getByText(/result text/i));
|
await userEvent.click(screen.getByText(/result text/i));
|
||||||
await waitFor(() => expect(getMock).toHaveBeenCalledTimes(1));
|
await waitFor(() => expect(getMock).toHaveBeenCalledTimes(1));
|
||||||
|
|
||||||
expect(getMock).toHaveBeenCalledWith('/api/search', { dashboardIds: 14 });
|
expect(getMock).toHaveBeenCalledWith('/api/search', { dashboardUIDs: '7MeksYbmk' });
|
||||||
expect(pushSpy).toHaveBeenCalledTimes(1);
|
expect(pushSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(pushSpy).toHaveBeenCalledWith('/d/asdkjhajksd/some-dash?from=1609458600000&to=1609459800000');
|
expect(pushSpy).toHaveBeenCalledWith('/d/asdkjhajksd/some-dash?from=1609458600000&to=1609459800000');
|
||||||
});
|
});
|
||||||
@ -223,7 +225,7 @@ describe('AnnoListPanel', () => {
|
|||||||
expect(getMock).toHaveBeenCalledWith(
|
expect(getMock).toHaveBeenCalledWith(
|
||||||
'/api/annotations',
|
'/api/annotations',
|
||||||
{
|
{
|
||||||
dashboardId: 1,
|
dashboardUID: 'srx16xR4z',
|
||||||
limit: 10,
|
limit: 10,
|
||||||
tags: ['tag A', 'tag B', 'Result tag B'],
|
tags: ['tag A', 'tag B', 'Result tag B'],
|
||||||
type: 'annotation',
|
type: 'annotation',
|
||||||
@ -247,7 +249,7 @@ describe('AnnoListPanel', () => {
|
|||||||
expect(getMock).toHaveBeenCalledWith(
|
expect(getMock).toHaveBeenCalledWith(
|
||||||
'/api/annotations',
|
'/api/annotations',
|
||||||
{
|
{
|
||||||
dashboardId: 1,
|
dashboardUID: 'srx16xR4z',
|
||||||
limit: 10,
|
limit: 10,
|
||||||
tags: ['tag A', 'tag B'],
|
tags: ['tag A', 'tag B'],
|
||||||
type: 'annotation',
|
type: 'annotation',
|
||||||
|
@ -97,7 +97,7 @@ export class AnnoListPanel extends PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (options.onlyFromThisDashboard) {
|
if (options.onlyFromThisDashboard) {
|
||||||
params.dashboardId = getDashboardSrv().getCurrent()?.id;
|
params.dashboardUID = getDashboardSrv().getCurrent()?.uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
let timeInfo = '';
|
let timeInfo = '';
|
||||||
@ -148,13 +148,13 @@ export class AnnoListPanel extends PureComponent<Props, State> {
|
|||||||
params.viewPanel = anno.panelId;
|
params.viewPanel = anno.panelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current?.id === anno.dashboardId) {
|
if (current?.uid === anno.dashboardUID) {
|
||||||
locationService.partial(params);
|
locationService.partial(params);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await getBackendSrv().get('/api/search', { dashboardIds: anno.dashboardId });
|
const result = await getBackendSrv().get('/api/search', { dashboardUIDs: anno.dashboardUID });
|
||||||
if (result && result.length && result[0].id === anno.dashboardId) {
|
if (result && result.length && result[0].uid === anno.dashboardUID) {
|
||||||
const dash = result[0];
|
const dash = result[0];
|
||||||
const url = new URL(dash.url, window.location.origin);
|
const url = new URL(dash.url, window.location.origin);
|
||||||
url.searchParams.set('from', params.from);
|
url.searchParams.set('from', params.from);
|
||||||
@ -162,7 +162,7 @@ export class AnnoListPanel extends PureComponent<Props, State> {
|
|||||||
locationService.push(locationUtil.stripBaseFromUrl(url.toString()));
|
locationService.push(locationUtil.stripBaseFromUrl(url.toString()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
appEvents.emit(AppEvents.alertWarning, ['Unknown Dashboard: ' + anno.dashboardId]);
|
appEvents.emit(AppEvents.alertWarning, ['Unknown Dashboard: ' + anno.dashboardUID]);
|
||||||
};
|
};
|
||||||
|
|
||||||
_timeOffset(time: number, offset: string, subtract = false): number {
|
_timeOffset(time: number, offset: string, subtract = false): number {
|
||||||
|
@ -23,7 +23,7 @@ export class EventEditorCtrl {
|
|||||||
|
|
||||||
$onInit() {
|
$onInit() {
|
||||||
this.event.panelId = this.panelCtrl.panel.id; // set correct id if in panel edit
|
this.event.panelId = this.panelCtrl.panel.id; // set correct id if in panel edit
|
||||||
this.event.dashboardId = this.panelCtrl.dashboard.id;
|
this.event.dashboardUID = this.panelCtrl.dashboard.uid;
|
||||||
|
|
||||||
// Annotations query returns time as Unix timestamp in milliseconds
|
// Annotations query returns time as Unix timestamp in milliseconds
|
||||||
this.event.time = tryEpochToMoment(this.event.time);
|
this.event.time = tryEpochToMoment(this.event.time);
|
||||||
|
@ -31,7 +31,7 @@ export class EventManager {
|
|||||||
updateTime(range: { from: any; to: any }) {
|
updateTime(range: { from: any; to: any }) {
|
||||||
if (!this.event) {
|
if (!this.event) {
|
||||||
this.event = {};
|
this.event = {};
|
||||||
this.event.dashboardId = this.panelCtrl.dashboard.id;
|
this.event.dashboardUID = this.panelCtrl.dashboard.uid;
|
||||||
this.event.panelId = this.panelCtrl.panel.id;
|
this.event.panelId = this.panelCtrl.panel.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,8 +95,8 @@ export function AnnotationMarker({ annotation, timeZone, width }: Props) {
|
|||||||
timeFormatter={timeFormatter}
|
timeFormatter={timeFormatter}
|
||||||
onEdit={onAnnotationEdit}
|
onEdit={onAnnotationEdit}
|
||||||
onDelete={onAnnotationDelete}
|
onDelete={onAnnotationDelete}
|
||||||
canEdit={canEditAnnotations!(annotation.dashboardId)}
|
canEdit={canEditAnnotations!(annotation.dashboardUID)}
|
||||||
canDelete={canDeleteAnnotations!(annotation.dashboardId)}
|
canDelete={canDeleteAnnotations!(annotation.dashboardUID)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}, [canEditAnnotations, canDeleteAnnotations, onAnnotationDelete, onAnnotationEdit, timeFormatter, annotation]);
|
}, [canEditAnnotations, canDeleteAnnotations, onAnnotationDelete, onAnnotationEdit, timeFormatter, annotation]);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
interface AnnotationsDataFrameViewDTO {
|
interface AnnotationsDataFrameViewDTO {
|
||||||
id: string;
|
id: string;
|
||||||
|
/** @deprecate */
|
||||||
dashboardId: number;
|
dashboardId: number;
|
||||||
|
dashboardUID: string;
|
||||||
time: number;
|
time: number;
|
||||||
timeEnd: number;
|
timeEnd: number;
|
||||||
text: string;
|
text: string;
|
||||||
|
Loading…
Reference in New Issue
Block a user