grafana/public/app/app.ts
Jack Westbrook ad68f3c5e6
DashboardSettings: Migrate Link Settings to React (#31150)
* feat(dashboardsettings): migrate dashboard links EmptyListCTA to react

* feat(dashboardsettings): initial commit of links settings migration to react

* feat(dashboardsettings): add links form functionality

* refactor(dashboardsettings): separate out linksettings components and concerns

* Updates to links list

* Form improvements

* test(dashboardlinks): update links so tests run

* refactor: move _.move to arrayMove for testing purposes

* test(dashboardsettings): initial commit of link settings tests

* refactor(app): put back lodash move method for backwards compatibility

* test(dashboardsettings): add links settings tests

* style(dashboardsettings): camelcase constants

* chore(dashboardsettings): delete old angular links settings view

* fix(dashboardsettings): forceupdate links on submenuVisibilityChanged and correct imports

* chore: remove reference to old angular link settings components

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2021-02-25 11:50:10 +01:00

229 lines
7.2 KiB
TypeScript

import 'symbol-observable';
import 'core-js/stable';
import 'regenerator-runtime/runtime';
import 'whatwg-fetch'; // fetch polyfill needed for PhantomJs rendering
import 'abortcontroller-polyfill/dist/polyfill-patch-fetch'; // fetch polyfill needed for PhantomJs rendering
// @ts-ignore
import ttiPolyfill from 'tti-polyfill';
import 'file-saver';
import 'jquery';
import _ from 'lodash';
import angular from 'angular';
import 'angular-route';
import 'angular-sanitize';
import 'angular-bindonce';
import 'react';
import 'react-dom';
import 'vendor/bootstrap/bootstrap';
import 'vendor/angular-other/angular-strap';
import config from 'app/core/config';
// @ts-ignore ignoring this for now, otherwise we would have to extend _ interface with move
import {
AppEvents,
setLocale,
setTimeZoneResolver,
standardEditorsRegistry,
standardFieldConfigEditorRegistry,
standardTransformersRegistry,
} from '@grafana/data';
import appEvents from 'app/core/app_events';
import { checkBrowserCompatibility } from 'app/core/utils/browser';
import { arrayMove } from 'app/core/utils/arrayMove';
import { importPluginModule } from 'app/features/plugins/plugin_loader';
import { angularModules, coreModule } from 'app/core/core_module';
import { registerAngularDirectives } from 'app/core/core';
import { setupAngularRoutes } from 'app/routes/routes';
import { registerEchoBackend, setEchoSrv } from '@grafana/runtime';
import { Echo } from './core/services/echo/Echo';
import { reportPerformance } from './core/services/echo/EchoSrv';
import { PerformanceBackend } from './core/services/echo/backends/PerformanceBackend';
import 'app/routes/GrafanaCtrl';
import 'app/features/all';
import { getScrollbarWidth, getStandardFieldConfigs, getStandardOptionEditors } from '@grafana/ui';
import { getDefaultVariableAdapters, variableAdapters } from './features/variables/adapters';
import { initDevFeatures } from './dev';
import { getStandardTransformers } from 'app/core/utils/standardTransformers';
import { SentryEchoBackend } from './core/services/echo/backends/sentry/SentryBackend';
import { monkeyPatchInjectorWithPreAssignedBindings } from './core/injectorMonkeyPatch';
import { setVariableQueryRunner, VariableQueryRunner } from './features/variables/query/VariableQueryRunner';
// add move to lodash for backward compatabilty with plugins
// @ts-ignore
_.move = arrayMove;
// import symlinked extensions
const extensionsIndex = (require as any).context('.', true, /extensions\/index.ts/);
extensionsIndex.keys().forEach((key: any) => {
extensionsIndex(key);
});
if (process.env.NODE_ENV === 'development') {
initDevFeatures();
}
export class GrafanaApp {
registerFunctions: any;
ngModuleDependencies: any[];
preBootModules: any[] | null;
constructor() {
this.preBootModules = [];
this.registerFunctions = {};
this.ngModuleDependencies = [];
}
useModule(module: angular.IModule) {
if (this.preBootModules) {
this.preBootModules.push(module);
} else {
_.extend(module, this.registerFunctions);
}
this.ngModuleDependencies.push(module.name);
return module;
}
init() {
const app = angular.module('grafana', []);
addClassIfNoOverlayScrollbar();
setLocale(config.bootData.user.locale);
setTimeZoneResolver(() => config.bootData.user.timezone);
standardEditorsRegistry.setInit(getStandardOptionEditors);
standardFieldConfigEditorRegistry.setInit(getStandardFieldConfigs);
standardTransformersRegistry.setInit(getStandardTransformers);
variableAdapters.setInit(getDefaultVariableAdapters);
setVariableQueryRunner(new VariableQueryRunner());
app.config(
(
$controllerProvider: angular.IControllerProvider,
$compileProvider: angular.ICompileProvider,
$filterProvider: angular.IFilterProvider,
$httpProvider: angular.IHttpProvider,
$provide: angular.auto.IProvideService
) => {
if (config.buildInfo.env !== 'development') {
$compileProvider.debugInfoEnabled(false);
}
$httpProvider.useApplyAsync(true);
this.registerFunctions.controller = $controllerProvider.register;
this.registerFunctions.directive = $compileProvider.directive;
this.registerFunctions.factory = $provide.factory;
this.registerFunctions.service = $provide.service;
this.registerFunctions.filter = $filterProvider.register;
$provide.decorator('$http', [
'$delegate',
'$templateCache',
($delegate: any, $templateCache: any) => {
const get = $delegate.get;
$delegate.get = (url: string, config: any) => {
if (url.match(/\.html$/)) {
// some template's already exist in the cache
if (!$templateCache.get(url)) {
url += '?v=' + new Date().getTime();
}
}
return get(url, config);
};
return $delegate;
},
]);
}
);
this.ngModuleDependencies = [
'grafana.core',
'ngRoute',
'ngSanitize',
'$strap.directives',
'grafana',
'pasvaz.bindonce',
'react',
];
// makes it possible to add dynamic stuff
_.each(angularModules, (m: angular.IModule) => {
this.useModule(m);
});
// register react angular wrappers
coreModule.config(setupAngularRoutes);
registerAngularDirectives();
// disable tool tip animation
$.fn.tooltip.defaults.animation = false;
// bootstrap the app
const injector: any = angular.bootstrap(document, this.ngModuleDependencies);
injector.invoke(() => {
_.each(this.preBootModules, (module: angular.IModule) => {
_.extend(module, this.registerFunctions);
});
this.preBootModules = null;
if (!checkBrowserCompatibility()) {
setTimeout(() => {
appEvents.emit(AppEvents.alertWarning, [
'Your browser is not fully supported',
'A newer browser version is recommended',
]);
}, 1000);
}
});
monkeyPatchInjectorWithPreAssignedBindings(injector);
// Preload selected app plugins
for (const modulePath of config.pluginsToPreload) {
importPluginModule(modulePath);
}
}
initEchoSrv() {
setEchoSrv(new Echo({ debug: process.env.NODE_ENV === 'development' }));
ttiPolyfill.getFirstConsistentlyInteractive().then((tti: any) => {
// Collecting paint metrics first
const paintMetrics = performance && performance.getEntriesByType ? performance.getEntriesByType('paint') : [];
for (const metric of paintMetrics) {
reportPerformance(metric.name, Math.round(metric.startTime + metric.duration));
}
reportPerformance('tti', tti);
});
registerEchoBackend(new PerformanceBackend({}));
if (config.sentry.enabled) {
registerEchoBackend(
new SentryEchoBackend({
...config.sentry,
user: config.bootData.user,
buildInfo: config.buildInfo,
})
);
}
window.addEventListener('DOMContentLoaded', () => {
reportPerformance('dcl', Math.round(performance.now()));
});
}
}
function addClassIfNoOverlayScrollbar() {
if (getScrollbarWidth() > 0) {
document.body.classList.add('no-overlay-scrollbar');
}
}
export default new GrafanaApp();