mirror of https://github.com/grafana/grafana
EventBus: Introduces new event bus with emitter backward compatible interface (#27564)
* updated * Experimenting with event bus with legacy support * Before switch to emitter * EventBus & Emitter unification * Everything using new EventBus * Making progress * Fixing merge issues * Final merge issues * Updated * Updates * Fix * Updated * Update * Update * Rename methods to publish and subscribe * Ts fixes * Updated * updated * fixing doc warnigns * removed unused filepull/28784/head
parent
d84d8a134f
commit
74c65eca26
@ -0,0 +1,173 @@ |
|||||||
|
import { EventBusSrv } from './EventBus'; |
||||||
|
import { BusEventWithPayload } from './types'; |
||||||
|
import { eventFactory } from './eventFactory'; |
||||||
|
|
||||||
|
interface LoginEventPayload { |
||||||
|
logins: number; |
||||||
|
} |
||||||
|
|
||||||
|
interface HelloEventPayload { |
||||||
|
hellos: number; |
||||||
|
} |
||||||
|
|
||||||
|
class LoginEvent extends BusEventWithPayload<LoginEventPayload> { |
||||||
|
static type = 'login-event'; |
||||||
|
} |
||||||
|
|
||||||
|
class HelloEvent extends BusEventWithPayload<HelloEventPayload> { |
||||||
|
static type = 'hello-event'; |
||||||
|
} |
||||||
|
|
||||||
|
type LegacyEventPayload = [string, string]; |
||||||
|
|
||||||
|
export const legacyEvent = eventFactory<LegacyEventPayload>('legacy-event'); |
||||||
|
|
||||||
|
class AlertSuccessEvent extends BusEventWithPayload<LegacyEventPayload> { |
||||||
|
static type = 'legacy-event'; |
||||||
|
} |
||||||
|
|
||||||
|
describe('EventBus', () => { |
||||||
|
it('Can create events', () => { |
||||||
|
expect(new LoginEvent({ logins: 1 }).type).toBe('login-event'); |
||||||
|
}); |
||||||
|
|
||||||
|
it('Can subscribe specific event', () => { |
||||||
|
const bus = new EventBusSrv(); |
||||||
|
const events: LoginEvent[] = []; |
||||||
|
|
||||||
|
bus.subscribe(LoginEvent, event => { |
||||||
|
events.push(event); |
||||||
|
}); |
||||||
|
|
||||||
|
bus.publish(new LoginEvent({ logins: 10 })); |
||||||
|
bus.publish(new HelloEvent({ hellos: 10 })); |
||||||
|
|
||||||
|
expect(events[0].payload.logins).toBe(10); |
||||||
|
expect(events.length).toBe(1); |
||||||
|
}); |
||||||
|
|
||||||
|
describe('Legacy emitter behavior', () => { |
||||||
|
it('Supports legacy events', () => { |
||||||
|
const bus = new EventBusSrv(); |
||||||
|
const events: any = []; |
||||||
|
const handler = (event: LegacyEventPayload) => { |
||||||
|
events.push(event); |
||||||
|
}; |
||||||
|
|
||||||
|
bus.on(legacyEvent, handler); |
||||||
|
bus.emit(legacyEvent, ['hello', 'hello2']); |
||||||
|
|
||||||
|
bus.off(legacyEvent, handler); |
||||||
|
bus.emit(legacyEvent, ['hello', 'hello2']); |
||||||
|
|
||||||
|
expect(events.length).toEqual(1); |
||||||
|
expect(events[0]).toEqual(['hello', 'hello2']); |
||||||
|
}); |
||||||
|
|
||||||
|
it('Interoperability with legacy events', () => { |
||||||
|
const bus = new EventBusSrv(); |
||||||
|
const legacyEvents: any = []; |
||||||
|
const newEvents: any = []; |
||||||
|
|
||||||
|
bus.on(legacyEvent, event => { |
||||||
|
legacyEvents.push(event); |
||||||
|
}); |
||||||
|
|
||||||
|
bus.subscribe(AlertSuccessEvent, event => { |
||||||
|
newEvents.push(event); |
||||||
|
}); |
||||||
|
|
||||||
|
bus.emit(legacyEvent, ['legacy', 'params']); |
||||||
|
bus.publish(new AlertSuccessEvent(['new', 'event'])); |
||||||
|
|
||||||
|
expect(legacyEvents).toEqual([ |
||||||
|
['legacy', 'params'], |
||||||
|
['new', 'event'], |
||||||
|
]); |
||||||
|
|
||||||
|
expect(newEvents).toEqual([ |
||||||
|
{ |
||||||
|
type: 'legacy-event', |
||||||
|
payload: ['legacy', 'params'], |
||||||
|
}, |
||||||
|
{ |
||||||
|
type: 'legacy-event', |
||||||
|
payload: ['new', 'event'], |
||||||
|
}, |
||||||
|
]); |
||||||
|
}); |
||||||
|
|
||||||
|
it('should notfiy subscribers', () => { |
||||||
|
const bus = new EventBusSrv(); |
||||||
|
let sub1Called = false; |
||||||
|
let sub2Called = false; |
||||||
|
|
||||||
|
bus.on(legacyEvent, () => { |
||||||
|
sub1Called = true; |
||||||
|
}); |
||||||
|
bus.on(legacyEvent, () => { |
||||||
|
sub2Called = true; |
||||||
|
}); |
||||||
|
|
||||||
|
bus.emit(legacyEvent, null); |
||||||
|
|
||||||
|
expect(sub1Called).toBe(true); |
||||||
|
expect(sub2Called).toBe(true); |
||||||
|
}); |
||||||
|
|
||||||
|
it('when subscribing twice', () => { |
||||||
|
const bus = new EventBusSrv(); |
||||||
|
let sub1Called = 0; |
||||||
|
|
||||||
|
function handler() { |
||||||
|
sub1Called += 1; |
||||||
|
} |
||||||
|
|
||||||
|
bus.on(legacyEvent, handler); |
||||||
|
bus.on(legacyEvent, handler); |
||||||
|
|
||||||
|
bus.emit(legacyEvent, null); |
||||||
|
|
||||||
|
expect(sub1Called).toBe(2); |
||||||
|
}); |
||||||
|
|
||||||
|
it('should handle errors', () => { |
||||||
|
const bus = new EventBusSrv(); |
||||||
|
let sub1Called = 0; |
||||||
|
let sub2Called = 0; |
||||||
|
|
||||||
|
bus.on(legacyEvent, () => { |
||||||
|
sub1Called++; |
||||||
|
throw { message: 'hello' }; |
||||||
|
}); |
||||||
|
|
||||||
|
bus.on(legacyEvent, () => { |
||||||
|
sub2Called++; |
||||||
|
}); |
||||||
|
|
||||||
|
try { |
||||||
|
bus.emit(legacyEvent, null); |
||||||
|
} catch (_) {} |
||||||
|
try { |
||||||
|
bus.emit(legacyEvent, null); |
||||||
|
} catch (_) {} |
||||||
|
|
||||||
|
expect(sub1Called).toBe(2); |
||||||
|
expect(sub2Called).toBe(0); |
||||||
|
}); |
||||||
|
|
||||||
|
it('removeAllListeners should unsubscribe to all', () => { |
||||||
|
const bus = new EventBusSrv(); |
||||||
|
const events: LoginEvent[] = []; |
||||||
|
|
||||||
|
bus.subscribe(LoginEvent, event => { |
||||||
|
events.push(event); |
||||||
|
}); |
||||||
|
|
||||||
|
bus.removeAllListeners(); |
||||||
|
bus.publish(new LoginEvent({ logins: 10 })); |
||||||
|
|
||||||
|
expect(events.length).toBe(0); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
||||||
@ -0,0 +1,85 @@ |
|||||||
|
import EventEmitter from 'eventemitter3'; |
||||||
|
import { Unsubscribable, Observable } from 'rxjs'; |
||||||
|
import { AppEvent } from './types'; |
||||||
|
import { EventBus, LegacyEmitter, BusEventHandler, BusEventType, LegacyEventHandler, BusEvent } from './types'; |
||||||
|
|
||||||
|
/** |
||||||
|
* @alpha |
||||||
|
*/ |
||||||
|
export class EventBusSrv implements EventBus, LegacyEmitter { |
||||||
|
private emitter: EventEmitter; |
||||||
|
|
||||||
|
constructor() { |
||||||
|
this.emitter = new EventEmitter(); |
||||||
|
} |
||||||
|
|
||||||
|
publish<T extends BusEvent>(event: T): void { |
||||||
|
this.emitter.emit(event.type, event); |
||||||
|
} |
||||||
|
|
||||||
|
subscribe<T extends BusEvent>(typeFilter: BusEventType<T>, handler: BusEventHandler<T>): Unsubscribable { |
||||||
|
return this.getStream(typeFilter).subscribe({ next: handler }); |
||||||
|
} |
||||||
|
|
||||||
|
getStream<T extends BusEvent>(eventType: BusEventType<T>): Observable<T> { |
||||||
|
return new Observable<T>(observer => { |
||||||
|
const handler = (event: T) => { |
||||||
|
observer.next(event); |
||||||
|
}; |
||||||
|
|
||||||
|
this.emitter.on(eventType.type, handler); |
||||||
|
|
||||||
|
return () => { |
||||||
|
this.emitter.off(eventType.type, handler); |
||||||
|
}; |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Legacy functions |
||||||
|
*/ |
||||||
|
emit<T>(event: AppEvent<T> | string, payload?: T | any): void { |
||||||
|
// console.log(`Deprecated emitter function used (emit), use $emit`);
|
||||||
|
|
||||||
|
if (typeof event === 'string') { |
||||||
|
this.emitter.emit(event, { type: event, payload }); |
||||||
|
} else { |
||||||
|
this.emitter.emit(event.name, { type: event.name, payload }); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
on<T>(event: AppEvent<T> | string, handler: LegacyEventHandler<T>, scope?: any) { |
||||||
|
// console.log(`Deprecated emitter function used (on), use $on`);
|
||||||
|
|
||||||
|
// need this wrapper to make old events compatible with old handlers
|
||||||
|
handler.wrapper = (emittedEvent: BusEvent) => { |
||||||
|
handler(emittedEvent.payload); |
||||||
|
}; |
||||||
|
|
||||||
|
if (typeof event === 'string') { |
||||||
|
this.emitter.on(event, handler.wrapper); |
||||||
|
} else { |
||||||
|
this.emitter.on(event.name, handler.wrapper); |
||||||
|
} |
||||||
|
|
||||||
|
if (scope) { |
||||||
|
const unbind = scope.$on('$destroy', () => { |
||||||
|
this.off(event, handler); |
||||||
|
unbind(); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
off<T>(event: AppEvent<T> | string, handler: LegacyEventHandler<T>) { |
||||||
|
if (typeof event === 'string') { |
||||||
|
this.emitter.off(event, handler.wrapper); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
this.emitter.off(event.name, handler.wrapper); |
||||||
|
} |
||||||
|
|
||||||
|
removeAllListeners() { |
||||||
|
this.emitter.removeAllListeners(); |
||||||
|
} |
||||||
|
} |
||||||
@ -1,9 +1,7 @@ |
|||||||
import { AppEvent } from './appEvents'; |
import { AppEvent } from './types'; |
||||||
|
|
||||||
export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>; |
|
||||||
export type Subtract<T, K> = Omit<T, keyof K>; |
|
||||||
|
|
||||||
const typeList: Set<string> = new Set(); |
const typeList: Set<string> = new Set(); |
||||||
|
|
||||||
export function eventFactory<T = undefined>(name: string): AppEvent<T> { |
export function eventFactory<T = undefined>(name: string): AppEvent<T> { |
||||||
if (typeList.has(name)) { |
if (typeList.has(name)) { |
||||||
throw new Error(`There is already an event defined with type '${name}'`); |
throw new Error(`There is already an event defined with type '${name}'`); |
||||||
@ -0,0 +1,3 @@ |
|||||||
|
export * from './eventFactory'; |
||||||
|
export * from './types'; |
||||||
|
export * from './EventBus'; |
||||||
@ -0,0 +1,115 @@ |
|||||||
|
import { Unsubscribable, Observable } from 'rxjs'; |
||||||
|
|
||||||
|
/** |
||||||
|
* @alpha |
||||||
|
* internal interface |
||||||
|
*/ |
||||||
|
export interface BusEvent { |
||||||
|
readonly type: string; |
||||||
|
readonly payload?: any; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @alpha |
||||||
|
* Base event type |
||||||
|
*/ |
||||||
|
export abstract class BusEventBase implements BusEvent { |
||||||
|
readonly type: string; |
||||||
|
readonly payload?: any; |
||||||
|
|
||||||
|
constructor() { |
||||||
|
//@ts-ignore
|
||||||
|
this.type = this.__proto__.constructor.type; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @alpha |
||||||
|
* Base event type with payload |
||||||
|
*/ |
||||||
|
export abstract class BusEventWithPayload<T> extends BusEventBase { |
||||||
|
readonly payload: T; |
||||||
|
|
||||||
|
constructor(payload: T) { |
||||||
|
super(); |
||||||
|
this.payload = payload; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Interface for an event type constructor |
||||||
|
*/ |
||||||
|
export interface BusEventType<T extends BusEvent> { |
||||||
|
type: string; |
||||||
|
new (...args: any[]): T; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @alpha |
||||||
|
* Event callback/handler type |
||||||
|
*/ |
||||||
|
export interface BusEventHandler<T extends BusEvent> { |
||||||
|
(event: T): void; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @alpha |
||||||
|
* Main minimal interface |
||||||
|
*/ |
||||||
|
export interface EventBus { |
||||||
|
/** |
||||||
|
* Publish single vent |
||||||
|
*/ |
||||||
|
publish<T extends BusEvent>(event: T): void; |
||||||
|
|
||||||
|
/** |
||||||
|
* Subscribe to single event |
||||||
|
*/ |
||||||
|
subscribe<T extends BusEvent>(eventType: BusEventType<T>, handler: BusEventHandler<T>): Unsubscribable; |
||||||
|
|
||||||
|
/** |
||||||
|
* Get observable of events |
||||||
|
*/ |
||||||
|
getStream<T extends BusEvent>(eventType: BusEventType<T>): Observable<T>; |
||||||
|
|
||||||
|
/** |
||||||
|
* Remove all event subscriptions |
||||||
|
*/ |
||||||
|
removeAllListeners(): void; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @public |
||||||
|
* @deprecated event type |
||||||
|
*/ |
||||||
|
export interface AppEvent<T> { |
||||||
|
readonly name: string; |
||||||
|
payload?: T; |
||||||
|
} |
||||||
|
|
||||||
|
/** @public */ |
||||||
|
export interface LegacyEmitter { |
||||||
|
/** |
||||||
|
* @deprecated use $emit |
||||||
|
*/ |
||||||
|
emit<T>(event: AppEvent<T> | string, payload?: T): void; |
||||||
|
|
||||||
|
/** |
||||||
|
* @deprecated use $on |
||||||
|
*/ |
||||||
|
on<T>(event: AppEvent<T> | string, handler: LegacyEventHandler<T>, scope?: any): void; |
||||||
|
|
||||||
|
/** |
||||||
|
* @deprecated use $on |
||||||
|
*/ |
||||||
|
off<T>(event: AppEvent<T> | string, handler: (payload?: T | any) => void): void; |
||||||
|
} |
||||||
|
|
||||||
|
/** @public */ |
||||||
|
export interface LegacyEventHandler<T> { |
||||||
|
(payload: T): void; |
||||||
|
wrapper?: (event: BusEvent) => void; |
||||||
|
} |
||||||
|
|
||||||
|
/** @alpha */ |
||||||
|
export interface EventBusExtended extends EventBus, LegacyEmitter {} |
||||||
@ -1,13 +0,0 @@ |
|||||||
import { eventFactory } from './utils'; |
|
||||||
|
|
||||||
export interface AppEvent<T> { |
|
||||||
readonly name: string; |
|
||||||
payload?: T; |
|
||||||
} |
|
||||||
|
|
||||||
export type AlertPayload = [string, string?]; |
|
||||||
export type AlertErrorPayload = [string, (string | Error)?]; |
|
||||||
|
|
||||||
export const alertSuccess = eventFactory<AlertPayload>('alert-success'); |
|
||||||
export const alertWarning = eventFactory<AlertPayload>('alert-warning'); |
|
||||||
export const alertError = eventFactory<AlertErrorPayload>('alert-error'); |
|
||||||
@ -0,0 +1,47 @@ |
|||||||
|
import { DataQueryError, DataQueryResponseData } from './datasource'; |
||||||
|
import { AngularPanelMenuItem } from './panel'; |
||||||
|
import { DataFrame } from './dataFrame'; |
||||||
|
import { eventFactory } from '../events/eventFactory'; |
||||||
|
import { BusEventBase, BusEventWithPayload } from '../events/types'; |
||||||
|
|
||||||
|
export type AlertPayload = [string, string?]; |
||||||
|
export type AlertErrorPayload = [string, (string | Error)?]; |
||||||
|
|
||||||
|
export const AppEvents = { |
||||||
|
alertSuccess: eventFactory<AlertPayload>('alert-success'), |
||||||
|
alertWarning: eventFactory<AlertPayload>('alert-warning'), |
||||||
|
alertError: eventFactory<AlertErrorPayload>('alert-error'), |
||||||
|
}; |
||||||
|
|
||||||
|
export const PanelEvents = { |
||||||
|
refresh: eventFactory('refresh'), |
||||||
|
componentDidMount: eventFactory('component-did-mount'), |
||||||
|
dataReceived: eventFactory<DataQueryResponseData[]>('data-received'), |
||||||
|
dataError: eventFactory<DataQueryError>('data-error'), |
||||||
|
dataFramesReceived: eventFactory<DataFrame[]>('data-frames-received'), |
||||||
|
dataSnapshotLoad: eventFactory<DataQueryResponseData[]>('data-snapshot-load'), |
||||||
|
editModeInitialized: eventFactory('init-edit-mode'), |
||||||
|
initPanelActions: eventFactory<AngularPanelMenuItem[]>('init-panel-actions'), |
||||||
|
panelInitialized: eventFactory('panel-initialized'), |
||||||
|
panelSizeChanged: eventFactory('panel-size-changed'), |
||||||
|
panelTeardown: eventFactory('panel-teardown'), |
||||||
|
render: eventFactory<any>('render'), |
||||||
|
}; |
||||||
|
|
||||||
|
/** @public */ |
||||||
|
export interface LegacyGraphHoverEventPayload { |
||||||
|
pos: any; |
||||||
|
panel: { |
||||||
|
id: number; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
/** @alpha */ |
||||||
|
export class LegacyGraphHoverEvent extends BusEventWithPayload<LegacyGraphHoverEventPayload> { |
||||||
|
static type = 'graph-hover'; |
||||||
|
} |
||||||
|
|
||||||
|
/** @alpha */ |
||||||
|
export class LegacyGraphHoverClearEvent extends BusEventBase { |
||||||
|
static type = 'graph-hover-clear'; |
||||||
|
} |
||||||
@ -1,28 +0,0 @@ |
|||||||
import { eventFactory } from './utils'; |
|
||||||
import { DataQueryError, DataQueryResponseData } from './datasource'; |
|
||||||
import { AngularPanelMenuItem } from './panel'; |
|
||||||
import { DataFrame } from './dataFrame'; |
|
||||||
|
|
||||||
/** Payloads */ |
|
||||||
export interface PanelChangeViewPayload { |
|
||||||
fullscreen?: boolean; |
|
||||||
edit?: boolean; |
|
||||||
panelId?: number; |
|
||||||
toggle?: boolean; |
|
||||||
} |
|
||||||
|
|
||||||
/** Events */ |
|
||||||
export const refresh = eventFactory('refresh'); |
|
||||||
export const componentDidMount = eventFactory('component-did-mount'); |
|
||||||
export const dataError = eventFactory<DataQueryError>('data-error'); |
|
||||||
export const dataReceived = eventFactory<DataQueryResponseData[]>('data-received'); |
|
||||||
export const dataFramesReceived = eventFactory<DataFrame[]>('data-frames-received'); |
|
||||||
export const dataSnapshotLoad = eventFactory<DataQueryResponseData[]>('data-snapshot-load'); |
|
||||||
export const editModeInitialized = eventFactory('init-edit-mode'); |
|
||||||
export const initPanelActions = eventFactory<AngularPanelMenuItem[]>('init-panel-actions'); |
|
||||||
export const panelChangeView = eventFactory<PanelChangeViewPayload>('panel-change-view'); |
|
||||||
export const panelInitialized = eventFactory('panel-initialized'); |
|
||||||
export const panelSizeChanged = eventFactory('panel-size-changed'); |
|
||||||
export const panelTeardown = eventFactory('panel-teardown'); |
|
||||||
export const render = eventFactory<any>('render'); |
|
||||||
export const viewModeChanged = eventFactory('view-mode-changed'); |
|
||||||
@ -1,5 +1,5 @@ |
|||||||
import { Emitter } from './utils/emitter'; |
import { EventBusSrv, EventBusExtended } from '@grafana/data'; |
||||||
|
|
||||||
export const appEvents = new Emitter(); |
export const appEvents: EventBusExtended = new EventBusSrv(); |
||||||
|
|
||||||
export default appEvents; |
export default appEvents; |
||||||
|
|||||||
@ -1,67 +0,0 @@ |
|||||||
import { Emitter } from '../utils/emitter'; |
|
||||||
import { eventFactory } from '@grafana/data'; |
|
||||||
|
|
||||||
const testEvent = eventFactory('test'); |
|
||||||
|
|
||||||
describe('Emitter', () => { |
|
||||||
describe('given 2 subscribers', () => { |
|
||||||
it('should notfiy subscribers', () => { |
|
||||||
const events = new Emitter(); |
|
||||||
let sub1Called = false; |
|
||||||
let sub2Called = false; |
|
||||||
|
|
||||||
events.on(testEvent, () => { |
|
||||||
sub1Called = true; |
|
||||||
}); |
|
||||||
events.on(testEvent, () => { |
|
||||||
sub2Called = true; |
|
||||||
}); |
|
||||||
|
|
||||||
events.emit(testEvent, null); |
|
||||||
|
|
||||||
expect(sub1Called).toBe(true); |
|
||||||
expect(sub2Called).toBe(true); |
|
||||||
}); |
|
||||||
|
|
||||||
it('when subscribing twice', () => { |
|
||||||
const events = new Emitter(); |
|
||||||
let sub1Called = 0; |
|
||||||
|
|
||||||
function handler() { |
|
||||||
sub1Called += 1; |
|
||||||
} |
|
||||||
|
|
||||||
events.on(testEvent, handler); |
|
||||||
events.on(testEvent, handler); |
|
||||||
|
|
||||||
events.emit(testEvent, null); |
|
||||||
|
|
||||||
expect(sub1Called).toBe(2); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should handle errors', () => { |
|
||||||
const events = new Emitter(); |
|
||||||
let sub1Called = 0; |
|
||||||
let sub2Called = 0; |
|
||||||
|
|
||||||
events.on(testEvent, () => { |
|
||||||
sub1Called++; |
|
||||||
throw { message: 'hello' }; |
|
||||||
}); |
|
||||||
|
|
||||||
events.on(testEvent, () => { |
|
||||||
sub2Called++; |
|
||||||
}); |
|
||||||
|
|
||||||
try { |
|
||||||
events.emit(testEvent, null); |
|
||||||
} catch (_) {} |
|
||||||
try { |
|
||||||
events.emit(testEvent, null); |
|
||||||
} catch (_) {} |
|
||||||
|
|
||||||
expect(sub1Called).toBe(2); |
|
||||||
expect(sub2Called).toBe(0); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
@ -1,101 +0,0 @@ |
|||||||
import EventEmitter3, { EventEmitter } from 'eventemitter3'; |
|
||||||
import { AppEvent } from '@grafana/data'; |
|
||||||
|
|
||||||
export class Emitter { |
|
||||||
private emitter: EventEmitter3; |
|
||||||
|
|
||||||
constructor() { |
|
||||||
this.emitter = new EventEmitter(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* DEPRECATED. |
|
||||||
*/ |
|
||||||
emit(name: string, data?: any): void; |
|
||||||
|
|
||||||
/** |
|
||||||
* Emits an `event` with `payload`. |
|
||||||
*/ |
|
||||||
emit<T extends undefined>(event: AppEvent<T>): void; |
|
||||||
emit<T extends (U extends any ? Partial<T> : unknown) extends T ? Partial<T> : never, U = any>( |
|
||||||
event: AppEvent<T> |
|
||||||
): void; |
|
||||||
emit<T>(event: AppEvent<T>, payload: T): void; |
|
||||||
emit<T>(event: AppEvent<T> | string, payload?: T | any): void { |
|
||||||
if (typeof event === 'string') { |
|
||||||
console.warn(`Using strings as events is deprecated and will be removed in a future version. (${event})`); |
|
||||||
this.emitter.emit(event, payload); |
|
||||||
} else { |
|
||||||
this.emitter.emit(event.name, payload); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* DEPRECATED. |
|
||||||
*/ |
|
||||||
on(name: string, handler: (payload?: any) => void, scope?: any): void; |
|
||||||
|
|
||||||
/** |
|
||||||
* Handles `event` with `handler()` when emitted. |
|
||||||
*/ |
|
||||||
on<T extends undefined>(event: AppEvent<T>, handler: () => void, scope?: any): void; |
|
||||||
on<T extends (U extends any ? Partial<T> : unknown) extends T ? Partial<T> : never, U = any>( |
|
||||||
event: AppEvent<T>, |
|
||||||
handler: () => void, |
|
||||||
scope?: any |
|
||||||
): void; |
|
||||||
on<T>(event: AppEvent<T>, handler: (payload: T) => void, scope?: any): void; |
|
||||||
on<T>(event: AppEvent<T> | string, handler: (payload?: T | any) => void, scope?: any) { |
|
||||||
if (typeof event === 'string') { |
|
||||||
console.warn(`Using strings as events is deprecated and will be removed in a future version. (${event})`); |
|
||||||
this.emitter.on(event, handler); |
|
||||||
|
|
||||||
if (scope) { |
|
||||||
const unbind = scope.$on('$destroy', () => { |
|
||||||
this.emitter.off(event, handler); |
|
||||||
unbind(); |
|
||||||
}); |
|
||||||
} |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
this.emitter.on(event.name, handler); |
|
||||||
|
|
||||||
if (scope) { |
|
||||||
const unbind = scope.$on('$destroy', () => { |
|
||||||
this.emitter.off(event.name, handler); |
|
||||||
unbind(); |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* DEPRECATED. |
|
||||||
*/ |
|
||||||
off(name: string, handler: (payload?: any) => void): void; |
|
||||||
|
|
||||||
off<T extends undefined>(event: AppEvent<T>, handler: () => void): void; |
|
||||||
off<T extends (U extends any ? Partial<T> : unknown) extends T ? Partial<T> : never, U = any>( |
|
||||||
event: AppEvent<T>, |
|
||||||
handler: () => void, |
|
||||||
scope?: any |
|
||||||
): void; |
|
||||||
off<T>(event: AppEvent<T>, handler: (payload: T) => void): void; |
|
||||||
off<T>(event: AppEvent<T> | string, handler: (payload?: T | any) => void) { |
|
||||||
if (typeof event === 'string') { |
|
||||||
console.warn(`Using strings as events is deprecated and will be removed in a future version. (${event})`); |
|
||||||
this.emitter.off(event, handler); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
this.emitter.off(event.name, handler); |
|
||||||
} |
|
||||||
|
|
||||||
removeAllListeners(evt?: string) { |
|
||||||
this.emitter.removeAllListeners(evt); |
|
||||||
} |
|
||||||
|
|
||||||
getEventCount(): number { |
|
||||||
return (this.emitter as any)._eventsCount; |
|
||||||
} |
|
||||||
} |
|
||||||
Loading…
Reference in new issue