Add a @grafana/runtime package with backendSrv interface (#16533)

grafana-runtime/tsconfig.json imports query to avoid a build error  ¯\_(ツ)_/¯
This commit is contained in:
Ryan McKinley 2019-06-03 17:55:59 +02:00 committed by GitHub
parent b7a9533476
commit 96ba32d0c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 255 additions and 74 deletions

View File

@ -0,0 +1,3 @@
# Grafana Runtime library
Interfaces that let you use the runtime...

View File

@ -0,0 +1,7 @@
'use strict'
if (process.env.NODE_ENV === 'production') {
module.exports = require('./index.production.js');
} else {
module.exports = require('./index.development.js');
}

View File

@ -0,0 +1,37 @@
{
"name": "@grafana/runtime",
"version": "6.0.1-alpha.0",
"description": "Grafana Runtime Library",
"keywords": [
"typescript",
"react",
"react-component"
],
"main": "src/index.ts",
"scripts": {
"tslint": "tslint -c tslint.json --project tsconfig.json",
"typecheck": "tsc --noEmit",
"clean": "rimraf ./dist ./compiled",
"build": "rollup -c rollup.config.ts"
},
"author": "Grafana Labs",
"license": "Apache-2.0",
"dependencies": {
},
"devDependencies": {
"awesome-typescript-loader": "^5.2.1",
"lodash": "^4.17.10",
"pretty-format": "^24.5.0",
"rollup": "1.6.0",
"rollup-plugin-commonjs": "9.2.1",
"rollup-plugin-node-resolve": "4.0.1",
"rollup-plugin-sourcemaps": "0.4.2",
"rollup-plugin-terser": "4.0.4",
"rollup-plugin-typescript2": "0.19.3",
"rollup-plugin-visualizer": "0.9.2",
"typescript": "3.4.1"
},
"resolutions": {
"@types/lodash": "4.14.119"
}
}

View File

@ -0,0 +1,50 @@
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import sourceMaps from 'rollup-plugin-sourcemaps';
import { terser } from 'rollup-plugin-terser';
const pkg = require('./package.json');
const libraryName = pkg.name;
const buildCjsPackage = ({ env }) => {
return {
input: `compiled/index.js`,
output: [
{
file: `dist/index.${env}.js`,
name: libraryName,
format: 'cjs',
sourcemap: true,
exports: 'named',
globals: {},
},
],
external: ['lodash'], // Use Lodash from grafana
plugins: [
commonjs({
include: /node_modules/,
namedExports: {
'../../node_modules/lodash/lodash.js': [
'flatten',
'find',
'upperFirst',
'debounce',
'isNil',
'isNumber',
'flattenDeep',
'map',
'chunk',
'sortBy',
'uniqueId',
'zip',
],
},
}),
resolve(),
sourceMaps(),
env === 'production' && terser(),
],
};
};
export default [buildCjsPackage({ env: 'development' }), buildCjsPackage({ env: 'production' })];

View File

@ -0,0 +1 @@
export * from './services';

View File

@ -0,0 +1,19 @@
export interface AngularComponent {
destroy(): void;
digest(): void;
getScope(): any;
}
export interface AngularLoader {
load(elem: any, scopeProps: any, template: string): AngularComponent;
}
let instance: AngularLoader;
export function setAngularLoader(v: AngularLoader) {
instance = v;
}
export function getAngularLoader(): AngularLoader {
return instance;
}

View File

@ -0,0 +1,42 @@
/**
* Currently implemented with:
* https://docs.angularjs.org/api/ng/service/$http#usage
* but that will likely change in the future
*/
export type BackendSrvRequest = {
url: string;
retry?: number;
headers?: any;
method?: string;
// Show a message with the result
showSuccessAlert?: boolean;
[key: string]: any;
};
export interface BackendSrv {
get(url: string, params?: any): Promise<any>;
delete(url: string): Promise<any>;
post(url: string, data: any): Promise<any>;
patch(url: string, data: any): Promise<any>;
put(url: string, data: any): Promise<any>;
// If there is an error, set: err.isHandled = true
// otherwise the backend will show a message for you
request(options: BackendSrvRequest): Promise<any>;
}
let singletonInstance: BackendSrv;
export function setBackendSrv(instance: BackendSrv) {
singletonInstance = instance;
}
export function getBackendSrv(): BackendSrv {
return singletonInstance;
}

View File

@ -0,0 +1,15 @@
import { ScopedVars, DataSourceApi } from '@grafana/ui';
export interface DataSourceSrv {
get(name?: string, scopedVars?: ScopedVars): Promise<DataSourceApi>;
}
let singletonInstance: DataSourceSrv;
export function setDataSourceSrv(instance: DataSourceSrv) {
singletonInstance = instance;
}
export function getDataSourceSrv(): DataSourceSrv {
return singletonInstance;
}

View File

@ -0,0 +1,3 @@
export * from './backendSrv';
export * from './AngularLoader';
export * from './dataSourceSrv';

View File

@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["dist", "node_modules", "**/*.test.ts", "**/*.test.tsx"]
}

