Peter Holmberg 7 лет назад
Родитель
Сommit
4ecd33c79c

+ 90 - 0
public/app/features/datasources/EditDataSourcePage.tsx

@@ -0,0 +1,90 @@
+import React, { PureComponent } from 'react';
+import { hot } from 'react-hot-loader';
+import { connect } from 'react-redux';
+import PageHeader from '../../core/components/PageHeader/PageHeader';
+import { DataSource, NavModel } from 'app/types';
+import { loadDataSource } from './state/actions';
+import { getNavModel } from '../../core/selectors/navModel';
+import { getRouteParamsId, getRouteParamsPage } from '../../core/selectors/location';
+import { getDataSourceLoadingNav } from './state/navModel';
+import { getDataSource } from './state/selectors';
+
+export interface Props {
+  navModel: NavModel;
+  dataSource: DataSource;
+  dataSourceId: number;
+  pageName: string;
+  loadDataSource: typeof loadDataSource;
+}
+
+enum PageTypes {
+  Settings = 'settings',
+  Permissions = 'permissions',
+  Dashboards = 'dashboards',
+}
+
+export class EditDataSourcePage extends PureComponent<Props> {
+  componentDidMount() {
+    this.fetchDataSource();
+  }
+
+  async fetchDataSource() {
+    await this.props.loadDataSource(this.props.dataSourceId);
+  }
+
+  isValidPage(currentPage) {
+    return (Object as any).values(PageTypes).includes(currentPage);
+  }
+
+  getCurrentPage() {
+    const currentPage = this.props.pageName;
+
+    return this.isValidPage(currentPage) ? currentPage : PageTypes.Settings;
+  }
+
+  renderPage() {
+    switch (this.getCurrentPage()) {
+      case PageTypes.Settings:
+        return <div>Settings</div>;
+
+      case PageTypes.Permissions:
+        return <div>Permissions</div>;
+
+      case PageTypes.Dashboards:
+        return <div>Dashboards</div>;
+    }
+
+    return null;
+  }
+
+  render() {
+    const { navModel } = this.props;
+
+    return (
+      <div>
+        <PageHeader model={navModel} />
+        <div className="page-container page-body" />
+        {this.renderPage()}
+      </div>
+    );
+  }
+}
+
+function mapStateToProps(state) {
+  const pageName = getRouteParamsPage(state.location) || 'settings';
+  const dataSourceId = getRouteParamsId(state.location);
+  const dataSourceLoadingNav = getDataSourceLoadingNav(pageName);
+
+  return {
+    navModel: getNavModel(state.navIndex, `datasource-${pageName}-${dataSourceId}`, dataSourceLoadingNav),
+    dataSourceId: dataSourceId,
+    dataSource: getDataSource(state.dataSources, dataSourceId),
+    pageName: pageName,
+  };
+}
+
+const mapDispatchToProps = {
+  loadDataSource,
+};
+
+export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(EditDataSourcePage));

+ 25 - 2
public/app/features/datasources/state/actions.ts

@@ -2,12 +2,14 @@ import { ThunkAction } from 'redux-thunk';
 import { DataSource, Plugin, StoreState } from 'app/types';
 import { getBackendSrv } from '../../../core/services/backend_srv';
 import { LayoutMode } from '../../../core/components/LayoutSelector/LayoutSelector';
-import { updateLocation } from '../../../core/actions';
+import { updateLocation, updateNavIndex, UpdateNavIndexAction } from '../../../core/actions';
 import { UpdateLocationAction } from '../../../core/actions/location';
