Now handles all dashbord routes

This commit is contained in:
Torkel Ödegaard
2019-02-04 13:49:14 +01:00
parent 217468074f
commit ae768193e3
9 changed files with 132 additions and 36 deletions

View File

@@ -8,12 +8,13 @@ export const initialState: LocationState = {
path: '', path: '',
query: {}, query: {},
routeParams: {}, routeParams: {},
replace: false,
}; };
export const locationReducer = (state = initialState, action: Action): LocationState => { export const locationReducer = (state = initialState, action: Action): LocationState => {
switch (action.type) { switch (action.type) {
case CoreActionTypes.UpdateLocation: { case CoreActionTypes.UpdateLocation: {
const { path, routeParams } = action.payload; const { path, routeParams, replace } = action.payload;
let query = action.payload.query || state.query; let query = action.payload.query || state.query;
if (action.payload.partial) { if (action.payload.partial) {
@@ -26,6 +27,7 @@ export const locationReducer = (state = initialState, action: Action): LocationS
path: path || state.path, path: path || state.path,
query: { ...query }, query: { ...query },
routeParams: routeParams || state.routeParams, routeParams: routeParams || state.routeParams,
replace: replace === true,
}; };
} }
} }

View File

@@ -46,6 +46,10 @@ export class BridgeSrv {
if (angularUrl !== url) { if (angularUrl !== url) {
this.$timeout(() => { this.$timeout(() => {
this.$location.url(url); this.$location.url(url);
// some state changes should not trigger new browser history
if (state.location.replace) {
this.$location.replace();
}
}); });
console.log('store updating angular $location.url', url); console.log('store updating angular $location.url', url);
} }

View File

@@ -22,9 +22,8 @@ import { updateLocation } from 'app/core/actions';
import { notifyApp } from 'app/core/actions'; import { notifyApp } from 'app/core/actions';
// Types // Types
import { StoreState } from 'app/types'; import { StoreState, DashboardLoadingState, DashboardRouteInfo } from 'app/types';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { DashboardLoadingState } from 'app/types/dashboard';
interface Props { interface Props {
urlUid?: string; urlUid?: string;
@@ -32,8 +31,10 @@ interface Props {
urlType?: string; urlType?: string;
editview?: string; editview?: string;
urlPanelId?: string; urlPanelId?: string;
urlFolderId?: string;
$scope: any; $scope: any;
$injector: any; $injector: any;
routeInfo: DashboardRouteInfo;
urlEdit: boolean; urlEdit: boolean;
urlFullscreen: boolean; urlFullscreen: boolean;
loadingState: DashboardLoadingState; loadingState: DashboardLoadingState;
@@ -66,6 +67,8 @@ export class DashboardPage extends PureComponent<Props, State> {
urlSlug: this.props.urlSlug, urlSlug: this.props.urlSlug,
urlUid: this.props.urlUid, urlUid: this.props.urlUid,
urlType: this.props.urlType, urlType: this.props.urlType,
urlFolderId: this.props.urlFolderId,
routeInfo: this.props.routeInfo,
}); });
} }
@@ -208,6 +211,7 @@ const mapStateToProps = (state: StoreState) => ({
urlType: state.location.routeParams.type, urlType: state.location.routeParams.type,
editview: state.location.query.editview, editview: state.location.query.editview,
urlPanelId: state.location.query.panelId, urlPanelId: state.location.query.panelId,
urlFolderId: state.location.query.folderId,
urlFullscreen: state.location.query.fullscreen === true, urlFullscreen: state.location.query.fullscreen === true,
urlEdit: state.location.query.edit === true, urlEdit: state.location.query.edit === true,
loadingState: state.dashboard.loadingState, loadingState: state.dashboard.loadingState,

View File

@@ -23,10 +23,10 @@ export class DashboardViewStateSrv {
self.dashboard = $scope.dashboard; self.dashboard = $scope.dashboard;
$scope.onAppEvent('$routeUpdate', () => { $scope.onAppEvent('$routeUpdate', () => {
const urlState = self.getQueryStringState(); // const urlState = self.getQueryStringState();
if (self.needsSync(urlState)) { // if (self.needsSync(urlState)) {
self.update(urlState, true); // self.update(urlState, true);
} // }
}); });
$scope.onAppEvent('panel-change-view', (evt, payload) => { $scope.onAppEvent('panel-change-view', (evt, payload) => {
@@ -35,8 +35,8 @@ export class DashboardViewStateSrv {
// this marks changes to location during this digest cycle as not to add history item // this marks changes to location during this digest cycle as not to add history item
// don't want url changes like adding orgId to add browser history // don't want url changes like adding orgId to add browser history
$location.replace(); // $location.replace();
this.update(this.getQueryStringState()); // this.update(this.getQueryStringState());
} }
needsSync(urlState) { needsSync(urlState) {

View File

@@ -15,7 +15,7 @@ import { setDashboardLoadingState, ThunkResult, setDashboardModel } from './acti
import { removePanel } from '../utils/panel'; import { removePanel } from '../utils/panel';
// Types // Types
import { DashboardLoadingState } from 'app/types/dashboard'; import { DashboardLoadingState, DashboardRouteInfo } from 'app/types';
import { DashboardModel } from './DashboardModel'; import { DashboardModel } from './DashboardModel';
export interface InitDashboardArgs { export interface InitDashboardArgs {
@@ -24,6 +24,8 @@ export interface InitDashboardArgs {
urlUid?: string; urlUid?: string;
urlSlug?: string; urlSlug?: string;
urlType?: string; urlType?: string;
urlFolderId: string;
routeInfo: string;
} }
async function redirectToNewUrl(slug: string, dispatch: any) { async function redirectToNewUrl(slug: string, dispatch: any) {
@@ -35,36 +37,67 @@ async function redirectToNewUrl(slug: string, dispatch: any) {
} }
} }
export function initDashboard({ $injector, $scope, urlUid, urlSlug, urlType }: InitDashboardArgs): ThunkResult<void> { export function initDashboard({
return async dispatch => { $injector,
// handle old urls with no uid $scope,
if (!urlUid && urlSlug && !urlType) { urlUid,
redirectToNewUrl(urlSlug, dispatch); urlSlug,
return; urlType,
} urlFolderId,
routeInfo,
}: InitDashboardArgs): ThunkResult<void> {
return async (dispatch, getState) => {
let dashDTO = null; let dashDTO = null;
// set fetching state // set fetching state
dispatch(setDashboardLoadingState(DashboardLoadingState.Fetching)); dispatch(setDashboardLoadingState(DashboardLoadingState.Fetching));
try { try {
// if no uid or slug, load home dashboard switch (routeInfo) {
if (!urlUid && !urlSlug) { // handle old urls with no uid
dashDTO = await getBackendSrv().get('/api/dashboards/home'); case DashboardRouteInfo.Old: {
redirectToNewUrl(urlSlug, dispatch);
if (dashDTO.redirectUri) {
const newUrl = locationUtil.stripBaseFromUrl(dashDTO.redirectUri);
dispatch(updateLocation({ path: newUrl }));
return; return;
} else { }
case DashboardRouteInfo.Home: {
// load home dash
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.canSave = false;
dashDTO.meta.canShare = false; dashDTO.meta.canShare = false;
dashDTO.meta.canStar = false; dashDTO.meta.canStar = false;
break;
}
case DashboardRouteInfo.Normal: {
const loaderSrv = $injector.get('dashboardLoaderSrv');
dashDTO = await loaderSrv.loadDashboard(urlType, urlSlug, urlUid);
// check if the current url is correct (might be old slug)
const dashboardUrl = locationUtil.stripBaseFromUrl(dashDTO.meta.url);
const currentPath = getState().location.path;
console.log('loading dashboard: currentPath', currentPath);
console.log('loading dashboard: dashboardUrl', dashboardUrl);
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;
} }
} else {
const loaderSrv = $injector.get('dashboardLoaderSrv');
dashDTO = await loaderSrv.loadDashboard(urlType, urlSlug, urlUid);
} }
} catch (err) { } catch (err) {
dispatch(setDashboardLoadingState(DashboardLoadingState.Error)); dispatch(setDashboardLoadingState(DashboardLoadingState.Error));
@@ -136,3 +169,30 @@ export function initDashboard({ $injector, $scope, urlUid, urlSlug, urlType }: I
dispatch(setDashboardModel(dashboard)); dispatch(setDashboardModel(dashboard));
}; };
} }
function getNewDashboardModelData(urlFolderId?: string): any {
const data = {
meta: {
canStar: false,
canShare: false,
isNew: true,
folderId: 0,
},
dashboard: {
title: 'New dashboard',
panels: [
{
type: 'add-panel',
gridPos: { x: 0, y: 0, w: 12, h: 9 },
title: 'Panel Title',
},
],
},
};
if (urlFolderId) {
data.meta.folderId = parseInt(urlFolderId, 10);
}
return data;
}

View File

@@ -44,6 +44,7 @@ export function reactContainer(
$injector: $injector, $injector: $injector,
$rootScope: $rootScope, $rootScope: $rootScope,
$scope: scope, $scope: scope,
routeInfo: $route.current.$$route.routeInfo,
}; };
ReactDOM.render(WrapInProvider(store, component, props), elem[0]); ReactDOM.render(WrapInProvider(store, component, props), elem[0]);

View File

@@ -2,6 +2,7 @@ import './dashboard_loaders';
import './ReactContainer'; import './ReactContainer';
import { applyRouteRegistrationHandlers } from './registry'; import { applyRouteRegistrationHandlers } from './registry';
// Pages
import ServerStats from 'app/features/admin/ServerStats'; import ServerStats from 'app/features/admin/ServerStats';
import AlertRuleList from 'app/features/alerting/AlertRuleList'; import AlertRuleList from 'app/features/alerting/AlertRuleList';
import TeamPages from 'app/features/teams/TeamPages'; import TeamPages from 'app/features/teams/TeamPages';
@@ -23,6 +24,9 @@ import SoloPanelPage from '../features/dashboard/containers/SoloPanelPage';
import DashboardPage from '../features/dashboard/containers/DashboardPage'; import DashboardPage from '../features/dashboard/containers/DashboardPage';
import config from 'app/core/config'; import config from 'app/core/config';
// Types
import { DashboardRouteInfo } from 'app/types';
/** @ngInject */ /** @ngInject */
export function setupAngularRoutes($routeProvider, $locationProvider) { export function setupAngularRoutes($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true); $locationProvider.html5Mode(true);
@@ -31,6 +35,7 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
.when('/', { .when('/', {
template: '<react-container />', template: '<react-container />',
pageClass: 'page-dashboard', pageClass: 'page-dashboard',
routeInfo: DashboardRouteInfo.Home,
reloadOnSearch: false, reloadOnSearch: false,
resolve: { resolve: {
component: () => DashboardPage, component: () => DashboardPage,
@@ -39,6 +44,7 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
.when('/d/:uid/:slug', { .when('/d/:uid/:slug', {
template: '<react-container />', template: '<react-container />',
pageClass: 'page-dashboard', pageClass: 'page-dashboard',
routeInfo: DashboardRouteInfo.Normal,
reloadOnSearch: false, reloadOnSearch: false,
resolve: { resolve: {
component: () => DashboardPage, component: () => DashboardPage,
@@ -48,6 +54,7 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
template: '<react-container />', template: '<react-container />',
pageClass: 'page-dashboard', pageClass: 'page-dashboard',
reloadOnSearch: false, reloadOnSearch: false,
routeInfo: DashboardRouteInfo.Normal,
resolve: { resolve: {
component: () => DashboardPage, component: () => DashboardPage,
}, },
@@ -55,6 +62,16 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
.when('/dashboard/:type/:slug', { .when('/dashboard/:type/:slug', {
template: '<react-container />', template: '<react-container />',
pageClass: 'page-dashboard', pageClass: 'page-dashboard',
routeInfo: DashboardRouteInfo.Old,
reloadOnSearch: false,
resolve: {
component: () => DashboardPage,
},
})
.when('/dashboard/new', {
template: '<react-container />',
pageClass: 'page-dashboard',
routeInfo: DashboardRouteInfo.New,
reloadOnSearch: false, reloadOnSearch: false,
resolve: { resolve: {
component: () => DashboardPage, component: () => DashboardPage,
@@ -63,6 +80,7 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
.when('/d-solo/:uid/:slug', { .when('/d-solo/:uid/:slug', {
template: '<react-container />', template: '<react-container />',
pageClass: 'dashboard-solo', pageClass: 'dashboard-solo',
routeInfo: DashboardRouteInfo.Normal,
resolve: { resolve: {
component: () => SoloPanelPage, component: () => SoloPanelPage,
}, },
@@ -70,16 +88,11 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
.when('/dashboard-solo/:type/:slug', { .when('/dashboard-solo/:type/:slug', {
template: '<react-container />', template: '<react-container />',
pageClass: 'dashboard-solo', pageClass: 'dashboard-solo',
routeInfo: DashboardRouteInfo.Old,
resolve: { resolve: {
component: () => SoloPanelPage, component: () => SoloPanelPage,
}, },
}) })
.when('/dashboard/new', {
templateUrl: 'public/app/partials/dashboard.html',
controller: 'NewDashboardCtrl',
reloadOnSearch: false,
pageClass: 'page-dashboard',
})
.when('/dashboard/import', { .when('/dashboard/import', {
templateUrl: 'public/app/features/manage-dashboards/partials/dashboard_import.html', templateUrl: 'public/app/features/manage-dashboards/partials/dashboard_import.html',
controller: DashboardImportCtrl, controller: DashboardImportCtrl,

View File

@@ -7,9 +7,16 @@ export interface MutableDashboard {
}; };
} }
export enum DashboardRouteInfo {
Old = 'old-dashboard',
Home = 'home-dashboard',
New = 'new-dashboard',
Normal = 'normal-dashboard',
}
export enum DashboardLoadingState { export enum DashboardLoadingState {
NotStarted = 'Not started', NotStarted = 'Not started',
Fetching = 'Fetching', Fetching = 'Fetching',
Initializing = 'Initializing', Initializing = 'Initializing',
Error = 'Error', Error = 'Error',
Done = 'Done', Done = 'Done',

View File

@@ -3,6 +3,10 @@ export interface LocationUpdate {
query?: UrlQueryMap; query?: UrlQueryMap;
routeParams?: UrlQueryMap; routeParams?: UrlQueryMap;
partial?: boolean; partial?: boolean;
/*
* If true this will replace url state (ie cause no new browser history)
*/
replace?: boolean;
} }
export interface LocationState { export interface LocationState {
@@ -10,6 +14,7 @@ export interface LocationState {
path: string; path: string;
query: UrlQueryMap; query: UrlQueryMap;
routeParams: UrlQueryMap; routeParams: UrlQueryMap;
replace: boolean;
} }
export type UrlQueryValue = string | number | boolean | string[] | number[] | boolean[]; export type UrlQueryValue = string | number | boolean | string[] | number[] | boolean[];