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:
parent
e7c37cc316
commit
99411bf37a
4
packages/grafana-data/src/types/appEvent.ts
Normal file
4
packages/grafana-data/src/types/appEvent.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface AppEvent<T> {
|
||||
readonly name: string;
|
||||
payload?: T;
|
||||
}
|
7
packages/grafana-data/src/types/events.ts
Normal file
7
packages/grafana-data/src/types/events.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { eventFactory } from './utils';
|
||||
|
||||
export type AlertPayload = [string, string?];
|
||||
|
||||
export const alertSuccess = eventFactory<AlertPayload>('alert-success');
|
||||
export const alertWarning = eventFactory<AlertPayload>('alert-warning');
|
||||
export const alertError = eventFactory<AlertPayload>('alert-error');
|
@ -13,3 +13,7 @@ export * from './graph';
|
||||
export * from './ScopedVars';
|
||||
export * from './transformations';
|
||||
export * from './vector';
|
||||
export * from './appEvent';
|
||||
|
||||
import * as AppEvents from './events';
|
||||
export { AppEvents };
|
||||
|
@ -1,2 +1,14 @@
|
||||
import { AppEvent } from './appEvent';
|
||||
|
||||
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();
|
||||
export function eventFactory<T = undefined>(name: string): AppEvent<T> {
|
||||
if (typeList.has(name)) {
|
||||
throw new Error(`There is already an event defined with type '${name}'`);
|
||||
}
|
||||
|
||||
typeList.add(name);
|
||||
return { name };
|
||||
}
|
||||
|
34
packages/grafana-ui/src/types/events.ts
Normal file
34
packages/grafana-ui/src/types/events.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { eventFactory } from '@grafana/data';
|
||||
import { DataQueryResponseData, DataQueryError } from '.';
|
||||
|
||||
/** Payloads */
|
||||
|
||||
export interface PanelChangeViewPayload {
|
||||
fullscreen?: boolean;
|
||||
edit?: boolean;
|
||||
panelId?: number;
|
||||
toggle?: boolean;
|
||||
}
|
||||
|
||||
export interface MenuElement {
|
||||
text: string;
|
||||
click: string;
|
||||
role?: string;
|
||||
shortcut?: string;
|
||||
}
|
||||
|
||||
/** 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 dataSnapshotLoad = eventFactory<DataQueryResponseData[]>('data-snapshot-load');
|
||||
export const editModeInitialized = eventFactory('init-edit-mode');
|
||||
export const initPanelActions = eventFactory<MenuElement[]>('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');
|
@ -4,3 +4,6 @@ export * from './app';
|
||||
export * from './datasource';
|
||||
export * from './theme';
|
||||
export * from './input';
|
||||
|
||||
import * as PanelEvents from './events';
|
||||
export { PanelEvents };
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1,13 +1,19 @@
|
||||
import _ from 'lodash';
|
||||
import { dateTime } from '@grafana/data';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { NavModelSrv } from 'app/core/core';
|
||||
import { User } from 'app/core/services/context_srv';
|
||||
import { UserSession } from 'app/types';
|
||||
import { UserSession, Scope, CoreEvents, AppEventEmitter } from 'app/types';
|
||||
import { dateTime } from '@grafana/data';
|
||||
|
||||
export default class AdminEditUserCtrl {
|
||||
/** @ngInject */
|
||||
constructor($scope: any, $routeParams: any, backendSrv: BackendSrv, $location: any, navModelSrv: NavModelSrv) {
|
||||
constructor(
|
||||
$scope: Scope & AppEventEmitter,
|
||||
$routeParams: any,
|
||||
backendSrv: BackendSrv,
|
||||
$location: any,
|
||||
navModelSrv: NavModelSrv
|
||||
) {
|
||||
$scope.user = {};
|
||||
$scope.sessions = [];
|
||||
$scope.newOrg = { name: '', role: 'Editor' };
|
||||
@ -162,7 +168,7 @@ export default class AdminEditUserCtrl {
|
||||
};
|
||||
|
||||
$scope.deleteUser = (user: any) => {
|
||||
$scope.appEvent('confirm-modal', {
|
||||
$scope.appEvent(CoreEvents.showConfirmModal, {
|
||||
title: 'Delete',
|
||||
text: 'Do you want to delete ' + user.login + '?',
|
||||
icon: 'fa-trash',
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { NavModelSrv } from 'app/core/core';
|
||||
import { Scope, CoreEvents, AppEventEmitter } from 'app/types';
|
||||
|
||||
export default class AdminListOrgsCtrl {
|
||||
/** @ngInject */
|
||||
constructor($scope: any, backendSrv: BackendSrv, navModelSrv: NavModelSrv) {
|
||||
constructor($scope: Scope & AppEventEmitter, backendSrv: BackendSrv, navModelSrv: NavModelSrv) {
|
||||
$scope.init = () => {
|
||||
$scope.navModel = navModelSrv.getNav('admin', 'global-orgs', 0);
|
||||
$scope.getOrgs();
|
||||
@ -16,9 +17,9 @@ export default class AdminListOrgsCtrl {
|
||||
};
|
||||
|
||||
$scope.deleteOrg = (org: any) => {
|
||||
$scope.appEvent('confirm-modal', {
|
||||
$scope.appEvent(CoreEvents.showConfirmModal, {
|
||||
title: 'Delete',
|
||||
text: 'Do you want to delete organization ' + org.name + '?',
|
||||
text: `Do you want to delete organization ${org.name}?`,
|
||||
text2: 'All dashboards for this organization will be removed!',
|
||||
icon: 'fa-trash',
|
||||
yesText: 'Delete',
|
||||
|
@ -6,6 +6,7 @@ import appEvents from '../../core/app_events';
|
||||
import { mockActionCreator } from 'app/core/redux';
|
||||
import { updateLocation } from 'app/core/actions';
|
||||
import { NavModel } from '@grafana/data';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
jest.mock('../../core/app_events', () => ({
|
||||
emit: jest.fn(),
|
||||
@ -139,7 +140,7 @@ describe('Functions', () => {
|
||||
|
||||
instance.onOpenHowTo();
|
||||
|
||||
expect(appEvents.emit).toHaveBeenCalledWith('show-modal', {
|
||||
expect(appEvents.emit).toHaveBeenCalledWith(CoreEvents.showModal, {
|
||||
src: 'public/app/features/alerting/partials/alert_howto.html',
|
||||
modalClass: 'confirm-modal',
|
||||
model: {},
|
||||
|
@ -6,7 +6,7 @@ import AlertRuleItem from './AlertRuleItem';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { updateLocation } from 'app/core/actions';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { StoreState, AlertRule } from 'app/types';
|
||||
import { StoreState, AlertRule, CoreEvents } from 'app/types';
|
||||
import { getAlertRulesAsync, setSearchQuery, togglePauseAlertRule } from './state/actions';
|
||||
import { getAlertRuleItems, getSearchQuery } from './state/selectors';
|
||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
||||
@ -64,7 +64,7 @@ export class AlertRuleList extends PureComponent<Props, any> {
|
||||
};
|
||||
|
||||
onOpenHowTo = () => {
|
||||
appEvents.emit('show-modal', {
|
||||
appEvents.emit(CoreEvents.showModal, {
|
||||
src: 'public/app/features/alerting/partials/alert_howto.html',
|
||||
modalClass: 'confirm-modal',
|
||||
model: {},
|
||||
|
@ -19,6 +19,7 @@ import { TestRuleResult } from './TestRuleResult';
|
||||
import { AppNotificationSeverity, StoreState } from 'app/types';
|
||||
import { PanelEditorTabIds, getPanelEditorTab } from '../dashboard/panel_editor/state/reducers';
|
||||
import { changePanelEditorTab } from '../dashboard/panel_editor/state/actions';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
interface Props {
|
||||
angularPanel?: AngularComponent;
|
||||
@ -116,7 +117,7 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
|
||||
title: 'Delete',
|
||||
btnType: 'danger',
|
||||
onClick: () => {
|
||||
appEvents.emit('confirm-modal', {
|
||||
appEvents.emit(CoreEvents.showConfirmModal, {
|
||||
title: 'Delete Alert',
|
||||
text: 'Are you sure you want to delete this alert rule?',
|
||||
text2: 'You need to save dashboard for the delete to take effect',
|
||||
|
@ -11,6 +11,7 @@ import DatasourceSrv from '../plugins/datasource_srv';
|
||||
import { DataQuery } from '@grafana/ui/src/types/datasource';
|
||||
import { PanelModel } from 'app/features/dashboard/state';
|
||||
import { getDefaultCondition } from './getAlertingValidationMessage';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export class AlertTabCtrl {
|
||||
panel: PanelModel;
|
||||
@ -58,11 +59,11 @@ export class AlertTabCtrl {
|
||||
|
||||
// subscribe to graph threshold handle changes
|
||||
const thresholdChangedEventHandler = this.graphThresholdChanged.bind(this);
|
||||
this.panelCtrl.events.on('threshold-changed', thresholdChangedEventHandler);
|
||||
this.panelCtrl.events.on(CoreEvents.thresholdChanged, thresholdChangedEventHandler);
|
||||
|
||||
// set panel alert edit mode
|
||||
this.$scope.$on('$destroy', () => {
|
||||
this.panelCtrl.events.off('threshold-changed', thresholdChangedEventHandler);
|
||||
this.panelCtrl.events.off(CoreEvents.thresholdChanged, thresholdChangedEventHandler);
|
||||
this.panelCtrl.editingThresholds = false;
|
||||
this.panelCtrl.render();
|
||||
});
|
||||
@ -352,7 +353,7 @@ export class AlertTabCtrl {
|
||||
}
|
||||
|
||||
delete() {
|
||||
appEvents.emit('confirm-modal', {
|
||||
appEvents.emit(CoreEvents.showConfirmModal, {
|
||||
title: 'Delete Alert',
|
||||
text: 'Are you sure you want to delete this alert rule?',
|
||||
text2: 'You need to save dashboard for the delete to take effect',
|
||||
@ -402,7 +403,7 @@ export class AlertTabCtrl {
|
||||
}
|
||||
|
||||
clearHistory() {
|
||||
appEvents.emit('confirm-modal', {
|
||||
appEvents.emit(CoreEvents.showConfirmModal, {
|
||||
title: 'Delete Alert History',
|
||||
text: 'Are you sure you want to remove all history & annotations for this alert?',
|
||||
icon: 'fa-trash',
|
||||
|
@ -1,6 +1,7 @@
|
||||
import _ from 'lodash';
|
||||
import { appEvents, coreModule, NavModelSrv } from 'app/core/core';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export class AlertNotificationEditCtrl {
|
||||
theForm: any;
|
||||
@ -78,23 +79,23 @@ export class AlertNotificationEditCtrl {
|
||||
.put(`/api/alert-notifications/${this.model.id}`, this.model)
|
||||
.then((res: any) => {
|
||||
this.model = res;
|
||||
appEvents.emit('alert-success', ['Notification updated', '']);
|
||||
appEvents.emit(AppEvents.alertSuccess, ['Notification updated']);
|
||||
})
|
||||
.catch((err: any) => {
|
||||
if (err.data && err.data.error) {
|
||||
appEvents.emit('alert-error', [err.data.error]);
|
||||
appEvents.emit(AppEvents.alertError, [err.data.error]);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.backendSrv
|
||||
.post(`/api/alert-notifications`, this.model)
|
||||
.then((res: any) => {
|
||||
appEvents.emit('alert-success', ['Notification created', '']);
|
||||
appEvents.emit(AppEvents.alertSuccess, ['Notification created']);
|
||||
this.$location.path('alerting/notifications');
|
||||
})
|
||||
.catch((err: any) => {
|
||||
if (err.data && err.data.error) {
|
||||
appEvents.emit('alert-error', [err.data.error]);
|
||||
appEvents.emit(AppEvents.alertError, [err.data.error]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import alertDef from './state/alertDef';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import { DashboardModel } from '../dashboard/state/DashboardModel';
|
||||
import appEvents from '../../core/app_events';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
interface Props {
|
||||
dashboard: DashboardModel;
|
||||
@ -42,7 +43,7 @@ class StateHistory extends PureComponent<Props, State> {
|
||||
clearHistory = () => {
|
||||
const { dashboard, onRefresh, panelId } = this.props;
|
||||
|
||||
appEvents.emit('confirm-modal', {
|
||||
appEvents.emit(CoreEvents.showConfirmModal, {
|
||||
title: 'Delete Alert History',
|
||||
text: 'Are you sure you want to remove all history & annotations for this alert?',
|
||||
icon: 'fa-trash',
|
||||
|
@ -5,6 +5,7 @@ import appEvents from 'app/core/app_events';
|
||||
import { CopyToClipboard } from 'app/core/components/CopyToClipboard/CopyToClipboard';
|
||||
import { DashboardModel } from '../dashboard/state/DashboardModel';
|
||||
import { getBackendSrv, BackendSrv } from '@grafana/runtime';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export interface Props {
|
||||
panelId: number;
|
||||
@ -55,7 +56,7 @@ export class TestRuleResult extends PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
onClipboardSuccess = () => {
|
||||
appEvents.emit('alert-success', ['Content copied to clipboard']);
|
||||
appEvents.emit(AppEvents.alertSuccess, ['Content copied to clipboard']);
|
||||
};
|
||||
|
||||
onToggleExpand = () => {
|
||||
|
@ -11,11 +11,12 @@ import { dedupAnnotations } from './events_processing';
|
||||
|
||||
// Types
|
||||
import { DashboardModel } from '../dashboard/state/DashboardModel';
|
||||
import { AnnotationEvent } from '@grafana/data';
|
||||
import DatasourceSrv from '../plugins/datasource_srv';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { TimeSrv } from '../dashboard/services/TimeSrv';
|
||||
import { DataSourceApi } from '@grafana/ui';
|
||||
import { DataSourceApi, PanelEvents } from '@grafana/ui';
|
||||
import { AnnotationEvent, AppEvents } from '@grafana/data';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
export class AnnotationsSrv {
|
||||
globalAnnotationsPromise: any;
|
||||
@ -24,7 +25,7 @@ export class AnnotationsSrv {
|
||||
|
||||
/** @ngInject */
|
||||
constructor(
|
||||
private $rootScope: any,
|
||||
private $rootScope: GrafanaRootScope,
|
||||
private $q: IQService,
|
||||
private datasourceSrv: DatasourceSrv,
|
||||
private backendSrv: BackendSrv,
|
||||
@ -35,7 +36,7 @@ export class AnnotationsSrv {
|
||||
// always clearPromiseCaches when loading new dashboard
|
||||
this.clearPromiseCaches();
|
||||
// clear promises on refresh events
|
||||
dashboard.on('refresh', this.clearPromiseCaches.bind(this));
|
||||
dashboard.on(PanelEvents.refresh, this.clearPromiseCaches.bind(this));
|
||||
}
|
||||
|
||||
clearPromiseCaches() {
|
||||
@ -75,7 +76,7 @@ export class AnnotationsSrv {
|
||||
err.message = err.data.message;
|
||||
}
|
||||
console.log('AnnotationSrv.query error', err);
|
||||
this.$rootScope.appEvent('alert-error', ['Annotation Query Failed', err.message || err]);
|
||||
this.$rootScope.appEvent(AppEvents.alertError, ['Annotation Query Failed', err.message || err]);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import coreModule from 'app/core/core_module';
|
||||
import { DashboardModel } from 'app/features/dashboard/state';
|
||||
import DatasourceSrv from '../plugins/datasource_srv';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export class AnnotationsEditorCtrl {
|
||||
mode: any;
|
||||
@ -103,7 +104,7 @@ export class AnnotationsEditorCtrl {
|
||||
add() {
|
||||
const sameName: any = _.find(this.annotations, { name: this.currentAnnotation.name });
|
||||
if (sameName) {
|
||||
appEvents.emit('alert-warning', ['Validation', 'Annotations with the same name already exists']);
|
||||
appEvents.emit(AppEvents.alertWarning, ['Validation', 'Annotations with the same name already exists']);
|
||||
return;
|
||||
}
|
||||
this.annotations.push(this.currentAnnotation);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { AnnotationsSrv } from '../annotations_srv';
|
||||
|
||||
describe('AnnotationsSrv', () => {
|
||||
const $rootScope = {
|
||||
const $rootScope: any = {
|
||||
onAppEvent: jest.fn(),
|
||||
};
|
||||
|
||||
|
@ -13,13 +13,13 @@ import config from 'app/core/config';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||
import { DeleteButton, EventsWithValidation, FormLabel, Input, ValidationEvents } from '@grafana/ui';
|
||||
import { NavModel } from '@grafana/data';
|
||||
import { NavModel, dateTime, isDateTime } from '@grafana/data';
|
||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
||||
import { store } from 'app/store/store';
|
||||
import kbn from 'app/core/utils/kbn';
|
||||
|
||||
// Utils
|
||||
import { dateTime, isDateTime } from '@grafana/data';
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { getTimeZone } from 'app/features/profile/state/selectors';
|
||||
|
||||
const timeRangeValidationEvents: ValidationEvents = {
|
||||
@ -106,7 +106,7 @@ export class ApiKeysPage extends PureComponent<Props, any> {
|
||||
const rootPath = window.location.origin + config.appSubUrl;
|
||||
const modalTemplate = ReactDOMServer.renderToString(<ApiKeysAddedModal apiKey={apiKey} rootPath={rootPath} />);
|
||||
|
||||
appEvents.emit('show-modal', {
|
||||
appEvents.emit(CoreEvents.showModal, {
|
||||
templateHtml: modalTemplate,
|
||||
});
|
||||
};
|
||||
|
@ -4,6 +4,7 @@ import coreModule from 'app/core/core_module';
|
||||
import { DashboardModel } from 'app/features/dashboard/state';
|
||||
import DatasourceSrv from 'app/features/plugins/datasource_srv';
|
||||
import { VariableSrv } from 'app/features/templating/all';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export class AdHocFiltersCtrl {
|
||||
segments: any;
|
||||
@ -24,7 +25,7 @@ export class AdHocFiltersCtrl {
|
||||
value: '-- remove filter --',
|
||||
});
|
||||
this.buildSegmentModel();
|
||||
this.dashboard.events.on('template-variable-value-updated', this.buildSegmentModel.bind(this), $scope);
|
||||
this.dashboard.events.on(CoreEvents.templateVariableValueUpdated, this.buildSegmentModel.bind(this), $scope);
|
||||
}
|
||||
|
||||
buildSegmentModel() {
|
||||
|
@ -5,6 +5,8 @@ import coreModule from 'app/core/core_module';
|
||||
import { DashboardExporter } from './DashboardExporter';
|
||||
import { DashboardSrv } from '../../services/DashboardSrv';
|
||||
import DatasourceSrv from 'app/features/plugins/datasource_srv';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export class DashExportCtrl {
|
||||
dash: any;
|
||||
@ -17,7 +19,7 @@ export class DashExportCtrl {
|
||||
private dashboardSrv: DashboardSrv,
|
||||
datasourceSrv: DatasourceSrv,
|
||||
private $scope: any,
|
||||
private $rootScope: any
|
||||
private $rootScope: GrafanaRootScope
|
||||
) {
|
||||
this.exporter = new DashboardExporter(datasourceSrv);
|
||||
|
||||
@ -61,7 +63,7 @@ export class DashExportCtrl {
|
||||
enableCopy: true,
|
||||
};
|
||||
|
||||
this.$rootScope.appEvent('show-modal', {
|
||||
this.$rootScope.appEvent(CoreEvents.showModal, {
|
||||
src: 'public/app/partials/edit_json.html',
|
||||
model: model,
|
||||
});
|
||||
|
@ -4,6 +4,9 @@ import { iconMap } from './DashLinksEditorCtrl';
|
||||
import { LinkSrv } from 'app/features/panel/panellinks/link_srv';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { DashboardSrv } from '../../services/DashboardSrv';
|
||||
import { PanelEvents } from '@grafana/ui';
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
export type DashboardLink = { tags: any; target: string; keepTime: any; includeVars: any };
|
||||
|
||||
@ -84,7 +87,7 @@ function dashLink($compile: any, $sanitize: any, linkSrv: LinkSrv) {
|
||||
}
|
||||
|
||||
update();
|
||||
dashboard.events.on('refresh', update, scope);
|
||||
dashboard.events.on(PanelEvents.refresh, update, scope);
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -93,7 +96,7 @@ export class DashLinksContainerCtrl {
|
||||
/** @ngInject */
|
||||
constructor(
|
||||
$scope: any,
|
||||
$rootScope: any,
|
||||
$rootScope: GrafanaRootScope,
|
||||
$q: IQService,
|
||||
backendSrv: BackendSrv,
|
||||
dashboardSrv: DashboardSrv,
|
||||
@ -184,7 +187,7 @@ export class DashLinksContainerCtrl {
|
||||
};
|
||||
|
||||
updateDashLinks();
|
||||
$rootScope.onAppEvent('dash-links-updated', updateDashLinks, $scope);
|
||||
$rootScope.onAppEvent(CoreEvents.dashLinksUpdated, updateDashLinks, $scope);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
import angular from 'angular';
|
||||
import _ from 'lodash';
|
||||
import { DashboardModel } from 'app/features/dashboard/state';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export let iconMap = {
|
||||
'external link': 'fa-external-link',
|
||||
@ -32,13 +34,13 @@ export class DashLinksEditorCtrl {
|
||||
};
|
||||
|
||||
/** @ngInject */
|
||||
constructor($scope: any, $rootScope: any) {
|
||||
constructor($scope: any, $rootScope: GrafanaRootScope) {
|
||||
this.iconMap = iconMap;
|
||||
this.dashboard.links = this.dashboard.links || [];
|
||||
this.mode = 'list';
|
||||
|
||||
$scope.$on('$destroy', () => {
|
||||
$rootScope.appEvent('dash-links-updated');
|
||||
$rootScope.appEvent(CoreEvents.dashLinksUpdated);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ import { updateLocation } from 'app/core/actions';
|
||||
|
||||
// Types
|
||||
import { DashboardModel } from '../../state';
|
||||
import { StoreState } from 'app/types';
|
||||
import { StoreState, CoreEvents } from 'app/types';
|
||||
|
||||
export interface OwnProps {
|
||||
dashboard: DashboardModel;
|
||||
@ -43,11 +43,11 @@ export class DashNav extends PureComponent<Props> {
|
||||
}
|
||||
|
||||
onDahboardNameClick = () => {
|
||||
appEvents.emit('show-dash-search');
|
||||
appEvents.emit(CoreEvents.showDashSearch);
|
||||
};
|
||||
|
||||
onFolderNameClick = () => {
|
||||
appEvents.emit('show-dash-search', {
|
||||
appEvents.emit(CoreEvents.showDashSearch, {
|
||||
query: 'folder:current',
|
||||
});
|
||||
};
|
||||
@ -67,7 +67,7 @@ export class DashNav extends PureComponent<Props> {
|
||||
};
|
||||
|
||||
onToggleTVMode = () => {
|
||||
appEvents.emit('toggle-kiosk-mode');
|
||||
appEvents.emit(CoreEvents.toggleKioskMode);
|
||||
};
|
||||
|
||||
onSave = () => {
|
||||
@ -112,7 +112,7 @@ export class DashNav extends PureComponent<Props> {
|
||||
modalScope.tabIndex = 0;
|
||||
modalScope.dashboard = this.props.dashboard;
|
||||
|
||||
appEvents.emit('show-modal', {
|
||||
appEvents.emit(CoreEvents.showModal, {
|
||||
src: 'public/app/features/dashboard/components/ShareModal/template.html',
|
||||
scope: modalScope,
|
||||
});
|
||||
|
@ -4,7 +4,7 @@ import { dateMath } from '@grafana/data';
|
||||
|
||||
// Types
|
||||
import { DashboardModel } from '../../state';
|
||||
import { LocationState } from 'app/types';
|
||||
import { LocationState, CoreEvents } from 'app/types';
|
||||
import { TimeRange, TimeOption, RawTimeRange } from '@grafana/data';
|
||||
|
||||
// State
|
||||
@ -43,10 +43,10 @@ export class DashNavTimeControls extends Component<Props> {
|
||||
};
|
||||
|
||||
onMoveBack = () => {
|
||||
this.$rootScope.appEvent('shift-time', -1);
|
||||
this.$rootScope.appEvent(CoreEvents.shiftTime, -1);
|
||||
};
|
||||
onMoveForward = () => {
|
||||
this.$rootScope.appEvent('shift-time', 1);
|
||||
this.$rootScope.appEvent(CoreEvents.shiftTime, 1);
|
||||
};
|
||||
|
||||
onChangeTimePicker = (timeRange: TimeRange) => {
|
||||
@ -65,7 +65,7 @@ export class DashNavTimeControls extends Component<Props> {
|
||||
};
|
||||
|
||||
onZoom = () => {
|
||||
this.$rootScope.appEvent('zoom-out', 2);
|
||||
this.$rootScope.appEvent(CoreEvents.zoomOut, 2);
|
||||
};
|
||||
|
||||
setActiveTimeOption = (timeOptions: TimeOption[], rawTimeRange: RawTimeRange): TimeOption[] => {
|
||||
|
@ -4,6 +4,7 @@ import { PanelModel } from '../../state/PanelModel';
|
||||
import { DashboardModel } from '../../state/DashboardModel';
|
||||
import templateSrv from 'app/features/templating/template_srv';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export interface DashboardRowProps {
|
||||
panel: PanelModel;
|
||||
@ -18,11 +19,11 @@ export class DashboardRow extends React.Component<DashboardRowProps, any> {
|
||||
collapsed: this.props.panel.collapsed,
|
||||
};
|
||||
|
||||
this.props.dashboard.on('template-variable-value-updated', this.onVariableUpdated);
|
||||
this.props.dashboard.on(CoreEvents.templateVariableValueUpdated, this.onVariableUpdated);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.dashboard.off('template-variable-value-updated', this.onVariableUpdated);
|
||||
this.props.dashboard.off(CoreEvents.templateVariableValueUpdated, this.onVariableUpdated);
|
||||
}
|
||||
|
||||
onVariableUpdated = () => {
|
||||
@ -43,7 +44,7 @@ export class DashboardRow extends React.Component<DashboardRowProps, any> {
|
||||
};
|
||||
|
||||
onOpenSettings = () => {
|
||||
appEvents.emit('show-modal', {
|
||||
appEvents.emit(CoreEvents.showModal, {
|
||||
templateHtml: `<row-options row="model.row" on-updated="model.onUpdated()" dismiss="dismiss()"></row-options>`,
|
||||
modalClass: 'modal--narrow',
|
||||
model: {
|
||||
@ -54,7 +55,7 @@ export class DashboardRow extends React.Component<DashboardRowProps, any> {
|
||||
};
|
||||
|
||||
onDelete = () => {
|
||||
appEvents.emit('confirm-modal', {
|
||||
appEvents.emit(CoreEvents.showConfirmModal, {
|
||||
title: 'Delete Row',
|
||||
text: 'Are you sure you want to remove this row and all its panels?',
|
||||
altActionText: 'Delete row only',
|
||||
|
@ -6,6 +6,9 @@ import angular, { ILocationService } from 'angular';
|
||||
import config from 'app/core/config';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { DashboardSrv } from '../../services/DashboardSrv';
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export class SettingsCtrl {
|
||||
dashboard: DashboardModel;
|
||||
@ -24,7 +27,7 @@ export class SettingsCtrl {
|
||||
private $scope: any,
|
||||
private $route: any,
|
||||
private $location: ILocationService,
|
||||
private $rootScope: any,
|
||||
private $rootScope: GrafanaRootScope,
|
||||
private backendSrv: BackendSrv,
|
||||
private dashboardSrv: DashboardSrv
|
||||
) {
|
||||
@ -35,7 +38,7 @@ export class SettingsCtrl {
|
||||
this.$scope.$on('$destroy', () => {
|
||||
this.dashboard.updateSubmenuVisibility();
|
||||
setTimeout(() => {
|
||||
this.$rootScope.appEvent('dash-scroll', { restore: true });
|
||||
this.$rootScope.appEvent(CoreEvents.dashScroll, { restore: true });
|
||||
this.dashboard.startRefresh();
|
||||
});
|
||||
});
|
||||
@ -47,9 +50,9 @@ export class SettingsCtrl {
|
||||
this.buildSectionList();
|
||||
this.onRouteUpdated();
|
||||
|
||||
this.$rootScope.onAppEvent('$routeUpdate', this.onRouteUpdated.bind(this), $scope);
|
||||
this.$rootScope.appEvent('dash-scroll', { animate: false, pos: 0 });
|
||||
this.$rootScope.onAppEvent('dashboard-saved', this.onPostSave.bind(this), $scope);
|
||||
this.$rootScope.onAppEvent(CoreEvents.routeUpdated, this.onRouteUpdated.bind(this), $scope);
|
||||
this.$rootScope.appEvent(CoreEvents.dashScroll, { animate: false, pos: 0 });
|
||||
this.$rootScope.onAppEvent(CoreEvents.dashboardSaved, this.onPostSave.bind(this), $scope);
|
||||
}
|
||||
|
||||
buildSectionList() {
|
||||
@ -185,7 +188,7 @@ export class SettingsCtrl {
|
||||
let text2 = this.dashboard.title;
|
||||
|
||||
if (this.dashboard.meta.provisioned) {
|
||||
appEvents.emit('confirm-modal', {
|
||||
appEvents.emit(CoreEvents.showConfirmModal, {
|
||||
title: 'Cannot delete provisioned dashboard',
|
||||
text: `
|
||||
This dashboard is managed by Grafanas provisioning and cannot be deleted. Remove the dashboard from the
|
||||
@ -213,7 +216,7 @@ export class SettingsCtrl {
|
||||
text2 = `This dashboard contains ${alerts} alerts. Deleting this dashboard will also delete those alerts`;
|
||||
}
|
||||
|
||||
appEvents.emit('confirm-modal', {
|
||||
appEvents.emit(CoreEvents.showConfirmModal, {
|
||||
title: 'Delete',
|
||||
text: 'Do you want to delete this dashboard?',
|
||||
text2: text2,
|
||||
@ -229,7 +232,7 @@ export class SettingsCtrl {
|
||||
|
||||
deleteDashboardConfirmed() {
|
||||
this.backendSrv.deleteDashboard(this.dashboard.uid, false).then(() => {
|
||||
appEvents.emit('alert-success', ['Dashboard Deleted', this.dashboard.title + ' has been deleted']);
|
||||
appEvents.emit(AppEvents.alertSuccess, ['Dashboard Deleted', this.dashboard.title + ' has been deleted']);
|
||||
this.$location.url('/');
|
||||
});
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import angular from 'angular';
|
||||
import * as fileExport from 'app/core/utils/file_export';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { DashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export class ExportDataModalCtrl {
|
||||
private data: any;
|
||||
@ -34,7 +35,7 @@ export class ExportDataModalCtrl {
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
appEvents.emit('hide-modal');
|
||||
appEvents.emit(CoreEvents.hideModal);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import appEvents from 'app/core/app_events';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { ValidationSrv } from 'app/features/manage-dashboards';
|
||||
import { ContextSrv } from 'app/core/services/context_srv';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export class FolderPickerCtrl {
|
||||
initialTitle: string;
|
||||
@ -105,7 +106,7 @@ export class FolderPickerCtrl {
|
||||
}
|
||||
|
||||
return this.backendSrv.createFolder({ title: this.newFolderName }).then((result: { title: string; id: number }) => {
|
||||
appEvents.emit('alert-success', ['Folder Created', 'OK']);
|
||||
appEvents.emit(AppEvents.alertSuccess, ['Folder Created', 'OK']);
|
||||
|
||||
this.closeCreateFolder();
|
||||
this.folder = { text: result.title, value: result.id };
|
||||
|
@ -45,7 +45,7 @@ describe('ShareModalCtrl', () => {
|
||||
// @ts-ignore
|
||||
ctx.ctrl = new ShareModalCtrl(
|
||||
ctx.scope,
|
||||
{},
|
||||
{} as any,
|
||||
ctx.$location,
|
||||
{},
|
||||
ctx.timeSrv,
|
||||
|
@ -5,11 +5,12 @@ import { appendQueryToUrl, toUrlParams } from 'app/core/utils/url';
|
||||
import { TimeSrv } from '../../services/TimeSrv';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { LinkSrv } from 'app/features/panel/panellinks/link_srv';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
/** @ngInject */
|
||||
export function ShareModalCtrl(
|
||||
$scope: any,
|
||||
$rootScope: any,
|
||||
$rootScope: GrafanaRootScope,
|
||||
$location: ILocationService,
|
||||
$timeout: any,
|
||||
timeSrv: TimeSrv,
|
||||
|
@ -4,12 +4,13 @@ import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { TimeSrv } from '../../services/TimeSrv';
|
||||
import { DashboardModel } from '../../state/DashboardModel';
|
||||
import { PanelModel } from '../../state/PanelModel';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
export class ShareSnapshotCtrl {
|
||||
/** @ngInject */
|
||||
constructor(
|
||||
$scope: any,
|
||||
$rootScope: any,
|
||||
$rootScope: GrafanaRootScope,
|
||||
$location: ILocationService,
|
||||
backendSrv: BackendSrv,
|
||||
$timeout: any,
|
||||
|
@ -3,6 +3,7 @@ import { HistoryListCtrl } from './HistoryListCtrl';
|
||||
import { versions, compare, restore } from './__mocks__/history';
|
||||
// @ts-ignore
|
||||
import $q from 'q';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
describe('HistoryListCtrl', () => {
|
||||
const RESTORE_ID = 4;
|
||||
@ -118,9 +119,9 @@ describe('HistoryListCtrl', () => {
|
||||
historyListCtrl.resetFromSource = jest.fn();
|
||||
});
|
||||
|
||||
it('should listen for the `dashboard-saved` appEvent', () => {
|
||||
it('should listen for the `dashboardSaved` appEvent', () => {
|
||||
expect($rootScope.onAppEvent).toHaveBeenCalledTimes(1);
|
||||
expect($rootScope.onAppEvent.mock.calls[0][0]).toBe('dashboard-saved');
|
||||
expect($rootScope.onAppEvent.mock.calls[0][0]).toBe(CoreEvents.dashboardSaved);
|
||||
});
|
||||
|
||||
it('should call `onDashboardSaved` when the appEvent is received', () => {
|
||||
@ -292,7 +293,7 @@ describe('HistoryListCtrl', () => {
|
||||
|
||||
it('should display a modal allowing the user to restore or cancel', () => {
|
||||
expect($rootScope.appEvent).toHaveBeenCalledTimes(1);
|
||||
expect($rootScope.appEvent.mock.calls[0][0]).toBe('confirm-modal');
|
||||
expect($rootScope.appEvent.mock.calls[0][0]).toBe(CoreEvents.showConfirmModal);
|
||||
});
|
||||
|
||||
describe('and restore fails to fetch', () => {
|
||||
|
@ -4,7 +4,9 @@ import angular, { ILocationService, IQService } from 'angular';
|
||||
import locationUtil from 'app/core/utils/location_util';
|
||||
import { DashboardModel } from '../../state/DashboardModel';
|
||||
import { HistoryListOpts, RevisionsModel, CalculateDiffOptions, HistorySrv } from './HistorySrv';
|
||||
import { dateTime, toUtc, DateTimeInput } from '@grafana/data';
|
||||
import { dateTime, toUtc, DateTimeInput, AppEvents } from '@grafana/data';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export class HistoryListCtrl {
|
||||
appending: boolean;
|
||||
@ -25,7 +27,7 @@ export class HistoryListCtrl {
|
||||
/** @ngInject */
|
||||
constructor(
|
||||
private $route: any,
|
||||
private $rootScope: any,
|
||||
private $rootScope: GrafanaRootScope,
|
||||
private $location: ILocationService,
|
||||
private $q: IQService,
|
||||
private historySrv: HistorySrv,
|
||||
@ -40,7 +42,7 @@ export class HistoryListCtrl {
|
||||
this.start = 0;
|
||||
this.canCompare = false;
|
||||
|
||||
this.$rootScope.onAppEvent('dashboard-saved', this.onDashboardSaved.bind(this), $scope);
|
||||
this.$rootScope.onAppEvent(CoreEvents.dashboardSaved, this.onDashboardSaved.bind(this), $scope);
|
||||
this.resetFromSource();
|
||||
}
|
||||
|
||||
@ -56,7 +58,7 @@ export class HistoryListCtrl {
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
this.$rootScope.appEvent('hide-dash-editor');
|
||||
this.$rootScope.appEvent(CoreEvents.hideDashEditor);
|
||||
}
|
||||
|
||||
addToLog() {
|
||||
@ -172,7 +174,7 @@ export class HistoryListCtrl {
|
||||
}
|
||||
|
||||
restore(version: number) {
|
||||
this.$rootScope.appEvent('confirm-modal', {
|
||||
this.$rootScope.appEvent(CoreEvents.showConfirmModal, {
|
||||
title: 'Restore version',
|
||||
text: '',
|
||||
text2: `Are you sure you want to restore the dashboard to version ${version}? All unsaved changes will be lost.`,
|
||||
@ -189,7 +191,7 @@ export class HistoryListCtrl {
|
||||
.then((response: any) => {
|
||||
this.$location.url(locationUtil.stripBaseFromUrl(response.url)).replace();
|
||||
this.$route.reload();
|
||||
this.$rootScope.appEvent('alert-success', ['Dashboard restored', 'Restored from version ' + version]);
|
||||
this.$rootScope.appEvent(AppEvents.alertSuccess, ['Dashboard restored', 'Restored from version ' + version]);
|
||||
})
|
||||
.catch(() => {
|
||||
this.mode = 'list';
|
||||
|
@ -10,6 +10,9 @@ import sizeMe from 'react-sizeme';
|
||||
import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT } from 'app/core/constants';
|
||||
import { DashboardPanel } from './DashboardPanel';
|
||||
import { DashboardModel, PanelModel } from '../state';
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { PanelEvents } from '@grafana/ui';
|
||||
import { panelAdded, panelRemoved } from '../state/PanelModel';
|
||||
|
||||
let lastGridWidth = 1200;
|
||||
let ignoreNextWidthChange = false;
|
||||
@ -93,22 +96,22 @@ export class DashboardGrid extends PureComponent<Props> {
|
||||
|
||||
componentDidMount() {
|
||||
const { dashboard } = this.props;
|
||||
dashboard.on('panel-added', this.triggerForceUpdate);
|
||||
dashboard.on('panel-removed', this.triggerForceUpdate);
|
||||
dashboard.on('repeats-processed', this.triggerForceUpdate);
|
||||
dashboard.on('view-mode-changed', this.onViewModeChanged);
|
||||
dashboard.on('row-collapsed', this.triggerForceUpdate);
|
||||
dashboard.on('row-expanded', this.triggerForceUpdate);
|
||||
dashboard.on(panelAdded, this.triggerForceUpdate);
|
||||
dashboard.on(panelRemoved, this.triggerForceUpdate);
|
||||
dashboard.on(CoreEvents.repeatsProcessed, this.triggerForceUpdate);
|
||||
dashboard.on(PanelEvents.viewModeChanged, this.onViewModeChanged);
|
||||
dashboard.on(CoreEvents.rowCollapsed, this.triggerForceUpdate);
|
||||
dashboard.on(CoreEvents.rowExpanded, this.triggerForceUpdate);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { dashboard } = this.props;
|
||||
dashboard.off('panel-added', this.triggerForceUpdate);
|
||||
dashboard.off('panel-removed', this.triggerForceUpdate);
|
||||
dashboard.off('repeats-processed', this.triggerForceUpdate);
|
||||
dashboard.off('view-mode-changed', this.onViewModeChanged);
|
||||
dashboard.off('row-collapsed', this.triggerForceUpdate);
|
||||
dashboard.off('row-expanded', this.triggerForceUpdate);
|
||||
dashboard.off(panelAdded, this.triggerForceUpdate);
|
||||
dashboard.off(panelRemoved, this.triggerForceUpdate);
|
||||
dashboard.off(CoreEvents.repeatsProcessed, this.triggerForceUpdate);
|
||||
dashboard.off(PanelEvents.viewModeChanged, this.onViewModeChanged);
|
||||
dashboard.off(CoreEvents.rowCollapsed, this.triggerForceUpdate);
|
||||
dashboard.off(CoreEvents.rowExpanded, this.triggerForceUpdate);
|
||||
}
|
||||
|
||||
buildLayout() {
|
||||
|
@ -14,7 +14,8 @@ import templateSrv from 'app/features/templating/template_srv';
|
||||
import config from 'app/core/config';
|
||||
// Types
|
||||
import { DashboardModel, PanelModel } from '../state';
|
||||
import { LoadingState, ScopedVars, AbsoluteTimeRange, toUtc, toDataFrameDTO, DefaultTimeRange } from '@grafana/data';
|
||||
import { LoadingState, ScopedVars, AbsoluteTimeRange, DefaultTimeRange, toUtc, toDataFrameDTO } from '@grafana/data';
|
||||
import { PanelEvents } from '@grafana/ui';
|
||||
|
||||
const DEFAULT_PLUGIN_ERROR = 'Error in plugin';
|
||||
|
||||
@ -59,8 +60,8 @@ export class PanelChrome extends PureComponent<Props, State> {
|
||||
|
||||
componentDidMount() {
|
||||
const { panel, dashboard } = this.props;
|
||||
panel.events.on('refresh', this.onRefresh);
|
||||
panel.events.on('render', this.onRender);
|
||||
panel.events.on(PanelEvents.refresh, this.onRefresh);
|
||||
panel.events.on(PanelEvents.render, this.onRender);
|
||||
dashboard.panelInitialized(this.props.panel);
|
||||
|
||||
// Move snapshot data into the query response
|
||||
@ -79,8 +80,7 @@ export class PanelChrome extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.panel.events.off('refresh', this.onRefresh);
|
||||
|
||||
this.props.panel.events.off(PanelEvents.refresh, this.onRefresh);
|
||||
if (this.querySubscription) {
|
||||
this.querySubscription.unsubscribe();
|
||||
this.querySubscription = null;
|
||||
|
@ -9,7 +9,7 @@ import { Emitter } from 'app/core/utils/emitter';
|
||||
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||
// Types
|
||||
import { PanelModel } from '../state/PanelModel';
|
||||
import { DataQuery, DataSourceApi, PanelData, DataQueryRequest, ErrorBoundaryAlert } from '@grafana/ui';
|
||||
import { DataQuery, DataSourceApi, PanelData, DataQueryRequest, ErrorBoundaryAlert, PanelEvents } from '@grafana/ui';
|
||||
import { TimeRange, LoadingState, toLegacyResponseData } from '@grafana/data';
|
||||
import { DashboardModel } from '../state/DashboardModel';
|
||||
|
||||
@ -273,9 +273,9 @@ function notifyAngularQueryEditorsOfData(panel: PanelModel, data: PanelData, edi
|
||||
|
||||
if (data.state === LoadingState.Done) {
|
||||
const legacy = data.series.map(v => toLegacyResponseData(v));
|
||||
panel.events.emit('data-received', legacy);
|
||||
panel.events.emit(PanelEvents.dataReceived, legacy);
|
||||
} else if (data.state === LoadingState.Error) {
|
||||
panel.events.emit('data-error', data.error);
|
||||
panel.events.emit(PanelEvents.dataError, data.error);
|
||||
}
|
||||
|
||||
// Some query controllers listen to data error events and need a digest
|
||||
|
@ -1,7 +1,9 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { CopyToClipboard } from 'app/core/components/CopyToClipboard/CopyToClipboard';
|
||||
import { LoadingPlaceholder, JSONFormatter } from '@grafana/ui';
|
||||
import { LoadingPlaceholder, JSONFormatter, PanelEvents } from '@grafana/ui';
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
interface DsQuery {
|
||||
isLoading: boolean;
|
||||
@ -39,20 +41,20 @@ export class QueryInspector extends PureComponent<Props, State> {
|
||||
componentDidMount() {
|
||||
const { panel } = this.props;
|
||||
|
||||
appEvents.on('ds-request-response', this.onDataSourceResponse);
|
||||
appEvents.on('ds-request-error', this.onRequestError);
|
||||
appEvents.on(CoreEvents.dsRequestResponse, this.onDataSourceResponse);
|
||||
appEvents.on(CoreEvents.dsRequestError, this.onRequestError);
|
||||
|
||||
panel.events.on('refresh', this.onPanelRefresh);
|
||||
panel.events.on(PanelEvents.refresh, this.onPanelRefresh);
|
||||
panel.refresh();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { panel } = this.props;
|
||||
|
||||
appEvents.off('ds-request-response', this.onDataSourceResponse);
|
||||
appEvents.on('ds-request-error', this.onRequestError);
|
||||
appEvents.off(CoreEvents.dsRequestResponse, this.onDataSourceResponse);
|
||||
appEvents.on(CoreEvents.dsRequestError, this.onRequestError);
|
||||
|
||||
panel.events.off('refresh', this.onPanelRefresh);
|
||||
panel.events.off(PanelEvents.refresh, this.onPanelRefresh);
|
||||
}
|
||||
|
||||
handleMocking(response: any) {
|
||||
@ -61,7 +63,7 @@ export class QueryInspector extends PureComponent<Props, State> {
|
||||
try {
|
||||
mockedData = JSON.parse(mockedResponse);
|
||||
} catch (err) {
|
||||
appEvents.emit('alert-error', ['R: Failed to parse mocked response']);
|
||||
appEvents.emit(AppEvents.alertError, ['R: Failed to parse mocked response']);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -134,7 +136,7 @@ export class QueryInspector extends PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
onClipboardSuccess = () => {
|
||||
appEvents.emit('alert-success', ['Content copied to clipboard']);
|
||||
appEvents.emit(AppEvents.alertSuccess, ['Content copied to clipboard']);
|
||||
};
|
||||
|
||||
onToggleExpand = () => {
|
||||
|
@ -10,7 +10,7 @@ jest.mock('app/core/services/context_srv', () => ({
|
||||
}));
|
||||
|
||||
describe('ChangeTracker', () => {
|
||||
let rootScope;
|
||||
let rootScope: any;
|
||||
let location;
|
||||
const timeout = () => {};
|
||||
let tracker: ChangeTracker;
|
||||
@ -57,7 +57,7 @@ describe('ChangeTracker', () => {
|
||||
path: jest.fn(),
|
||||
};
|
||||
|
||||
tracker = new ChangeTracker(dash, scope, undefined, location as any, window, timeout, contextSrv, rootScope);
|
||||
tracker = new ChangeTracker(dash, scope as any, undefined, location as any, window, timeout, contextSrv, rootScope);
|
||||
});
|
||||
|
||||
it('No changes should not have changes', () => {
|
||||
|
@ -1,7 +1,9 @@
|
||||
import angular, { ILocationService } from 'angular';
|
||||
import angular, { ILocationService, IRootScopeService } from 'angular';
|
||||
import _ from 'lodash';
|
||||
import { DashboardModel } from '../state/DashboardModel';
|
||||
import { ContextSrv } from 'app/core/services/context_srv';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
import { CoreEvents, AppEventConsumer } from 'app/types';
|
||||
|
||||
export class ChangeTracker {
|
||||
current: any;
|
||||
@ -14,13 +16,13 @@ export class ChangeTracker {
|
||||
/** @ngInject */
|
||||
constructor(
|
||||
dashboard: DashboardModel,
|
||||
scope: any,
|
||||
scope: IRootScopeService & AppEventConsumer,
|
||||
originalCopyDelay: any,
|
||||
private $location: ILocationService,
|
||||
$window: any,
|
||||
private $timeout: any,
|
||||
private contextSrv: ContextSrv,
|
||||
private $rootScope: any
|
||||
private $rootScope: GrafanaRootScope
|
||||
) {
|
||||
this.$location = $location;
|
||||
this.$window = $window;
|
||||
@ -30,7 +32,7 @@ export class ChangeTracker {
|
||||
this.scope = scope;
|
||||
|
||||
// register events
|
||||
scope.onAppEvent('dashboard-saved', () => {
|
||||
scope.onAppEvent(CoreEvents.dashboardSaved, () => {
|
||||
this.original = this.current.getSaveModelClone();
|
||||
this.originalPath = $location.path();
|
||||
});
|
||||
@ -161,7 +163,7 @@ export class ChangeTracker {
|
||||
}
|
||||
|
||||
open_modal() {
|
||||
this.$rootScope.appEvent('show-modal', {
|
||||
this.$rootScope.appEvent(CoreEvents.showModal, {
|
||||
templateHtml: '<unsaved-changes-modal dismiss="dismiss()"></unsaved-changes-modal>',
|
||||
modalClass: 'modal--narrow confirm-modal',
|
||||
});
|
||||
@ -176,7 +178,7 @@ export class ChangeTracker {
|
||||
});
|
||||
});
|
||||
|
||||
this.$rootScope.appEvent('save-dashboard');
|
||||
this.$rootScope.appEvent(CoreEvents.saveDashboard);
|
||||
}
|
||||
|
||||
gotoNext() {
|
||||
|
@ -4,12 +4,13 @@ import moment from 'moment';
|
||||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import kbn from 'app/core/utils/kbn';
|
||||
import { dateMath } from '@grafana/data';
|
||||
import { dateMath, AppEvents } from '@grafana/data';
|
||||
import impressionSrv from 'app/core/services/impression_srv';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { DashboardSrv } from './DashboardSrv';
|
||||
import DatasourceSrv from 'app/features/plugins/datasource_srv';
|
||||
import { UrlQueryValue } from '@grafana/runtime';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
export class DashboardLoaderSrv {
|
||||
/** @ngInject */
|
||||
@ -22,7 +23,7 @@ export class DashboardLoaderSrv {
|
||||
private $timeout: any,
|
||||
contextSrv: any,
|
||||
private $routeParams: any,
|
||||
private $rootScope: any
|
||||
private $rootScope: GrafanaRootScope
|
||||
) {}
|
||||
|
||||
_dashboardLoadFailed(title: string, snapshot?: boolean) {
|
||||
@ -54,7 +55,7 @@ export class DashboardLoaderSrv {
|
||||
.getDashboardByUid(uid)
|
||||
.then((result: any) => {
|
||||
if (result.meta.isFolder) {
|
||||
this.$rootScope.appEvent('alert-error', ['Dashboard not found']);
|
||||
this.$rootScope.appEvent(AppEvents.alertError, ['Dashboard not found']);
|
||||
throw new Error('Dashboard not found');
|
||||
}
|
||||
return result;
|
||||
@ -94,7 +95,7 @@ export class DashboardLoaderSrv {
|
||||
},
|
||||
(err: any) => {
|
||||
console.log('Script dashboard error ' + err);
|
||||
this.$rootScope.appEvent('alert-error', [
|
||||
this.$rootScope.appEvent(AppEvents.alertError, [
|
||||
'Script Error',
|
||||
'Please make sure it exists and returns a valid dashboard',
|
||||
]);
|
||||
|
@ -3,9 +3,12 @@ import { appEvents } from 'app/core/app_events';
|
||||
import locationUtil from 'app/core/utils/location_util';
|
||||
import { DashboardModel } from '../state/DashboardModel';
|
||||
import { removePanel } from '../utils/panel';
|
||||
import { DashboardMeta } from 'app/types';
|
||||
import { DashboardMeta, CoreEvents } from 'app/types';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { ILocationService } from 'angular';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
import { PanelEvents } from '@grafana/ui';
|
||||
|
||||
interface DashboardSaveOptions {
|
||||
folderId?: number;
|
||||
@ -18,10 +21,14 @@ export class DashboardSrv {
|
||||
dashboard: DashboardModel;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private backendSrv: BackendSrv, private $rootScope: any, private $location: ILocationService) {
|
||||
appEvents.on('save-dashboard', this.saveDashboard.bind(this), $rootScope);
|
||||
appEvents.on('panel-change-view', this.onPanelChangeView);
|
||||
appEvents.on('remove-panel', this.onRemovePanel);
|
||||
constructor(
|
||||
private backendSrv: BackendSrv,
|
||||
private $rootScope: GrafanaRootScope,
|
||||
private $location: ILocationService
|
||||
) {
|
||||
appEvents.on(CoreEvents.saveDashboard, this.saveDashboard.bind(this), $rootScope);
|
||||
appEvents.on(PanelEvents.panelChangeView, this.onPanelChangeView);
|
||||
appEvents.on(CoreEvents.removePanel, this.onRemovePanel);
|
||||
|
||||
// Export to react
|
||||
setDashboardSrv(this);
|
||||
@ -96,7 +103,7 @@ export class DashboardSrv {
|
||||
if (err.data && err.data.status === 'version-mismatch') {
|
||||
err.isHandled = true;
|
||||
|
||||
this.$rootScope.appEvent('confirm-modal', {
|
||||
this.$rootScope.appEvent(CoreEvents.showConfirmModal, {
|
||||
title: 'Conflict',
|
||||
text: 'Someone else has updated this dashboard.',
|
||||
text2: 'Would you still like to save this dashboard?',
|
||||
@ -111,7 +118,7 @@ export class DashboardSrv {
|
||||
if (err.data && err.data.status === 'name-exists') {
|
||||
err.isHandled = true;
|
||||
|
||||
this.$rootScope.appEvent('confirm-modal', {
|
||||
this.$rootScope.appEvent(CoreEvents.showConfirmModal, {
|
||||
title: 'Conflict',
|
||||
text: 'A dashboard with the same name in selected folder already exists.',
|
||||
text2: 'Would you still like to save this dashboard?',
|
||||
@ -126,7 +133,7 @@ export class DashboardSrv {
|
||||
if (err.data && err.data.status === 'plugin-dashboard') {
|
||||
err.isHandled = true;
|
||||
|
||||
this.$rootScope.appEvent('confirm-modal', {
|
||||
this.$rootScope.appEvent(CoreEvents.showConfirmModal, {
|
||||
title: 'Plugin Dashboard',
|
||||
text: err.data.message,
|
||||
text2: 'Your changes will be lost when you update the plugin. Use Save As to create custom version.',
|
||||
@ -147,8 +154,8 @@ export class DashboardSrv {
|
||||
this.dashboard.version = data.version;
|
||||
|
||||
// important that these happen before location redirect below
|
||||
this.$rootScope.appEvent('dashboard-saved', this.dashboard);
|
||||
this.$rootScope.appEvent('alert-success', ['Dashboard saved']);
|
||||
this.$rootScope.appEvent(CoreEvents.dashboardSaved, this.dashboard);
|
||||
this.$rootScope.appEvent(AppEvents.alertSuccess, ['Dashboard saved']);
|
||||
|
||||
const newUrl = locationUtil.stripBaseFromUrl(data.url);
|
||||
const currentPath = this.$location.path();
|
||||
@ -201,20 +208,20 @@ export class DashboardSrv {
|
||||
}
|
||||
|
||||
showDashboardProvisionedModal() {
|
||||
this.$rootScope.appEvent('show-modal', {
|
||||
this.$rootScope.appEvent(CoreEvents.showModal, {
|
||||
templateHtml: '<save-provisioned-dashboard-modal dismiss="dismiss()"></save-provisioned-dashboard-modal>',
|
||||
});
|
||||
}
|
||||
|
||||
showSaveAsModal() {
|
||||
this.$rootScope.appEvent('show-modal', {
|
||||
this.$rootScope.appEvent(CoreEvents.showModal, {
|
||||
templateHtml: '<save-dashboard-as-modal dismiss="dismiss()"></save-dashboard-as-modal>',
|
||||
modalClass: 'modal--narrow',
|
||||
});
|
||||
}
|
||||
|
||||
showSaveModal() {
|
||||
this.$rootScope.appEvent('show-modal', {
|
||||
this.$rootScope.appEvent(CoreEvents.showModal, {
|
||||
templateHtml: '<save-dashboard-modal dismiss="dismiss()"></save-dashboard-modal>',
|
||||
modalClass: 'modal--narrow',
|
||||
});
|
||||
|
@ -17,6 +17,7 @@ import {
|
||||
import { ITimeoutService, ILocationService } from 'angular';
|
||||
import { ContextSrv } from 'app/core/services/context_srv';
|
||||
import { DashboardModel } from '../state/DashboardModel';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
import { getZoomedTimeRange, getShiftedTimeRange } from 'app/core/utils/timePicker';
|
||||
|
||||
export class TimeSrv {
|
||||
@ -30,7 +31,7 @@ export class TimeSrv {
|
||||
|
||||
/** @ngInject */
|
||||
constructor(
|
||||
$rootScope: any,
|
||||
$rootScope: GrafanaRootScope,
|
||||
private $timeout: ITimeoutService,
|
||||
private $location: ILocationService,
|
||||
private timer: any,
|
||||
|
@ -2,11 +2,12 @@ import angular, { IQService, ILocationService } from 'angular';
|
||||
import { ChangeTracker } from './ChangeTracker';
|
||||
import { ContextSrv } from 'app/core/services/context_srv';
|
||||
import { DashboardSrv } from './DashboardSrv';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
/** @ngInject */
|
||||
export function unsavedChangesSrv(
|
||||
this: any,
|
||||
$rootScope: any,
|
||||
$rootScope: GrafanaRootScope,
|
||||
$q: IQService,
|
||||
$location: ILocationService,
|
||||
$timeout: any,
|
||||
|
@ -11,11 +11,12 @@ import { contextSrv } from 'app/core/services/context_srv';
|
||||
import sortByKeys from 'app/core/utils/sort_by_keys';
|
||||
|
||||
// Types
|
||||
import { PanelModel, GridPos } from './PanelModel';
|
||||
import { PanelModel, GridPos, panelAdded, panelRemoved } from './PanelModel';
|
||||
import { DashboardMigrator } from './DashboardMigrator';
|
||||
import { TimeRange, TimeZone } from '@grafana/data';
|
||||
import { TimeRange, TimeZone, AppEvent } from '@grafana/data';
|
||||
import { UrlQueryValue } from '@grafana/runtime';
|
||||
import { KIOSK_MODE_TV, DashboardMeta } from 'app/types';
|
||||
import { PanelEvents } from '@grafana/ui';
|
||||
import { KIOSK_MODE_TV, DashboardMeta, CoreEvents } from 'app/types';
|
||||
import { toUtc, DateTimeInput, dateTime, isDateTime } from '@grafana/data';
|
||||
|
||||
export interface CloneOptions {
|
||||
@ -215,15 +216,15 @@ export class DashboardModel {
|
||||
|
||||
panel.setViewMode(fullscreen, this.meta.isEditing);
|
||||
|
||||
this.events.emit('view-mode-changed', panel);
|
||||
this.events.emit(PanelEvents.viewModeChanged, panel);
|
||||
}
|
||||
|
||||
timeRangeUpdated(timeRange: TimeRange) {
|
||||
this.events.emit('time-range-updated', timeRange);
|
||||
this.events.emit(CoreEvents.timeRangeUpdated, timeRange);
|
||||
}
|
||||
|
||||
startRefresh() {
|
||||
this.events.emit('refresh');
|
||||
this.events.emit(PanelEvents.refresh);
|
||||
|
||||
for (const panel of this.panels) {
|
||||
if (!this.otherPanelInFullscreen(panel)) {
|
||||
@ -233,7 +234,7 @@ export class DashboardModel {
|
||||
}
|
||||
|
||||
render() {
|
||||
this.events.emit('render');
|
||||
this.events.emit(PanelEvents.render);
|
||||
|
||||
for (const panel of this.panels) {
|
||||
panel.render();
|
||||
@ -306,7 +307,7 @@ export class DashboardModel {
|
||||
|
||||
this.sortPanelsByGridPos();
|
||||
|
||||
this.events.emit('panel-added', panel);
|
||||
this.events.emit(panelAdded, panel);
|
||||
}
|
||||
|
||||
sortPanelsByGridPos() {
|
||||
@ -343,7 +344,7 @@ export class DashboardModel {
|
||||
_.pull(this.panels, ...panelsToRemove);
|
||||
panelsToRemove.map(p => p.destroy());
|
||||
this.sortPanelsByGridPos();
|
||||
this.events.emit('repeats-processed');
|
||||
this.events.emit(CoreEvents.repeatsProcessed);
|
||||
}
|
||||
|
||||
processRepeats() {
|
||||
@ -363,7 +364,7 @@ export class DashboardModel {
|
||||
}
|
||||
|
||||
this.sortPanelsByGridPos();
|
||||
this.events.emit('repeats-processed');
|
||||
this.events.emit(CoreEvents.repeatsProcessed);
|
||||
}
|
||||
|
||||
cleanUpRowRepeats(rowPanels: PanelModel[]) {
|
||||
@ -596,7 +597,7 @@ export class DashboardModel {
|
||||
removePanel(panel: PanelModel) {
|
||||
const index = _.indexOf(this.panels, panel);
|
||||
this.panels.splice(index, 1);
|
||||
this.events.emit('panel-removed', panel);
|
||||
this.events.emit(panelRemoved, panel);
|
||||
}
|
||||
|
||||
removeRow(row: PanelModel, removePanels: boolean) {
|
||||
@ -761,7 +762,7 @@ export class DashboardModel {
|
||||
this.sortPanelsByGridPos();
|
||||
|
||||
// emit change event
|
||||
this.events.emit('row-expanded');
|
||||
this.events.emit(CoreEvents.rowExpanded);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -774,7 +775,7 @@ export class DashboardModel {
|
||||
row.collapsed = true;
|
||||
|
||||
// emit change event
|
||||
this.events.emit('row-collapsed');
|
||||
this.events.emit(CoreEvents.rowCollapsed);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -798,12 +799,12 @@ export class DashboardModel {
|
||||
return rowPanels;
|
||||
}
|
||||
|
||||
on(eventName: string, callback: (payload?: any) => void) {
|
||||
this.events.on(eventName, callback);
|
||||
on<T>(event: AppEvent<T>, callback: (payload?: T) => void) {
|
||||
this.events.on(event, callback);
|
||||
}
|
||||
|
||||
off(eventName: string, callback?: (payload?: any) => void) {
|
||||
this.events.off(eventName, callback);
|
||||
off<T>(event: AppEvent<T>, callback?: (payload?: T) => void) {
|
||||
this.events.off(event, callback);
|
||||
}
|
||||
|
||||
cycleGraphTooltip() {
|
||||
@ -911,7 +912,7 @@ export class DashboardModel {
|
||||
|
||||
templateVariableValueUpdated() {
|
||||
this.processRepeats();
|
||||
this.events.emit('template-variable-value-updated');
|
||||
this.events.emit(CoreEvents.templateVariableValueUpdated);
|
||||
}
|
||||
|
||||
expandParentRowFor(panelId: number) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { PanelModel } from './PanelModel';
|
||||
import { getPanelPlugin } from '../../plugins/__mocks__/pluginMocks';
|
||||
import { PanelEvents } from '@grafana/ui';
|
||||
|
||||
class TablePanelCtrl {}
|
||||
|
||||
@ -144,7 +145,7 @@ describe('PanelModel', () => {
|
||||
let tearDownPublished = false;
|
||||
|
||||
beforeEach(() => {
|
||||
model.events.on('panel-teardown', () => {
|
||||
model.events.on(PanelEvents.panelTeardown, () => {
|
||||
tearDownPublished = true;
|
||||
});
|
||||
model.changePlugin(getPanelPlugin({ id: 'graph' }));
|
||||
|
@ -4,12 +4,16 @@ import _ from 'lodash';
|
||||
import { Emitter } from 'app/core/utils/emitter';
|
||||
import { getNextRefIdChar } from 'app/core/utils/query';
|
||||
// Types
|
||||
import { DataQuery, DataQueryResponseData, PanelPlugin } from '@grafana/ui';
|
||||
import { DataQuery, DataQueryResponseData, PanelPlugin, PanelEvents } from '@grafana/ui';
|
||||
import { DataLink, DataTransformerConfig, ScopedVars } from '@grafana/data';
|
||||
|
||||
import config from 'app/core/config';
|
||||
|
||||
import { PanelQueryRunner } from './PanelQueryRunner';
|
||||
import { eventFactory } from '@grafana/data';
|
||||
|
||||
export const panelAdded = eventFactory<PanelModel | undefined>('panel-added');
|
||||
export const panelRemoved = eventFactory<PanelModel | undefined>('panel-removed');
|
||||
|
||||
export interface GridPos {
|
||||
x: number;
|
||||
@ -179,7 +183,7 @@ export class PanelModel {
|
||||
setViewMode(fullscreen: boolean, isEditing: boolean) {
|
||||
this.fullscreen = fullscreen;
|
||||
this.isEditing = isEditing;
|
||||
this.events.emit('view-mode-changed');
|
||||
this.events.emit(PanelEvents.viewModeChanged);
|
||||
}
|
||||
|
||||
updateGridPos(newPos: GridPos) {
|
||||
@ -195,29 +199,29 @@ export class PanelModel {
|
||||
this.gridPos.h = newPos.h;
|
||||
|
||||
if (sizeChanged) {
|
||||
this.events.emit('panel-size-changed');
|
||||
this.events.emit(PanelEvents.panelSizeChanged);
|
||||
}
|
||||
}
|
||||
|
||||
resizeDone() {
|
||||
this.events.emit('panel-size-changed');
|
||||
this.events.emit(PanelEvents.panelSizeChanged);
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.hasRefreshed = true;
|
||||
this.events.emit('refresh');
|
||||
this.events.emit(PanelEvents.refresh);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.hasRefreshed) {
|
||||
this.refresh();
|
||||
} else {
|
||||
this.events.emit('render');
|
||||
this.events.emit(PanelEvents.render);
|
||||
}
|
||||
}
|
||||
|
||||
initialized() {
|
||||
this.events.emit('panel-initialized');
|
||||
this.events.emit(PanelEvents.panelInitialized);
|
||||
}
|
||||
|
||||
private getOptionsToRemember() {
|
||||
@ -343,7 +347,7 @@ export class PanelModel {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.events.emit('panel-teardown');
|
||||
this.events.emit(PanelEvents.panelTeardown);
|
||||
this.events.removeAllListeners();
|
||||
|
||||
if (this.queryRunner) {
|
||||
|
@ -3,8 +3,8 @@ import store from 'app/core/store';
|
||||
|
||||
// Models
|
||||
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
|
||||
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
|
||||
import { TimeRange } from '@grafana/data';
|
||||
import { PanelModel, panelRemoved, panelAdded } from 'app/features/dashboard/state/PanelModel';
|
||||
import { TimeRange, AppEvents } from '@grafana/data';
|
||||
|
||||
// Utils
|
||||
import { isString as _isString } from 'lodash';
|
||||
@ -18,6 +18,7 @@ import templateSrv from 'app/features/templating/template_srv';
|
||||
|
||||
// Constants
|
||||
import { LS_PANEL_COPY_KEY, PANEL_BORDER } from 'app/core/constants';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export const removePanel = (dashboard: DashboardModel, panel: PanelModel, ask: boolean) => {
|
||||
// confirm deletion
|
||||
@ -25,7 +26,7 @@ export const removePanel = (dashboard: DashboardModel, panel: PanelModel, ask: b
|
||||
const text2 = panel.alert ? 'Panel includes an alert rule, removing panel will also remove alert rule' : null;
|
||||
const confirmText = panel.alert ? 'YES' : null;
|
||||
|
||||
appEvents.emit('confirm-modal', {
|
||||
appEvents.emit(CoreEvents.showConfirmModal, {
|
||||
title: 'Remove Panel',
|
||||
text: 'Are you sure you want to remove this panel?',
|
||||
text2: text2,
|
||||
@ -45,7 +46,7 @@ export const duplicatePanel = (dashboard: DashboardModel, panel: PanelModel) =>
|
||||
|
||||
export const copyPanel = (panel: PanelModel) => {
|
||||
store.set(LS_PANEL_COPY_KEY, JSON.stringify(panel.getSaveModel()));
|
||||
appEvents.emit('alert-success', ['Panel copied. Open Add Panel to paste']);
|
||||
appEvents.emit(AppEvents.alertSuccess, ['Panel copied. Open Add Panel to paste']);
|
||||
};
|
||||
|
||||
const replacePanel = (dashboard: DashboardModel, newPanel: PanelModel, oldPanel: PanelModel) => {
|
||||
@ -53,15 +54,15 @@ const replacePanel = (dashboard: DashboardModel, newPanel: PanelModel, oldPanel:
|
||||
return panel.id === oldPanel.id;
|
||||
});
|
||||
|
||||
const deletedPanel = dashboard.panels.splice(index, 1);
|
||||
dashboard.events.emit('panel-removed', deletedPanel);
|
||||
const deletedPanel = dashboard.panels.splice(index, 1)[0];
|
||||
dashboard.events.emit(panelRemoved, deletedPanel);
|
||||
|
||||
newPanel = new PanelModel(newPanel);
|
||||
newPanel.id = oldPanel.id;
|
||||
|
||||
dashboard.panels.splice(index, 0, newPanel);
|
||||
dashboard.sortPanelsByGridPos();
|
||||
dashboard.events.emit('panel-added', newPanel);
|
||||
dashboard.events.emit(panelAdded, newPanel);
|
||||
};
|
||||
|
||||
export const editPanelJson = (dashboard: DashboardModel, panel: PanelModel) => {
|
||||
@ -74,14 +75,14 @@ export const editPanelJson = (dashboard: DashboardModel, panel: PanelModel) => {
|
||||
enableCopy: true,
|
||||
};
|
||||
|
||||
appEvents.emit('show-modal', {
|
||||
appEvents.emit(CoreEvents.showModal, {
|
||||
src: 'public/app/partials/edit_json.html',
|
||||
model: model,
|
||||
});
|
||||
};
|
||||
|
||||
export const sharePanel = (dashboard: DashboardModel, panel: PanelModel) => {
|
||||
appEvents.emit('show-modal', {
|
||||
appEvents.emit(CoreEvents.showModal, {
|
||||
src: 'public/app/features/dashboard/components/ShareModal/template.html',
|
||||
model: {
|
||||
dashboard: dashboard,
|
||||
|
@ -29,7 +29,7 @@ import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { getRouteParamsId } from 'app/core/selectors/location';
|
||||
|
||||
// Types
|
||||
import { StoreState } from 'app/types/';
|
||||
import { StoreState, CoreEvents } from 'app/types/';
|
||||
import { UrlQueryMap } from '@grafana/runtime';
|
||||
import { DataSourceSettings, DataSourcePluginMeta } from '@grafana/ui';
|
||||
import { NavModel } from '@grafana/data';
|
||||
@ -114,7 +114,7 @@ export class DataSourceSettingsPage extends PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
onDelete = () => {
|
||||
appEvents.emit('confirm-modal', {
|
||||
appEvents.emit(CoreEvents.showConfirmModal, {
|
||||
title: 'Delete',
|
||||
text: 'Are you sure you want to delete this data source?',
|
||||
yesText: 'Delete',
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
} from 'app/core/utils/explore';
|
||||
import { ExploreItemState, ExploreState, ExploreId, ExploreUpdateState, ExploreMode } from 'app/types/explore';
|
||||
import { LoadingState, toLegacyResponseData, DefaultTimeRange } from '@grafana/data';
|
||||
import { DataQuery, DataSourceApi, PanelData, DataQueryRequest, RefreshPicker } from '@grafana/ui';
|
||||
import { DataQuery, DataSourceApi, PanelData, DataQueryRequest, RefreshPicker, PanelEvents } from '@grafana/ui';
|
||||
import {
|
||||
HigherOrderAction,
|
||||
ActionTypes,
|
||||
@ -600,7 +600,7 @@ export const processQueryResponse = (
|
||||
}
|
||||
|
||||
// For Angular editors
|
||||
state.eventBridge.emit('data-error', error);
|
||||
state.eventBridge.emit(PanelEvents.dataError, error);
|
||||
|
||||
return {
|
||||
...state,
|
||||
@ -624,7 +624,7 @@ export const processQueryResponse = (
|
||||
if (state.datasourceInstance.components.QueryCtrl) {
|
||||
const legacy = series.map(v => toLegacyResponseData(v));
|
||||
|
||||
state.eventBridge.emit('data-received', legacy);
|
||||
state.eventBridge.emit(PanelEvents.dataReceived, legacy);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -4,6 +4,7 @@ import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { ILocationService } from 'angular';
|
||||
import { ValidationSrv } from 'app/features/manage-dashboards';
|
||||
import { NavModelSrv } from 'app/core/nav_model_srv';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export default class CreateFolderCtrl {
|
||||
title = '';
|
||||
@ -28,7 +29,7 @@ export default class CreateFolderCtrl {
|
||||
}
|
||||
|
||||
return this.backendSrv.createFolder({ title: this.title }).then((result: any) => {
|
||||
appEvents.emit('alert-success', ['Folder Created', 'OK']);
|
||||
appEvents.emit(AppEvents.alertSuccess, ['Folder Created', 'OK']);
|
||||
this.$location.url(locationUtil.stripBaseFromUrl(result.url));
|
||||
});
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import { Input } from '@grafana/ui';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { StoreState, FolderState } from 'app/types';
|
||||
import { StoreState, FolderState, CoreEvents } from 'app/types';
|
||||
import { getFolderByUid, setFolderTitle, saveFolder, deleteFolder } from './state/actions';
|
||||
import { getLoadingNav } from './state/navModel';
|
||||
|
||||
@ -52,7 +52,7 @@ export class FolderSettingsPage extends PureComponent<Props, State> {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
|
||||
appEvents.emit('confirm-modal', {
|
||||
appEvents.emit(CoreEvents.showConfirmModal, {
|
||||
title: 'Delete',
|
||||
text: `Do you want to delete this folder and all its dashboards?`,
|
||||
icon: 'fa-trash',
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
import { updateNavIndex, updateLocation } from 'app/core/actions';
|
||||
import { buildNavModel } from './navModel';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export enum ActionTypes {
|
||||
LoadFolder = 'LOAD_FOLDER',
|
||||
@ -71,7 +72,7 @@ export function saveFolder(folder: FolderState): ThunkResult<void> {
|
||||
});
|
||||
|
||||
// this should be redux action at some point
|
||||
appEvents.emit('alert-success', ['Folder saved']);
|
||||
appEvents.emit(AppEvents.alertSuccess, ['Folder saved']);
|
||||
|
||||
dispatch(updateLocation({ path: `${res.url}/settings` }));
|
||||
};
|
||||
|
@ -2,6 +2,8 @@ import _ from 'lodash';
|
||||
import { NavModelSrv } from 'app/core/core';
|
||||
import { ILocationService } from 'angular';
|
||||
import { BackendSrv } from '@grafana/runtime';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export class SnapshotListCtrl {
|
||||
navModel: any;
|
||||
@ -9,7 +11,7 @@ export class SnapshotListCtrl {
|
||||
|
||||
/** @ngInject */
|
||||
constructor(
|
||||
private $rootScope: any,
|
||||
private $rootScope: GrafanaRootScope,
|
||||
private backendSrv: BackendSrv,
|
||||
navModelSrv: NavModelSrv,
|
||||
private $location: ILocationService
|
||||
@ -35,7 +37,7 @@ export class SnapshotListCtrl {
|
||||
}
|
||||
|
||||
removeSnapshot(snapshot: any) {
|
||||
this.$rootScope.appEvent('confirm-modal', {
|
||||
this.$rootScope.appEvent(CoreEvents.showConfirmModal, {
|
||||
title: 'Delete',
|
||||
text: 'Are you sure you want to delete snapshot ' + snapshot.name + '?',
|
||||
yesText: 'Delete',
|
||||
|
@ -1,6 +1,7 @@
|
||||
import coreModule from 'app/core/core_module';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export class MoveToFolderCtrl {
|
||||
dashboards: any;
|
||||
@ -23,11 +24,11 @@ export class MoveToFolderCtrl {
|
||||
const msg = `${result.successCount} dashboard${result.successCount === 1 ? '' : 's'} moved to ${
|
||||
this.folder.title
|
||||
}`;
|
||||
appEvents.emit('alert-success', [header, msg]);
|
||||
appEvents.emit(AppEvents.alertSuccess, [header, msg]);
|
||||
}
|
||||
|
||||
if (result.totalCount === result.alreadyInFolderCount) {
|
||||
appEvents.emit('alert-error', ['Error', `Dashboards already belongs to folder ${this.folder.title}`]);
|
||||
appEvents.emit(AppEvents.alertError, ['Error', `Dashboards already belongs to folder ${this.folder.title}`]);
|
||||
}
|
||||
|
||||
this.dismiss();
|
||||
|
@ -1,6 +1,7 @@
|
||||
import coreModule from 'app/core/core_module';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import angular, { ILocationService } from 'angular';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
const template = `
|
||||
<input type="file" id="dashupload" name="dashupload" class="hide" onchange="angular.element(this).scope().file_selected"/>
|
||||
@ -30,7 +31,10 @@ export function uploadDashboardDirective(timer: any, $location: ILocationService
|
||||
dash = JSON.parse(e.target.result);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
appEvents.emit('alert-error', ['Import failed', 'JSON -> JS Serialization failed: ' + err.message]);
|
||||
appEvents.emit(AppEvents.alertError, [
|
||||
'Import failed',
|
||||
'JSON -> JS Serialization failed: ' + err.message,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -58,7 +62,7 @@ export function uploadDashboardDirective(timer: any, $location: ILocationService
|
||||
// Something
|
||||
elem[0].addEventListener('change', file_selected, false);
|
||||
} else {
|
||||
appEvents.emit('alert-error', ['Oops', 'The HTML5 File APIs are not fully supported in this browser']);
|
||||
appEvents.emit(AppEvents.alertError, ['Oops', 'The HTML5 File APIs are not fully supported in this browser']);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -6,11 +6,12 @@ import { PanelCtrl } from 'app/features/panel/panel_ctrl';
|
||||
import { getExploreUrl } from 'app/core/utils/explore';
|
||||
import { applyPanelTimeOverrides, getResolution } from 'app/features/dashboard/utils/panel';
|
||||
import { ContextSrv } from 'app/core/services/context_srv';
|
||||
import { toLegacyResponseData, TimeRange, LoadingState, DataFrame, toDataFrameDTO } from '@grafana/data';
|
||||
import { toLegacyResponseData, toDataFrameDTO, TimeRange, LoadingState, DataFrame } from '@grafana/data';
|
||||
|
||||
import { LegacyResponseData, DataSourceApi, PanelData, DataQueryResponse } from '@grafana/ui';
|
||||
import { LegacyResponseData, DataSourceApi, PanelData, DataQueryResponse, PanelEvents } from '@grafana/ui';
|
||||
import { Unsubscribable } from 'rxjs';
|
||||
import { PanelModel } from 'app/features/dashboard/state';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
class MetricsPanelCtrl extends PanelCtrl {
|
||||
scope: any;
|
||||
@ -42,8 +43,8 @@ class MetricsPanelCtrl extends PanelCtrl {
|
||||
this.scope = $scope;
|
||||
this.panel.datasource = this.panel.datasource || null;
|
||||
|
||||
this.events.on('refresh', this.onMetricsPanelRefresh.bind(this));
|
||||
this.events.on('panel-teardown', this.onPanelTearDown.bind(this));
|
||||
this.events.on(PanelEvents.refresh, this.onMetricsPanelRefresh.bind(this));
|
||||
this.events.on(PanelEvents.panelTeardown, this.onPanelTearDown.bind(this));
|
||||
}
|
||||
|
||||
private onPanelTearDown() {
|
||||
@ -71,7 +72,7 @@ class MetricsPanelCtrl extends PanelCtrl {
|
||||
// Defer panel rendering till the next digest cycle.
|
||||
// For some reason snapshot panels don't init at this time, so this helps to avoid rendering issues.
|
||||
return this.$timeout(() => {
|
||||
this.events.emit('data-snapshot-load', data);
|
||||
this.events.emit(PanelEvents.dataSnapshotLoad, data);
|
||||
});
|
||||
}
|
||||
|
||||
@ -111,7 +112,7 @@ class MetricsPanelCtrl extends PanelCtrl {
|
||||
|
||||
console.log('Panel data error:', err);
|
||||
return this.$timeout(() => {
|
||||
this.events.emit('data-error', err);
|
||||
this.events.emit(PanelEvents.dataError, err);
|
||||
});
|
||||
}
|
||||
|
||||
@ -214,7 +215,7 @@ class MetricsPanelCtrl extends PanelCtrl {
|
||||
}
|
||||
|
||||
try {
|
||||
this.events.emit('data-frames-received', data);
|
||||
this.events.emit(CoreEvents.dataFramesReceived, data);
|
||||
} catch (err) {
|
||||
this.processDataError(err);
|
||||
}
|
||||
@ -233,7 +234,7 @@ class MetricsPanelCtrl extends PanelCtrl {
|
||||
}
|
||||
|
||||
try {
|
||||
this.events.emit('data-received', result.data);
|
||||
this.events.emit(PanelEvents.dataReceived, result.data);
|
||||
} catch (err) {
|
||||
this.processDataError(err);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import _ from 'lodash';
|
||||
import { sanitize, escapeHtml } from 'app/core/utils/text';
|
||||
import { renderMarkdown } from '@grafana/data';
|
||||
import { renderMarkdown, AppEvent } from '@grafana/data';
|
||||
|
||||
import config from 'app/core/config';
|
||||
import { profiler } from 'app/core/core';
|
||||
@ -14,12 +14,12 @@ import {
|
||||
sharePanel as sharePanelUtil,
|
||||
calculateInnerPanelHeight,
|
||||
} from 'app/features/dashboard/utils/panel';
|
||||
|
||||
import { GRID_COLUMN_COUNT } from 'app/core/constants';
|
||||
import { auto } from 'angular';
|
||||
import { TemplateSrv } from '../templating/template_srv';
|
||||
import { PanelPluginMeta } from '@grafana/ui/src/types/panel';
|
||||
import { getPanelLinksSupplier } from './panellinks/linkSuppliers';
|
||||
import { PanelEvents } from '@grafana/ui';
|
||||
|
||||
export class PanelCtrl {
|
||||
panel: any;
|
||||
@ -41,6 +41,7 @@ export class PanelCtrl {
|
||||
timing: any;
|
||||
maxPanelsPerRowOptions: number[];
|
||||
|
||||
/** @ngInject */
|
||||
constructor($scope: any, $injector: auto.IInjectorService) {
|
||||
this.$injector = $injector;
|
||||
this.$location = $injector.get('$location');
|
||||
@ -56,11 +57,11 @@ export class PanelCtrl {
|
||||
this.pluginName = plugin.name;
|
||||
}
|
||||
|
||||
$scope.$on('component-did-mount', () => this.panelDidMount());
|
||||
$scope.$on(PanelEvents.componentDidMount.name, () => this.panelDidMount());
|
||||
}
|
||||
|
||||
panelDidMount() {
|
||||
this.events.emit('component-did-mount');
|
||||
this.events.emit(PanelEvents.componentDidMount);
|
||||
this.dashboard.panelInitialized(this.panel);
|
||||
}
|
||||
|
||||
@ -72,12 +73,12 @@ export class PanelCtrl {
|
||||
this.panel.refresh();
|
||||
}
|
||||
|
||||
publishAppEvent(evtName: string, evt: any) {
|
||||
this.$scope.$root.appEvent(evtName, evt);
|
||||
publishAppEvent<T>(event: AppEvent<T>, payload?: T) {
|
||||
this.$scope.$root.appEvent(event, payload);
|
||||
}
|
||||
|
||||
changeView(fullscreen: boolean, edit: boolean) {
|
||||
this.publishAppEvent('panel-change-view', {
|
||||
this.publishAppEvent(PanelEvents.panelChangeView, {
|
||||
fullscreen,
|
||||
edit,
|
||||
panelId: this.panel.id,
|
||||
@ -99,7 +100,7 @@ export class PanelCtrl {
|
||||
initEditMode() {
|
||||
if (!this.editModeInitiated) {
|
||||
this.editModeInitiated = true;
|
||||
this.events.emit('init-edit-mode', null);
|
||||
this.events.emit(PanelEvents.editModeInitialized);
|
||||
this.maxPanelsPerRowOptions = getFactors(GRID_COLUMN_COUNT);
|
||||
}
|
||||
}
|
||||
@ -193,7 +194,7 @@ export class PanelCtrl {
|
||||
click: 'ctrl.editPanelJson(); dismiss();',
|
||||
});
|
||||
|
||||
this.events.emit('init-panel-actions', menu);
|
||||
this.events.emit(PanelEvents.initPanelActions, menu);
|
||||
return menu;
|
||||
}
|
||||
|
||||
@ -212,7 +213,7 @@ export class PanelCtrl {
|
||||
}
|
||||
|
||||
render(payload?: any) {
|
||||
this.events.emit('render', payload);
|
||||
this.events.emit(PanelEvents.render, payload);
|
||||
}
|
||||
|
||||
duplicate() {
|
||||
|
@ -4,6 +4,7 @@ import $ from 'jquery';
|
||||
import Drop from 'tether-drop';
|
||||
// @ts-ignore
|
||||
import baron from 'baron';
|
||||
import { PanelEvents } from '@grafana/ui';
|
||||
|
||||
const module = angular.module('grafana.directives');
|
||||
|
||||
@ -73,7 +74,7 @@ module.directive('grafanaPanel', ($rootScope, $document, $timeout) => {
|
||||
}
|
||||
|
||||
// update scrollbar after mounting
|
||||
ctrl.events.on('component-did-mount', () => {
|
||||
ctrl.events.on(PanelEvents.componentDidMount, () => {
|
||||
if (ctrl.__proto__.constructor.scrollable) {
|
||||
const scrollRootClass = 'baron baron__root baron__clipper panel-content--scrollable';
|
||||
const scrollerClass = 'baron__scroller';
|
||||
@ -102,7 +103,7 @@ module.directive('grafanaPanel', ($rootScope, $document, $timeout) => {
|
||||
}
|
||||
});
|
||||
|
||||
ctrl.events.on('panel-size-changed', () => {
|
||||
ctrl.events.on(PanelEvents.panelSizeChanged, () => {
|
||||
ctrl.calculatePanelHeight(panelContainer[0].offsetHeight);
|
||||
$timeout(() => {
|
||||
resizeScrollableContent();
|
||||
@ -110,7 +111,7 @@ module.directive('grafanaPanel', ($rootScope, $document, $timeout) => {
|
||||
});
|
||||
});
|
||||
|
||||
ctrl.events.on('view-mode-changed', () => {
|
||||
ctrl.events.on(PanelEvents.viewModeChanged, () => {
|
||||
// first wait one pass for dashboard fullscreen view mode to take effect (classses being applied)
|
||||
setTimeout(() => {
|
||||
// then recalc style
|
||||
@ -123,7 +124,7 @@ module.directive('grafanaPanel', ($rootScope, $document, $timeout) => {
|
||||
}, 10);
|
||||
});
|
||||
|
||||
ctrl.events.on('render', () => {
|
||||
ctrl.events.on(PanelEvents.render, () => {
|
||||
// set initial height
|
||||
if (!ctrl.height) {
|
||||
ctrl.calculatePanelHeight(panelContainer[0].offsetHeight);
|
||||
|
@ -3,6 +3,8 @@ import coreModule from '../../core/core_module';
|
||||
import { ILocationService } from 'angular';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { NavModelSrv } from 'app/core/nav_model_srv';
|
||||
import { AppEventEmitter } from 'app/types';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export interface PlaylistItem {
|
||||
value: any;
|
||||
@ -27,7 +29,7 @@ export class PlaylistEditCtrl {
|
||||
|
||||
/** @ngInject */
|
||||
constructor(
|
||||
private $scope: any,
|
||||
private $scope: AppEventEmitter,
|
||||
private backendSrv: BackendSrv,
|
||||
private $location: ILocationService,
|
||||
$route: any,
|
||||
@ -102,11 +104,11 @@ export class PlaylistEditCtrl {
|
||||
|
||||
savePromise.then(
|
||||
() => {
|
||||
this.$scope.appEvent('alert-success', ['Playlist saved', '']);
|
||||
this.$scope.appEvent(AppEvents.alertSuccess, ['Playlist saved']);
|
||||
this.$location.path('/playlists');
|
||||
},
|
||||
() => {
|
||||
this.$scope.appEvent('alert-error', ['Unable to save playlist', '']);
|
||||
this.$scope.appEvent(AppEvents.alertError, ['Unable to save playlist']);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import appEvents from 'app/core/app_events';
|
||||
import locationUtil from 'app/core/utils/location_util';
|
||||
import kbn from 'app/core/utils/kbn';
|
||||
import { store } from 'app/store/store';
|
||||
import { CoreEvents } from 'app/types';
|
||||
|
||||
export const queryParamsToPreserve: { [key: string]: boolean } = {
|
||||
kiosk: true,
|
||||
@ -86,7 +87,7 @@ export class PlaylistSrv {
|
||||
this.storeUnsub = store.subscribe(() => this.storeUpdated());
|
||||
this.validPlaylistUrl = this.$location.path();
|
||||
|
||||
appEvents.emit('playlist-started');
|
||||
appEvents.emit(CoreEvents.playlistStarted);
|
||||
|
||||
return this.backendSrv.get(`/api/playlists/${playlistId}`).then((playlist: any) => {
|
||||
return this.backendSrv.get(`/api/playlists/${playlistId}/dashboards`).then((dashboards: any) => {
|
||||
@ -101,7 +102,7 @@ export class PlaylistSrv {
|
||||
if (this.isPlaying) {
|
||||
const queryParams = this.$location.search();
|
||||
if (queryParams.kiosk) {
|
||||
appEvents.emit('toggle-kiosk-mode', { exit: true });
|
||||
appEvents.emit(CoreEvents.toggleKioskMode, { exit: true });
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,7 +117,7 @@ export class PlaylistSrv {
|
||||
this.$timeout.cancel(this.cancelPromise);
|
||||
}
|
||||
|
||||
appEvents.emit('playlist-stopped');
|
||||
appEvents.emit(CoreEvents.playlistStopped);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,8 @@ import _ from 'lodash';
|
||||
import coreModule from '../../core/core_module';
|
||||
import { BackendSrv } from '@grafana/runtime';
|
||||
import { NavModelSrv } from 'app/core/nav_model_srv';
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export class PlaylistsCtrl {
|
||||
playlists: any;
|
||||
@ -24,17 +26,17 @@ export class PlaylistsCtrl {
|
||||
|
||||
this.backendSrv.delete('/api/playlists/' + playlist.id).then(
|
||||
() => {
|
||||
this.$scope.appEvent('alert-success', ['Playlist deleted', '']);
|
||||
this.$scope.appEvent(AppEvents.alertSuccess, ['Playlist deleted']);
|
||||
},
|
||||
() => {
|
||||
this.$scope.appEvent('alert-error', ['Unable to delete playlist', '']);
|
||||
this.$scope.appEvent(AppEvents.alertError, ['Unable to delete playlist']);
|
||||
this.playlists.push(playlist);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
removePlaylist(playlist: any) {
|
||||
this.$scope.appEvent('confirm-modal', {
|
||||
this.$scope.appEvent(CoreEvents.showConfirmModal, {
|
||||
title: 'Delete',
|
||||
text: 'Are you sure you want to delete playlist ' + playlist.name + '?',
|
||||
yesText: 'Delete',
|
||||
|
@ -11,7 +11,7 @@ import Page from 'app/core/components/Page/Page';
|
||||
import { getPluginSettings } from './PluginSettingsCache';
|
||||
import { importAppPlugin } from './plugin_loader';
|
||||
import { AppPlugin, AppPluginMeta, PluginType } from '@grafana/ui';
|
||||
import { NavModel } from '@grafana/data';
|
||||
import { NavModel, AppEvents } from '@grafana/data';
|
||||
import { getLoadingNav } from './PluginPage';
|
||||
import { getNotFoundNav, getWarningNav } from 'app/core/nav_model_srv';
|
||||
import { appEvents } from 'app/core/core';
|
||||
@ -58,7 +58,7 @@ class AppRootPage extends Component<Props, State> {
|
||||
const app = await getPluginSettings(pluginId).then(info => {
|
||||
const error = getAppPluginPageError(info);
|
||||
if (error) {
|
||||
appEvents.emit('alert-error', [error]);
|
||||
appEvents.emit(AppEvents.alertError, [error]);
|
||||
this.setState({ nav: getWarningNav(error) });
|
||||
return null;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import { PluginDashboard } from 'app/types';
|
||||
import { getBackendSrv } from 'app/core/services/backend_srv';
|
||||
import { appEvents } from 'app/core/core';
|
||||
import DashboardsTable from 'app/features/datasources/DashboardsTable';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
interface Props {
|
||||
plugin: PluginMeta;
|
||||
@ -79,7 +80,7 @@ export class PluginDashboards extends PureComponent<Props, State> {
|
||||
return getBackendSrv()
|
||||
.post(`/api/dashboards/import`, installCmd)
|
||||
.then((res: PluginDashboard) => {
|
||||
appEvents.emit('alert-success', ['Dashboard Imported', dash.title]);
|
||||
appEvents.emit(AppEvents.alertSuccess, ['Dashboard Imported', dash.title]);
|
||||
extend(dash, res);
|
||||
this.setState({ dashboards: [...this.state.dashboards] });
|
||||
});
|
||||
|
@ -5,7 +5,7 @@ import { connect } from 'react-redux';
|
||||
import find from 'lodash/find';
|
||||
// Types
|
||||
import { UrlQueryMap } from '@grafana/runtime';
|
||||
import { AppNotificationSeverity, StoreState } from 'app/types';
|
||||
import { StoreState, AppNotificationSeverity, CoreEvents } from 'app/types';
|
||||
import {
|
||||
Alert,
|
||||
AppPlugin,
|
||||
@ -173,7 +173,7 @@ class PluginPage extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
showUpdateInfo = () => {
|
||||
appEvents.emit('show-modal', {
|
||||
appEvents.emit(CoreEvents.showModal, {
|
||||
src: 'public/app/features/plugins/partials/update_instructions.html',
|
||||
model: this.state.plugin.meta,
|
||||
});
|
||||
|
@ -9,9 +9,10 @@ import { DataSourceSrv as DataSourceService, getDataSourceSrv as getDataSourceSe
|
||||
|
||||
// Types
|
||||
import { DataSourceApi, DataSourceSelectItem } from '@grafana/ui';
|
||||
import { ScopedVars } from '@grafana/data';
|
||||
import { ScopedVars, AppEvents } from '@grafana/data';
|
||||
import { auto } from 'angular';
|
||||
import { TemplateSrv } from '../templating/template_srv';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
export class DatasourceSrv implements DataSourceService {
|
||||
datasources: { [name: string]: DataSourceApi };
|
||||
@ -20,7 +21,7 @@ export class DatasourceSrv implements DataSourceService {
|
||||
constructor(
|
||||
private $q: any,
|
||||
private $injector: auto.IInjectorService,
|
||||
private $rootScope: any,
|
||||
private $rootScope: GrafanaRootScope,
|
||||
private templateSrv: TemplateSrv
|
||||
) {
|
||||
this.init();
|
||||
@ -86,7 +87,7 @@ export class DatasourceSrv implements DataSourceService {
|
||||
deferred.resolve(instance);
|
||||
})
|
||||
.catch(err => {
|
||||
this.$rootScope.appEvent('alert-error', [dsConfig.name + ' plugin failed', err.toString()]);
|
||||
this.$rootScope.appEvent(AppEvents.alertError, [dsConfig.name + ' plugin failed', err.toString()]);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
|
@ -7,12 +7,13 @@ import coreModule from 'app/core/core_module';
|
||||
import { DataSourceApi } from '@grafana/ui';
|
||||
import { importPanelPlugin, importDataSourcePlugin, importAppPlugin } from './plugin_loader';
|
||||
import DatasourceSrv from './datasource_srv';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
|
||||
/** @ngInject */
|
||||
function pluginDirectiveLoader(
|
||||
$compile: any,
|
||||
datasourceSrv: DatasourceSrv,
|
||||
$rootScope: any,
|
||||
$rootScope: GrafanaRootScope,
|
||||
$q: IQService,
|
||||
$http: any,
|
||||
$templateCache: any,
|
||||
|
@ -4,6 +4,8 @@ import _ from 'lodash';
|
||||
import { getPluginSettings } from './PluginSettingsCache';
|
||||
import { PluginMeta } from '@grafana/ui';
|
||||
import { NavModelSrv } from 'app/core/core';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export class AppPageCtrl {
|
||||
page: any;
|
||||
@ -14,7 +16,7 @@ export class AppPageCtrl {
|
||||
/** @ngInject */
|
||||
constructor(
|
||||
private $routeParams: any,
|
||||
private $rootScope: any,
|
||||
private $rootScope: GrafanaRootScope,
|
||||
private navModelSrv: NavModelSrv,
|
||||
private $q: IQService
|
||||
) {
|
||||
@ -26,7 +28,7 @@ export class AppPageCtrl {
|
||||
this.initPage(settings);
|
||||
})
|
||||
.catch(err => {
|
||||
this.$rootScope.appEvent('alert-error', ['Unknown Plugin', '']);
|
||||
this.$rootScope.appEvent(AppEvents.alertError, ['Unknown Plugin']);
|
||||
this.navModel = this.navModelSrv.getNotFoundNav();
|
||||
});
|
||||
}
|
||||
@ -36,12 +38,12 @@ export class AppPageCtrl {
|
||||
this.page = _.find(app.includes, { slug: this.$routeParams.slug });
|
||||
|
||||
if (!this.page) {
|
||||
this.$rootScope.appEvent('alert-error', ['App Page Not Found', '']);
|
||||
this.$rootScope.appEvent(AppEvents.alertError, ['App Page Not Found']);
|
||||
this.navModel = this.navModelSrv.getNotFoundNav();
|
||||
return;
|
||||
}
|
||||
if (app.type !== 'app' || !app.enabled) {
|
||||
this.$rootScope.appEvent('alert-error', ['Application Not Enabled', '']);
|
||||
this.$rootScope.appEvent(AppEvents.alertError, ['Application Not Enabled']);
|
||||
this.navModel = this.navModelSrv.getNotFoundNav();
|
||||
return;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ const templateSrv: any = {
|
||||
};
|
||||
|
||||
describe('datasource_srv', () => {
|
||||
const _datasourceSrv = new DatasourceSrv({}, {} as any, {}, templateSrv);
|
||||
const _datasourceSrv = new DatasourceSrv({}, {} as any, {} as any, templateSrv);
|
||||
|
||||
describe('when loading external datasources', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -5,6 +5,7 @@ import appEvents from 'app/core/app_events';
|
||||
import DatasourceSrv from '../plugins/datasource_srv';
|
||||
import { VariableSrv } from './all';
|
||||
import { TemplateSrv } from './template_srv';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
export class VariableEditorCtrl {
|
||||
/** @ngInject */
|
||||
@ -85,13 +86,16 @@ export class VariableEditorCtrl {
|
||||
}
|
||||
|
||||
if (!$scope.current.name.match(/^\w+$/)) {
|
||||
appEvents.emit('alert-warning', ['Validation', 'Only word and digit characters are allowed in variable names']);
|
||||
appEvents.emit(AppEvents.alertWarning, [
|
||||
'Validation',
|
||||
'Only word and digit characters are allowed in variable names',
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
|
||||
const sameName: any = _.find($scope.variables, { name: $scope.current.name });
|
||||
if (sameName && sameName !== $scope.current) {
|
||||
appEvents.emit('alert-warning', ['Validation', 'Variable with the same name already exists']);
|
||||
appEvents.emit(AppEvents.alertWarning, ['Validation', 'Variable with the same name already exists']);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -100,7 +104,7 @@ export class VariableEditorCtrl {
|
||||
_.isString($scope.current.query) &&
|
||||
$scope.current.query.match(new RegExp('\\$' + $scope.current.name + '(/| |$)'))
|
||||
) {
|
||||
appEvents.emit('alert-warning', [
|
||||
appEvents.emit(AppEvents.alertWarning, [
|
||||
'Validation',
|
||||
'Query cannot contain a reference to itself. Variable: $' + $scope.current.name,
|
||||
]);
|
||||
@ -128,7 +132,10 @@ export class VariableEditorCtrl {
|
||||
if (err.data && err.data.message) {
|
||||
err.message = err.data.message;
|
||||
}
|
||||
appEvents.emit('alert-error', ['Templating', 'Template variables could not be initialized: ' + err.message]);
|
||||
appEvents.emit(AppEvents.alertError, [
|
||||
'Templating',
|
||||
'Template variables could not be initialized: ' + err.message,
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { VariableEditorCtrl } from '../editor_ctrl';
|
||||
import { TemplateSrv } from '../template_srv';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
|
||||
let mockEmit: any;
|
||||
jest.mock('app/core/app_events', () => {
|
||||
@ -32,7 +33,7 @@ describe('VariableEditorCtrl', () => {
|
||||
it('should emit an error', () => {
|
||||
return scope.runQuery().then(res => {
|
||||
expect(mockEmit).toBeCalled();
|
||||
expect(mockEmit.mock.calls[0][0]).toBe('alert-error');
|
||||
expect(mockEmit.mock.calls[0][0]).toBe(AppEvents.alertError);
|
||||
expect(mockEmit.mock.calls[0][1][0]).toBe('Templating');
|
||||
expect(mockEmit.mock.calls[0][1][1]).toBe('Template variables could not be initialized: error');
|
||||
});
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user