The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/angular/GrafanaCtrl.ts

166 lines
5.1 KiB

import { IRootScopeService, IAngularEvent, auto } from 'angular';
import $ from 'jquery';
import _ from 'lodash'; // eslint-disable-line lodash/import-scope
import { AppEvent } from '@grafana/data';
import { setLegacyAngularInjector, setAppEvents, setAngularLoader } from '@grafana/runtime';
import { colors } from '@grafana/ui';
import coreModule from 'app/angular/core_module';
import { AngularLoader } from 'app/angular/services/AngularLoader';
import appEvents from 'app/core/app_events';
import config from 'app/core/config';
import { ContextSrv } from 'app/core/services/context_srv';
import { initGrafanaLive } from 'app/features/live';
import { CoreEvents, AppEventEmitter, AppEventConsumer } from 'app/types';
import { UtilSrv } from './services/UtilSrv';
export type GrafanaRootScope = IRootScopeService & AppEventEmitter & AppEventConsumer & { colors: string[] };
export class GrafanaCtrl {
/** @ngInject */
constructor(
$scope: any,
utilSrv: UtilSrv,
$rootScope: GrafanaRootScope,
contextSrv: ContextSrv,
angularLoader: AngularLoader,
$injector: auto.IInjectorService
) {
// make angular loader service available to react components
setAngularLoader(angularLoader);
setLegacyAngularInjector($injector);
setAppEvents(appEvents);
initGrafanaLive();
$scope.init = () => {
$scope.contextSrv = contextSrv;
$scope.appSubUrl = config.appSubUrl;
$scope._ = _;
utilSrv.init();
};
$rootScope.colors = colors;
$rootScope.onAppEvent = function <T>(
event: AppEvent<T> | string,
callback: (event: IAngularEvent, ...args: any[]) => void,
localScope?: any
) {
let unbind;
if (typeof event === 'string') {
unbind = $rootScope.$on(event, callback);
} else {
unbind = $rootScope.$on(event.name, callback);
}
let callerScope = this;
if (callerScope.$id === 1 && !localScope) {
console.warn('warning rootScope onAppEvent called without localscope');
}
if (localScope) {
callerScope = localScope;
}
callerScope.$on('$destroy', unbind);
};
$rootScope.appEvent = <T>(event: AppEvent<T> | string, payload?: T | any) => {
if (typeof event === 'string') {
$rootScope.$emit(event, payload);
appEvents.emit(event, payload);
} else {
$rootScope.$emit(event.name, payload);
appEvents.emit(event, payload);
}
};
$scope.init();
}
}
/** @ngInject */
export function grafanaAppDirective() {
return {
restrict: 'E',
controller: GrafanaCtrl,
link: (scope: IRootScopeService & AppEventEmitter, elem: JQuery) => {
const body = $('body');
// see https://github.com/zenorocha/clipboard.js/issues/155
$.fn.modal.Constructor.prototype.enforceFocus = () => {};
appEvents.on(CoreEvents.toggleSidemenuHidden, () => {
body.toggleClass('sidemenu-hidden');
});
// handle in active view state class
let lastActivity = new Date().getTime();
let activeUser = true;
const inActiveTimeLimit = 60 * 5000;
function checkForInActiveUser() {
if (!activeUser) {
return;
}
// only go to activity low mode on dashboard page
if (!body.hasClass('page-dashboard')) {
return;
}
if (new Date().getTime() - lastActivity > inActiveTimeLimit) {
activeUser = false;
body.addClass('view-mode--inactive');
}
}
function userActivityDetected() {
lastActivity = new Date().getTime();
if (!activeUser) {
activeUser = true;
body.removeClass('view-mode--inactive');
}
}
// mouse and keyboard is user activity
body.mousemove(userActivityDetected);
body.keydown(userActivityDetected);
// set useCapture = true to catch event here
document.addEventListener('wheel', userActivityDetected, { capture: true, passive: true });
// treat tab change as activity
document.addEventListener('visibilitychange', userActivityDetected);
// check every 2 seconds
setInterval(checkForInActiveUser, 2000);
// handle document clicks that should hide things
body.click((evt) => {
const target = $(evt.target);
if (target.parents().length === 0) {
return;
}
// ensure dropdown menu doesn't impact on z-index
body.find('.dropdown-menu-open').removeClass('dropdown-menu-open');
// for stuff that animates, slides out etc, clicking it needs to
// hide it right away
const clickAutoHide = target.closest('[data-click-hide]');
if (clickAutoHide.length) {
const clickAutoHideParent = clickAutoHide.parent();
clickAutoHide.detach();
setTimeout(() => {
clickAutoHideParent.append(clickAutoHide);
}, 100);
}
// hide popovers
const popover = elem.find('.popover');
if (popover.length > 0 && target.parents('.graph-legend').length === 0) {
popover.hide();
}
});
},
};
}
coreModule.directive('grafanaApp', grafanaAppDirective);