Browse Source

wip: progress

Torkel Ödegaard 7 years ago
parent
commit
2cb1733c59

+ 64 - 33
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<Props> {
   };
 
   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<Props> {
     );
   }
 
+
   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 (
       <div className="navbar">
@@ -95,53 +113,66 @@ export class DashNav extends PureComponent<Props> {
             </button>
           )}
 
+          {canStar && (
+            <button
+              className="btn navbar-button navbar-button--star"
+              onClick={this.onStarDashboard}
+              title="Mark as favorite"
+            >
+              {isStarred && <i className="fa fa-star" />}
+              {!isStarred && <i className="fa fa-star-o" />}
+            </button>
+          )}
+
           {
-            // 	<button class="btn navbar-button navbar-button--star" ng-show="::ctrl.dashboard.meta.canStar" ng-click="ctrl.starDashboard()" bs-tooltip="'Mark as favorite'" data-placement="bottom">
-              // 		<i class="fa" ng-class="{'fa-star-o': !ctrl.dashboard.meta.isStarred, 'fa-star': ctrl.dashboard.meta.isStarred}"></i>
-              // 	</button>
             //
             //   <button class="btn navbar-button navbar-button--share" ng-show="::ctrl.dashboard.meta.canShare" ng-click="ctrl.shareDashboard(0)" bs-tooltip="'Share dashboard'" data-placement="bottom">
-              // 		<i class="fa fa-share-square-o"></i></a>
+            // 		<i class="fa fa-share-square-o"></i></a>
+            // 	</button>
+            //
+            //   <button class="btn navbar-button navbar-button--save" ng-show="ctrl.dashboard.meta.canSave" ng-click="ctrl.saveDashboard()" bs-tooltip="'Save dashboard <br> CTRL+S'" data-placement="bottom">
+            // 		<i class="fa fa-save"></i>
             // 	</button>
-          //
-          //   <button class="btn navbar-button navbar-button--save" ng-show="ctrl.dashboard.meta.canSave" ng-click="ctrl.saveDashboard()" bs-tooltip="'Save dashboard <br> CTRL+S'" data-placement="bottom">
-              // 		<i class="fa fa-save"></i>
-              // 	</button>
             //
             // 	<a class="btn navbar-button navbar-button--snapshot-origin" ng-if="::ctrl.dashboard.snapshot.originalUrl" href="{{ctrl.dashboard.snapshot.originalUrl}}" bs-tooltip="'Open original dashboard'" data-placement="bottom">
-              // 		<i class="fa fa-link"></i>
-              // 	</a>
+            // 		<i class="fa fa-link"></i>
+            // 	</a>
             //
             // 	<button class="btn navbar-button navbar-button--settings" ng-click="ctrl.toggleSettings()" bs-tooltip="'Dashboard Settings'" data-placement="bottom" ng-show="ctrl.dashboard.meta.showSettings">
-              // 		<i class="fa fa-cog"></i>
-              // 	</button>
+            // 		<i class="fa fa-cog"></i>
+            // 	</button>
             // </div>
-          //
-          // <div class="navbar-buttons navbar-buttons--tv">
+            //
+            // <div class="navbar-buttons navbar-buttons--tv">
             //   <button class="btn navbar-button navbar-button--tv" ng-click="ctrl.toggleViewMode()" bs-tooltip="'Cycle view mode'" data-placement="bottom">
-              //     <i class="fa fa-desktop"></i>
-              //   </button>
-            // </div>
-          //
-          // <gf-time-picker class="gf-timepicker-nav" dashboard="ctrl.dashboard" ng-if="!ctrl.dashboard.timepicker.hidden"></gf-time-picker>
-          //
-          // <div class="navbar-buttons navbar-buttons--close">
-            // 	<button class="btn navbar-button navbar-button--primary" ng-click="ctrl.close()" bs-tooltip="'Back to dashboard'" data-placement="bottom">
-            // 		<i class="fa fa-reply"></i>
-            // 	</button>
+            //     <i class="fa fa-desktop"></i>
+            //   </button>
             // </div>
+            //
+            // <gf-time-picker class="gf-timepicker-nav" dashboard="ctrl.dashboard" ng-if="!ctrl.dashboard.timepicker.hidden"></gf-time-picker>
+            //
           }
+          {(isFullscreen || editview) && (
+            <div className="navbar-buttons navbar-buttons--close">
+              <button
+                className="btn navbar-button navbar-button--primary"
+                onClick={this.onClose}
+                title="Back to dashboard"
+              >
+                <i className="fa fa-reply" />
+              </button>
+            </div>
+          )}
         </div>
       </div>
     );
   }
 }
 
-const mapStateToProps = () => ({
-});
+const mapStateToProps = () => ({});
 
 const mapDispatchToProps = {
-  updateLocation
+  updateLocation,
 };
 
 export default connect(mapStateToProps, mapDispatchToProps)(DashNav);

+ 11 - 5
public/app/features/dashboard/containers/DashboardPage.tsx

@@ -60,8 +60,8 @@ export class DashboardPage extends PureComponent<Props, State> {
 
   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<Props, State> {
         fullscreen: null,
         panelId: null,
       },
-      partial: true
+      partial: true,
     });
   }
 
@@ -163,7 +163,7 @@ export class DashboardPage extends PureComponent<Props, State> {
   }
 
   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<Props, State> {
 
     return (
       <div className={classes}>
-        <DashNav dashboard={dashboard} isEditing={isEditing} isFullscreen={isFullscreen} editview={editview} />
+        <DashNav
+          dashboard={dashboard}
+          isEditing={isEditing}
+          isFullscreen={isFullscreen}
+          editview={editview}
+          $injector={$injector}
+        />
         {!dashboard && this.renderLoadingState()}
         {dashboard && this.renderDashboard()}
       </div>

+ 1 - 2
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<DashboardLoadingSta
 export const setDashboardModel = actionCreatorFactory<MutableDashboard>('SET_DASHBOARD_MODEL').create();
 
 export type Action = ActionOf<DashboardAclDTO[]>;
-
 export type ThunkResult<R> = ThunkAction<R, StoreState, undefined, any>;
 
 export function getDashboardPermissions(id: number): ThunkResult<void> {

+ 45 - 15
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<void> {
-  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<void> {
+  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);

+ 15 - 9
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: '<react-container />',
       pageClass: 'page-dashboard',
+      reloadOnSearch: false,
+      resolve: {
+        component: () => DashboardPage,
+      },
     })
     .when('/d/:uid/:slug', {
       template: '<react-container />',
@@ -43,16 +45,20 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
       },
     })
     .when('/d/:uid', {
-      templateUrl: 'public/app/partials/dashboard.html',
-      controller: 'LoadDashboardCtrl',
-      reloadOnSearch: false,
+      template: '<react-container />',
       pageClass: 'page-dashboard',
+      reloadOnSearch: false,
+      resolve: {
+        component: () => DashboardPage,
+      },
     })
     .when('/dashboard/:type/:slug', {
-      templateUrl: 'public/app/partials/dashboard.html',
-      controller: 'LoadDashboardCtrl',
-      reloadOnSearch: false,
+      template: '<react-container />',
       pageClass: 'page-dashboard',
+      reloadOnSearch: false,
+      resolve: {
+        component: () => DashboardPage,
+      },
     })
     .when('/d-solo/:uid/:slug', {
       template: '<react-container />',

+ 1 - 1
public/app/types/dashboard.ts

@@ -4,7 +4,7 @@ export interface MutableDashboard {
   meta: {
     fullscreen: boolean;
     isEditing: boolean;
-  }
+  };
 }
 
 export enum DashboardLoadingState {