diff --git a/public/app/features/datasources/DashboardsTable.tsx b/public/app/features/datasources/DashboardsTable.tsx new file mode 100644 index 00000000000..c252d8b1229 --- /dev/null +++ b/public/app/features/datasources/DashboardsTable.tsx @@ -0,0 +1,55 @@ +import React, { SFC } from 'react'; +import { PluginDashboard } from '../../types'; + +interface Props { + dashboards: PluginDashboard[]; + onImport: (dashboard, overwrite) => void; + onRemove: (dashboard) => void; +} + +const DashboardsTable: SFC = ({ dashboards, onImport, onRemove }) => { + function buttonText(dashboard: PluginDashboard) { + return dashboard.revision !== dashboard.importedRevision ? 'Update' : 'Re-import'; + } + + return ( + + + {dashboards.map((dashboard, index) => { + return ( + + + + + + ); + })} + +
+ + + {dashboard.imported ? ( + {dashboard.title} + ) : ( + {dashboard.title} + )} + + {!dashboard.imported ? ( + + ) : ( + + )} + {dashboard.imported && ( + + )} +
+ ); +}; + +export default DashboardsTable; diff --git a/public/app/features/datasources/DataSourceDashboards.tsx b/public/app/features/datasources/DataSourceDashboards.tsx new file mode 100644 index 00000000000..774c4ca46be --- /dev/null +++ b/public/app/features/datasources/DataSourceDashboards.tsx @@ -0,0 +1,64 @@ +import React, { PureComponent } from 'react'; +import { hot } from 'react-hot-loader'; +import { connect } from 'react-redux'; +import PageHeader from 'app/core/components/PageHeader/PageHeader'; +import DashboardTable from './DashboardsTable'; +import { NavModel, PluginDashboard } from 'app/types'; +import { getNavModel } from 'app/core/selectors/navModel'; +import { getRouteParamsId } from 'app/core/selectors/location'; +import { loadDataSource } from './state/actions'; +import { loadPluginDashboards } from '../plugins/state/actions'; + +export interface Props { + navModel: NavModel; + dashboards: PluginDashboard[]; + pageId: number; + loadDataSource: typeof loadDataSource; + loadPluginDashboards: typeof loadPluginDashboards; +} + +export class DataSourceDashboards extends PureComponent { + async componentDidMount() { + const { loadDataSource, pageId } = this.props; + + await loadDataSource(pageId); + this.props.loadPluginDashboards(); + } + + onImport = (dashboard, state) => {}; + + onRemove = dashboard => {}; + + render() { + const { dashboards, navModel } = this.props; + return ( +
+ +
+ this.onImport(dashboard, overwrite)} + onRemove={dashboard => this.onRemove(dashboard)} + /> +
+
+ ); + } +} + +function mapStateToProps(state) { + const pageId = getRouteParamsId(state.location); + + return { + navModel: getNavModel(state.navIndex, `datasource-dashboards-${pageId}`), + pageId: pageId, + dashboards: state.plugins.dashboards, + }; +} + +const mapDispatchToProps = { + loadDataSource, + loadPluginDashboards, +}; + +export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(DataSourceDashboards)); diff --git a/public/app/features/plugins/state/actions.ts b/public/app/features/plugins/state/actions.ts index dcfd510ffa0..9f53f3c1fd0 100644 --- a/public/app/features/plugins/state/actions.ts +++ b/public/app/features/plugins/state/actions.ts @@ -2,9 +2,11 @@ import { Plugin, StoreState } from 'app/types'; import { ThunkAction } from 'redux-thunk'; import { getBackendSrv } from '../../../core/services/backend_srv'; import { LayoutMode } from '../../../core/components/LayoutSelector/LayoutSelector'; +import { PluginDashboard } from '../../../types/plugins'; export enum ActionTypes { LoadPlugins = 'LOAD_PLUGINS', + LoadPluginDashboards = 'LOAD_PLUGIN_DASHBOARDS', SetPluginsSearchQuery = 'SET_PLUGIN_SEARCH_QUERY', SetLayoutMode = 'SET_LAYOUT_MODE', } @@ -14,6 +16,11 @@ export interface LoadPluginsAction { payload: Plugin[]; } +export interface LoadPluginDashboardsAction { + type: ActionTypes.LoadPluginDashboards; + payload: PluginDashboard[]; +} + export interface SetPluginsSearchQueryAction { type: ActionTypes.SetPluginsSearchQuery; payload: string; @@ -39,7 +46,12 @@ const pluginsLoaded = (plugins: Plugin[]): LoadPluginsAction => ({ payload: plugins, }); -export type Action = LoadPluginsAction | SetPluginsSearchQueryAction | SetLayoutModeAction; +const pluginDashboardsLoaded = (dashboards: PluginDashboard[]): LoadPluginDashboardsAction => ({ + type: ActionTypes.LoadPluginDashboards, + payload: dashboards, +}); + +export type Action = LoadPluginsAction | LoadPluginDashboardsAction | SetPluginsSearchQueryAction | SetLayoutModeAction; type ThunkResult = ThunkAction; @@ -49,3 +61,12 @@ export function loadPlugins(): ThunkResult { dispatch(pluginsLoaded(result)); }; } + +export function loadPluginDashboards(): ThunkResult { + return async (dispatch, getStore) => { + const dataSourceType = getStore().dataSources.dataSource.type; + + const response = await getBackendSrv().get(`api/plugins/${dataSourceType}/dashboards`); + dispatch(pluginDashboardsLoaded(response)); + }; +} diff --git a/public/app/features/plugins/state/reducers.ts b/public/app/features/plugins/state/reducers.ts index bd99d2029f5..0d464ef1772 100644 --- a/public/app/features/plugins/state/reducers.ts +++ b/public/app/features/plugins/state/reducers.ts @@ -1,12 +1,14 @@ import { Action, ActionTypes } from './actions'; import { Plugin, PluginsState } from 'app/types'; import { LayoutModes } from '../../../core/components/LayoutSelector/LayoutSelector'; +import { PluginDashboard } from '../../../types/plugins'; export const initialState: PluginsState = { plugins: [] as Plugin[], searchQuery: '', layoutMode: LayoutModes.Grid, hasFetched: false, + dashboards: [] as PluginDashboard[], }; export const pluginsReducer = (state = initialState, action: Action): PluginsState => { @@ -19,6 +21,9 @@ export const pluginsReducer = (state = initialState, action: Action): PluginsSta case ActionTypes.SetLayoutMode: return { ...state, layoutMode: action.payload }; + + case ActionTypes.LoadPluginDashboards: + return { ...state, dashboards: action.payload }; } return state; }; diff --git a/public/app/routes/routes.ts b/public/app/routes/routes.ts index e94275f6aef..94b6b2706f2 100644 --- a/public/app/routes/routes.ts +++ b/public/app/routes/routes.ts @@ -13,6 +13,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 DataSourceDashboards from 'app/features/datasources/DataSourceDashboards'; /** @ngInject */ export function setupAngularRoutes($routeProvider, $locationProvider) { @@ -78,9 +79,10 @@ export function setupAngularRoutes($routeProvider, $locationProvider) { controllerAs: 'ctrl', }) .when('/datasources/edit/:id/dashboards', { - templateUrl: 'public/app/features/plugins/partials/ds_dashboards.html', - controller: 'DataSourceDashboardsCtrl', - controllerAs: 'ctrl', + template: '', + resolve: { + component: () => DataSourceDashboards, + }, }) .when('/datasources/new', { template: '', diff --git a/public/app/types/index.ts b/public/app/types/index.ts index 26f15d582ac..7b35f3d6787 100644 --- a/public/app/types/index.ts +++ b/public/app/types/index.ts @@ -8,7 +8,7 @@ import { DashboardAcl, OrgRole, PermissionLevel } from './acl'; import { ApiKey, ApiKeysState, NewApiKey } from './apiKeys'; import { Invitee, OrgUser, User, UsersState } from './user'; import { DataSource, DataSourcesState } from './datasources'; -import { PluginMeta, Plugin, PluginsState } from './plugins'; +import { PluginDashboard, PluginMeta, Plugin, PluginsState } from './plugins'; export { Team, @@ -45,6 +45,7 @@ export { OrgUser, User, UsersState, + PluginDashboard, }; export interface StoreState { diff --git a/public/app/types/plugins.ts b/public/app/types/plugins.ts index c7e9aa7a564..184e091b5e6 100644 --- a/public/app/types/plugins.ts +++ b/public/app/types/plugins.ts @@ -40,9 +40,26 @@ export interface Plugin { type: string; } +export interface PluginDashboard { + dashboardId: number; + description: string; + folderId: number; + imported: boolean; + importedRevision: number; + importedUri: string; + importedUrl: string; + path: string; + pluginId: string; + removed: boolean; + revision: number; + slug: string; + title: string; +} + export interface PluginsState { plugins: Plugin[]; searchQuery: string; layoutMode: string; hasFetched: boolean; + dashboards: PluginDashboard[]; }