diff --git a/public/app/features/datasources/DataSourceSettings.tsx b/public/app/features/datasources/DataSourceSettings.tsx new file mode 100644 index 00000000000..f7d641d34b0 --- /dev/null +++ b/public/app/features/datasources/DataSourceSettings.tsx @@ -0,0 +1,125 @@ +import React, { PureComponent } from 'react'; +import { connect } from 'react-redux'; +import { DataSource, Plugin } from 'app/types'; + +export interface Props { + dataSource: DataSource; + dataSourceMeta: Plugin; +} +interface State { + name: string; +} + +enum DataSourceStates { + Alpha = 'alpha', + Beta = 'beta', +} + +export class DataSourceSettings extends PureComponent { + constructor(props) { + super(props); + + this.state = { + name: props.dataSource.name, + }; + } + + onNameChange = event => { + this.setState({ + name: event.target.value, + }); + }; + + onSubmit = event => { + event.preventDefault(); + console.log(event); + }; + + onDelete = event => { + console.log(event); + }; + + isReadyOnly() { + 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; + } + + render() { + const { name } = this.state; + + return ( +
+

Settings

+
+
+
+
+ Name + +
+
+
+ {this.shouldRenderInfoBox() &&
{this.getInfoText()}
} + {this.isReadyOnly() && ( +
+ This datasource was added by config and cannot be modified using the UI. Please contact your server admin + to update this datasource. +
+ )} +
+ + + + Back + +
+
+
+ ); + } +} + +function mapStateToProps(state) { + return { + dataSource: state.dataSources.dataSource, + dataSourceMeta: state.dataSources.dataSourceMeta, + }; +} + +export default connect(mapStateToProps)(DataSourceSettings); diff --git a/public/app/features/datasources/EditDataSourcePage.tsx b/public/app/features/datasources/EditDataSourcePage.tsx index 7c19266d53a..46966dcbb58 100644 --- a/public/app/features/datasources/EditDataSourcePage.tsx +++ b/public/app/features/datasources/EditDataSourcePage.tsx @@ -39,19 +39,13 @@ export class EditDataSourcePage extends PureComponent { getCurrentPage() { const currentPage = this.props.pageName; - return this.isValidPage(currentPage) ? currentPage : PageTypes.Settings; + return this.isValidPage(currentPage) ? currentPage : PageTypes.Permissions; } renderPage() { switch (this.getCurrentPage()) { - case PageTypes.Settings: - return
Settings
; - case PageTypes.Permissions: return
Permissions
; - - case PageTypes.Dashboards: - return
Dashboards
; } return null; @@ -63,15 +57,14 @@ export class EditDataSourcePage extends PureComponent { return (
-
- {this.renderPage()} +
{this.renderPage()}
); } } function mapStateToProps(state) { - const pageName = getRouteParamsPage(state.location) || 'settings'; + const pageName = getRouteParamsPage(state.location) || PageTypes.Permissions; const dataSourceId = getRouteParamsId(state.location); const dataSourceLoadingNav = getDataSourceLoadingNav(pageName); diff --git a/public/app/features/datasources/state/actions.ts b/public/app/features/datasources/state/actions.ts index 2b6b986774f..bb8fce8424a 100644 --- a/public/app/features/datasources/state/actions.ts +++ b/public/app/features/datasources/state/actions.ts @@ -10,6 +10,7 @@ export enum ActionTypes { LoadDataSources = 'LOAD_DATA_SOURCES', LoadDataSourceTypes = 'LOAD_DATA_SOURCE_TYPES', LoadDataSource = 'LOAD_DATA_SOURCE', + LoadDataSourceMeta = 'LOAD_DATA_SOURCE_META', SetDataSourcesSearchQuery = 'SET_DATA_SOURCES_SEARCH_QUERY', SetDataSourcesLayoutMode = 'SET_DATA_SOURCES_LAYOUT_MODE', SetDataSourceTypeSearchQuery = 'SET_DATA_SOURCE_TYPE_SEARCH_QUERY', @@ -45,6 +46,11 @@ export interface LoadDataSourceAction { payload: DataSource; } +export interface LoadDataSourceMetaAction { + type: ActionTypes.LoadDataSourceMeta; + payload: Plugin; +} + const dataSourcesLoaded = (dataSources: DataSource[]): LoadDataSourcesAction => ({ type: ActionTypes.LoadDataSources, payload: dataSources, @@ -55,6 +61,11 @@ const dataSourceLoaded = (dataSource: DataSource): LoadDataSourceAction => ({ payload: dataSource, }); +const dataSourceMetaLoaded = (dataSourceMeta: Plugin): LoadDataSourceMetaAction => ({ + type: ActionTypes.LoadDataSourceMeta, + payload: dataSourceMeta, +}); + const dataSourceTypesLoaded = (dataSourceTypes: Plugin[]): LoadDataSourceTypesAction => ({ type: ActionTypes.LoadDataSourceTypes, payload: dataSourceTypes, @@ -83,7 +94,8 @@ export type Action = | LoadDataSourceTypesAction | SetDataSourceTypeSearchQueryAction | LoadDataSourceAction - | UpdateNavIndexAction; + | UpdateNavIndexAction + | LoadDataSourceMetaAction; type ThunkResult = ThunkAction; @@ -99,6 +111,7 @@ export function loadDataSource(id: number): ThunkResult { const dataSource = await getBackendSrv().get(`/api/datasources/${id}`); const pluginInfo = await getBackendSrv().get(`/api/plugins/${dataSource.type}/settings`); dispatch(dataSourceLoaded(dataSource)); + dispatch(dataSourceMetaLoaded(pluginInfo)); dispatch(updateNavIndex(buildNavModel(dataSource, pluginInfo))); }; } diff --git a/public/app/features/datasources/state/navModel.ts b/public/app/features/datasources/state/navModel.ts index d80ab5d52a2..47eadb82376 100644 --- a/public/app/features/datasources/state/navModel.ts +++ b/public/app/features/datasources/state/navModel.ts @@ -1,4 +1,5 @@ import { DataSource, NavModel, NavModelItem, PluginMeta } from 'app/types'; +import config from 'app/core/config'; export function buildNavModel(dataSource: DataSource, pluginMeta: PluginMeta): NavModelItem { const navModel = { @@ -16,26 +17,29 @@ export function buildNavModel(dataSource: DataSource, pluginMeta: PluginMeta): N text: 'Settings', url: `datasources/edit/${dataSource.id}/settings`, }, - { - active: false, - icon: 'fa fa-fw fa-sliders', - id: `datasource-permissions-${dataSource.id}`, - text: 'Permissions', - url: `datasources/edit/${dataSource.id}/permissions`, - }, ], }; - if (pluginMeta.includes && pluginMeta.includes.length > 0) { + if (pluginMeta.includes && hasDashboards(pluginMeta.includes)) { navModel.children.push({ active: false, - icon: 'gicon gicon-dashboard', + icon: 'fa fa-fw fa-th-large', id: `datasource-dashboards-${dataSource.id}`, text: 'Dashboards', url: `datasources/edit/${dataSource.id}/dashboards`, }); } + if (config.buildInfo.isEnterprise) { + navModel.children.push({ + active: false, + icon: 'fa fa-fw fa-lock', + id: `datasource-permissions-${dataSource.id}`, + text: 'Permissions', + url: `datasources/edit/${dataSource.id}/permissions`, + }); + } + return navModel; } @@ -95,3 +99,11 @@ export function getDataSourceLoadingNav(pageName: string): NavModel { node: node, }; } + +function hasDashboards(includes) { + return ( + includes.filter(include => { + return include.type === 'dashboard'; + }).length > 0 + ); +} diff --git a/public/app/features/datasources/state/reducers.ts b/public/app/features/datasources/state/reducers.ts index 075483945a4..051966c81be 100644 --- a/public/app/features/datasources/state/reducers.ts +++ b/public/app/features/datasources/state/reducers.ts @@ -10,6 +10,7 @@ const initialState: DataSourcesState = { dataSourcesCount: 0, dataSourceTypes: [] as Plugin[], dataSourceTypeSearchQuery: '', + dataSourceMeta: {} as Plugin, }; export const dataSourcesReducer = (state = initialState, action: Action): DataSourcesState => { @@ -31,6 +32,9 @@ export const dataSourcesReducer = (state = initialState, action: Action): DataSo case ActionTypes.SetDataSourceTypeSearchQuery: return { ...state, dataSourceTypeSearchQuery: action.payload }; + + case ActionTypes.LoadDataSourceMeta: + return { ...state, dataSourceMeta: action.payload }; } return state; diff --git a/public/app/features/plugins/state/navModel.ts b/public/app/features/plugins/state/navModel.ts index 852eb2806f9..f12967ebb7a 100644 --- a/public/app/features/plugins/state/navModel.ts +++ b/public/app/features/plugins/state/navModel.ts @@ -1,5 +1,6 @@ import _ from 'lodash'; import { DataSource, PluginMeta, NavModel } from 'app/types'; +import config from 'app/core/config'; export function buildNavModel(ds: DataSource, plugin: PluginMeta, currentPage: string): NavModel { let title = 'New'; @@ -38,6 +39,16 @@ export function buildNavModel(ds: DataSource, plugin: PluginMeta, currentPage: s }); } + if (config.buildInfo.isEnterprise) { + main.children.push({ + active: currentPage === 'datasource-permissions', + icon: 'fa fa-fw fa-lock', + id: 'datasource-permissions', + text: 'Permissions', + url: `datasources/edit/${ds.id}/permissions`, + }); + } + return { main: main, node: _.find(main.children, { active: true }), diff --git a/public/app/routes/routes.ts b/public/app/routes/routes.ts index 54f4a6718e1..43c513aea38 100644 --- a/public/app/routes/routes.ts +++ b/public/app/routes/routes.ts @@ -72,6 +72,16 @@ export function setupAngularRoutes($routeProvider, $locationProvider) { component: () => DataSourcesListPage, }, }) + .when('/datasources/edit/:id', { + templateUrl: 'public/app/features/plugins/partials/ds_edit.html', + controller: 'DataSourceEditCtrl', + controllerAs: 'ctrl', + }) + .when('/datasources/edit/:id/dashboards', { + templateUrl: 'public/app/features/plugins/partials/ds_dashboards.html', + controller: 'DataSourceDashboardsCtrl', + controllerAs: 'ctrl', + }) .when('/datasources/edit/:id/:page?', { template: '', resolve: { diff --git a/public/app/types/datasources.ts b/public/app/types/datasources.ts index 9d35794b89e..95c754faa6b 100644 --- a/public/app/types/datasources.ts +++ b/public/app/types/datasources.ts @@ -12,10 +12,10 @@ export interface DataSource { password: string; user: string; database: string; - basicAuth: false; - isDefault: false; + basicAuth: boolean; + isDefault: boolean; jsonData: { authType: string; defaultRegion: string }; - readOnly: false; + readOnly: boolean; } export interface DataSourcesState { @@ -26,4 +26,5 @@ export interface DataSourcesState { dataSourcesCount: number; dataSourceTypes: Plugin[]; dataSource: DataSource; + dataSourceMeta: Plugin; }