diff --git a/public/app/features/dashboard/components/DashNav/DashNav.tsx b/public/app/features/dashboard/components/DashNav/DashNav.tsx index f9df483bf5f..79d4da94aca 100644 --- a/public/app/features/dashboard/components/DashNav/DashNav.tsx +++ b/public/app/features/dashboard/components/DashNav/DashNav.tsx @@ -16,6 +16,7 @@ export interface Props { editview: string; isEditing: boolean; isFullscreen: boolean; + $injector: any; updateLocation: typeof updateLocation; } @@ -25,13 +26,29 @@ export class DashNav extends PureComponent { }; onAddPanel = () => {}; + + onClose = () => { + this.props.updateLocation({ + query: { editview: null, panelId: null, edit: null, fullscreen: null }, + partial: true, + }); + }; + onOpenSettings = () => { this.props.updateLocation({ - query: { - editview: 'settings', - }, + query: { editview: 'settings' }, partial: true, - }) + }); + }; + + onStarDashboard = () => { + const { $injector, dashboard } = this.props; + const dashboardSrv = $injector.get('dashboardSrv'); + + dashboardSrv.starDashboard(dashboard.id, dashboard.meta.isStarred).then(newState => { + dashboard.meta.isStarred = newState; + this.forceUpdate(); + }); }; renderLoadingState() { @@ -48,15 +65,16 @@ export class DashNav extends PureComponent { ); } + render() { - let { dashboard } = this.props; + const { dashboard, isFullscreen, editview } = this.props; if (!dashboard) { return this.renderLoadingState(); } const haveFolder = dashboard.meta.folderId > 0; - const { canEdit, canSave, folderTitle, showSettings } = dashboard.meta; + const { canEdit, canStar, canSave, folderTitle, showSettings, isStarred } = dashboard.meta; return (
@@ -95,53 +113,66 @@ export class DashNav extends PureComponent { )} + {canStar && ( + + )} + { - // // // + // + // - // - // // // - // - // + // + // // // - //
- // - // - // - // - // - // + // + // + // + // + // } + {(isFullscreen || editview) && ( +
+ +
+ )} ); } } -const mapStateToProps = () => ({ -}); +const mapStateToProps = () => ({}); const mapDispatchToProps = { - updateLocation + updateLocation, }; export default connect(mapStateToProps, mapDispatchToProps)(DashNav); diff --git a/public/app/features/dashboard/containers/DashboardPage.tsx b/public/app/features/dashboard/containers/DashboardPage.tsx index 281916acb14..9f0f1cdff5f 100644 --- a/public/app/features/dashboard/containers/DashboardPage.tsx +++ b/public/app/features/dashboard/containers/DashboardPage.tsx @@ -60,8 +60,8 @@ export class DashboardPage extends PureComponent { async componentDidMount() { this.props.initDashboard({ - injector: this.props.$injector, - scope: this.props.$scope, + $injector: this.props.$injector, + $scope: this.props.$scope, urlSlug: this.props.urlSlug, urlUid: this.props.urlUid, urlType: this.props.urlType, @@ -123,7 +123,7 @@ export class DashboardPage extends PureComponent { fullscreen: null, panelId: null, }, - partial: true + partial: true, }); } @@ -163,7 +163,7 @@ export class DashboardPage extends PureComponent { } render() { - const { dashboard, editview } = this.props; + const { dashboard, editview, $injector } = this.props; const { isSettingsOpening, isEditing, isFullscreen } = this.state; const classes = classNames({ @@ -173,7 +173,13 @@ export class DashboardPage extends PureComponent { return (
- + {!dashboard && this.renderLoadingState()} {dashboard && this.renderDashboard()}
diff --git a/public/app/features/dashboard/state/actions.ts b/public/app/features/dashboard/state/actions.ts index 14721cdbe96..bc57b8e5f10 100644 --- a/public/app/features/dashboard/state/actions.ts +++ b/public/app/features/dashboard/state/actions.ts @@ -1,5 +1,4 @@ // Libaries -import { StoreState } from 'app/types'; import { ThunkAction } from 'redux-thunk'; // Services & Utils @@ -13,6 +12,7 @@ import { loadPluginDashboards } from '../../plugins/state/actions'; import { notifyApp } from 'app/core/actions'; // Types +import { StoreState } from 'app/types'; import { DashboardAcl, DashboardAclDTO, @@ -27,7 +27,6 @@ export const setDashboardLoadingState = actionCreatorFactory('SET_DASHBOARD_MODEL').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 10d7164fbff..f7e23238b7c 100644 --- a/public/app/features/dashboard/state/initDashboard.ts +++ b/public/app/features/dashboard/state/initDashboard.ts @@ -1,5 +1,6 @@ // Services & Utils import { createErrorNotification } from 'app/core/copy/appNotification'; +import { getBackendSrv } from 'app/core/services/backend_srv'; // Actions import { updateLocation } from 'app/core/actions'; @@ -12,24 +13,53 @@ import { DashboardLoadingState } from 'app/types/dashboard'; import { DashboardModel } from './DashboardModel'; export interface InitDashboardArgs { - injector: any; - scope: any; + $injector: any; + $scope: any; urlUid?: string; urlSlug?: string; urlType?: string; } -export function initDashboard({ injector, scope, urlUid, urlSlug, urlType }: InitDashboardArgs): ThunkResult { - return async dispatch => { - const loaderSrv = injector.get('dashboardLoaderSrv'); +async function redirectToNewUrl(slug: string, dispatch: any) { + const res = await getBackendSrv().getDashboardBySlug(slug); - dispatch(setDashboardLoadingState(DashboardLoadingState.Fetching)); + if (res) { + const url = locationUtil.stripBaseFromUrl(res.meta.url.replace('/d/', '/d-solo/')); + dispatch(updateLocation(url)); + } +} + +export function initDashboard({ $injector, $scope, urlUid, urlSlug, urlType }: InitDashboardArgs): ThunkResult { + return async dispatch => { + // handle old urls with no uid + if (!urlUid && urlSlug) { + redirectToNewUrl(urlSlug, dispatch); + return; + } let dashDTO = null; + // set fetching state + dispatch(setDashboardLoadingState(DashboardLoadingState.Fetching)); + try { - // fetch dashboard from api - dashDTO = await loaderSrv.loadDashboard(urlType, urlSlug, urlUid); + // if no uid or slug, load home dashboard + if (!urlUid && !urlSlug) { + dashDTO = await getBackendSrv().get('/api/dashboards/home'); + + if (dashDTO.redirectUri) { + const newUrl = locationUtil.stripBaseFromUrl(dashDTO.redirectUri); + dispatch(updateLocation({ path: newUrl })); + return; + } else { + dashDTO.meta.canSave = false; + dashDTO.meta.canShare = false; + dashDTO.meta.canStar = false; + } + } else { + const loaderSrv = $injector.get('dashboardLoaderSrv'); + dashDTO = await loaderSrv.loadDashboard(urlType, urlSlug, urlUid); + } } catch (err) { dispatch(setDashboardLoadingState(DashboardLoadingState.Error)); console.log(err); @@ -50,13 +80,13 @@ export function initDashboard({ injector, scope, urlUid, urlSlug, urlType }: Ini } // init services - injector.get('timeSrv').init(dashboard); - injector.get('annotationsSrv').init(dashboard); + $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 try { - await injector.get('variableSrv').init(dashboard); + await $injector.get('variableSrv').init(dashboard); } catch (err) { dispatch(notifyApp(createErrorNotification('Templating init failed', err.toString()))); console.log(err); @@ -68,11 +98,11 @@ export function initDashboard({ injector, scope, urlUid, urlSlug, urlType }: Ini dashboard.autoFitPanels(window.innerHeight); // init unsaved changes tracking - injector.get('unsavedChangesSrv').init(dashboard, scope); + $injector.get('unsavedChangesSrv').init(dashboard, $scope); - scope.dashboard = dashboard; - injector.get('dashboardViewStateSrv').create(scope); - injector.get('keybindingSrv').setupDashboardBindings(scope, dashboard); + $scope.dashboard = dashboard; + $injector.get('dashboardViewStateSrv').create($scope); + $injector.get('keybindingSrv').setupDashboardBindings($scope, dashboard); } catch (err) { dispatch(notifyApp(createErrorNotification('Dashboard init failed', err.toString()))); console.log(err); diff --git a/public/app/routes/routes.ts b/public/app/routes/routes.ts index cdd9ed89a08..abe347d689a 100644 --- a/public/app/routes/routes.ts +++ b/public/app/routes/routes.ts @@ -29,10 +29,12 @@ export function setupAngularRoutes($routeProvider, $locationProvider) { $routeProvider .when('/', { - templateUrl: 'public/app/partials/dashboard.html', - controller: 'LoadDashboardCtrl', - reloadOnSearch: false, + template: '', pageClass: 'page-dashboard', + reloadOnSearch: false, + resolve: { + component: () => DashboardPage, + }, }) .when('/d/:uid/:slug', { template: '', @@ -43,16 +45,20 @@ export function setupAngularRoutes($routeProvider, $locationProvider) { }, }) .when('/d/:uid', { - templateUrl: 'public/app/partials/dashboard.html', - controller: 'LoadDashboardCtrl', - reloadOnSearch: false, + template: '', pageClass: 'page-dashboard', + reloadOnSearch: false, + resolve: { + component: () => DashboardPage, + }, }) .when('/dashboard/:type/:slug', { - templateUrl: 'public/app/partials/dashboard.html', - controller: 'LoadDashboardCtrl', - reloadOnSearch: false, + template: '', pageClass: 'page-dashboard', + reloadOnSearch: false, + resolve: { + component: () => DashboardPage, + }, }) .when('/d-solo/:uid/:slug', { template: '', diff --git a/public/app/types/dashboard.ts b/public/app/types/dashboard.ts index 713cd28efb1..9b1e750e859 100644 --- a/public/app/types/dashboard.ts +++ b/public/app/types/dashboard.ts @@ -4,7 +4,7 @@ export interface MutableDashboard { meta: { fullscreen: boolean; isEditing: boolean; - } + }; } export enum DashboardLoadingState {