+import { buildNavModel } from './navModel';
 
 export enum ActionTypes {
   LoadDataSources = 'LOAD_DATA_SOURCES',
   LoadDataSourceTypes = 'LOAD_DATA_SOURCE_TYPES',
+  LoadDataSource = 'LOAD_DATA_SOURCE',
   SetDataSourcesSearchQuery = 'SET_DATA_SOURCES_SEARCH_QUERY',
   SetDataSourcesLayoutMode = 'SET_DATA_SOURCES_LAYOUT_MODE',
   SetDataSourceTypeSearchQuery = 'SET_DATA_SOURCE_TYPE_SEARCH_QUERY',
@@ -38,11 +40,21 @@ export interface SetDataSourceTypeSearchQueryAction {
   payload: string;
 }
 
+export interface LoadDataSourceAction {
+  type: ActionTypes.LoadDataSource;
+  payload: DataSource;
+}
+
 const dataSourcesLoaded = (dataSources: DataSource[]): LoadDataSourcesAction => ({
   type: ActionTypes.LoadDataSources,
   payload: dataSources,
 });
 
+const dataSourceLoaded = (dataSource: DataSource): LoadDataSourceAction => ({
+  type: ActionTypes.LoadDataSource,
+  payload: dataSource,
+});
+
 const dataSourceTypesLoaded = (dataSourceTypes: Plugin[]): LoadDataSourceTypesAction => ({
   type: ActionTypes.LoadDataSourceTypes,
   payload: dataSourceTypes,
@@ -69,7 +81,9 @@ export type Action =
   | SetDataSourcesLayoutModeAction
   | UpdateLocationAction
   | LoadDataSourceTypesAction
-  | SetDataSourceTypeSearchQueryAction;
+  | SetDataSourceTypeSearchQueryAction
+  | LoadDataSourceAction
+  | UpdateNavIndexAction;
 
 type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action>;
 
@@ -80,6 +94,15 @@ export function loadDataSources(): ThunkResult<void> {
   };
 }
 
+export function loadDataSource(id: number): ThunkResult<void> {
+  return async dispatch => {
+    const dataSource = await getBackendSrv().get(`/api/datasources/${id}`);
+    const pluginInfo = await getBackendSrv().get(`/api/plugins/${dataSource.type}/settings`);
+    dispatch(dataSourceLoaded(dataSource));
+    dispatch(updateNavIndex(buildNavModel(dataSource, pluginInfo)));
+  };
+}
+
 export function addDataSource(plugin: Plugin): ThunkResult<void> {
   return async (dispatch, getStore) => {
     await dispatch(loadDataSources());

+ 97 - 0
public/app/features/datasources/state/navModel.ts

@@ -0,0 +1,97 @@
+import { DataSource, NavModel, NavModelItem, PluginMeta } from 'app/types';
+
+export function buildNavModel(dataSource: DataSource, pluginMeta: PluginMeta): NavModelItem {
+  const navModel = {
+    img: pluginMeta.info.logos.large,
+    id: 'datasource-' + dataSource.id,
+    subTitle: `Type: ${pluginMeta.name}`,
+    url: '',
+    text: dataSource.name,
+    breadcrumbs: [{ title: 'Data Sources', url: 'datasources' }],
+    children: [
+      {
+        active: false,
+        icon: 'fa fa-fw fa-sliders',
+        id: `datasource-settings-${dataSource.id}`,
+        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) {
+    navModel.children.push({
+      active: false,
+      icon: 'gicon gicon-dashboard',
+      id: `datasource-dashboards-${dataSource.id}`,
+      text: 'Dashboards',
+      url: `datasources/edit/${dataSource.id}/dashboards`,
+    });
+  }
+
+  return navModel;
+}
+
+export function getDataSourceLoadingNav(pageName: string): NavModel {
+  const main = buildNavModel(
+    {
+      access: '',
+      basicAuth: false,
+      database: '',
+      id: 1,
+      isDefault: false,
+      jsonData: { authType: 'credentials', defaultRegion: 'eu-west-2' },
+      name: 'Loading',
+      orgId: 1,
+      password: '',
+      readOnly: false,
+      type: 'Loading',
+      typeLogoUrl: 'public/img/icn-datasource.svg',
+      url: '',
+      user: '',
+    },
+    {
+      id: '1',
+      name: '',
+      info: {
+        author: {
+          name: '',
+          url: '',
+        },
+        description: '',
+        links: [''],
+        logos: {
+          large: '',
+          small: '',
+        },
+        screenshots: '',
+        updated: '',
+        version: '',
+      },
+      includes: [{ type: '', name: '', path: '' }],
+    }
+  );
+
+  let node: NavModelItem;
+
+  // find active page
+  for (const child of main.children) {
+    if (child.id.indexOf(pageName) > 0) {
+      child.active = true;
+      node = child;
+      break;
+    }
+  }
+
+  return {
+    main: main,
+    node: node,
+  };
+}

+ 4 - 0
public/app/features/datasources/state/reducers.ts

@@ -4,6 +4,7 @@ import { LayoutModes } from '../../../core/components/LayoutSelector/LayoutSelec
 
 const initialState: DataSourcesState = {
   dataSources: [] as DataSource[],
+  dataSource: {} as DataSource,
   layoutMode: LayoutModes.Grid,
   searchQuery: '',
   dataSourcesCount: 0,
@@ -16,6 +17,9 @@ export const dataSourcesReducer = (state = initialState, action: Action): DataSo
     case ActionTypes.LoadDataSources:
       return { ...state, dataSources: action.payload, dataSourcesCount: action.payload.length };
 
+    case ActionTypes.LoadDataSource:
+      return { ...state, dataSource: action.payload };
+
     case ActionTypes.SetDataSourcesSearchQuery:
       return { ...state, searchQuery: action.payload };
 

+ 9 - 0
public/app/features/datasources/state/selectors.ts

@@ -1,3 +1,5 @@
+import { DataSource } from '../../../types';
+
 export const getDataSources = state => {
   const regex = new RegExp(state.searchQuery, 'i');
 
@@ -14,6 +16,13 @@ export const getDataSourceTypes = state => {
   });
 };
 
+export const getDataSource = (state, dataSourceId): DataSource | null => {
+  if (state.dataSource.id === parseInt(dataSourceId, 10)) {
+    return state.dataSource;
+  }
+  return null;
+};
+
 export const getDataSourcesSearchQuery = state => state.searchQuery;
 export const getDataSourcesLayoutMode = state => state.layoutMode;
 export const getDataSourcesCount = state => state.dataSourcesCount;

+ 6 - 9
public/app/routes/routes.ts

@@ -12,6 +12,7 @@ import FolderPermissions from 'app/features/folders/FolderPermissions';
 import DataSourcesListPage from 'app/features/datasources/DataSourcesListPage';
 import NewDataSourcePage from '../features/datasources/NewDataSourcePage';
 import UsersListPage from 'app/features/users/UsersListPage';
+import EditDataSourcePage from 'app/features/datasources/EditDataSourcePage';
 
 /** @ngInject */
 export function setupAngularRoutes($routeProvider, $locationProvider) {
@@ -71,15 +72,11 @@ 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: '<react-container />',
+      resolve: {
+        component: () => EditDataSourcePage,
+      },
     })
     .when('/datasources/new', {
       template: '<react-container />',

+ 1 - 0
public/app/types/datasources.ts

@@ -25,4 +25,5 @@ export interface DataSourcesState {
   layoutMode: LayoutMode;
   dataSourcesCount: number;
   dataSourceTypes: Plugin[];
+  dataSource: DataSource;
 }