diff --git a/public/app/features/dashboard/state/actions.ts b/public/app/features/dashboard/state/actions.ts index da4c195c953..c25388bbcb8 100644 --- a/public/app/features/dashboard/state/actions.ts +++ b/public/app/features/dashboard/state/actions.ts @@ -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('SET_DASHBOARD_MODEL').create(); export const setDashboardLoadingSlow = noPayloadActionCreatorFactory('SET_DASHBOARD_LOADING_SLOW').create(); -export type Action = ActionOf; export type ThunkResult = ThunkAction; export function getDashboardPermissions(id: number): ThunkResult { diff --git a/public/app/features/dashboard/state/initDashboard.ts b/public/app/features/dashboard/state/initDashboard.ts index c774c4926f4..ba218c1583d 100644 --- a/public/app/features/dashboard/state/initDashboard.ts +++ b/public/app/features/dashboard/state/initDashboard.ts @@ -1,3 +1,6 @@ +// 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; + 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,6 +50,61 @@ async function redirectToNewUrl(slug: string, dispatch: any, currentPath: string } } +async function fetchDashboard(args: InitDashboardArgs, dispatch: Dispatch, getState: () => StoreState): Promise { + try { + switch (args.routeInfo) { + case DashboardRouteInfo.Home: { + // load home dash + const dashDTO = await getBackendSrv().get('/api/dashboards/home'); + + // if user specified a custom home dashboard redirect to that + if (dashDTO.redirectUri) { + const newUrl = locationUtil.stripBaseFromUrl(dashDTO.redirectUri); + dispatch(updateLocation({ path: newUrl, replace: true })); + return; + } + + // disable some actions on the default home dashboard + dashDTO.meta.canSave = false; + dashDTO.meta.canShare = false; + dashDTO.meta.canStar = false; + return dashDTO; + } + case DashboardRouteInfo.Normal: { + // for old db routes we redirect + if (args.urlType === 'db') { + redirectToNewUrl(args.urlSlug, dispatch, getState().location.path); + return null; + } + + const loaderSrv = args.$injector.get('dashboardLoaderSrv'); + const dashDTO = await loaderSrv.loadDashboard(args.urlType, args.urlSlug, args.urlUid); + + 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; + + 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 null; + } + } + return dashDTO; + } + case DashboardRouteInfo.New: { + 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) @@ -54,19 +114,8 @@ async function redirectToNewUrl(slug: string, dispatch: any, currentPath: string * 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 { +export function initDashboard(args: InitDashboardArgs): ThunkResult { return async (dispatch, getState) => { - let dashDTO = null; - // set fetching state dispatch(setDashboardLoadingState(DashboardLoadingState.Fetching)); @@ -78,58 +127,11 @@ export function initDashboard({ } }, 500); - try { - switch (routeInfo) { - case DashboardRouteInfo.Home: { - // load home dash - dashDTO = await getBackendSrv().get('/api/dashboards/home'); + // fetch dashboard data + const dashDTO = await fetchDashboard(args, dispatch, getState); - // if user specified a custom home dashboard redirect to that - if (dashDTO.redirectUri) { - const newUrl = locationUtil.stripBaseFromUrl(dashDTO.redirectUri); - dispatch(updateLocation({ path: newUrl, replace: true })); - return; - } - - // disable some actions on the default home dashboard - dashDTO.meta.canSave = false; - dashDTO.meta.canShare = false; - dashDTO.meta.canStar = false; - break; - } - case DashboardRouteInfo.Normal: { - // for old db routes we redirect - if (urlType === 'db') { - redirectToNewUrl(urlSlug, dispatch, getState().location.path); - return; - } - - const loaderSrv = $injector.get('dashboardLoaderSrv'); - dashDTO = await loaderSrv.loadDashboard(urlType, urlSlug, urlUid); - - if (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; - - 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; - } - } - - break; - } - case DashboardRouteInfo.New: { - dashDTO = getNewDashboardModelData(urlFolderId); - break; - } - } - } catch (err) { - dispatch(setDashboardLoadingState(DashboardLoadingState.Error)); - dispatch(notifyApp(createErrorNotification('Dashboard fetch failed', err))); - console.log(err); + // 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); diff --git a/public/app/features/dashboard/state/reducers.test.ts b/public/app/features/dashboard/state/reducers.test.ts index ea3353ce741..b96666019ba 100644 --- a/public/app/features/dashboard/state/reducers.test.ts +++ b/public/app/features/dashboard/state/reducers.test.ts @@ -1,4 +1,4 @@ -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: [ - { id: 2, dashboardId: 1, role: OrgRole.Viewer, permission: PermissionLevel.View }, - { id: 3, dashboardId: 1, role: OrgRole.Editor, permission: PermissionLevel.Edit }, - ], - }; + 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); });