mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Types: Adds type safety to appEvents (#19418)
* Types: Add type safety to appEvents
This commit is contained in:
@@ -4,11 +4,13 @@ import AppNotificationItem from './AppNotificationItem';
|
||||
import { notifyApp, clearAppNotification } from 'app/core/actions';
|
||||
import { connectWithStore } from 'app/core/utils/connectWithReduxStore';
|
||||
import { AppNotification, StoreState } from 'app/types';
|
||||
|
||||
import {
|
||||
createErrorNotification,
|
||||
createSuccessNotification,
|
||||
createWarningNotification,
|
||||
} from '../../copy/appNotification';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export interface Props {
|
||||
appNotifications: AppNotification[];
|
||||
@@ -20,9 +22,9 @@ export class AppNotificationList extends PureComponent<Props> {
|
||||
componentDidMount() {
|
||||
const { notifyApp } = this.props;
|
||||
|
||||
appEvents.on('alert-warning', (options: string[]) => notifyApp(createWarningNotification(options[0], options[1])));
|
||||
appEvents.on('alert-success', (options: string[]) => notifyApp(createSuccessNotification(options[0], options[1])));
|
||||
appEvents.on('alert-error', (options: string[]) => notifyApp(createErrorNotification(options[0], options[1])));
|
||||
appEvents.on(AppEvents.alertWarning, payload => notifyApp(createWarningNotification(...payload)));
|
||||
appEvents.on(AppEvents.alertSuccess, payload => notifyApp(createSuccessNotification(...payload)));
|
||||
appEvents.on(AppEvents.alertError, payload => notifyApp(createErrorNotification(...payload)));
|
||||
}
|
||||
|
||||
onClearAppNotification = (id: number) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { PureComponent, SyntheticEvent, ChangeEvent } from 'react';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
interface Props {
|
||||
onSubmit: (pw: string) => void;
|
||||
@@ -42,7 +43,7 @@ export class ChangePassword extends PureComponent<Props, State> {
|
||||
if (valid) {
|
||||
this.props.onSubmit(newPassword);
|
||||
} else {
|
||||
appEvents.emit('alert-warning', ['New passwords do not match', '']);
|
||||
appEvents.emit(AppEvents.alertWarning, ['New passwords do not match']);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { PureComponent } from 'react';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
const isOauthEnabled = () => {
|
||||
return !!config.oauth && Object.keys(config.oauth).length > 0;
|
||||
@@ -52,7 +53,7 @@ export class LoginCtrl extends PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
if (config.loginError) {
|
||||
appEvents.emit('alert-warning', ['Login Failed', config.loginError]);
|
||||
appEvents.emit(AppEvents.alertWarning, ['Login Failed', config.loginError]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { FormEvent } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { NavModel, NavModelItem, NavModelBreadcrumb } from '@grafana/data';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export interface Props {
|
||||
model: NavModel;
|
||||
@@ -15,7 +16,7 @@ const SelectNav = ({ main, customCss }: { main: NavModelItem; customCss: string
|
||||
const gotoUrl = (evt: FormEvent) => {
|
||||
const element = evt.target as HTMLSelectElement;
|
||||
const url = element.options[element.selectedIndex].value;
|
||||
appEvents.emit('location-change', { href: url });
|
||||
appEvents.emit(CoreEvents.locationChange, { href: url });
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import store from 'app/core/store';
|
||||
import coreModule from 'app/core/core_module';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
const template = `
|
||||
<div class="layout-selector">
|
||||
@@ -16,20 +18,20 @@ export class LayoutSelectorCtrl {
|
||||
mode: string;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private $rootScope: any) {
|
||||
constructor(private $rootScope: GrafanaRootScope) {
|
||||
this.mode = store.get('grafana.list.layout.mode') || 'grid';
|
||||
}
|
||||
|
||||
listView() {
|
||||
this.mode = 'list';
|
||||
store.set('grafana.list.layout.mode', 'list');
|
||||
this.$rootScope.appEvent('layout-mode-changed', 'list');
|
||||
this.$rootScope.appEvent(CoreEvents.layoutModeChanged, 'list');
|
||||
}
|
||||
|
||||
gridView() {
|
||||
this.mode = 'grid';
|
||||
store.set('grafana.list.layout.mode', 'grid');
|
||||
this.$rootScope.appEvent('layout-mode-changed', 'grid');
|
||||
this.$rootScope.appEvent(CoreEvents.layoutModeChanged, 'grid');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +48,7 @@ export function layoutSelector() {
|
||||
}
|
||||
|
||||
/** @ngInject */
|
||||
export function layoutMode($rootScope: any) {
|
||||
export function layoutMode($rootScope: GrafanaRootScope) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: {},
|
||||
@@ -56,7 +58,7 @@ export function layoutMode($rootScope: any) {
|
||||
elem.addClass(className);
|
||||
|
||||
$rootScope.onAppEvent(
|
||||
'layout-mode-changed',
|
||||
CoreEvents.layoutModeChanged,
|
||||
(evt: any, newLayout: any) => {
|
||||
elem.removeClass(className);
|
||||
className = 'card-list-layout-' + newLayout;
|
||||
|
||||
@@ -5,6 +5,7 @@ import { SearchSrv } from 'app/core/services/search_srv';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { NavModelSrv } from 'app/core/nav_model_srv';
|
||||
import { ContextSrv } from 'app/core/services/context_srv';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export interface Section {
|
||||
id: number;
|
||||
@@ -200,7 +201,7 @@ export class ManageDashboardsCtrl {
|
||||
text += `selected dashboard${dashCount === 1 ? '' : 's'}?`;
|
||||
}
|
||||
|
||||
appEvents.emit('confirm-modal', {
|
||||
appEvents.emit(CoreEvents.showConfirmModal, {
|
||||
title: 'Delete',
|
||||
text: text,
|
||||
text2: text2,
|
||||
@@ -236,7 +237,7 @@ export class ManageDashboardsCtrl {
|
||||
'<move-to-folder-modal dismiss="dismiss()" ' +
|
||||
'dashboards="model.dashboards" after-save="model.afterSave()">' +
|
||||
'</move-to-folder-modal>';
|
||||
appEvents.emit('show-modal', {
|
||||
appEvents.emit(CoreEvents.showModal, {
|
||||
templateHtml: template,
|
||||
modalClass: 'modal--narrow',
|
||||
model: {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { contextSrv } from 'app/core/services/context_srv';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { parse, SearchParserOptions, SearchParserResult } from 'search-query-parser';
|
||||
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export interface SearchQuery {
|
||||
query: string;
|
||||
@@ -60,9 +61,9 @@ export class SearchCtrl {
|
||||
|
||||
/** @ngInject */
|
||||
constructor($scope: any, private $location: any, private $timeout: any, private searchSrv: SearchSrv) {
|
||||
appEvents.on('show-dash-search', this.openSearch.bind(this), $scope);
|
||||
appEvents.on('hide-dash-search', this.closeSearch.bind(this), $scope);
|
||||
appEvents.on('search-query', debounce(this.search.bind(this), 500), $scope);
|
||||
appEvents.on(CoreEvents.showDashSearch, this.openSearch.bind(this), $scope);
|
||||
appEvents.on(CoreEvents.hideDashSearch, this.closeSearch.bind(this), $scope);
|
||||
appEvents.on(CoreEvents.searchQuery, debounce(this.search.bind(this), 500), $scope);
|
||||
|
||||
this.initialFolderFilterTitle = 'All';
|
||||
this.isEditor = contextSrv.isEditor;
|
||||
@@ -95,7 +96,7 @@ export class SearchCtrl {
|
||||
} else {
|
||||
this.query = query;
|
||||
}
|
||||
appEvents.emit('search-query');
|
||||
appEvents.emit(CoreEvents.searchQuery);
|
||||
}
|
||||
|
||||
openSearch(payload: OpenSearchParams = {}) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import _ from 'lodash';
|
||||
import coreModule from '../../core_module';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export class SearchResultsCtrl {
|
||||
results: any;
|
||||
@@ -65,7 +66,7 @@ export class SearchResultsCtrl {
|
||||
onItemClick(item: any) {
|
||||
//Check if one string can be found in the other
|
||||
if (this.$location.path().indexOf(item.url) > -1 || item.url.indexOf(this.$location.path()) > -1) {
|
||||
appEvents.emit('hide-dash-search');
|
||||
appEvents.emit(CoreEvents.hideDashSearch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import BottomNavLinks from './BottomNavLinks';
|
||||
import appEvents from '../../app_events';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
jest.mock('../../app_events', () => ({
|
||||
emit: jest.fn(),
|
||||
@@ -93,7 +94,7 @@ describe('Functions', () => {
|
||||
const instance = wrapper.instance() as BottomNavLinks;
|
||||
instance.itemClicked(mockEvent as any, child);
|
||||
|
||||
expect(appEvents.emit).toHaveBeenCalledWith('show-modal', { templateHtml: '<help-modal></help-modal>' });
|
||||
expect(appEvents.emit).toHaveBeenCalledWith(CoreEvents.showModal, { templateHtml: '<help-modal></help-modal>' });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { PureComponent } from 'react';
|
||||
import appEvents from '../../app_events';
|
||||
import { User } from '../../services/context_srv';
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export interface Props {
|
||||
link: NavModelItem;
|
||||
@@ -12,14 +13,14 @@ class BottomNavLinks extends PureComponent<Props> {
|
||||
itemClicked = (event: React.SyntheticEvent, child: NavModelItem) => {
|
||||
if (child.url === '/shortcuts') {
|
||||
event.preventDefault();
|
||||
appEvents.emit('show-modal', {
|
||||
appEvents.emit(CoreEvents.showModal, {
|
||||
templateHtml: '<help-modal></help-modal>',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
switchOrg = () => {
|
||||
appEvents.emit('show-modal', {
|
||||
appEvents.emit(CoreEvents.showModal, {
|
||||
templateHtml: '<org-switcher dismiss="dismiss()"></org-switcher>',
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { SideMenu } from './SideMenu';
|
||||
import appEvents from '../../app_events';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
jest.mock('../../app_events', () => ({
|
||||
emit: jest.fn(),
|
||||
@@ -58,7 +59,7 @@ describe('Functions', () => {
|
||||
instance.toggleSideMenuSmallBreakpoint();
|
||||
|
||||
it('should emit toggle sidemenu event', () => {
|
||||
expect(appEvents.emit).toHaveBeenCalledWith('toggle-sidemenu-mobile');
|
||||
expect(appEvents.emit).toHaveBeenCalledWith(CoreEvents.toggleSidemenuMobile);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,12 +3,13 @@ import appEvents from '../../app_events';
|
||||
import TopSection from './TopSection';
|
||||
import BottomSection from './BottomSection';
|
||||
import config from 'app/core/config';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
const homeUrl = config.appSubUrl || '/';
|
||||
|
||||
export class SideMenu extends PureComponent {
|
||||
toggleSideMenuSmallBreakpoint = () => {
|
||||
appEvents.emit('toggle-sidemenu-mobile');
|
||||
appEvents.emit(CoreEvents.toggleSidemenuMobile);
|
||||
};
|
||||
|
||||
render() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import config from 'app/core/config';
|
||||
import coreModule from '../core_module';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export class ErrorCtrl {
|
||||
/** @ngInject */
|
||||
@@ -9,12 +10,12 @@ export class ErrorCtrl {
|
||||
$scope.appSubUrl = config.appSubUrl;
|
||||
|
||||
if (!contextSrv.isSignedIn) {
|
||||
appEvents.emit('toggle-sidemenu-hidden');
|
||||
appEvents.emit(CoreEvents.toggleSidemenuHidden);
|
||||
}
|
||||
|
||||
$scope.$on('destroy', () => {
|
||||
if (!contextSrv.isSignedIn) {
|
||||
appEvents.emit('toggle-sidemenu-hidden');
|
||||
appEvents.emit(CoreEvents.toggleSidemenuHidden);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import coreModule from '../core_module';
|
||||
import config from 'app/core/config';
|
||||
import { BackendSrv } from '../services/backend_srv';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export class ResetPasswordCtrl {
|
||||
/** @ngInject */
|
||||
@@ -41,7 +42,7 @@ export class ResetPasswordCtrl {
|
||||
}
|
||||
|
||||
if ($scope.formModel.newPassword !== $scope.formModel.confirmPassword) {
|
||||
$scope.appEvent('alert-warning', ['New passwords do not match', '']);
|
||||
$scope.appEvent(AppEvents.alertWarning, ['New passwords do not match']);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,14 +25,14 @@ const defaultErrorNotification = {
|
||||
timeout: AppNotificationTimeout.Error,
|
||||
};
|
||||
|
||||
export const createSuccessNotification = (title: string, text?: string): AppNotification => ({
|
||||
export const createSuccessNotification = (title: string, text = ''): AppNotification => ({
|
||||
...defaultSuccessNotification,
|
||||
title: title,
|
||||
text: text,
|
||||
id: Date.now(),
|
||||
});
|
||||
|
||||
export const createErrorNotification = (title: string, text?: any): AppNotification => {
|
||||
export const createErrorNotification = (title: string, text = ''): AppNotification => {
|
||||
return {
|
||||
...defaultErrorNotification,
|
||||
title: title,
|
||||
@@ -41,7 +41,7 @@ export const createErrorNotification = (title: string, text?: any): AppNotificat
|
||||
};
|
||||
};
|
||||
|
||||
export const createWarningNotification = (title: string, text?: string): AppNotification => ({
|
||||
export const createWarningNotification = (title: string, text = ''): AppNotification => ({
|
||||
...defaultWarningNotification,
|
||||
title: title,
|
||||
text: text,
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import angular from 'angular';
|
||||
import coreModule from '../core_module';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export class DeltaCtrl {
|
||||
observer: any;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private $rootScope: any) {
|
||||
constructor(private $rootScope: GrafanaRootScope) {
|
||||
const waitForCompile = (mutations: any) => {
|
||||
if (mutations.length === 1) {
|
||||
this.$rootScope.appEvent('json-diff-ready');
|
||||
this.$rootScope.appEvent(CoreEvents.jsonDiffReady);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -42,7 +44,7 @@ coreModule.directive('diffDelta', delta);
|
||||
// Link to JSON line number
|
||||
export class LinkJSONCtrl {
|
||||
/** @ngInject */
|
||||
constructor(private $scope: any, private $rootScope: any, private $anchorScroll: any) {}
|
||||
constructor(private $scope: any, private $rootScope: GrafanaRootScope, private $anchorScroll: any) {}
|
||||
|
||||
goToLine(line: number) {
|
||||
let unbind: () => void;
|
||||
|
||||
@@ -3,6 +3,7 @@ import Clipboard from 'clipboard';
|
||||
import coreModule from '../core_module';
|
||||
import kbn from 'app/core/utils/kbn';
|
||||
import { appEvents } from 'app/core/core';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
/** @ngInject */
|
||||
function tip($compile: any) {
|
||||
@@ -34,7 +35,7 @@ function clipboardButton() {
|
||||
});
|
||||
|
||||
scope.clipboard.on('success', () => {
|
||||
appEvents.emit('alert-success', ['Content copied to clipboard']);
|
||||
appEvents.emit(AppEvents.alertSuccess, ['Content copied to clipboard']);
|
||||
});
|
||||
|
||||
scope.$on('$destroy', () => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import angular from 'angular';
|
||||
import _ from 'lodash';
|
||||
import coreModule from '../core_module';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
export class ValueSelectDropdownCtrl {
|
||||
dropdownVisible: any;
|
||||
@@ -245,7 +246,7 @@ export class ValueSelectDropdownCtrl {
|
||||
}
|
||||
|
||||
/** @ngInject */
|
||||
export function valueSelectDropdown($compile: any, $window: any, $timeout: any, $rootScope: any) {
|
||||
export function valueSelectDropdown($compile: any, $window: any, $timeout: any, $rootScope: GrafanaRootScope) {
|
||||
return {
|
||||
scope: { dashboard: '=', variable: '=', onUpdated: '&' },
|
||||
templateUrl: 'public/app/partials/valueSelectDropdown.html',
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
export class Profiler {
|
||||
panelsRendered: number;
|
||||
enabled: boolean;
|
||||
$rootScope: any;
|
||||
$rootScope: GrafanaRootScope;
|
||||
window: any;
|
||||
|
||||
init(config: any, $rootScope: any) {
|
||||
init(config: any, $rootScope: GrafanaRootScope) {
|
||||
this.$rootScope = $rootScope;
|
||||
this.window = window;
|
||||
|
||||
|
||||
@@ -7,10 +7,11 @@ import {
|
||||
AngularLoader as AngularLoaderInterface,
|
||||
setAngularLoader as setAngularLoaderInterface,
|
||||
} from '@grafana/runtime';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
export class AngularLoader implements AngularLoaderInterface {
|
||||
/** @ngInject */
|
||||
constructor(private $compile: any, private $rootScope: any) {}
|
||||
constructor(private $compile: any, private $rootScope: GrafanaRootScope) {}
|
||||
|
||||
load(elem: any, scopeProps: any, template: string): AngularComponent {
|
||||
const scope = this.$rootScope.$new();
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import $ from 'jquery';
|
||||
import coreModule from 'app/core/core_module';
|
||||
import config from 'app/core/config';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
export class Analytics {
|
||||
/** @ngInject */
|
||||
constructor(private $rootScope: any, private $location: any) {}
|
||||
constructor(private $rootScope: GrafanaRootScope, private $location: any) {}
|
||||
|
||||
gaInit() {
|
||||
$.ajax({
|
||||
|
||||
@@ -6,8 +6,9 @@ import config from 'app/core/config';
|
||||
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
|
||||
import { DashboardSearchHit } from 'app/types/search';
|
||||
import { ContextSrv } from './context_srv';
|
||||
import { FolderInfo, DashboardDTO } from 'app/types';
|
||||
import { FolderInfo, DashboardDTO, CoreEvents } from 'app/types';
|
||||
import { BackendSrv as BackendService, getBackendSrv as getBackendService, BackendSrvRequest } from '@grafana/runtime';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export class BackendSrv implements BackendService {
|
||||
private inFlightRequests: { [key: string]: Array<angular.IDeferred<any>> } = {};
|
||||
@@ -60,16 +61,10 @@ export class BackendSrv implements BackendService {
|
||||
}
|
||||
|
||||
if (err.status === 422) {
|
||||
appEvents.emit('alert-warning', ['Validation failed', data.message]);
|
||||
appEvents.emit(AppEvents.alertWarning, ['Validation failed', data.message]);
|
||||
throw data;
|
||||
}
|
||||
|
||||
let severity = 'error';
|
||||
|
||||
if (err.status < 500) {
|
||||
severity = 'warning';
|
||||
}
|
||||
|
||||
if (data.message) {
|
||||
let description = '';
|
||||
let message = data.message;
|
||||
@@ -78,7 +73,7 @@ export class BackendSrv implements BackendService {
|
||||
message = 'Error';
|
||||
}
|
||||
|
||||
appEvents.emit('alert-' + severity, [message, description]);
|
||||
appEvents.emit(err.status < 500 ? AppEvents.alertWarning : AppEvents.alertError, [message, description]);
|
||||
}
|
||||
|
||||
throw data;
|
||||
@@ -105,7 +100,7 @@ export class BackendSrv implements BackendService {
|
||||
if (options.method !== 'GET') {
|
||||
if (results && results.data.message) {
|
||||
if (options.showSuccessAlert !== false) {
|
||||
appEvents.emit('alert-success', [results.data.message]);
|
||||
appEvents.emit(AppEvents.alertSuccess, [results.data.message]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,7 +187,7 @@ export class BackendSrv implements BackendService {
|
||||
return this.$http(options)
|
||||
.then((response: any) => {
|
||||
if (!options.silent) {
|
||||
appEvents.emit('ds-request-response', response);
|
||||
appEvents.emit(CoreEvents.dsRequestResponse, response);
|
||||
}
|
||||
return response;
|
||||
})
|
||||
@@ -232,7 +227,7 @@ export class BackendSrv implements BackendService {
|
||||
err.data.message = err.data.error;
|
||||
}
|
||||
if (!options.silent) {
|
||||
appEvents.emit('ds-request-error', err);
|
||||
appEvents.emit(CoreEvents.dsRequestError, err);
|
||||
}
|
||||
throw err;
|
||||
})
|
||||
|
||||
@@ -3,7 +3,9 @@ import appEvents from 'app/core/app_events';
|
||||
import { store } from 'app/store/store';
|
||||
import locationUtil from 'app/core/utils/location_util';
|
||||
import { updateLocation } from 'app/core/actions';
|
||||
import { ITimeoutService, ILocationService, IWindowService, IRootScopeService } from 'angular';
|
||||
import { ITimeoutService, ILocationService, IWindowService } from 'angular';
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
// Services that handles angular -> redux store sync & other react <-> angular sync
|
||||
export class BridgeSrv {
|
||||
@@ -14,7 +16,7 @@ export class BridgeSrv {
|
||||
private $location: ILocationService,
|
||||
private $timeout: ITimeoutService,
|
||||
private $window: IWindowService,
|
||||
private $rootScope: IRootScopeService,
|
||||
private $rootScope: GrafanaRootScope,
|
||||
private $route: any
|
||||
) {
|
||||
this.fullPageReloadRoutes = ['/logout'];
|
||||
@@ -62,7 +64,7 @@ export class BridgeSrv {
|
||||
}
|
||||
});
|
||||
|
||||
appEvents.on('location-change', (payload: any) => {
|
||||
appEvents.on(CoreEvents.locationChange, payload => {
|
||||
const urlWithoutBase = locationUtil.stripBaseFromUrl(payload.href);
|
||||
if (this.fullPageReloadRoutes.indexOf(urlWithoutBase) > -1) {
|
||||
this.$window.location.href = payload.href;
|
||||
|
||||
@@ -5,11 +5,14 @@ import appEvents from 'app/core/app_events';
|
||||
import { getExploreUrl } from 'app/core/utils/explore';
|
||||
import locationUtil from 'app/core/utils/location_util';
|
||||
import { store } from 'app/store/store';
|
||||
import { CoreEvents, AppEventEmitter } from 'app/types';
|
||||
|
||||
import Mousetrap from 'mousetrap';
|
||||
import { PanelEvents } from '@grafana/ui';
|
||||
import 'mousetrap-global-bind';
|
||||
import { ContextSrv } from './context_srv';
|
||||
import { ILocationService, ITimeoutService } from 'angular';
|
||||
import { ILocationService, ITimeoutService, IRootScopeService } from 'angular';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
export class KeybindingSrv {
|
||||
helpModal: boolean;
|
||||
@@ -18,7 +21,7 @@ export class KeybindingSrv {
|
||||
|
||||
/** @ngInject */
|
||||
constructor(
|
||||
private $rootScope: any,
|
||||
private $rootScope: GrafanaRootScope,
|
||||
private $location: ILocationService,
|
||||
private $timeout: ITimeoutService,
|
||||
private datasourceSrv: any,
|
||||
@@ -33,9 +36,9 @@ export class KeybindingSrv {
|
||||
});
|
||||
|
||||
this.setupGlobal();
|
||||
appEvents.on('show-modal', () => (this.modalOpen = true));
|
||||
appEvents.on('timepickerOpen', () => (this.timepickerOpen = true));
|
||||
appEvents.on('timepickerClosed', () => (this.timepickerOpen = false));
|
||||
appEvents.on(CoreEvents.showModal, () => (this.modalOpen = true));
|
||||
appEvents.on(CoreEvents.timepickerOpen, () => (this.timepickerOpen = true));
|
||||
appEvents.on(CoreEvents.timepickerClosed, () => (this.timepickerOpen = false));
|
||||
}
|
||||
|
||||
setupGlobal() {
|
||||
@@ -78,7 +81,7 @@ export class KeybindingSrv {
|
||||
}
|
||||
|
||||
openSearch() {
|
||||
appEvents.emit('show-dash-search');
|
||||
appEvents.emit(CoreEvents.showDashSearch);
|
||||
}
|
||||
|
||||
openAlerting() {
|
||||
@@ -94,11 +97,11 @@ export class KeybindingSrv {
|
||||
}
|
||||
|
||||
showHelpModal() {
|
||||
appEvents.emit('show-modal', { templateHtml: '<help-modal></help-modal>' });
|
||||
appEvents.emit(CoreEvents.showModal, { templateHtml: '<help-modal></help-modal>' });
|
||||
}
|
||||
|
||||
exit() {
|
||||
appEvents.emit('hide-modal');
|
||||
appEvents.emit(CoreEvents.hideModal);
|
||||
|
||||
if (this.modalOpen) {
|
||||
this.modalOpen = false;
|
||||
@@ -106,7 +109,7 @@ export class KeybindingSrv {
|
||||
}
|
||||
|
||||
if (this.timepickerOpen) {
|
||||
this.$rootScope.appEvent('closeTimepicker');
|
||||
this.$rootScope.appEvent(CoreEvents.closeTimepicker);
|
||||
this.timepickerOpen = false;
|
||||
return;
|
||||
}
|
||||
@@ -120,12 +123,12 @@ export class KeybindingSrv {
|
||||
}
|
||||
|
||||
if (search.fullscreen) {
|
||||
appEvents.emit('panel-change-view', { fullscreen: false, edit: false });
|
||||
appEvents.emit(PanelEvents.panelChangeView, { fullscreen: false, edit: false });
|
||||
return;
|
||||
}
|
||||
|
||||
if (search.kiosk) {
|
||||
this.$rootScope.appEvent('toggle-kiosk-mode', { exit: true });
|
||||
this.$rootScope.appEvent(CoreEvents.toggleKioskMode, { exit: true });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,37 +167,37 @@ export class KeybindingSrv {
|
||||
this.$location.search(search);
|
||||
}
|
||||
|
||||
setupDashboardBindings(scope: any, dashboard: any) {
|
||||
setupDashboardBindings(scope: IRootScopeService & AppEventEmitter, dashboard: any) {
|
||||
this.bind('mod+o', () => {
|
||||
dashboard.graphTooltip = (dashboard.graphTooltip + 1) % 3;
|
||||
appEvents.emit('graph-hover-clear');
|
||||
appEvents.emit(CoreEvents.graphHoverClear);
|
||||
dashboard.startRefresh();
|
||||
});
|
||||
|
||||
this.bind('mod+s', () => {
|
||||
scope.appEvent('save-dashboard');
|
||||
scope.appEvent(CoreEvents.saveDashboard);
|
||||
});
|
||||
|
||||
this.bind('t z', () => {
|
||||
scope.appEvent('zoom-out', 2);
|
||||
scope.appEvent(CoreEvents.zoomOut, 2);
|
||||
});
|
||||
|
||||
this.bind('ctrl+z', () => {
|
||||
scope.appEvent('zoom-out', 2);
|
||||
scope.appEvent(CoreEvents.zoomOut, 2);
|
||||
});
|
||||
|
||||
this.bind('t left', () => {
|
||||
scope.appEvent('shift-time', -1);
|
||||
scope.appEvent(CoreEvents.shiftTime, -1);
|
||||
});
|
||||
|
||||
this.bind('t right', () => {
|
||||
scope.appEvent('shift-time', 1);
|
||||
scope.appEvent(CoreEvents.shiftTime, 1);
|
||||
});
|
||||
|
||||
// edit panel
|
||||
this.bind('e', () => {
|
||||
if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) {
|
||||
appEvents.emit('panel-change-view', {
|
||||
appEvents.emit(PanelEvents.panelChangeView, {
|
||||
fullscreen: true,
|
||||
edit: true,
|
||||
panelId: dashboard.meta.focusPanelId,
|
||||
@@ -206,7 +209,7 @@ export class KeybindingSrv {
|
||||
// view panel
|
||||
this.bind('v', () => {
|
||||
if (dashboard.meta.focusPanelId) {
|
||||
appEvents.emit('panel-change-view', {
|
||||
appEvents.emit(PanelEvents.panelChangeView, {
|
||||
fullscreen: true,
|
||||
panelId: dashboard.meta.focusPanelId,
|
||||
toggle: true,
|
||||
@@ -233,7 +236,7 @@ export class KeybindingSrv {
|
||||
// delete panel
|
||||
this.bind('p r', () => {
|
||||
if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) {
|
||||
appEvents.emit('remove-panel', dashboard.meta.focusPanelId);
|
||||
appEvents.emit(CoreEvents.removePanel, dashboard.meta.focusPanelId);
|
||||
dashboard.meta.focusPanelId = 0;
|
||||
}
|
||||
});
|
||||
@@ -249,12 +252,12 @@ export class KeybindingSrv {
|
||||
// share panel
|
||||
this.bind('p s', () => {
|
||||
if (dashboard.meta.focusPanelId) {
|
||||
const shareScope = scope.$new();
|
||||
const shareScope: any = scope.$new();
|
||||
const panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId);
|
||||
shareScope.panel = panelInfo.panel;
|
||||
shareScope.dashboard = dashboard;
|
||||
|
||||
appEvents.emit('show-modal', {
|
||||
appEvents.emit(CoreEvents.showModal, {
|
||||
src: 'public/app/features/dashboard/components/ShareModal/template.html',
|
||||
scope: shareScope,
|
||||
});
|
||||
@@ -301,11 +304,11 @@ export class KeybindingSrv {
|
||||
});
|
||||
|
||||
this.bind('d k', () => {
|
||||
appEvents.emit('toggle-kiosk-mode');
|
||||
appEvents.emit(CoreEvents.toggleKioskMode);
|
||||
});
|
||||
|
||||
this.bind('d v', () => {
|
||||
appEvents.emit('toggle-view-mode');
|
||||
appEvents.emit(CoreEvents.toggleViewMode);
|
||||
});
|
||||
|
||||
//Autofit panels
|
||||
|
||||
@@ -2,9 +2,10 @@ import _ from 'lodash';
|
||||
import coreModule from 'app/core/core_module';
|
||||
// @ts-ignore
|
||||
import Drop from 'tether-drop';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
/** @ngInject */
|
||||
function popoverSrv(this: any, $compile: any, $rootScope: any, $timeout: any) {
|
||||
function popoverSrv(this: any, $compile: any, $rootScope: GrafanaRootScope, $timeout: any) {
|
||||
let openDrop: any = null;
|
||||
|
||||
this.close = () => {
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import coreModule from 'app/core/core_module';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
export class UtilSrv {
|
||||
modalScope: any;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private $rootScope: any, private $modal: any) {}
|
||||
constructor(private $rootScope: GrafanaRootScope, private $modal: any) {}
|
||||
|
||||
init() {
|
||||
appEvents.on('show-modal', this.showModal.bind(this), this.$rootScope);
|
||||
appEvents.on('hide-modal', this.hideModal.bind(this), this.$rootScope);
|
||||
appEvents.on('confirm-modal', this.showConfirmModal.bind(this), this.$rootScope);
|
||||
appEvents.on(CoreEvents.showModal, this.showModal.bind(this), this.$rootScope);
|
||||
appEvents.on(CoreEvents.hideModal, this.hideModal.bind(this), this.$rootScope);
|
||||
appEvents.on(CoreEvents.showConfirmModal, this.showConfirmModal.bind(this), this.$rootScope);
|
||||
}
|
||||
|
||||
hideModal() {
|
||||
@@ -50,7 +52,7 @@ export class UtilSrv {
|
||||
}
|
||||
|
||||
showConfirmModal(payload: any) {
|
||||
const scope = this.$rootScope.$new();
|
||||
const scope: any = this.$rootScope.$new();
|
||||
|
||||
scope.updateConfirmText = (value: any) => {
|
||||
scope.confirmTextValid = payload.confirmText.toLowerCase() === value.toLowerCase();
|
||||
@@ -70,7 +72,7 @@ export class UtilSrv {
|
||||
scope.noText = payload.noText || 'Cancel';
|
||||
scope.confirmTextValid = scope.confirmText ? false : true;
|
||||
|
||||
appEvents.emit('show-modal', {
|
||||
appEvents.emit(CoreEvents.showModal, {
|
||||
src: 'public/app/partials/confirm_modal.html',
|
||||
scope: scope,
|
||||
modalClass: 'confirm-modal',
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { Emitter } from '../utils/emitter';
|
||||
import { eventFactory } from '@grafana/data';
|
||||
|
||||
const testEvent = eventFactory('test');
|
||||
|
||||
describe('Emitter', () => {
|
||||
describe('given 2 subscribers', () => {
|
||||
@@ -7,14 +10,14 @@ describe('Emitter', () => {
|
||||
let sub1Called = false;
|
||||
let sub2Called = false;
|
||||
|
||||
events.on('test', () => {
|
||||
events.on(testEvent, () => {
|
||||
sub1Called = true;
|
||||
});
|
||||
events.on('test', () => {
|
||||
events.on(testEvent, () => {
|
||||
sub2Called = true;
|
||||
});
|
||||
|
||||
events.emit('test', null);
|
||||
events.emit(testEvent, null);
|
||||
|
||||
expect(sub1Called).toBe(true);
|
||||
expect(sub2Called).toBe(true);
|
||||
@@ -28,10 +31,10 @@ describe('Emitter', () => {
|
||||
sub1Called += 1;
|
||||
}
|
||||
|
||||
events.on('test', handler);
|
||||
events.on('test', handler);
|
||||
events.on(testEvent, handler);
|
||||
events.on(testEvent, handler);
|
||||
|
||||
events.emit('test', null);
|
||||
events.emit(testEvent, null);
|
||||
|
||||
expect(sub1Called).toBe(2);
|
||||
});
|
||||
@@ -41,20 +44,20 @@ describe('Emitter', () => {
|
||||
let sub1Called = 0;
|
||||
let sub2Called = 0;
|
||||
|
||||
events.on('test', () => {
|
||||
events.on(testEvent, () => {
|
||||
sub1Called++;
|
||||
throw { message: 'hello' };
|
||||
});
|
||||
|
||||
events.on('test', () => {
|
||||
events.on(testEvent, () => {
|
||||
sub2Called++;
|
||||
});
|
||||
|
||||
try {
|
||||
events.emit('test', null);
|
||||
events.emit(testEvent, null);
|
||||
} catch (_) {}
|
||||
try {
|
||||
events.emit('test', null);
|
||||
events.emit(testEvent, null);
|
||||
} catch (_) {}
|
||||
|
||||
expect(sub1Called).toBe(2);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { SearchResultsCtrl } from '../components/search/search_results';
|
||||
import { beforeEach, afterEach } from 'test/lib/common';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
jest.mock('app/core/app_events', () => {
|
||||
return {
|
||||
@@ -121,7 +122,7 @@ describe('SearchResultsCtrl', () => {
|
||||
|
||||
it('should close the search', () => {
|
||||
expect(appEventsMock.emit.mock.calls.length).toBe(1);
|
||||
expect(appEventsMock.emit.mock.calls[0][0]).toBe('hide-dash-search');
|
||||
expect(appEventsMock.emit.mock.calls[0][0]).toBe(CoreEvents.hideDashSearch);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import { AppEvent } from '@grafana/data';
|
||||
|
||||
export class Emitter {
|
||||
private emitter: EventEmitter;
|
||||
@@ -7,29 +8,83 @@ export class Emitter {
|
||||
this.emitter = new EventEmitter();
|
||||
}
|
||||
|
||||
emit(name: string, data?: any) {
|
||||
this.emitter.emit(name, data);
|
||||
/**
|
||||
* DEPRECATED.
|
||||
*/
|
||||
emit(name: string, data?: any): void;
|
||||
|
||||
/**
|
||||
* Emits an `event` with `payload`.
|
||||
*/
|
||||
emit<T extends undefined>(event: AppEvent<T>): void;
|
||||
emit<T extends Partial<T> extends T ? Partial<T> : never>(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.log(`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);
|
||||
}
|
||||
}
|
||||
|
||||
on(name: string, handler: (payload?: any) => void, scope?: any) {
|
||||
this.emitter.on(name, handler);
|
||||
/**
|
||||
* 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 Partial<T> extends T ? Partial<T> : never>(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.log(`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(name, handler);
|
||||
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 Partial<T> extends T ? Partial<T> : never>(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.log(`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);
|
||||
}
|
||||
|
||||
off(name: string, handler: (payload?: any) => void) {
|
||||
this.emitter.off(name, handler);
|
||||
}
|
||||
|
||||
getEventCount(): number {
|
||||
return (this.emitter as any)._eventsCount;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user