Commit d86e773c by Torkel Ödegaard

wip: minor progress

parent 60f700a1
......@@ -3,21 +3,16 @@ import React, { Component } from 'react';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
// Utils & Services
import locationUtil from 'app/core/utils/location_util';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { createErrorNotification } from 'app/core/copy/appNotification';
// Components
import { LoadingPlaceholder } from '@grafana/ui';
// Redux
import { updateLocation } from 'app/core/actions';
import { notifyApp } from 'app/core/actions';
import { initDashboard } from '../state/initDashboard';
// Types
import { StoreState } from 'app/types';
import { DashboardModel } from 'app/features/dashboard/state';
import { DashboardLoadingState } from 'app/types/dashboard';
interface Props {
panelId: string;
......@@ -26,8 +21,9 @@ interface Props {
urlType?: string;
$scope: any;
$injector: any;
updateLocation: typeof updateLocation;
notifyApp: typeof notifyApp;
initDashboard: typeof initDashboard;
loadingState: DashboardLoadingState;
dashboard: DashboardModel;
}
interface State {
......@@ -42,81 +38,54 @@ export class DashboardPage extends Component<Props, State> {
};
async componentDidMount() {
const { $injector, urlUid, urlType, urlSlug } = this.props;
// handle old urls with no uid
if (!urlUid && !(urlType === 'script' || urlType === 'snapshot')) {
this.redirectToNewUrl();
return;
}
const loaderSrv = $injector.get('dashboardLoaderSrv');
const dashDTO = await loaderSrv.loadDashboard(urlType, urlSlug, urlUid);
try {
this.initDashboard(dashDTO);
} catch (err) {
this.props.notifyApp(createErrorNotification('Failed to init dashboard', err.toString()));
console.log(err);
}
}
redirectToNewUrl() {
getBackendSrv()
.getDashboardBySlug(this.props.urlSlug)
.then(res => {
if (res) {
const url = locationUtil.stripBaseFromUrl(res.meta.url.replace('/d/', '/d-solo/'));
this.props.updateLocation(url);
}
});
this.props.initDashboard({
injector: this.props.$injector,
scope: this.props.$scope,
urlSlug: this.props.urlSlug,
urlUid: this.props.urlUid,
urlType: this.props.urlType,
})
// const { $injector, urlUid, urlType, urlSlug } = this.props;
//
// // handle old urls with no uid
// if (!urlUid && !(urlType === 'script' || urlType === 'snapshot')) {
// this.redirectToNewUrl();
// return;
// }
//
// const loaderSrv = $injector.get('dashboardLoaderSrv');
// const dashDTO = await loaderSrv.loadDashboard(urlType, urlSlug, urlUid);
//
// try {
// this.initDashboard(dashDTO);
// } catch (err) {
// this.props.notifyApp(createErrorNotification('Failed to init dashboard', err.toString()));
// console.log(err);
// }
}
initDashboard(dashDTO: any) {
const dashboard = new DashboardModel(dashDTO.dashboard, dashDTO.meta);
// init services
this.timeSrv.init(dashboard);
this.annotationsSrv.init(dashboard);
// template values service needs to initialize completely before
// the rest of the dashboard can load
this.variableSrv
.init(dashboard)
// template values failes are non fatal
.catch(this.onInitFailed.bind(this, 'Templating init failed', false))
// continue
.finally(() => {
this.dashboard = dashboard;
this.dashboard.processRepeats();
this.dashboard.updateSubmenuVisibility();
this.dashboard.autoFitPanels(window.innerHeight);
this.unsavedChangesSrv.init(dashboard, this.$scope);
// TODO refactor ViewStateSrv
this.$scope.dashboard = dashboard;
this.dashboardViewState = this.dashboardViewStateSrv.create(this.$scope);
this.keybindingSrv.setupDashboardBindings(this.$scope, dashboard);
this.setWindowTitleAndTheme();
appEvents.emit('dashboard-initialized', dashboard);
})
.catch(this.onInitFailed.bind(this, 'Dashboard init failed', true));
this.setState({ dashboard });
}
// redirectToNewUrl() {
// getBackendSrv()
// .getDashboardBySlug(this.props.urlSlug)
// .then(res => {
// if (res) {
// const url = locationUtil.stripBaseFromUrl(res.meta.url.replace('/d/', '/d-solo/'));
// this.props.updateLocation(url);
// }
// });
// }
//
// initDashboard(dashDTO: any) {
// const dashboard = new DashboardModel(dashDTO.dashboard, dashDTO.meta);
// this.setState({ dashboard });
// }
render() {
const { notFound, dashboard } = this.state;
if (notFound) {
return <div className="alert alert-error">Dashboard not found</div>;
}
const { loadingState, dashboard } = this.props;
if (!dashboard) {
return <LoadingPlaceholder text="Loading dashboard" />;
return <LoadingPlaceholder text={loadingState.toString()} />;
}
return <div>title: {dashboard.title}</div>;
......@@ -128,11 +97,12 @@ const mapStateToProps = (state: StoreState) => ({
urlSlug: state.location.routeParams.slug,
urlType: state.location.routeParams.type,
panelId: state.location.query.panelId,
loadingState: state.dashboard.loadingState,
dashboard: state.dashboard as DashboardModel,
});
const mapDispatchToProps = {
updateLocation,
notifyApp,
initDashboard
};
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(DashboardPage));
// Libaries
import { StoreState } from 'app/types';
import { ThunkAction } from 'redux-thunk';
// Services & Utils
import { getBackendSrv } from 'app/core/services/backend_srv';
import appEvents from 'app/core/app_events';
import { actionCreatorFactory } from 'app/core/redux';
import { ActionOf } from 'app/core/redux/actionCreatorFactory';
import { createSuccessNotification } from 'app/core/copy/appNotification';
// Actions
import { loadPluginDashboards } from '../../plugins/state/actions';
import { notifyApp } from 'app/core/actions';
// Types
import {
DashboardAcl,
DashboardAclDTO,
......@@ -10,30 +20,14 @@ import {
DashboardAclUpdateDTO,
NewDashboardAclItem,
} from 'app/types/acl';
import { DashboardLoadingState } from 'app/types/dashboard';
export enum ActionTypes {
LoadDashboardPermissions = 'LOAD_DASHBOARD_PERMISSIONS',
LoadStarredDashboards = 'LOAD_STARRED_DASHBOARDS',
}
export interface LoadDashboardPermissionsAction {
type: ActionTypes.LoadDashboardPermissions;
payload: DashboardAcl[];
}
export interface LoadStarredDashboardsAction {
type: ActionTypes.LoadStarredDashboards;
payload: DashboardAcl[];
}
export const loadDashboardPermissions = actionCreatorFactory<DashboardAclDTO[]>('LOAD_DASHBOARD_PERMISSIONS').create();
export const setDashboardLoadingState = actionCreatorFactory<DashboardLoadingState>('SET_DASHBOARD_LOADING_STATE').create();
export type Action = LoadDashboardPermissionsAction | LoadStarredDashboardsAction;
export type Action = ActionOf<DashboardAclDTO[]>;
type ThunkResult<R> = ThunkAction<R, StoreState, undefined, any>;
export const loadDashboardPermissions = (items: DashboardAclDTO[]): LoadDashboardPermissionsAction => ({
type: ActionTypes.LoadDashboardPermissions,
payload: items,
});
export type ThunkResult<R> = ThunkAction<R, StoreState, undefined, any>;
export function getDashboardPermissions(id: number): ThunkResult<void> {
return async dispatch => {
......@@ -124,7 +118,7 @@ export function addDashboardPermission(dashboardId: number, newItem: NewDashboar
export function importDashboard(data, dashboardTitle: string): ThunkResult<void> {
return async dispatch => {
await getBackendSrv().post('/api/dashboards/import', data);
appEvents.emit('alert-success', ['Dashboard Imported', dashboardTitle]);
dispatch(notifyApp(createSuccessNotification('Dashboard Imported', dashboardTitle)));
dispatch(loadPluginDashboards());
};
}
......@@ -135,3 +129,4 @@ export function removeDashboard(uri: string): ThunkResult<void> {
dispatch(loadPluginDashboards());
};
}
// Libaries
import { StoreState } from 'app/types';
import { ThunkAction } from 'redux-thunk';
// Services & Utils
import { getBackendSrv } from 'app/core/services/backend_srv';
import { createErrorNotification } from 'app/core/copy/appNotification';
export function initDashboard(dashboard: DashboardModel, $injector: any, $scope: any) {
// Actions
import { updateLocation } from 'app/core/actions';
import { notifyApp } from 'app/core/actions';
import locationUtil from 'app/core/utils/location_util';
import { setDashboardLoadingState, ThunkResult } from './actions';
// Types
import { DashboardLoadingState } from 'app/types/dashboard';
import { DashboardModel } from './DashboardModel';
export interface InitDashboardArgs {
injector: any;
scope: any;
urlUid?: string;
urlSlug?: string;
urlType?: string;
}
export function initDashboard({ injector, scope, urlUid, urlSlug, urlType }: InitDashboardArgs): ThunkResult<void> {
return async dispatch => {
const loaderSrv = injector.get('dashboardLoaderSrv');
dispatch(setDashboardLoadingState(DashboardLoadingState.Fetching));
try {
// fetch dashboard from api
const dashDTO = await loaderSrv.loadDashboard(urlType, urlSlug, urlUid);
// set initializing state
dispatch(setDashboardLoadingState(DashboardLoadingState.Initializing));
// create model
const dashboard = new DashboardModel(dashDTO.dashboard, dashDTO.meta);
// init services
injector.get('timeSrv').init(dashboard);
injector.get('annotationsSrv').init(dashboard);
// template values service needs to initialize completely before
// the rest of the dashboard can load
injector.get('variableSrv').init(dashboard)
.catch(err => {
dispatch(notifyApp(createErrorNotification('Templating init failed')));
})
.finally(() => {
dashboard.processRepeats();
dashboard.updateSubmenuVisibility();
dashboard.autoFitPanels(window.innerHeight);
injector.get('unsavedChangesSrv').init(dashboard, scope);
scope.dashboard = dashboard;
injector.get('dashboardViewStateSrv').create(scope);
injector.get('keybindingSrv').setupDashboardBindings(scope, dashboard);
})
.catch(err => {
dispatch(setDashboardLoadingState(DashboardLoadingState.Error));
});
} catch (err) {
dispatch(setDashboardLoadingState(DashboardLoadingState.Error));
}
};
}
import { Action, ActionTypes } from './actions';
import { Action } from './actions';
import { OrgRole, PermissionLevel, DashboardState } from 'app/types';
import { initialState, dashboardReducer } from './reducers';
......@@ -8,7 +8,7 @@ describe('dashboard reducer', () => {
beforeEach(() => {
const action: Action = {
type: ActionTypes.LoadDashboardPermissions,
type: 'LOAD_DASHBOARD_PERMISSIONS',
payload: [
{ id: 2, dashboardId: 1, role: OrgRole.Viewer, permission: PermissionLevel.View },
{ id: 3, dashboardId: 1, role: OrgRole.Editor, permission: PermissionLevel.Edit },
......
import { DashboardState } from 'app/types';
import { Action, ActionTypes } from './actions';
import { DashboardState, DashboardLoadingState } from 'app/types/dashboard';
import { loadDashboardPermissions, setDashboardLoadingState } from './actions';
import { reducerFactory } from 'app/core/redux';
import { processAclItems } from 'app/core/utils/acl';
export const initialState: DashboardState = {
loadingState: DashboardLoadingState.NotStarted,
dashboard: null,
permissions: [],
};
export const dashboardReducer = (state = initialState, action: Action): DashboardState => {
switch (action.type) {
case ActionTypes.LoadDashboardPermissions:
return {
...state,
permissions: processAclItems(action.payload),
};
}
return state;
};
export const dashboardReducer = reducerFactory(initialState)
.addMapper({
filter: loadDashboardPermissions,
mapper: (state, action) => ({
...state,
permissions: processAclItems(action.payload),
}),
})
.addMapper({
filter: setDashboardLoadingState,
mapper: (state, action) => ({
...state,
loadingState: action.payload
}),
})
.create()
export default {
dashboard: dashboardReducer,
......
import { DashboardAcl } from './acl';
export interface Dashboard {
}
export enum DashboardLoadingState {
NotStarted = 'Not started',
Fetching = 'Fetching',
Initializing = 'Initializing',
Error = 'Error',
Done = 'Done',
}
export interface DashboardState {
permissions: DashboardAcl[];
dashboard: Dashboard | null;
loadingState: DashboardLoadingState;
permissions: DashboardAcl[] | null;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment