浏览代码

Plugins: Unifying alpha state & options for all plugins (#16530)

* app pages

* app pages

* workign example

* started alpha support

* remove app stuff

* show warning on alpha/beta panels

* put app back on plugin file

* fix go

* add enum for PluginType and PluginIncludeType

* Refactoring and moving settings to plugins section

fixes #16529
Ryan McKinley 6 年之前
父节点
当前提交
3c21a121eb

+ 5 - 0
conf/defaults.ini

@@ -613,8 +613,13 @@ server_url =
 callback_url =
 
 [panels]
+# here for to support old env variables, can remove after a few months
 enable_alpha = false
 disable_sanitize_html = false
 
+[plugins]
+enable_alpha = false
+app_tls_skip_verify_insecure = false
+
 [enterprise]
 license_path =

+ 4 - 1
conf/sample.ini

@@ -540,7 +540,10 @@ log_queries =
 ;license_path =
 
 [panels]
-;enable_alpha = false
 # If set to true Grafana will allow script tags in text panels. Not recommended as it enable XSS vulnerabilities.
 ;disable_sanitize_html = false
 
+[plugins]
+;enable_alpha = false
+;app_tls_skip_verify_insecure = false
+

+ 10 - 7
docs/sources/installation/configuration.md

@@ -651,26 +651,29 @@ This limit will protect the server from render overloading and make sure notific
 value is `5`.
 
 
-### evaluation_timeout_seconds 
+### evaluation_timeout_seconds
 
-Default setting for alert calculation timeout. Default value is `30` 
+Default setting for alert calculation timeout. Default value is `30`
 
 ### notification_timeout_seconds
 
-Default setting for alert notification timeout. Default value is `30` 
+Default setting for alert notification timeout. Default value is `30`
 
 ### max_attempts
 
-Default setting for max attempts to sending alert notifications. Default value is `3` 
+Default setting for max attempts to sending alert notifications. Default value is `3`
 
 
 ## [panels]
 
-### enable_alpha
-Set to true if you want to test panels that are not yet ready for general usage.
-
 ### disable_sanitize_html
+
 If set to true Grafana will allow script tags in text panels. Not recommended as it enable XSS vulnerabilities. Default
 is false. This settings was introduced in Grafana v6.0.
 
+## [plugins]
+
+### enable_alpha
+
+Set to true if you want to test alpha plugins that are not yet ready for general usage.
 

+ 27 - 3
packages/grafana-ui/src/types/plugin.ts

@@ -1,10 +1,25 @@
+export enum PluginState {
+  alpha = 'alpha', // Only included it `enable_alpha` is true
+  beta = 'beta', // Will show a warning banner
+}
+
+export enum PluginType {
+  panel = 'panel',
+  datasource = 'datasource',
+  app = 'app',
+}
+
 export interface PluginMeta {
   id: string;
   name: string;
   info: PluginMetaInfo;
-  includes: PluginInclude[];
   module: string;
-  baseUrl: string;
+  includes?: PluginInclude[];
+  baseUrl?: string;
+
+  type: PluginType;
+  enabled?: boolean;
+  state?: PluginState;
 
   // Datasource-specific
   builtIn?: boolean;
@@ -24,8 +39,17 @@ interface PluginMetaQueryOptions {
   minInterval?: boolean;
 }
 
+export enum PluginIncludeType {
+  dashboard = 'dashboard',
+  page = 'page',
+
+  // Only valid for apps
+  panel = 'panel',
+  datasource = 'datasource',
+}
+
 export interface PluginInclude {
-  type: string;
+  type: PluginIncludeType;
   name: string;
   path: string;
 }

+ 1 - 2
pkg/api/app_routes.go

@@ -11,7 +11,6 @@ import (
 	"github.com/grafana/grafana/pkg/middleware"
 	m "github.com/grafana/grafana/pkg/models"
 	"github.com/grafana/grafana/pkg/plugins"
-	"github.com/grafana/grafana/pkg/setting"
 	"github.com/grafana/grafana/pkg/util"
 	macaron "gopkg.in/macaron.v1"
 )
@@ -21,7 +20,7 @@ var pluginProxyTransport *http.Transport
 func (hs *HTTPServer) initAppPluginRoutes(r *macaron.Macaron) {
 	pluginProxyTransport = &http.Transport{
 		TLSClientConfig: &tls.Config{
-			InsecureSkipVerify: setting.PluginAppsSkipVerifyTLS,
+			InsecureSkipVerify: hs.Cfg.PluginsAppsSkipVerifyTLS,
 			Renegotiation:      tls.RenegotiateFreelyAsClient,
 		},
 		Proxy: http.ProxyFromEnvironment,

+ 2 - 1
pkg/api/frontendsettings.go

@@ -145,7 +145,7 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *m.ReqContext) (map[string]interf
 
 	panels := map[string]interface{}{}
 	for _, panel := range enabledPlugins.Panels {
-		if panel.State == plugins.PluginStateAlpha && !hs.Cfg.EnableAlphaPanels {
+		if panel.State == plugins.PluginStateAlpha && !hs.Cfg.PluginsEnableAlpha {
 			continue
 		}
 
@@ -162,6 +162,7 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *m.ReqContext) (map[string]interf
 			"hideFromList": panel.HideFromList,
 			"sort":         getPanelSort(panel.Id),
 			"dataFormats":  panel.DataFormats,
+			"state":        panel.State,
 		}
 	}
 

+ 1 - 1
pkg/api/plugins.go

@@ -39,7 +39,7 @@ func (hs *HTTPServer) GetPluginList(c *m.ReqContext) Response {
 			continue
 		}
 
-		if pluginDef.State == plugins.PluginStateAlpha && !hs.Cfg.EnableAlphaPanels {
+		if pluginDef.State == plugins.PluginStateAlpha && !hs.Cfg.PluginsEnableAlpha {
 			continue
 		}
 

+ 13 - 10
pkg/setting/setting.go

@@ -142,9 +142,6 @@ var (
 	// Basic Auth
 	BasicAuthEnabled bool
 
-	// Plugin settings
-	PluginAppsSkipVerifyTLS bool
-
 	// Session settings.
 	SessionOptions         session.Options
 	SessionConnMaxLifetime int64
@@ -233,7 +230,8 @@ type Cfg struct {
 	MetricsEndpointEnabled           bool
 	MetricsEndpointBasicAuthUsername string
 	MetricsEndpointBasicAuthPassword string
-	EnableAlphaPanels                bool
+	PluginsEnableAlpha               bool
+	PluginsAppsSkipVerifyTLS         bool
 	DisableSanitizeHtml              bool
 	EnterpriseLicensePath            string
 
@@ -721,9 +719,6 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
 	authBasic := iniFile.Section("auth.basic")
 	BasicAuthEnabled = authBasic.Key("enabled").MustBool(true)
 
-	// global plugin settings
-	PluginAppsSkipVerifyTLS = iniFile.Section("plugins").Key("app_tls_skip_verify_insecure").MustBool(false)
-
 	// Rendering
 	renderSec := iniFile.Section("rendering")
 	cfg.RendererUrl = renderSec.Key("server_url").String()
@@ -771,9 +766,17 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
 	explore := iniFile.Section("explore")
 	ExploreEnabled = explore.Key("enabled").MustBool(true)
 
-	panels := iniFile.Section("panels")
-	cfg.EnableAlphaPanels = panels.Key("enable_alpha").MustBool(false)
-	cfg.DisableSanitizeHtml = panels.Key("disable_sanitize_html").MustBool(false)
+	panelsSection := iniFile.Section("panels")
+	cfg.DisableSanitizeHtml = panelsSection.Key("disable_sanitize_html").MustBool(false)
+
+	pluginsSection := iniFile.Section("plugins")
+	cfg.PluginsEnableAlpha = pluginsSection.Key("enable_alpha").MustBool(false)
+	cfg.PluginsAppsSkipVerifyTLS = iniFile.Section("plugins").Key("app_tls_skip_verify_insecure").MustBool(false)
+
+	// check old location for this option
+	if panelsSection.Key("enable_alpha").MustBool(false) {
+		cfg.PluginsEnableAlpha = true
+	}
 
 	cfg.readSessionConfig()
 	cfg.readSmtpSettings()

+ 2 - 1
public/app/features/dashboard/dashgrid/PanelPluginNotFound.tsx

@@ -7,7 +7,7 @@ import { AlertBox } from 'app/core/components/AlertBox/AlertBox';
 
 // Types
 import { PanelPlugin, AppNotificationSeverity } from 'app/types';
-import { PanelProps, ReactPanelPlugin } from '@grafana/ui';
+import { PanelProps, ReactPanelPlugin, PluginType } from '@grafana/ui';
 
 interface Props {
   pluginId: string;
@@ -45,6 +45,7 @@ export function getPanelPluginNotFound(id: string): PanelPlugin {
     id: id,
     name: id,
     sort: 100,
+    type: PluginType.panel,
     module: '',
     baseUrl: '',
     dataFormats: [],

+ 2 - 0
public/app/features/dashboard/panel_editor/VisualizationTab.tsx

@@ -18,6 +18,7 @@ import { PanelModel } from '../state';
 import { DashboardModel } from '../state';
 import { PanelPlugin } from 'app/types/plugins';
 import { VizPickerSearch } from './VizPickerSearch';
+import PluginStateinfo from 'app/features/plugins/PluginStateInfo';
 
 interface Props {
   panel: PanelModel;
@@ -238,6 +239,7 @@ export class VisualizationTab extends PureComponent<Props, State> {
               onClose={this.onCloseVizPicker}
             />
           </FadeIn>
+          <PluginStateinfo state={plugin.state} />
           {this.renderPanelOptions()}
         </>
       </EditorTabBody>

+ 2 - 32
public/app/features/datasources/settings/DataSourceSettingsPage.tsx

@@ -24,6 +24,7 @@ import { getRouteParamsId } from 'app/core/selectors/location';
 import { NavModel, Plugin, StoreState } from 'app/types/';
 import { DataSourceSettings } from '@grafana/ui/src/types/';
 import { getDataSourceLoadingNav } from '../state/navModel';
+import PluginStateinfo from 'app/features/plugins/PluginStateInfo';
 
 export interface Props {
   navModel: NavModel;
@@ -44,11 +45,6 @@ interface State {
   testingStatus?: string;
 }
 
-enum DataSourceStates {
-  Alpha = 'alpha',
-  Beta = 'beta',
-}
-
 export class DataSourceSettingsPage extends PureComponent<Props, State> {
   constructor(props: Props) {
     super(props);
@@ -110,32 +106,6 @@ export class DataSourceSettingsPage extends PureComponent<Props, State> {
     return this.props.dataSource.readOnly === true;
   }
 
-  shouldRenderInfoBox() {
-    const { state } = this.props.dataSourceMeta;
-
-    return state === DataSourceStates.Alpha || state === DataSourceStates.Beta;
-  }
-
-  getInfoText() {
-    const { dataSourceMeta } = this.props;
-
-    switch (dataSourceMeta.state) {
-      case DataSourceStates.Alpha:
-        return (
-          'This plugin is marked as being in alpha state, which means it is in early development phase and updates' +
-          ' will include breaking changes.'
-        );
-
-      case DataSourceStates.Beta:
-        return (
-          'This plugin is marked as being in a beta development state. This means it is in currently in active' +
-          ' development and could be missing important features.'
-        );
-    }
-
-    return null;
-  }
-
   renderIsReadOnlyMessage() {
     return (
       <div className="grafana-info-box span8">
@@ -196,7 +166,7 @@ export class DataSourceSettingsPage extends PureComponent<Props, State> {
             <div>
               <form onSubmit={this.onSubmit}>
                 {this.isReadOnly() && this.renderIsReadOnlyMessage()}
-                {this.shouldRenderInfoBox() && <div className="grafana-info-box">{this.getInfoText()}</div>}
+                <PluginStateinfo state={dataSourceMeta.state} />
 
                 <BasicSettings
                   dataSourceName={dataSource.name}

+ 20 - 20
public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap

@@ -11,11 +11,9 @@ exports[`Render should render alpha info text 1`] = `
       <form
         onSubmit={[Function]}
       >
-        <div
-          className="grafana-info-box"
-        >
-          This plugin is marked as being in alpha state, which means it is in early development phase and updates will include breaking changes.
-        </div>
+        <PluginStateinfo
+          state="alpha"
+        />
         <BasicSettings
           dataSourceName="gdev-cloudwatch"
           isDefault={false}
@@ -49,6 +47,7 @@ exports[`Render should render alpha info text 1`] = `
           }
           dataSourceMeta={
             Object {
+              "baseUrl": "path/to/plugin",
               "defaultNavUrl": "some/url",
               "enabled": false,
               "hasUpdate": false,
@@ -78,11 +77,11 @@ exports[`Render should render alpha info text 1`] = `
                 "version": "1",
               },
               "latestVersion": "1",
-              "module": Object {},
+              "module": "path/to/module",
               "name": "pretty cool plugin 1",
               "pinned": false,
               "state": "alpha",
-              "type": "",
+              "type": "panel",
             }
           }
           onModelChange={[Function]}
@@ -113,11 +112,9 @@ exports[`Render should render beta info text 1`] = `
       <form
         onSubmit={[Function]}
       >
-        <div
-          className="grafana-info-box"
-        >
-          This plugin is marked as being in a beta development state. This means it is in currently in active development and could be missing important features.
-        </div>
+        <PluginStateinfo
+          state="beta"
+        />
         <BasicSettings
           dataSourceName="gdev-cloudwatch"
           isDefault={false}
@@ -151,6 +148,7 @@ exports[`Render should render beta info text 1`] = `
           }
           dataSourceMeta={
             Object {
+              "baseUrl": "path/to/plugin",
               "defaultNavUrl": "some/url",
               "enabled": false,
               "hasUpdate": false,
@@ -180,11 +178,11 @@ exports[`Render should render beta info text 1`] = `
                 "version": "1",
               },
               "latestVersion": "1",
-              "module": Object {},
+              "module": "path/to/module",
               "name": "pretty cool plugin 1",
               "pinned": false,
               "state": "beta",
-              "type": "",
+              "type": "panel",
             }
           }
           onModelChange={[Function]}
@@ -215,6 +213,7 @@ exports[`Render should render component 1`] = `
       <form
         onSubmit={[Function]}
       >
+        <PluginStateinfo />
         <BasicSettings
           dataSourceName="gdev-cloudwatch"
           isDefault={false}
@@ -248,6 +247,7 @@ exports[`Render should render component 1`] = `
           }
           dataSourceMeta={
             Object {
+              "baseUrl": "path/to/plugin",
               "defaultNavUrl": "some/url",
               "enabled": false,
               "hasUpdate": false,
@@ -277,11 +277,10 @@ exports[`Render should render component 1`] = `
                 "version": "1",
               },
               "latestVersion": "1",
-              "module": Object {},
+              "module": "path/to/module",
               "name": "pretty cool plugin 1",
               "pinned": false,
-              "state": "",
-              "type": "",
+              "type": "panel",
             }
           }
           onModelChange={[Function]}
@@ -317,6 +316,7 @@ exports[`Render should render is ready only message 1`] = `
         >
           This datasource was added by config and cannot be modified using the UI. Please contact your server admin to update this datasource.
         </div>
+        <PluginStateinfo />
         <BasicSettings
           dataSourceName="gdev-cloudwatch"
           isDefault={false}
@@ -350,6 +350,7 @@ exports[`Render should render is ready only message 1`] = `
           }
           dataSourceMeta={
             Object {
+              "baseUrl": "path/to/plugin",
               "defaultNavUrl": "some/url",
               "enabled": false,
               "hasUpdate": false,
@@ -379,11 +380,10 @@ exports[`Render should render is ready only message 1`] = `
                 "version": "1",
               },
               "latestVersion": "1",
-              "module": Object {},
+              "module": "path/to/module",
               "name": "pretty cool plugin 1",
               "pinned": false,
-              "state": "",
-              "type": "",
+              "type": "panel",
             }
           }
           onModelChange={[Function]}

+ 3 - 2
public/app/features/datasources/state/navModel.ts

@@ -1,5 +1,5 @@
 import { NavModel, NavModelItem } from 'app/types';
-import { PluginMeta, DataSourceSettings } from '@grafana/ui/src/types';
+import { PluginMeta, DataSourceSettings, PluginType } from '@grafana/ui/src/types';
 import config from 'app/core/config';
 
 export function buildNavModel(dataSource: DataSourceSettings, pluginMeta: PluginMeta): NavModelItem {
@@ -67,6 +67,7 @@ export function getDataSourceLoadingNav(pageName: string): NavModel {
     },
     {
       id: '1',
+      type: PluginType.datasource,
       name: '',
       info: {
         author: {
@@ -83,7 +84,7 @@ export function getDataSourceLoadingNav(pageName: string): NavModel {
         updated: '',
         version: '',
       },
-      includes: [{ type: '', name: '', path: '' }],
+      includes: [],
       module: '',
       baseUrl: '',
     }

+ 16 - 16
public/app/features/datasources/state/reducers.test.ts

@@ -14,22 +14,22 @@ import {
 } from './actions';
 import { getMockDataSources, getMockDataSource } from '../__mocks__/dataSourcesMocks';
 import { LayoutModes } from 'app/core/components/LayoutSelector/LayoutSelector';
-import { DataSourcesState } from 'app/types';
-import { PluginMetaInfo } from '@grafana/ui';
-
-const mockPlugin = () => ({
-  defaultNavUrl: 'defaultNavUrl',
-  enabled: true,
-  hasUpdate: true,
-  id: 'id',
-  info: {} as PluginMetaInfo,
-  latestVersion: 'latestVersion',
-  name: 'name',
-  pinned: true,
-  state: 'state',
-  type: 'type',
-  module: {},
-});
+import { DataSourcesState, Plugin } from 'app/types';
+import { PluginMetaInfo, PluginType } from '@grafana/ui';
+
+const mockPlugin = () =>
+  ({
+    defaultNavUrl: 'defaultNavUrl',
+    enabled: true,
+    hasUpdate: true,
+    id: 'id',
+    info: {} as PluginMetaInfo,
+    latestVersion: 'latestVersion',
+    name: 'name',
+    pinned: true,
+    type: PluginType.datasource,
+    module: 'path/to/module',
+  } as Plugin);
 
 describe('dataSourcesReducer', () => {
   describe('when dataSourcesLoaded is dispatched', () => {

+ 34 - 0
public/app/features/plugins/PluginStateInfo.tsx

@@ -0,0 +1,34 @@
+import React, { FC } from 'react';
+import { PluginState } from '@grafana/ui';
+
+interface Props {
+  state?: PluginState;
+}
+
+function getPluginStateInfoText(state?: PluginState): string | null {
+  switch (state) {
+    case PluginState.alpha:
+      return (
+        'This plugin is marked as being in alpha state, which means it is in early development phase and updates' +
+        ' will include breaking changes.'
+      );
+
+    case PluginState.beta:
+      return (
+        'This plugin is marked as being in a beta development state. This means it is in currently in active' +
+        ' development and could be missing important features.'
+      );
+  }
+  return null;
+}
+
+const PluginStateinfo: FC<Props> = props => {
+  const text = getPluginStateInfoText(props.state);
+  if (!text) {
+    return null;
+  }
+
+  return <div className="grafana-info-box">{text}</div>;
+};
+
+export default PluginStateinfo;

+ 6 - 4
public/app/features/plugins/__mocks__/pluginMocks.ts

@@ -1,4 +1,5 @@
 import { Plugin, PanelPlugin, PanelDataFormat } from 'app/types';
+import { PluginType } from '@grafana/ui';
 
 export const getMockPlugins = (amount: number): Plugin[] => {
   const plugins = [];
@@ -36,6 +37,7 @@ export const getMockPlugins = (amount: number): Plugin[] => {
 export const getPanelPlugin = (options: Partial<PanelPlugin>): PanelPlugin => {
   return {
     id: options.id,
+    type: PluginType.panel,
     name: options.id,
     sort: options.sort || 1,
     dataFormats: [PanelDataFormat.TimeSeries],
@@ -81,9 +83,9 @@ export const getMockPlugin = () => {
     },
     latestVersion: '1',
     name: 'pretty cool plugin 1',
+    baseUrl: 'path/to/plugin',
     pinned: false,
-    state: '',
-    type: '',
-    module: {},
-  };
+    type: PluginType.panel,
+    module: 'path/to/module',
+  } as Plugin;
 };

+ 4 - 2
public/app/features/plugins/__snapshots__/PluginListItem.test.tsx.snap

@@ -15,8 +15,9 @@ exports[`Render should render component 1`] = `
         className="card-item-type"
       >
         <i
-          className="icon-gf icon-gf-"
+          className="icon-gf icon-gf-panel"
         />
+        panel
       </div>
     </div>
     <div
@@ -63,8 +64,9 @@ exports[`Render should render has plugin section 1`] = `
         className="card-item-type"
       >
         <i
-          className="icon-gf icon-gf-"
+          className="icon-gf icon-gf-panel"
         />
+        panel
       </div>
       <div
         className="card-item-notice"

+ 3 - 13
public/app/types/plugins.ts

@@ -1,10 +1,7 @@
-import { AngularPanelPlugin, ReactPanelPlugin, PluginMetaInfo } from '@grafana/ui/src/types';
+import { AngularPanelPlugin, ReactPanelPlugin, PluginMetaInfo, PluginMeta } from '@grafana/ui/src/types';
 
-export interface PanelPlugin {
-  id: string;
-  name: string;
+export interface PanelPlugin extends PluginMeta {
   hideFromList?: boolean;
-  module: string;
   baseUrl: string;
   info: PluginMetaInfo;
   sort: number;
@@ -19,18 +16,11 @@ export enum PanelDataFormat {
   TimeSeries = 'time_series',
 }
 
-export interface Plugin {
+export interface Plugin extends PluginMeta {
   defaultNavUrl: string;
-  enabled: boolean;
   hasUpdate: boolean;
-  id: string;
-  info: PluginMetaInfo;
   latestVersion: string;
-  name: string;
   pinned: boolean;
-  state: string;
-  type: string;
-  module: any;
 }
 
 export interface PluginDashboard {