mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
	
	
		
			239 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
		
		
			
		
	
	
			239 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
|  | import { EventBusSrv } from '@grafana/data'; | ||
|  | import { BackendSrv, setBackendSrv } from '@grafana/runtime'; | ||
|  | import { PanelContext } from '@grafana/ui'; | ||
|  | 
 | ||
|  | import { transformSaveModelToScene } from '../serialization/transformSaveModelToScene'; | ||
|  | import { findVizPanelByKey } from '../utils/utils'; | ||
|  | 
 | ||
|  | import { getAdHocFilterSetFor, setDashboardPanelContext } from './setDashboardPanelContext'; | ||
|  | 
 | ||
|  | const postFn = jest.fn(); | ||
|  | const putFn = jest.fn(); | ||
|  | const deleteFn = jest.fn(); | ||
|  | 
 | ||
|  | setBackendSrv({ | ||
|  |   post: postFn, | ||
|  |   put: putFn, | ||
|  |   delete: deleteFn, | ||
|  | } as any as BackendSrv); | ||
|  | 
 | ||
|  | describe('setDashboardPanelContext', () => { | ||
|  |   describe('canAddAnnotations', () => { | ||
|  |     it('Can add when builtIn is enabled and permissions allow', () => { | ||
|  |       const { context } = buildTestScene({ builtInAnnotationsEnabled: true, dashboardCanEdit: true, canAdd: true }); | ||
|  |       expect(context.canAddAnnotations!()).toBe(true); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('Can not when builtIn is disabled', () => { | ||
|  |       const { context } = buildTestScene({ builtInAnnotationsEnabled: false, dashboardCanEdit: true, canAdd: true }); | ||
|  |       expect(context.canAddAnnotations!()).toBe(false); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('Can not when permission do not allow', () => { | ||
|  |       const { context } = buildTestScene({ builtInAnnotationsEnabled: true, dashboardCanEdit: true, canAdd: false }); | ||
|  |       expect(context.canAddAnnotations!()).toBe(false); | ||
|  |     }); | ||
|  |   }); | ||
|  | 
 | ||
|  |   describe('canEditAnnotations', () => { | ||
|  |     it('Can edit global event when user has org permission', () => { | ||
|  |       const { context } = buildTestScene({ dashboardCanEdit: true, orgCanEdit: true }); | ||
|  |       expect(context.canEditAnnotations!()).toBe(true); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('Can not edit global event when has no org permission', () => { | ||
|  |       const { context } = buildTestScene({ dashboardCanEdit: true, orgCanEdit: false }); | ||
|  |       expect(context.canEditAnnotations!()).toBe(false); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('Can edit dashboard event when has dashboard permission', () => { | ||
|  |       const { context } = buildTestScene({ dashboardCanEdit: true, canEdit: true }); | ||
|  |       expect(context.canEditAnnotations!('dash-uid')).toBe(true); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('Can not edit dashboard event when has no dashboard permission', () => { | ||
|  |       const { context } = buildTestScene({ dashboardCanEdit: true, canEdit: false }); | ||
|  |       expect(context.canEditAnnotations!('dash-uid')).toBe(false); | ||
|  |     }); | ||
|  |   }); | ||
|  | 
 | ||
|  |   describe('canDeleteAnnotations', () => { | ||
|  |     it('Can delete global event when user has org permission', () => { | ||
|  |       const { context } = buildTestScene({ dashboardCanEdit: true, canDelete: true }); | ||
|  |       expect(context.canDeleteAnnotations!()).toBe(true); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('Can not delete global event when has no org permission', () => { | ||
|  |       const { context } = buildTestScene({ dashboardCanEdit: true, canDelete: false }); | ||
|  |       expect(context.canDeleteAnnotations!()).toBe(false); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('Can delete dashboard event when has dashboard permission', () => { | ||
|  |       const { context } = buildTestScene({ dashboardCanEdit: true, canDelete: true }); | ||
|  |       expect(context.canDeleteAnnotations!('dash-uid')).toBe(true); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('Can not delete dashboard event when has no dashboard permission', () => { | ||
|  |       const { context } = buildTestScene({ dashboardCanEdit: true, canDelete: false }); | ||
|  |       expect(context.canDeleteAnnotations!('dash-uid')).toBe(false); | ||
|  |     }); | ||
|  |   }); | ||
|  | 
 | ||
|  |   describe('onAnnotationCreate', () => { | ||
|  |     it('should create annotation', () => { | ||
|  |       const { context } = buildTestScene({ dashboardCanEdit: true, canAdd: true }); | ||
|  | 
 | ||
|  |       context.onAnnotationCreate!({ from: 100, to: 200, description: 'save it', tags: [] }); | ||
|  | 
 | ||
|  |       expect(postFn).toHaveBeenCalledWith('/api/annotations', { | ||
|  |         dashboardUID: 'dash-1', | ||
|  |         isRegion: true, | ||
|  |         panelId: 4, | ||
|  |         tags: [], | ||
|  |         text: 'save it', | ||
|  |         time: 100, | ||
|  |         timeEnd: 200, | ||
|  |       }); | ||
|  |     }); | ||
|  |   }); | ||
|  | 
 | ||
|  |   describe('onAnnotationUpdate', () => { | ||
|  |     it('should update annotation', () => { | ||
|  |       const { context } = buildTestScene({ dashboardCanEdit: true, canAdd: true }); | ||
|  | 
 | ||
|  |       context.onAnnotationUpdate!({ from: 100, to: 200, id: 'event-id-123', description: 'updated', tags: [] }); | ||
|  | 
 | ||
|  |       expect(putFn).toHaveBeenCalledWith('/api/annotations/event-id-123', { | ||
|  |         id: 'event-id-123', | ||
|  |         dashboardUID: 'dash-1', | ||
|  |         isRegion: true, | ||
|  |         panelId: 4, | ||
|  |         tags: [], | ||
|  |         text: 'updated', | ||
|  |         time: 100, | ||
|  |         timeEnd: 200, | ||
|  |       }); | ||
|  |     }); | ||
|  |   }); | ||
|  | 
 | ||
|  |   describe('onAnnotationDelete', () => { | ||
|  |     it('should update annotation', () => { | ||
|  |       const { context } = buildTestScene({ dashboardCanEdit: true, canAdd: true }); | ||
|  | 
 | ||
|  |       context.onAnnotationDelete!('I-do-not-want-you'); | ||
|  | 
 | ||
|  |       expect(deleteFn).toHaveBeenCalledWith('/api/annotations/I-do-not-want-you'); | ||
|  |     }); | ||
|  |   }); | ||
|  | 
 | ||
|  |   describe('onAddAdHocFilter', () => { | ||
|  |     it('Should add new filter set', () => { | ||
|  |       const { scene, context } = buildTestScene({}); | ||
|  | 
 | ||
|  |       context.onAddAdHocFilter!({ key: 'hello', value: 'world', operator: '=' }); | ||
|  | 
 | ||
|  |       const set = getAdHocFilterSetFor(scene, { uid: 'my-ds-uid' }); | ||
|  | 
 | ||
|  |       expect(set.state.filters).toEqual([{ key: 'hello', value: 'world', operator: '=' }]); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('Should update and add filter to existing set', () => { | ||
|  |       const { scene, context } = buildTestScene({ existingFilterSet: true }); | ||
|  | 
 | ||
|  |       const set = getAdHocFilterSetFor(scene, { uid: 'my-ds-uid' }); | ||
|  | 
 | ||
|  |       set.setState({ filters: [{ key: 'existing', value: 'world', operator: '=' }] }); | ||
|  | 
 | ||
|  |       context.onAddAdHocFilter!({ key: 'hello', value: 'world', operator: '=' }); | ||
|  | 
 | ||
|  |       expect(set.state.filters.length).toBe(2); | ||
|  | 
 | ||
|  |       // Can update existing filter value without adding a new filter
 | ||
|  |       context.onAddAdHocFilter!({ key: 'hello', value: 'world2', operator: '=' }); | ||
|  |       // Verify existing filter value updated
 | ||
|  |       expect(set.state.filters[1].value).toBe('world2'); | ||
|  |     }); | ||
|  |   }); | ||
|  | }); | ||
|  | 
 | ||
|  | interface SceneOptions { | ||
|  |   builtInAnnotationsEnabled?: boolean; | ||
|  |   dashboardCanEdit?: boolean; | ||
|  |   canAdd?: boolean; | ||
|  |   canEdit?: boolean; | ||
|  |   canDelete?: boolean; | ||
|  |   orgCanEdit?: boolean; | ||
|  |   existingFilterSet?: boolean; | ||
|  | } | ||
|  | 
 | ||
|  | function buildTestScene(options: SceneOptions) { | ||
|  |   const scene = transformSaveModelToScene({ | ||
|  |     dashboard: { | ||
|  |       title: 'hello', | ||
|  |       uid: 'dash-1', | ||
|  |       schemaVersion: 38, | ||
|  |       annotations: { | ||
|  |         list: [ | ||
|  |           { | ||
|  |             builtIn: 1, | ||
|  |             datasource: { | ||
|  |               type: 'grafana', | ||
|  |               uid: '-- Grafana --', | ||
|  |             }, | ||
|  |             enable: options.builtInAnnotationsEnabled ?? false, | ||
|  |             hide: true, | ||
|  |             iconColor: 'rgba(0, 211, 255, 1)', | ||
|  |             name: 'Annotations & Alerts', | ||
|  |             target: { refId: 'A' }, | ||
|  |             type: 'dashboard', | ||
|  |           }, | ||
|  |         ], | ||
|  |       }, | ||
|  |       panels: [ | ||
|  |         { | ||
|  |           type: 'timeseries', | ||
|  |           id: 4, | ||
|  |           datasource: { uid: 'my-ds-uid', type: 'prometheus' }, | ||
|  |           targets: [], | ||
|  |         }, | ||
|  |       ], | ||
|  |       templating: { | ||
|  |         list: options.existingFilterSet | ||
|  |           ? [ | ||
|  |               { | ||
|  |                 type: 'adhoc', | ||
|  |                 name: 'Filters', | ||
|  |                 datasource: { uid: 'my-ds-uid' }, | ||
|  |               }, | ||
|  |             ] | ||
|  |           : [], | ||
|  |       }, | ||
|  |     }, | ||
|  |     meta: { | ||
|  |       canEdit: options.dashboardCanEdit, | ||
|  |       annotationsPermissions: { | ||
|  |         dashboard: { | ||
|  |           canAdd: options.canAdd ?? false, | ||
|  |           canEdit: options.canEdit ?? false, | ||
|  |           canDelete: options.canDelete ?? false, | ||
|  |         }, | ||
|  |         organization: { | ||
|  |           canAdd: false, | ||
|  |           canEdit: options.orgCanEdit ?? false, | ||
|  |           canDelete: options.canDelete ?? false, | ||
|  |         }, | ||
|  |       }, | ||
|  |     }, | ||
|  |   }); | ||
|  | 
 | ||
|  |   const vizPanel = findVizPanelByKey(scene, 'panel-4')!; | ||
|  |   const context: PanelContext = { | ||
|  |     eventBus: new EventBusSrv(), | ||
|  |     eventsScope: 'global', | ||
|  |   }; | ||
|  | 
 | ||
|  |   setDashboardPanelContext(vizPanel, context); | ||
|  | 
 | ||
|  |   return { scene, vizPanel, context }; | ||
|  | } |