Commit f5249d60 by Torkel Ödegaard

Breaking init dashboard up in to fetch & init

parent 49a597fc
......@@ -3,7 +3,7 @@ import { ThunkAction } from 'redux-thunk';
// Services & Utils
import { getBackendSrv } from 'app/core/services/backend_srv';
import { actionCreatorFactory, noPayloadActionCreatorFactory, ActionOf } from 'app/core/redux';
import { actionCreatorFactory, noPayloadActionCreatorFactory } from 'app/core/redux';
import { createSuccessNotification } from 'app/core/copy/appNotification';
// Actions
......@@ -26,7 +26,6 @@ export const setDashboardLoadingState = actionCreatorFactory<DashboardLoadingSta
export const setDashboardModel = actionCreatorFactory<MutableDashboard>('SET_DASHBOARD_MODEL').create();
export const setDashboardLoadingSlow = noPayloadActionCreatorFactory('SET_DASHBOARD_LOADING_SLOW').create();
export type Action = ActionOf<DashboardAclDTO[]>;
export type ThunkResult<R> = ThunkAction<R, StoreState, undefined, any>;
export function getDashboardPermissions(id: number): ThunkResult<void> {
......
// Libraries
import { ThunkDispatch } from 'redux-thunk';
// Services & Utils
import { createErrorNotification } from 'app/core/copy/appNotification';
import { getBackendSrv } from 'app/core/services/backend_srv';
......@@ -15,9 +18,11 @@ import locationUtil from 'app/core/utils/location_util';
import { setDashboardLoadingState, ThunkResult, setDashboardModel, setDashboardLoadingSlow } from './actions';
// Types
import { DashboardLoadingState, DashboardRouteInfo } from 'app/types';
import { DashboardLoadingState, DashboardRouteInfo, StoreState } from 'app/types';
import { DashboardModel } from './DashboardModel';
export type Dispatch = ThunkDispatch<StoreState, undefined, any>;
export interface InitDashboardArgs {
$injector: any;
$scope: any;
......@@ -25,11 +30,11 @@ export interface InitDashboardArgs {
urlSlug?: string;
urlType?: string;
urlFolderId?: string;
routeInfo: string;
routeInfo: DashboardRouteInfo;
fixUrl: boolean;
}
async function redirectToNewUrl(slug: string, dispatch: any, currentPath: string) {
async function redirectToNewUrl(slug: string, dispatch: Dispatch, currentPath: string) {
const res = await getBackendSrv().getDashboardBySlug(slug);
if (res) {
......@@ -45,44 +50,12 @@ async function redirectToNewUrl(slug: string, dispatch: any, currentPath: string
}
}
/**
* This action (or saga) does everything needed to bootstrap a dashboard & dashboard model.
* First it handles the process of fetching the dashboard, correcting the url if required (causing redirects/url updates)
*
* This is used both for single dashboard & solo panel routes, home & new dashboard routes.
*
* Then it handles the initializing of the old angular services that the dashboard components & panels still depend on
*
*/
export function initDashboard({
$injector,
$scope,
urlUid,
urlSlug,
urlType,
urlFolderId,
routeInfo,
fixUrl,
}: InitDashboardArgs): ThunkResult<void> {
return async (dispatch, getState) => {
let dashDTO = null;
// set fetching state
dispatch(setDashboardLoadingState(DashboardLoadingState.Fetching));
// Detect slow loading / initializing and set state flag
// This is in order to not show loading indication for fast loading dashboards as it creates blinking/flashing
setTimeout(() => {
if (getState().dashboard.model === null) {
dispatch(setDashboardLoadingSlow());
}
}, 500);
async function fetchDashboard(args: InitDashboardArgs, dispatch: Dispatch, getState: () => StoreState): Promise<any> {
try {
switch (routeInfo) {
switch (args.routeInfo) {
case DashboardRouteInfo.Home: {
// load home dash
dashDTO = await getBackendSrv().get('/api/dashboards/home');
const dashDTO = await getBackendSrv().get('/api/dashboards/home');
// if user specified a custom home dashboard redirect to that
if (dashDTO.redirectUri) {
......@@ -95,19 +68,19 @@ export function initDashboard({
dashDTO.meta.canSave = false;
dashDTO.meta.canShare = false;
dashDTO.meta.canStar = false;
break;
return dashDTO;
}
case DashboardRouteInfo.Normal: {
// for old db routes we redirect
if (urlType === 'db') {
redirectToNewUrl(urlSlug, dispatch, getState().location.path);
return;
if (args.urlType === 'db') {
redirectToNewUrl(args.urlSlug, dispatch, getState().location.path);
return null;
}
const loaderSrv = $injector.get('dashboardLoaderSrv');
dashDTO = await loaderSrv.loadDashboard(urlType, urlSlug, urlUid);
const loaderSrv = args.$injector.get('dashboardLoaderSrv');
const dashDTO = await loaderSrv.loadDashboard(args.urlType, args.urlSlug, args.urlUid);
if (fixUrl && dashDTO.meta.url) {
if (args.fixUrl && dashDTO.meta.url) {
// check if the current url is correct (might be old slug)
const dashboardUrl = locationUtil.stripBaseFromUrl(dashDTO.meta.url);
const currentPath = getState().location.path;
......@@ -115,21 +88,50 @@ export function initDashboard({
if (dashboardUrl !== currentPath) {
// replace url to not create additional history items and then return so that initDashboard below isn't executed multiple times.
dispatch(updateLocation({ path: dashboardUrl, partial: true, replace: true }));
return;
return null;
}
}
break;
return dashDTO;
}
case DashboardRouteInfo.New: {
dashDTO = getNewDashboardModelData(urlFolderId);
break;
return getNewDashboardModelData(args.urlFolderId);
}
}
} catch (err) {
dispatch(setDashboardLoadingState(DashboardLoadingState.Error));
dispatch(notifyApp(createErrorNotification('Dashboard fetch failed', err)));
console.log(err);
return null;
}
}
/**
* This action (or saga) does everything needed to bootstrap a dashboard & dashboard model.
* First it handles the process of fetching the dashboard, correcting the url if required (causing redirects/url updates)
*
* This is used both for single dashboard & solo panel routes, home & new dashboard routes.
*
* Then it handles the initializing of the old angular services that the dashboard components & panels still depend on
*
*/
export function initDashboard(args: InitDashboardArgs): ThunkResult<void> {
return async (dispatch, getState) => {
// set fetching state
dispatch(setDashboardLoadingState(DashboardLoadingState.Fetching));
// Detect slow loading / initializing and set state flag
// This is in order to not show loading indication for fast loading dashboards as it creates blinking/flashing
setTimeout(() => {
if (getState().dashboard.model === null) {
dispatch(setDashboardLoadingSlow());
}
}, 500);
// fetch dashboard data
const dashDTO = await fetchDashboard(args, dispatch, getState);
// returns null if there was a redirect or error
if (!dashDTO) {
return;
}
......@@ -153,12 +155,12 @@ export function initDashboard({
}
// init services
const timeSrv: TimeSrv = $injector.get('timeSrv');
const annotationsSrv: AnnotationsSrv = $injector.get('annotationsSrv');
const variableSrv: VariableSrv = $injector.get('variableSrv');
const keybindingSrv: KeybindingSrv = $injector.get('keybindingSrv');
const unsavedChangesSrv = $injector.get('unsavedChangesSrv');
const dashboardSrv: DashboardSrv = $injector.get('dashboardSrv');
const timeSrv: TimeSrv = args.$injector.get('timeSrv');
const annotationsSrv: AnnotationsSrv = args.$injector.get('annotationsSrv');
const variableSrv: VariableSrv = args.$injector.get('variableSrv');
const keybindingSrv: KeybindingSrv = args.$injector.get('keybindingSrv');
const unsavedChangesSrv = args.$injector.get('unsavedChangesSrv');
const dashboardSrv: DashboardSrv = args.$injector.get('dashboardSrv');
timeSrv.init(dashboard);
annotationsSrv.init(dashboard);
......@@ -183,9 +185,8 @@ export function initDashboard({
}
// init unsaved changes tracking
unsavedChangesSrv.init(dashboard, $scope);
keybindingSrv.setupDashboardBindings($scope, dashboard);
unsavedChangesSrv.init(dashboard, args.$scope);
keybindingSrv.setupDashboardBindings(args.$scope, dashboard);
} catch (err) {
dispatch(notifyApp(createErrorNotification('Dashboard init failed', err)));
console.log(err);
......
import { Action } from './actions';
import { loadDashboardPermissions } from './actions';
import { OrgRole, PermissionLevel, DashboardState } from 'app/types';
import { initialState, dashboardReducer } from './reducers';
......@@ -7,13 +7,10 @@ describe('dashboard reducer', () => {
let state: DashboardState;
beforeEach(() => {
const action: Action = {
type: 'LOAD_DASHBOARD_PERMISSIONS',
payload: [
const action = loadDashboardPermissions([
{ id: 2, dashboardId: 1, role: OrgRole.Viewer, permission: PermissionLevel.View },
{ id: 3, dashboardId: 1, role: OrgRole.Editor, permission: PermissionLevel.Edit },
],
};
]);
state = dashboardReducer(initialState, action);
});
......
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