View File

@ -0,0 +1,19 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.tsx", "../../public/app/types/jquery/*.ts"],
"exclude": ["dist", "node_modules"],
"compilerOptions": {
"rootDirs": ["."],
"module": "esnext",
"outDir": "compiled",
"declaration": true,
"declarationDir": "dist",
"strict": true,
"alwaysStrict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"typeRoots": ["./node_modules/@types", "types"],
"skipLibCheck": true, // Temp workaround for Duplicate identifier tsc errors,
"removeComments": false
}
}

View File

@ -0,0 +1,6 @@
{
"extends": "../../tslint.json",
"rules": {
"import-blacklist": [true, ["^@grafana/runtime.*"]]
}
}

View File

@ -1,6 +1,6 @@
{
"extends": "../../tslint.json",
"rules": {
"import-blacklist": [true, "moment", ["^@grafana/ui.*"]]
"import-blacklist": [true, "moment", ["^@grafana/ui.*"], ["^@grafana/runtime.*"]]
}
}

View File

@ -1,7 +1,7 @@
import React, { PureComponent } from 'react';
// @ts-ignore
import Remarkable from 'remarkable';
import { getBackendSrv } from '../../services/backend_srv';
import { getBackendSrv } from '@grafana/runtime';
interface Props {
plugin: {

View File

@ -1,9 +1,9 @@
import React, { PureComponent } from 'react';
import { FormLabel, Select } from '@grafana/ui';
import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv';
import { DashboardSearchHit, DashboardSearchHitType } from 'app/types';
import { getBackendSrv } from 'app/core/services/backend_srv';
export interface Props {
resourceUri: string;
@ -25,7 +25,7 @@ const timezones = [
];
export class SharedPreferences extends PureComponent<Props, State> {
backendSrv: BackendSrv = getBackendSrv();
backendSrv = getBackendSrv();
constructor(props: Props) {
super(props);

View File

@ -2,13 +2,9 @@ import angular from 'angular';
import coreModule from 'app/core/core_module';
import _ from 'lodash';
export interface AngularComponent {
destroy(): void;
digest(): void;
getScope(): any;
}
import { AngularComponent, AngularLoader } from '@grafana/runtime';
export class AngularLoader {
export class AngularLoaderClass implements AngularLoader {
/** @ngInject */
constructor(private $compile: any, private $rootScope: any) {}
@ -38,15 +34,4 @@ export class AngularLoader {
}
}
coreModule.service('angularLoader', AngularLoader);
let angularLoaderInstance: AngularLoader;
export function setAngularLoader(pl: AngularLoader) {
angularLoaderInstance = pl;
}
// away to access it from react
export function getAngularLoader(): AngularLoader {
return angularLoaderInstance;
}
coreModule.service('angularLoader', AngularLoaderClass);

View File

@ -7,8 +7,9 @@ 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 { BackendSrv as BackendService, getBackendSrv as getBackendService, BackendSrvRequest } from '@grafana/runtime';
export class BackendSrv {
export class BackendSrv implements BackendService {
private inFlightRequests: { [key: string]: Array<angular.IDeferred<any>> } = {};
private HTTP_REQUEST_CANCELED = -1;
private noBackendCache: boolean;
@ -83,7 +84,7 @@ export class BackendSrv {
throw data;
}
request(options: any) {
request(options: BackendSrvRequest) {
options.retry = options.retry || 0;
const requestIsLocal = !options.url.match(/^http/);
const firstAttempt = options.retry === 0;
@ -385,16 +386,7 @@ export class BackendSrv {
coreModule.service('backendSrv', BackendSrv);
//
// Code below is to expore the service to react components
//
let singletonInstance: BackendSrv;
export function setBackendSrv(instance: BackendSrv) {
singletonInstance = instance;
}
// Used for testing and things that really need BackendSrv
export function getBackendSrv(): BackendSrv {
return singletonInstance;
return getBackendService() as BackendSrv;
}

View File

@ -1,4 +1,4 @@
import { getBackendSrv } from 'app/core/services/backend_srv';
import { getBackendSrv } from '@grafana/runtime';
export interface ServerStat {
name: string;

View File

@ -2,7 +2,7 @@
import React, { PureComponent } from 'react';
// Services & Utils
import { AngularComponent, getAngularLoader } from 'app/core/services/AngularLoader';
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
import appEvents from 'app/core/app_events';
// Components

View File

@ -1,6 +1,6 @@
import React, { PureComponent } from 'react';
import alertDef from './state/alertDef';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { getBackendSrv } from '@grafana/runtime';
import { DashboardModel } from '../dashboard/state/DashboardModel';
import appEvents from '../../core/app_events';

View File

@ -1,6 +1,6 @@
import React, { PureComponent } from 'react';
import { JSONFormatter } from 'app/core/components/JSONFormatter/JSONFormatter';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { getBackendSrv } from '@grafana/runtime';
import { DashboardModel } from '../dashboard/state/DashboardModel';
import { LoadingPlaceholder } from '@grafana/ui/src';

View File

@ -1,4 +1,4 @@
import { getBackendSrv } from 'app/core/services/backend_srv';
import { getBackendSrv } from '@grafana/runtime';
import { AlertRuleDTO, StoreState } from 'app/types';
import { ThunkAction } from 'redux-thunk';

View File

@ -3,7 +3,7 @@ import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
// Utils & Services
import { AngularComponent, getAngularLoader } from 'app/core/services/AngularLoader';
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
import { appEvents } from 'app/core/app_events';
import { PlaylistSrv } from 'app/features/playlist/playlist_srv';

View File

@ -2,7 +2,7 @@
import React, { PureComponent } from 'react';
// Utils & Services
import { AngularComponent, getAngularLoader } from 'app/core/services/AngularLoader';
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
// Types
import { DashboardModel } from '../../state/DashboardModel';

View File

@ -2,7 +2,7 @@
import React, { PureComponent } from 'react';
// Utils & Services
import { AngularComponent, getAngularLoader } from 'app/core/services/AngularLoader';
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
// Types
import { DashboardModel } from '../../state/DashboardModel';

View File

@ -3,7 +3,7 @@ import React, { PureComponent } from 'react';
import classNames from 'classnames';
// Utils & Services
import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
import { getAngularLoader, AngularComponent } from '@grafana/runtime';
import { importPanelPlugin } from 'app/features/plugins/plugin_loader';
// Components

View File

@ -1,6 +1,6 @@
import React, { PureComponent } from 'react';
import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
import { getAngularLoader, AngularComponent } from '@grafana/runtime';
import { EditorTabBody } from './EditorTabBody';
import { PanelModel } from '../state/PanelModel';

View File

@ -9,7 +9,7 @@ import { AlertTab } from '../../alerting/AlertTab';
import config from 'app/core/config';
import { store } from 'app/store/store';
import { updateLocation } from 'app/core/actions';
import { AngularComponent } from 'app/core/services/AngularLoader';
import { AngularComponent } from '@grafana/runtime';
import { PanelModel } from '../state/PanelModel';
import { DashboardModel } from '../state/DashboardModel';

View File

@ -5,7 +5,7 @@ import _ from 'lodash';
// Utils & Services
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { AngularComponent, getAngularLoader } from 'app/core/services/AngularLoader';
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
import { Emitter } from 'app/core/utils/emitter';
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';

View File

@ -2,7 +2,7 @@
import React, { PureComponent } from 'react';
// Utils & Services
import { AngularComponent, getAngularLoader } from 'app/core/services/AngularLoader';
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
import { connectWithStore } from 'app/core/utils/connectWithReduxStore';
import { StoreState } from 'app/types';
import { updateLocation } from 'app/core/actions';

View File

@ -1,5 +1,5 @@
// Services & Utils
import { getBackendSrv } from 'app/core/services/backend_srv';
import { getBackendSrv } from '@grafana/runtime';
import { actionCreatorFactory, noPayloadActionCreatorFactory } from 'app/core/redux';
import { createSuccessNotification } from 'app/core/copy/appNotification';

View File

@ -8,7 +8,7 @@ import {
DataQuery,
DataSourceJsonData,
} from '@grafana/ui';
import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
import { getAngularLoader, AngularComponent } from '@grafana/runtime';
export type GenericDataSourcePlugin = DataSourcePlugin<DataSourceApi<DataQuery, DataSourceJsonData>>;

View File

@ -1,6 +1,6 @@
import { ThunkAction } from 'redux-thunk';
import config from '../../../core/config';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { getBackendSrv } from '@grafana/runtime';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { LayoutMode } from 'app/core/components/LayoutSelector/LayoutSelector';
import { updateLocation, updateNavIndex, UpdateNavIndexAction } from 'app/core/actions';

View File

@ -2,7 +2,7 @@
import React, { PureComponent } from 'react';
// Services
import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
import { getAngularLoader, AngularComponent } from '@grafana/runtime';
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
// Types

View File

@ -1,5 +1,5 @@
import { Organization, ThunkResult } from 'app/types';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { getBackendSrv } from '@grafana/runtime';
export enum ActionTypes {
LoadOrganization = 'LOAD_ORGANIZATION',

View File

@ -5,11 +5,12 @@ import coreModule from 'app/core/core_module';
// Services & Utils
import config from 'app/core/config';
import { importDataSourcePlugin } from './plugin_loader';
import { DataSourceSrv as DataSourceService, getDataSourceSrv as getDataSourceService } from '@grafana/runtime';
// Types
import { DataSourceApi, DataSourceSelectItem, ScopedVars } from '@grafana/ui/src/types';
export class DatasourceSrv {
export class DatasourceSrv implements DataSourceService {
datasources: { [name: string]: DataSourceApi };
/** @ngInject */
@ -175,14 +176,8 @@ export class DatasourceSrv {
}
}
let singleton: DatasourceSrv;
export function setDatasourceSrv(srv: DatasourceSrv) {
singleton = srv;
}
export function getDatasourceSrv(): DatasourceSrv {
return singleton;
return getDataSourceService() as DatasourceSrv;
}
coreModule.service('datasourceSrv', DatasourceSrv);

View File

@ -29,6 +29,7 @@ import impressionSrv from 'app/core/services/impression_srv';
import builtInPlugins from './built_in_plugins';
import * as d3 from 'd3';
import * as grafanaUI from '@grafana/ui';
import * as grafanaRT from '@grafana/runtime';
// rxjs
import { Observable, Subject } from 'rxjs';
@ -68,6 +69,7 @@ function exposeToPlugin(name: string, component: any) {
}
exposeToPlugin('@grafana/ui', grafanaUI);
exposeToPlugin('@grafana/runtime', grafanaRT);
exposeToPlugin('lodash', _);
exposeToPlugin('moment', moment);
exposeToPlugin('jquery', jquery);

View File

@ -1,6 +1,6 @@
import { StoreState } from 'app/types';
import { ThunkAction } from 'redux-thunk';
import { getBackendSrv } from '../../../core/services/backend_srv';
import { getBackendSrv } from '@grafana/runtime';
import { LayoutMode } from '../../../core/components/LayoutSelector/LayoutSelector';
import { PluginDashboard } from '../../../types/plugins';
import { PluginMeta } from '@grafana/ui';

View File

@ -5,7 +5,7 @@ import extend from 'lodash/extend';
import { PluginMeta, AppPlugin, Button } from '@grafana/ui';
import { AngularComponent, getAngularLoader } from 'app/core/services/AngularLoader';
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { ButtonVariant } from '@grafana/ui/src/components/Button/AbstractButton';
import { css } from 'emotion';

View File

@ -1,5 +1,5 @@
import { ThunkAction } from 'redux-thunk';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { getBackendSrv } from '@grafana/runtime';
import { StoreState, Team, TeamGroup, TeamMember } from 'app/types';
import { updateNavIndex, UpdateNavIndexAction } from 'app/core/actions';
import { buildNavModel } from './navModel';

View File

@ -1,6 +1,6 @@
import { ThunkAction } from 'redux-thunk';
import { StoreState } from '../../../types';
import { getBackendSrv } from '../../../core/services/backend_srv';
import { getBackendSrv } from '@grafana/runtime';
import { Invitee, OrgUser } from 'app/types';
export enum ActionTypes {

View File

@ -7,7 +7,7 @@ import { TemplateSrv } from 'app/features/templating/template_srv';
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { IQService } from 'angular';
jest.mock('../datasource');
jest.mock('app/core/services/backend_srv');
jest.mock('@grafana/ui');
describe('Prometheus editor completer', () => {
function getSessionStub(data) {

View File

@ -3,7 +3,7 @@ import _ from 'lodash';
import appEvents from 'app/core/app_events';
import { QueryMeta } from '../types';
import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
import { getAngularLoader, AngularComponent } from '@grafana/runtime';
import { TemplateSrv } from 'app/features/templating/template_srv';
import StackdriverDatasource from '../datasource';
import '../query_filter_ctrl';

View File

@ -3,7 +3,7 @@ import React, { PureComponent } from 'react';
import _ from 'lodash';
// Services & Utils
import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv';
import { getBackendSrv } from '@grafana/runtime';
// Components
import { FormLabel, Select, SelectOptionItem } from '@grafana/ui';
@ -21,7 +21,7 @@ interface State {
type Props = QueryEditorProps<TestDataDatasource, TestDataQuery>;
export class QueryEditor extends PureComponent<Props> {
backendSrv: BackendSrv = getBackendSrv();
backendSrv = getBackendSrv();
state: State = {
scenarioList: [],

View File

@ -5,15 +5,15 @@ import Drop from 'tether-drop';
// Utils and servies
import { colors } from '@grafana/ui';
import { setBackendSrv, BackendSrv, setDataSourceSrv } from '@grafana/runtime';
import config from 'app/core/config';
import coreModule from 'app/core/core_module';
import { profiler } from 'app/core/profiler';
import appEvents from 'app/core/app_events';
import { BackendSrv, setBackendSrv } from 'app/core/services/backend_srv';
import { TimeSrv, setTimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { DatasourceSrv, setDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { DatasourceSrv } from 'app/features/plugins/datasource_srv';
import { KeybindingSrv, setKeybindingSrv } from 'app/core/services/keybindingSrv';
import { AngularLoader, setAngularLoader } from 'app/core/services/AngularLoader';
import { AngularLoader, setAngularLoader } from '@grafana/runtime';
import { configureStore } from 'app/store/configureStore';
// Types
@ -37,7 +37,7 @@ export class GrafanaCtrl {
// make angular loader service available to react components
setAngularLoader(angularLoader);
setBackendSrv(backendSrv);
setDatasourceSrv(datasourceSrv);
setDataSourceSrv(datasourceSrv);
setTimeSrv(timeSrv);
setKeybindingSrv(keybindingSrv);
configureStore();

View File

@ -34,7 +34,8 @@ module.exports = function(grunt) {
grunt.registerTask('no-only-tests', function() {
var files = grunt.file.expand(
'public/**/*@(_specs|.test).@(ts|js|tsx|jsx)',
'packages/grafana-ui/**/*@(_specs|.test).@(ts|js|tsx|jsx)'
'packages/grafana-ui/**/*@(_specs|.test).@(ts|js|tsx|jsx)',
'packages/grafana-runtime/**/*@(_specs|.test).@(ts|js|tsx|jsx)'
);
grepFiles(files, '.only(', 'found only statement in test: ');
});