2022-04-22 08:33:13 -05:00
import * as emotion from '@emotion/css' ;
2022-09-19 09:54:13 -05:00
import * as emotionReact from '@emotion/react' ;
2022-04-22 08:33:13 -05:00
import * as d3 from 'd3' ;
2017-12-20 05:33:33 -06:00
import jquery from 'jquery' ;
2022-04-22 08:33:13 -05:00
import _ from 'lodash' ; // eslint-disable-line lodash/import-scope
import moment from 'moment' ; // eslint-disable-line no-restricted-imports
2018-06-14 06:32:57 -05:00
import prismjs from 'prismjs' ;
import react from 'react' ;
import reactDom from 'react-dom' ;
2022-09-19 04:49:35 -05:00
import * as reactRedux from 'react-redux' ; // eslint-disable-line no-restricted-imports
2023-04-27 00:18:38 -05:00
import * as reactRouterDom from 'react-router-dom' ;
import * as reactRouterCompat from 'react-router-dom-v5-compat' ;
2019-11-01 10:05:18 -05:00
import * as redux from 'redux' ;
2022-04-22 08:33:13 -05:00
import * as rxjs from 'rxjs' ;
import * as rxjsOperators from 'rxjs/operators' ;
import slate from 'slate' ;
import slatePlain from 'slate-plain-serializer' ;
2022-09-06 09:23:48 -05:00
import slateReact from 'slate-react' ;
2018-06-14 06:32:57 -05:00
2022-04-22 08:33:13 -05:00
import * as grafanaData from '@grafana/data' ;
import * as grafanaRuntime from '@grafana/runtime' ;
import * as grafanaUIraw from '@grafana/ui' ;
2022-08-03 05:33:13 -05:00
import TableModel from 'app/core/TableModel' ;
2017-12-20 05:33:33 -06:00
import config from 'app/core/config' ;
2021-11-09 01:37:16 -06:00
import { appEvents , contextSrv } from 'app/core/core' ;
2019-04-12 11:45:22 -05:00
import { BackendSrv , getBackendSrv } from 'app/core/services/backend_srv' ;
2017-12-20 05:33:33 -06:00
import impressionSrv from 'app/core/services/impression_srv' ;
2022-04-22 08:33:13 -05:00
import TimeSeries from 'app/core/time_series2' ;
import * as flatten from 'app/core/utils/flatten' ;
import kbn from 'app/core/utils/kbn' ;
import * as ticks from 'app/core/utils/ticks' ;
2022-07-20 02:25:09 -05:00
import { GenericDataSourcePlugin } from '../datasources/types' ;
2022-04-22 08:33:13 -05:00
import builtInPlugins from './built_in_plugins' ;
2023-06-28 08:58:37 -05:00
import { PLUGIN_CDN_URL_KEY } from './constants' ;
2023-06-05 03:51:36 -05:00
import { sandboxPluginDependencies } from './sandbox/plugin_dependencies' ;
import { importPluginModuleInSandbox } from './sandbox/sandbox_plugin_loader' ;
2023-01-27 08:08:17 -06:00
import { locateFromCDN , translateForCDN } from './systemjsPlugins/pluginCDN' ;
import { fetchCSS , locateCSS } from './systemjsPlugins/pluginCSS' ;
import { locateWithCache , registerPluginInCache } from './systemjsPlugins/pluginCacheBuster' ;
2017-10-01 13:02:25 -05:00
2019-11-06 07:27:14 -06:00
// Help the 6.4 to 6.5 migration
// The base classes were moved from @grafana/ui to @grafana/data
// This exposes the same classes on both import paths
const grafanaUI = grafanaUIraw as any ;
grafanaUI . PanelPlugin = grafanaData . PanelPlugin ;
grafanaUI . DataSourcePlugin = grafanaData . DataSourcePlugin ;
grafanaUI . AppPlugin = grafanaData . AppPlugin ;
grafanaUI . DataSourceApi = grafanaData . DataSourceApi ;
2023-01-27 08:08:17 -06:00
grafanaRuntime . SystemJS . registry . set ( 'css' , grafanaRuntime . SystemJS . newModule ( { locate : locateCSS , fetch : fetchCSS } ) ) ;
2021-11-10 04:54:58 -06:00
grafanaRuntime . SystemJS . registry . set ( 'plugin-loader' , grafanaRuntime . SystemJS . newModule ( { locate : locateWithCache } ) ) ;
2023-01-27 08:08:17 -06:00
grafanaRuntime . SystemJS . registry . set (
'cdn-loader' ,
grafanaRuntime . SystemJS . newModule ( { locate : locateFromCDN , translate : translateForCDN } )
) ;
2018-05-29 05:01:10 -05:00
2019-07-04 06:32:09 -05:00
grafanaRuntime . SystemJS . config ( {
2017-12-20 05:33:33 -06:00
baseURL : 'public' ,
defaultExtension : 'js' ,
2017-10-01 13:02:25 -05:00
packages : {
2017-12-19 09:06:54 -06:00
plugins : {
2017-12-20 05:33:33 -06:00
defaultExtension : 'js' ,
} ,
2023-01-27 08:08:17 -06:00
'plugin-cdn' : {
defaultExtension : 'js' ,
} ,
2017-10-01 13:02:25 -05:00
} ,
map : {
2017-12-20 05:33:33 -06:00
text : 'vendor/plugin-text/text.js' ,
2017-10-01 13:02:25 -05:00
} ,
2017-10-18 04:15:46 -05:00
meta : {
2018-07-12 06:16:41 -05:00
'/*' : {
2017-11-01 04:45:20 -05:00
esModule : true ,
2017-12-20 05:33:33 -06:00
authorization : true ,
2018-05-29 05:01:10 -05:00
loader : 'plugin-loader' ,
2017-12-20 05:33:33 -06:00
} ,
2023-01-27 08:08:17 -06:00
'*.css' : {
loader : 'css' ,
} ,
2023-06-28 08:58:37 -05:00
[ ` ${ PLUGIN_CDN_URL_KEY } /* ` ] : {
2023-01-27 08:08:17 -06:00
esModule : true ,
authorization : false ,
loader : 'cdn-loader' ,
} ,
2017-12-20 05:33:33 -06:00
} ,
2017-10-01 13:02:25 -05:00
} ) ;
2022-02-16 10:14:33 -06:00
export function exposeToPlugin ( name : string , component : any ) {
2019-07-18 01:03:04 -05:00
grafanaRuntime . SystemJS . registerDynamic ( name , [ ] , true , ( require : any , exports : any , module : { exports : any } ) = > {
2017-10-02 08:30:14 -05:00
module .exports = component ;
} ) ;
2023-06-05 03:51:36 -05:00
// exposes this dependency to sandboxed plugins too.
// the following sandboxPluginDependencies don't depend or interact
// with SystemJS in any way.
sandboxPluginDependencies . set ( name , component ) ;
2017-10-02 08:30:14 -05:00
}
2019-06-18 10:17:27 -05:00
exposeToPlugin ( '@grafana/data' , grafanaData ) ;
2018-12-21 05:27:43 -06:00
exposeToPlugin ( '@grafana/ui' , grafanaUI ) ;
2019-06-18 10:17:27 -05:00
exposeToPlugin ( '@grafana/runtime' , grafanaRuntime ) ;
2017-12-20 05:33:33 -06:00
exposeToPlugin ( 'lodash' , _ ) ;
exposeToPlugin ( 'moment' , moment ) ;
exposeToPlugin ( 'jquery' , jquery ) ;
exposeToPlugin ( 'd3' , d3 ) ;
2019-09-19 08:27:31 -05:00
exposeToPlugin ( 'rxjs' , rxjs ) ;
exposeToPlugin ( 'rxjs/operators' , rxjsOperators ) ;
2023-04-27 00:18:38 -05:00
// Migration - React Router v5 -> v6
// =================================
// Plugins that still use "react-router-dom@v5" don't depend on react-router directly, so they will not use this import.
// (The react-router-dom@v5 that we expose for them depends on the "react-router" package internally from core.)
//
// Plugins that would like update to "react-router-dom@v6" will need to bundle "react-router-dom",
// however they cannot bundle "react-router" - this would mean that we have two instances of "react-router"
// in the app, which would casue issues. As the "react-router-dom-v5-compat" package re-exports everything from "react-router-dom@v6"
// which then re-exports everything from "react-router@v6", we are in the lucky state to be able to expose a compatible v6 version of the router to plugins by
// just exposing "react-router-dom-v5-compat".
//
// (This means that we are exposing two versions of the same package).
exposeToPlugin ( 'react-router' , reactRouterCompat ) ; // react-router-dom@v6, react-router@v6 (included)
exposeToPlugin ( 'react-router-dom' , reactRouterDom ) ; // react-router-dom@v5
2017-10-26 05:07:23 -05:00
2018-06-14 06:32:57 -05:00
// Experimental modules
exposeToPlugin ( 'prismjs' , prismjs ) ;
exposeToPlugin ( 'slate' , slate ) ;
2022-09-06 09:23:48 -05:00
exposeToPlugin ( 'slate-react' , slateReact ) ;
2022-09-12 08:22:01 -05:00
exposeToPlugin ( '@grafana/slate-react' , slateReact ) ; // for backwards compatibility with older plugins
2018-06-14 06:32:57 -05:00
exposeToPlugin ( 'slate-plain-serializer' , slatePlain ) ;
exposeToPlugin ( 'react' , react ) ;
exposeToPlugin ( 'react-dom' , reactDom ) ;
2019-08-14 02:20:23 -05:00
exposeToPlugin ( 'react-redux' , reactRedux ) ;
exposeToPlugin ( 'redux' , redux ) ;
2019-07-05 06:33:42 -05:00
exposeToPlugin ( 'emotion' , emotion ) ;
2021-04-01 07:15:23 -05:00
exposeToPlugin ( '@emotion/css' , emotion ) ;
2022-09-19 09:54:13 -05:00
exposeToPlugin ( '@emotion/react' , emotionReact ) ;
2018-06-14 06:32:57 -05:00
2017-12-20 05:33:33 -06:00
exposeToPlugin ( 'app/features/dashboard/impression_store' , {
2017-11-24 09:18:56 -06:00
impressions : impressionSrv ,
2017-12-20 05:33:33 -06:00
__esModule : true ,
2017-10-20 03:38:52 -05:00
} ) ;
2019-04-12 11:45:22 -05:00
/ * *
* NOTE : this is added temporarily while we explore a long term solution
* If you use this export , only use the :
* get / delete / p o s t / p a t c h / r e q u e s t m e t h o d s
* /
exposeToPlugin ( 'app/core/services/backend_srv' , {
BackendSrv ,
getBackendSrv ,
} ) ;
2021-02-11 06:45:25 -06:00
exposeToPlugin ( 'app/core/utils/datemath' , grafanaData . dateMath ) ;
2017-12-20 05:33:33 -06:00
exposeToPlugin ( 'app/core/utils/flatten' , flatten ) ;
exposeToPlugin ( 'app/core/utils/kbn' , kbn ) ;
exposeToPlugin ( 'app/core/utils/ticks' , ticks ) ;
exposeToPlugin ( 'app/core/config' , config ) ;
exposeToPlugin ( 'app/core/time_series' , TimeSeries ) ;
exposeToPlugin ( 'app/core/time_series2' , TimeSeries ) ;
exposeToPlugin ( 'app/core/table_model' , TableModel ) ;
exposeToPlugin ( 'app/core/app_events' , appEvents ) ;
exposeToPlugin ( 'app/core/core' , {
2017-10-10 08:06:54 -05:00
appEvents : appEvents ,
contextSrv : contextSrv ,
2017-12-20 05:33:33 -06:00
__esModule : true ,
2017-10-10 08:06:54 -05:00
} ) ;
2017-10-01 13:02:25 -05:00
2017-12-20 05:33:33 -06:00
import 'vendor/flot/jquery.flot' ;
import 'vendor/flot/jquery.flot.selection' ;
import 'vendor/flot/jquery.flot.time' ;
import 'vendor/flot/jquery.flot.stack' ;
import 'vendor/flot/jquery.flot.stackpercent' ;
import 'vendor/flot/jquery.flot.fillbelow' ;
import 'vendor/flot/jquery.flot.crosshair' ;
import 'vendor/flot/jquery.flot.dashes' ;
2018-07-18 05:05:45 -05:00
import 'vendor/flot/jquery.flot.gauge' ;
2017-10-01 13:02:25 -05:00
2017-10-12 08:33:37 -05:00
const flotDeps = [
2017-12-20 05:33:33 -06:00
'jquery.flot' ,
'jquery.flot.pie' ,
'jquery.flot.time' ,
'jquery.flot.fillbelow' ,
'jquery.flot.crosshair' ,
'jquery.flot.stack' ,
'jquery.flot.selection' ,
'jquery.flot.stackpercent' ,
'jquery.flot.events' ,
2018-07-18 05:05:45 -05:00
'jquery.flot.gauge' ,
2017-10-12 08:33:37 -05:00
] ;
2018-07-05 15:10:39 -05:00
2018-08-26 10:14:40 -05:00
for ( const flotDep of flotDeps ) {
2017-12-19 09:06:54 -06:00
exposeToPlugin ( flotDep , { fakeDep : 1 } ) ;
2017-10-01 13:02:25 -05:00
}
2023-06-05 03:51:36 -05:00
export async function importPluginModule ( {
path ,
version ,
isAngular ,
pluginId ,
} : {
path : string ;
pluginId : string ;
version? : string ;
isAngular? : boolean ;
} ) : Promise < any > {
2021-11-10 04:54:58 -06:00
if ( version ) {
registerPluginInCache ( { path , version } ) ;
}
2018-08-26 10:14:40 -05:00
const builtIn = builtInPlugins [ path ] ;
2017-10-01 13:02:25 -05:00
if ( builtIn ) {
2019-09-03 03:29:02 -05:00
// for handling dynamic imports
if ( typeof builtIn === 'function' ) {
return await builtIn ( ) ;
} else {
2021-11-10 12:06:55 -06:00
return builtIn ;
2019-09-03 03:29:02 -05:00
}
2017-10-01 13:02:25 -05:00
}
2023-06-05 03:51:36 -05:00
// the sandboxing environment code cannot work in nodejs and requires a real browser
2023-07-05 04:16:56 -05:00
if ( isFrontendSandboxSupported ( { isAngular , pluginId } ) ) {
2023-06-05 03:51:36 -05:00
return importPluginModuleInSandbox ( { pluginId } ) ;
}
2019-07-04 06:32:09 -05:00
return grafanaRuntime . SystemJS . import ( path ) ;
2017-10-01 13:02:25 -05:00
}
2023-07-05 04:16:56 -05:00
function isFrontendSandboxSupported ( { isAngular , pluginId } : { isAngular? : boolean ; pluginId : string } ) : boolean {
2023-06-21 07:49:22 -05:00
// To fast test and debug the sandbox in the browser.
const sandboxQueryParam = location . search . includes ( 'nosandbox' ) && config . buildInfo . env === 'development' ;
2023-07-05 04:16:56 -05:00
const isPluginExcepted = config . disableFrontendSandboxForPlugins . includes ( pluginId ) ;
2023-06-21 07:49:22 -05:00
return (
! isAngular &&
Boolean ( config . featureToggles . pluginsFrontendSandbox ) &&
process . env . NODE_ENV !== 'test' &&
2023-07-05 04:16:56 -05:00
! isPluginExcepted &&
2023-06-21 07:49:22 -05:00
! sandboxQueryParam
) ;
2023-06-05 03:51:36 -05:00
}
2021-02-11 06:45:25 -06:00
export function importDataSourcePlugin ( meta : grafanaData.DataSourcePluginMeta ) : Promise < GenericDataSourcePlugin > {
2023-06-05 03:51:36 -05:00
return importPluginModule ( {
path : meta.module ,
version : meta.info?.version ,
isAngular : meta.angularDetected ,
pluginId : meta.id ,
} ) . then ( ( pluginExports ) = > {
2019-04-04 11:30:15 -05:00
if ( pluginExports . plugin ) {
2019-11-15 03:18:09 -06:00
const dsPlugin = pluginExports . plugin as GenericDataSourcePlugin ;
2019-05-01 00:36:46 -05:00
dsPlugin . meta = meta ;
return dsPlugin ;
2019-04-04 11:30:15 -05:00
}
if ( pluginExports . Datasource ) {
2021-02-11 06:45:25 -06:00
const dsPlugin = new grafanaData . DataSourcePlugin <
grafanaData . DataSourceApi < grafanaData.DataQuery , grafanaData.DataSourceJsonData > ,
grafanaData . DataQuery ,
grafanaData . DataSourceJsonData
2019-11-15 03:18:09 -06:00
> ( pluginExports . Datasource ) ;
2019-04-04 11:30:15 -05:00
dsPlugin . setComponentsFromLegacyExports ( pluginExports ) ;
2019-05-01 00:36:46 -05:00
dsPlugin . meta = meta ;
2019-04-04 11:30:15 -05:00
return dsPlugin ;
}
throw new Error ( 'Plugin module is missing DataSourcePlugin or Datasource constructor export' ) ;
} ) ;
}
2021-02-11 06:45:25 -06:00
export function importAppPlugin ( meta : grafanaData.PluginMeta ) : Promise < grafanaData.AppPlugin > {
2023-06-05 03:51:36 -05:00
return importPluginModule ( {
path : meta.module ,
version : meta.info?.version ,
isAngular : meta.angularDetected ,
pluginId : meta.id ,
} ) . then ( ( pluginExports ) = > {
2021-02-11 06:45:25 -06:00
const plugin = pluginExports . plugin ? ( pluginExports . plugin as grafanaData . AppPlugin ) : new grafanaData . AppPlugin ( ) ;
2019-05-20 15:05:23 -05:00
plugin . init ( meta ) ;
plugin . meta = meta ;
2019-06-15 01:26:31 -05:00
plugin . setComponentsFromLegacyExports ( pluginExports ) ;
2019-05-01 00:36:46 -05:00
return plugin ;
2019-04-04 11:30:15 -05:00
} ) ;
}