Browse Source

dashfolder: refactor breadcrumbs in PageHeader

Combines title and breadcrumbs in PageHeader instead of having to
set title to empty and add it as a breadcrumb.
Daniel Lee 8 years ago
parent
commit
21b5ded75b

+ 2 - 2
public/app/containers/ManageDashboards/FolderSettings.tsx

@@ -49,7 +49,7 @@ export class FolderSettings extends React.Component<IContainerProps, any> {
     const { nav, folder, view } = this.props;
 
     folder
-      .saveDashboard(this.dashboard, { overwrite: false })
+      .saveFolder(this.dashboard, { overwrite: false })
       .then(newUrl => {
         view.updatePathAndQuery(newUrl, '', '');
 
@@ -96,7 +96,7 @@ export class FolderSettings extends React.Component<IContainerProps, any> {
         yesText: 'Save & Overwrite',
         icon: 'fa-warning',
         onConfirm: () => {
-          this.props.folder.saveDashboard(this.dashboard, { overwrite: true });
+          this.props.folder.saveFolder(this.dashboard, { overwrite: true });
         },
       });
     }

+ 53 - 0
public/app/core/components/PageHeader/PageHeader.jest.tsx

@@ -0,0 +1,53 @@
+import React from 'react';
+import PageHeader from './PageHeader';
+import { shallow } from 'enzyme';
+
+describe('PageHeader', () => {
+  let wrapper;
+
+  describe('when the nav tree has a node with a title', () => {
+    beforeAll(() => {
+      const nav = {
+        main: {
+          icon: 'fa fa-folder-open',
+          id: 'node',
+          subTitle: 'node subtitle',
+          url: '',
+          text: 'node',
+        },
+        node: {},
+      };
+      wrapper = shallow(<PageHeader model={nav as any} />);
+    });
+
+    it('should render the title', () => {
+      const title = wrapper.find('.page-header__title');
+      expect(title.text()).toBe('node');
+    });
+  });
+
+  describe('when the nav tree has a node with breadcrumbs and a title', () => {
+    beforeAll(() => {
+      const nav = {
+        main: {
+          icon: 'fa fa-folder-open',
+          id: 'child',
+          subTitle: 'child subtitle',
+          url: '',
+          text: 'child',
+          breadcrumbs: [{ title: 'Parent', url: 'parentUrl' }],
+        },
+        node: {},
+      };
+      wrapper = shallow(<PageHeader model={nav as any} />);
+    });
+
+    it('should render the title with breadcrumbs first and then title last', () => {
+      const title = wrapper.find('.page-header__title');
+      expect(title.text()).toBe('Parent / child');
+
+      const parentLink = wrapper.find('.page-header__title > a.text-link');
+      expect(parentLink.prop('href')).toBe('parentUrl');
+    });
+  });
+});

+ 13 - 7
public/app/core/components/PageHeader/PageHeader.tsx

@@ -85,7 +85,15 @@ export default class PageHeader extends React.Component<IProps, any> {
     super(props);
   }
 
-  renderBreadcrumb(breadcrumbs) {
+  renderTitle(title: string, breadcrumbs: any[]) {
+    if (!title && (!breadcrumbs || breadcrumbs.length === 0)) {
+      return null;
+    }
+
+    if (!breadcrumbs || breadcrumbs.length === 0) {
+      return <h1 className="page-header__title">{title}</h1>;
+    }
+
     const breadcrumbsResult = [];
     for (let i = 0; i < breadcrumbs.length; i++) {
       const bc = breadcrumbs[i];
@@ -99,7 +107,9 @@ export default class PageHeader extends React.Component<IProps, any> {
         breadcrumbsResult.push(<span key={i}> / {bc.title}</span>);
       }
     }
-    return breadcrumbsResult;
+    breadcrumbsResult.push(<span key={breadcrumbs.length + 1}> / {title}</span>);
+
+    return <h1 className="page-header__title">{breadcrumbsResult}</h1>;
   }
 
   renderHeaderTitle(main) {
@@ -111,11 +121,7 @@ export default class PageHeader extends React.Component<IProps, any> {
         </span>
 
         <div className="page-header__info-block">
-          {main.text && <h1 className="page-header__title">{main.text}</h1>}
-          {main.breadcrumbs &&
-            main.breadcrumbs.length > 0 && (
-              <h1 className="page-header__title">{this.renderBreadcrumb(main.breadcrumbs)}</h1>
-            )}
+          {this.renderTitle(main.text, main.breadcrumbs)}
           {main.subTitle && <div className="page-header__sub-title">{main.subTitle}</div>}
           {main.subType && (
             <div className="page-header__stamps">

+ 2 - 1
public/app/core/controllers/invited_ctrl.ts

@@ -10,8 +10,9 @@ export class InvitedCtrl {
     $scope.navModel = {
       main: {
         icon: 'gicon gicon-branding',
+        text: 'Invite',
         subTitle: 'Register your Grafana account',
-        breadcrumbs: [{ title: 'Login', url: '/login' }, { title: 'Invite' }],
+        breadcrumbs: [{ title: 'Login', url: '/login' }],
       },
     };
 

+ 2 - 1
public/app/core/controllers/reset_password_ctrl.ts

@@ -16,8 +16,9 @@ export class ResetPasswordCtrl {
     $scope.navModel = {
       main: {
         icon: 'gicon gicon-branding',
+        text: 'Reset Password',
         subTitle: 'Reset your Grafana password',
-        breadcrumbs: [{ title: 'Login', url: 'login' }, { title: 'Reset Password' }],
+        breadcrumbs: [{ title: 'Login', url: 'login' }],
       },
     };
 

+ 2 - 3
public/app/features/dashboard/folder_page_loader.ts

@@ -11,7 +11,7 @@ export class FolderPageLoader {
         subTitle: 'Manage folder dashboards & permissions',
         url: '',
         text: '',
-        breadcrumbs: [{ title: 'Dashboards', url: 'dashboards' }, { title: ' ' }],
+        breadcrumbs: [{ title: 'Dashboards', url: 'dashboards' }],
         children: [
           {
             active: activeChildId === 'manage-folder-dashboards',
@@ -40,8 +40,7 @@ export class FolderPageLoader {
 
     return this.backendSrv.getDashboard('db', this.$routeParams.slug).then(result => {
       const folderTitle = result.dashboard.title;
-      ctrl.navModel.main.text = '';
-      ctrl.navModel.main.breadcrumbs = [{ title: 'Dashboards', url: 'dashboards' }, { title: folderTitle }];
+      ctrl.navModel.main.text = folderTitle;
 
       const folderUrl = this.createFolderUrl(folderId, result.meta.slug);
 

+ 2 - 2
public/app/features/plugins/plugin_edit_ctrl.ts

@@ -32,8 +32,8 @@ export class PluginEditCtrl {
         img: model.info.logos.large,
         subTitle: model.info.author.name,
         url: '',
-        text: '',
-        breadcrumbs: [{ title: 'Plugins', url: 'plugins' }, { title: model.name }],
+        text: model.name,
+        breadcrumbs: [{ title: 'Plugins', url: 'plugins' }],
         children: [
           {
             icon: 'fa fa-fw fa-file-text-o',

+ 2 - 2
public/app/features/plugins/plugin_page_ctrl.ts

@@ -40,8 +40,8 @@ export class AppPageCtrl {
         img: app.info.logos.large,
         subTitle: app.name,
         url: '',
-        text: '',
-        breadcrumbs: [{ title: app.name, url: pluginNav.main.url }, { title: this.page.name }],
+        text: this.page.name,
+        breadcrumbs: [{ title: app.name, url: pluginNav.main.url }],
       },
     };
   }

+ 4 - 1
public/app/stores/FolderStore/FolderStore.ts

@@ -25,11 +25,13 @@ export const FolderStore = types
       });
       return res;
     }),
+
     setTitle: function(originalTitle: string, title: string) {
       self.folder.title = title;
       self.folder.hasChanged = originalTitle.toLowerCase() !== title.trim().toLowerCase() && title.trim().length > 0;
     },
-    saveDashboard: flow(function* saveDashboard(dashboard: any, options: any) {
+
+    saveFolder: flow(function* saveFolder(dashboard: any, options: any) {
       const backendSrv = getEnv(self).backendSrv;
       dashboard.title = self.folder.title.trim();
 
@@ -37,6 +39,7 @@ export const FolderStore = types
       self.folder.slug = res.slug;
       return `dashboards/folder/${self.folder.id}/${res.slug}/settings`;
     }),
+
     deleteFolder: flow(function* deleteFolder() {
       const backendSrv = getEnv(self).backendSrv;