diff --git a/conf/defaults.ini b/conf/defaults.ini index ab0cc83cccd..2618cf61577 100644 --- a/conf/defaults.ini +++ b/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 = diff --git a/conf/sample.ini b/conf/sample.ini index 8d3cc0c2a1c..23956a62820 100644 --- a/conf/sample.ini +++ b/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 + diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index ae96ac44eb7..13eb1ac1a79 100644 --- a/docs/sources/installation/configuration.md +++ b/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. diff --git a/packages/grafana-ui/src/types/plugin.ts b/packages/grafana-ui/src/types/plugin.ts index d7899c79acc..05df2734299 100644 --- a/packages/grafana-ui/src/types/plugin.ts +++ b/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; } diff --git a/pkg/api/app_routes.go b/pkg/api/app_routes.go index abee55711b0..27fba4fe3c3 100644 --- a/pkg/api/app_routes.go +++ b/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, diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index e19c5732467..847ed6b9366 100644 --- a/pkg/api/frontendsettings.go +++ b/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, } } diff --git a/pkg/api/plugins.go b/pkg/api/plugins.go index 0d54f0707a6..4e4ff525ff4 100644 --- a/pkg/api/plugins.go +++ b/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 } diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index c97b85d68e5..36d6eb84c84 100644 --- a/pkg/setting/setting.go +++ b/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() diff --git a/public/app/features/dashboard/dashgrid/PanelPluginNotFound.tsx b/public/app/features/dashboard/dashgrid/PanelPluginNotFound.tsx index f0c7eff1fa3..72bbbb61d9f 100644 --- a/public/app/features/dashboard/dashgrid/PanelPluginNotFound.tsx +++ b/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: [], diff --git a/public/app/features/dashboard/panel_editor/VisualizationTab.tsx b/public/app/features/dashboard/panel_editor/VisualizationTab.tsx index b13a417fd73..a8f2c28c2c0 100644 --- a/public/app/features/dashboard/panel_editor/VisualizationTab.tsx +++ b/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 { onClose={this.onCloseVizPicker} /> + {this.renderPanelOptions()} diff --git a/public/app/features/datasources/settings/DataSourceSettingsPage.tsx b/public/app/features/datasources/settings/DataSourceSettingsPage.tsx index 27f60865c21..1bb94e7bb6d 100644 --- a/public/app/features/datasources/settings/DataSourceSettingsPage.tsx +++ b/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 { constructor(props: Props) { super(props); @@ -110,32 +106,6 @@ export class DataSourceSettingsPage extends PureComponent { 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 (
@@ -196,7 +166,7 @@ export class DataSourceSettingsPage extends PureComponent {
{this.isReadOnly() && this.renderIsReadOnlyMessage()} - {this.shouldRenderInfoBox() &&
{this.getInfoText()}
} + -
- This plugin is marked as being in alpha state, which means it is in early development phase and updates will include breaking changes. -
+ -
- 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. -
+ + This datasource was added by config and cannot be modified using the UI. Please contact your server admin to update this datasource.
+ ({ - defaultNavUrl: 'defaultNavUrl', - enabled: true, - hasUpdate: true, - id: 'id', - info: {} as PluginMetaInfo, - latestVersion: 'latestVersion', - name: 'name', - pinned: true, - state: 'state', - type: 'type', - module: {}, -}); +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', () => { diff --git a/public/app/features/plugins/PluginStateInfo.tsx b/public/app/features/plugins/PluginStateInfo.tsx new file mode 100644 index 00000000000..37f3f276c0d --- /dev/null +++ b/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 => { + const text = getPluginStateInfoText(props.state); + if (!text) { + return null; + } + + return
{text}
; +}; + +export default PluginStateinfo; diff --git a/public/app/features/plugins/__mocks__/pluginMocks.ts b/public/app/features/plugins/__mocks__/pluginMocks.ts index 10c38140ff8..f56fb21de29 100644 --- a/public/app/features/plugins/__mocks__/pluginMocks.ts +++ b/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 => { 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; }; diff --git a/public/app/features/plugins/__snapshots__/PluginListItem.test.tsx.snap b/public/app/features/plugins/__snapshots__/PluginListItem.test.tsx.snap index fc0cc68c522..46965f9ab81 100644 --- a/public/app/features/plugins/__snapshots__/PluginListItem.test.tsx.snap +++ b/public/app/features/plugins/__snapshots__/PluginListItem.test.tsx.snap @@ -15,8 +15,9 @@ exports[`Render should render component 1`] = ` className="card-item-type" > + panel
+ panel