Explorar o código

ux: navigation work

Torkel Ödegaard %!s(int64=8) %!d(string=hai) anos
pai
achega
1eab771231

+ 9 - 7
pkg/api/dtos/index.go

@@ -7,7 +7,7 @@ type IndexViewData struct {
 	AppSubUrl               string
 	GoogleAnalyticsId       string
 	GoogleTagManagerId      string
-	MainNavLinks            []*NavLink
+	NavTree                 []*NavLink
 	BuildVersion            string
 	BuildCommit             string
 	NewGrafanaVersionExists bool
@@ -20,10 +20,12 @@ type PluginCss struct {
 }
 
 type NavLink struct {
-	Text     string     `json:"text,omitempty"`
-	Icon     string     `json:"icon,omitempty"`
-	Img      string     `json:"img,omitempty"`
-	Url      string     `json:"url,omitempty"`
-	Divider  bool       `json:"divider,omitempty"`
-	Children []*NavLink `json:"children,omitempty"`
+	Id          string     `json:"id,omitempty"`
+	Text        string     `json:"text,omitempty"`
+	Description string     `json:"description,omitempty"`
+	Icon        string     `json:"icon,omitempty"`
+	Img         string     `json:"img,omitempty"`
+	Url         string     `json:"url,omitempty"`
+	Divider     bool       `json:"divider,omitempty"`
+	Children    []*NavLink `json:"children,omitempty"`
 }

+ 36 - 11
pkg/api/index.go

@@ -85,7 +85,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 	}
 
 	if c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR {
-		data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
+		data.NavTree = append(data.NavTree, &dtos.NavLink{
 			Text: "New",
 			Icon: "fa fa-fw fa-plus",
 			Url:  "",
@@ -103,7 +103,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 		{Text: "Snapshots", Url: setting.AppSubUrl + "/dashboard/snapshots", Icon: "icon-gf icon-gf-snapshot"},
 	}
 
-	data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
+	data.NavTree = append(data.NavTree, &dtos.NavLink{
 		Text:     "Dashboards",
 		Icon:     "icon-gf icon-gf-dashboard",
 		Url:      setting.AppSubUrl + "/",
@@ -116,7 +116,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 			{Text: "Notification channels", Url: setting.AppSubUrl + "/alerting/notifications", Icon: "fa fa-fw fa-bell-o"},
 		}
 
-		data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
+		data.NavTree = append(data.NavTree, &dtos.NavLink{
 			Text:     "Alerting",
 			Icon:     "icon-gf icon-gf-alert",
 			Url:      setting.AppSubUrl + "/alerting/list",
@@ -165,36 +165,61 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 			}
 
 			if len(appLink.Children) > 0 {
-				data.MainNavLinks = append(data.MainNavLinks, appLink)
+				data.NavTree = append(data.NavTree, appLink)
 			}
 		}
 	}
 
 	if c.OrgRole == m.ROLE_ADMIN {
 		cfgNode := &dtos.NavLink{
+			Id:   "cfg",
 			Text: "Configuration",
 			Icon: "fa fa-fw fa-cogs",
 			Url:  setting.AppSubUrl + "/configuration",
 			Children: []*dtos.NavLink{
 				{
-					Text: "Data Sources",
-					Icon: "icon-gf icon-gf-datasources",
-					Url:  setting.AppSubUrl + "/datasources",
+					Text:        "Data Sources",
+					Icon:        "icon-gf icon-gf-datasources",
+					Description: "Add and configure data sources",
+					Id:          "datasources",
+					Url:         setting.AppSubUrl + "/datasources",
 					Children: []*dtos.NavLink{
 						{Text: "List", Url: setting.AppSubUrl + "/datasources", Icon: "icon-gf icon-gf-datasources"},
 						{Text: "New", Url: setting.AppSubUrl + "/datasources", Icon: "fa fa-fw fa-plus"},
 					},
 				},
 				{
-					Text: "Plugins",
-					Icon: "icon-gf icon-gf-apps",
-					Url:  setting.AppSubUrl + "/plugins",
+					Text:        "Preferences",
+					Id:          "org",
+					Description: "Organization preferences",
+					Icon:        "fa fa-fw fa-sliders",
+					Url:         setting.AppSubUrl + "/org",
+				},
+				{
+					Text:        "Plugins",
+					Id:          "plugins",
+					Description: "View and configure plugins",
+					Icon:        "icon-gf icon-gf-apps",
+					Url:         setting.AppSubUrl + "/plugins",
 					Children: []*dtos.NavLink{
 						{Text: "Panels", Url: setting.AppSubUrl + "/plugins?type=panel", Icon: "fa fa-fw fa-stop"},
 						{Text: "Data sources", Url: setting.AppSubUrl + "/plugins?type=datasource", Icon: "icon-gf icon-gf-datasources"},
 						{Text: "Apps", Url: setting.AppSubUrl + "/plugins?type=app", Icon: "icon-gf icon-gf-apps"},
 					},
 				},
+				{
+					Text:        "User Management",
+					Id:          "users",
+					Description: "Manage users & user groups",
+					Icon:        "fa fa-fw fa-users",
+					Url:         setting.AppSubUrl + "/org/users",
+				},
+				{
+					Text:        "API Keys",
+					Description: "Create & manage API keys",
+					Icon:        "fa fa-fw fa-key",
+					Url:         setting.AppSubUrl + "/org/apikeys",
+				},
 			},
 		}
 
@@ -212,7 +237,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 			})
 		}
 
-		data.MainNavLinks = append(data.MainNavLinks, cfgNode)
+		data.NavTree = append(data.NavTree, cfgNode)
 	}
 
 	return &data, nil

+ 9 - 9
public/app/core/components/navbar/navbar.html

@@ -1,20 +1,20 @@
 <div class="page-nav">
   <div class="container">
     <div class="page-breadcrumb">
-      <div class="page-breadcrumb__item dropdown" ng-repeat="item in ctrl.model.items">
-        <a class="pointer" ng-href="{{::item.url}}" data-toggle="dropdown" ng-if="::item.items">
-          {{::item.title}}
-          <i class="page-breadcrumb__caret fa fa-caret-down"></i>
-        </a>
+      <div class="page-breadcrumb__item dropdown" ng-repeat="item in ctrl.model.breadcrumbs">
+        <!-- <a class="pointer" ng&#45;href="{{::item.url}}" data&#45;toggle="dropdown" ng&#45;if="::item.children"> -->
+        <!--   {{::item.text}} -->
+        <!--   <i class="page&#45;breadcrumb__caret fa fa&#45;caret&#45;down"></i> -->
+        <!-- </a> -->
 
-        <a class="pointer" ng-href="{{::item.url}}" ng-if="::!item.items">
-          {{::item.title}}
+        <a class="pointer" ng-href="{{::item.url}}">
+          {{::item.text}}
         </a>
 
         <ul class="dropdown-menu dropdown-menu--navbar">
-          <li ng-repeat="subItem in ::item.items">
+          <li ng-repeat="subItem in ::item.children">
             <a class="pointer" ng-href="{{::subItem.url}}" ng-click="ctrl.navItemClicked(subItem, $event)">
-              {{::subItem.title}}
+              {{::subItem.text}}
             </a>
           </li>
         </ul>

+ 1 - 0
public/app/core/components/navbar/navbar.ts

@@ -11,6 +11,7 @@ export class NavbarCtrl {
 
   /** @ngInject */
   constructor(private $scope, private $rootScope, private contextSrv) {
+    console.log(this.model);
   }
 
   showSearch() {

+ 0 - 1
public/app/core/components/sidemenu/sidemenu.html

@@ -1,4 +1,3 @@
-
 <div class="sidemenu__top">
 
 	<a class="navbar-brand-btn pointer" ng-click="ctrl.contextSrv.toggleSideMenu()">

+ 1 - 1
public/app/core/components/sidemenu/sidemenu.ts

@@ -26,7 +26,7 @@ export class SideMenuCtrl {
     this.showSignout = this.contextSrv.isSignedIn && !config['disableSignoutMenu'];
     this.maxShownOrgs = 10;
 
-    this.mainLinks = config.bootData.mainNavLinks;
+    this.mainLinks = config.bootData.navTree;
     this.openUserDropdown();
     this.loginUrl = 'login?redirect=' + encodeURIComponent(this.$location.path());
 

+ 37 - 31
public/app/core/nav_model_srv.ts

@@ -1,6 +1,8 @@
 ///<reference path="../headers/common.d.ts" />
 
 import coreModule from 'app/core/core_module';
+import config from 'app/core/config';
+import _ from 'lodash';
 
 export interface NavModelItem {
   title: string;
@@ -15,10 +17,24 @@ export interface NavModel {
 }
 
 export class NavModelSrv {
+  navItems: any;
 
 
   /** @ngInject */
   constructor(private contextSrv) {
+    this.navItems = config.bootData.navTree;
+  }
+
+  getCfgNode() {
+    return _.find(this.navItems, {id: 'cfg'});
+  }
+
+  getConfigurationNav() {
+    let cfg = this.getCfgNode();
+    return {
+      breadcrumbs: [cfg],
+      node: cfg,
+    };
   }
 
   getAlertingNav(subPage) {
@@ -36,21 +52,11 @@ export class NavModelSrv {
   }
 
   getDatasourceNav(subPage) {
+    let cfg = this.getCfgNode();
+    let ds = _.find(cfg.children, {id: 'datasources'});
     return {
-      items: [
-        {
-          title: 'Configuration',
-          items: [
-            {title: 'Data sources', active: subPage === 0, url: 'datasources',  icon: 'fa fa-database'},
-            {title: 'Users',        active: subPage === 0, url: 'users',        icon: 'fa fa-fw fa-users'},
-            {title: 'Plugins',      active: subPage === 0, url: 'plugins',      icon: 'icon-gf icon-gf-apps'},
-          ]
-        },
-        {
-          title: 'Data sources',
-          url: 'datasources',
-        }
-      ]
+      breadcrumbs: [cfg, ds],
+      node: ds
     };
   }
 
@@ -91,18 +97,11 @@ export class NavModelSrv {
   }
 
   getOrgNav(subPage) {
+    let cfg = this.getCfgNode();
+    let org = _.find(cfg.children, {id: 'org'});
     return {
-      section: {
-        title: 'Organization',
-        url: 'org',
-        icon: 'icon-gf icon-gf-users'
-      },
-      menu: [
-        {title: 'Preferences', active: subPage === 0, url: 'org', icon: 'fa fa-fw fa-cog'},
-        {title: 'Org Users', active: subPage === 1, url: 'org/users', icon: 'fa fa-fw fa-users'},
-        {title: 'API Keys', active: subPage === 2, url: 'org/apikeys', icon: 'fa fa-fw fa-key'},
-        {title: 'Org User Groups', active: subPage === 3, url: 'org/user-groups', icon: 'fa fa-fw fa-users'},
-      ]
+      breadcrumbs: [this.getCfgNode(), org],
+      node: org
     };
   }
 
@@ -124,13 +123,20 @@ export class NavModelSrv {
   }
 
   getPluginsNav() {
+    let cfg = this.getCfgNode();
+    let plugins = _.find(cfg.children, {id: 'plugins'});
     return {
-      section: {
-        title: 'Plugins',
-        url: 'plugins',
-        icon: 'icon-gf icon-gf-apps'
-      },
-      menu: []
+      breadcrumbs: [this.getCfgNode(), plugins],
+      node: plugins
+    };
+  }
+
+  getUserManNav() {
+    let cfg = this.getCfgNode();
+    let users = _.find(cfg.children, {id: 'users'});
+    return {
+      breadcrumbs: [cfg, users],
+      node: users,
     };
   }
 

+ 1 - 1
public/app/features/admin/admin.ts

@@ -47,7 +47,7 @@ export class ConfigurationHomeCtrl {
 
   /** @ngInject */
   constructor(private $scope, private backendSrv, private navModelSrv) {
-    this.navModel = navModelSrv.getAdminNav();
+    this.navModel = navModelSrv.getConfigurationNav();
   }
 }
 

+ 7 - 16
public/app/features/admin/partials/configuration_home.html

@@ -4,35 +4,30 @@
 	<div class="page-container">
 		<div class="page-header">
 			<h1>
-				<i class="fa fa-cogs"></i>
+				<i class="fa fa-fw fa-cogs"></i>
 				<span>Configuration</span>
 			</h1>
 		</div>
 
-		<section class="card-section" layout-mode>
-			<layout-selector></layout-selector>
+		<section class="card-section card-list-layout-grid">
 
 			<ol class="card-list" >
-				<li class="card-item-wrapper" ng-repeat="ds in ctrl.datasources">
-					<a class="card-item" href="datasources/edit/{{ds.id}}/">
+				<li class="card-item-wrapper" ng-repeat="navItem in ctrl.navModel.node.children">
+					<a class="card-item" ng-href="{{::navItem.url}}">
 						<div class="card-item-header">
 							<div class="card-item-type">
-								{{ds.type}}
 							</div>
 						</div>
 						<div class="card-item-body">
 							<figure class="card-item-figure">
-								<img ng-src="{{ds.typeLogoUrl}}">
+								<i class="{{navItem.icon}}"></i>
 							</figure>
 							<div class="card-item-details">
 								<div class="card-item-name">
-									{{ds.name}}
-									<span ng-if="ds.isDefault">
-										<span class="btn btn-secondary btn-mini">default</span>
-									</span>
+									{{navItem.text}}
 								</div>
 								<div class="card-item-sub-name">
-									{{ds.url}}
+									{{navItem.description}}
 								</div>
 							</div>
 						</div>
@@ -40,9 +35,5 @@
 				</li>
 			</ol>
 		</section>
-
-		<div ng-if="ctrl.datasources.length === 0">
-			<em>No data sources defined</em>
-		</div>
 	</div>
 </div>

+ 2 - 1
public/app/features/org/org_users_ctrl.ts

@@ -23,7 +23,8 @@ export class OrgUsersCtrl {
       loginOrEmail: '',
       role: 'Viewer',
     };
-    this.navModel = navModelSrv.getOrgNav(0);
+
+    this.navModel = navModelSrv.getUserManNav(0);
 
     this.get();
     this.editor = { index: 0 };

+ 5 - 12
public/app/features/org/partials/orgDetails.html

@@ -2,14 +2,17 @@
 
 <div class="page-container">
 	<div class="page-header">
-		<h1>Org Preferences</h1>
+		<h1>
+			<i class="{{navModel.node.icon}}"></i>
+			{{navModel.node.text}}
+		</h1>
 	</div>
 
 	<h3 class="page-heading">General</h3>
 	<form name="orgForm" class="gf-form-group">
 		<div class="gf-form-inline">
 			<div class="gf-form max-width-28">
-				<span class="gf-form-label width-6">Name</span>
+				<span class="gf-form-label">Organization name</span>
 				<input class="gf-form-input" type="text" required ng-model="org.name">
 			</div>
 			<div class="gf-form">
@@ -61,16 +64,6 @@
 		</div>
 	</form>
 
-	<h3 class="page-heading">Admin Pages</h3>
-	<div class="gf-form-group">
-		<div class="gf-form-inline">
-			<div class="gf-form">
-				<a href="org/users" class="btn gf-form-btn btn-inverse">Users &amp; Roles</a>
-			</div>
-			<div class="gf-form">
-			<a href="org/apikeys" class="btn gf-form-btn btn-inverse">API Keys</a>
-		</div>
-	</div>
 </div>
 
 

+ 14 - 4
public/app/features/org/partials/orgUsers.html

@@ -2,7 +2,10 @@
 
 <div class="page-container">
 	<div class="page-header">
-		<h1>Organization users</h1>
+		<h1>
+			<i class="{{ctrl.navModel.node.icon}}"></i>
+			{{ctrl.navModel.node.text}}
+		</h1>
 
 		<div class="page-header-tabs">
 
@@ -22,8 +25,13 @@
 						Users ({{ctrl.users.length}})
 					</a>
 				</li>
+				<li class="gf-tabs-item">
+					<a class="gf-tabs-link" ng-click="ctrl.editor.index = 0" ng-class="{active: ctrl.editor.index === 1}">
+						Groups (0)
+					</a>
+				</li>
 				<li class="gf-tabs-item" ng-show="ctrl.showInviteUI">
-					<a class="gf-tabs-link" ng-click="ctrl.editor.index = 1" ng-class="{active: ctrl.editor.index === 1}">
+					<a class="gf-tabs-link" ng-click="ctrl.editor.index = 1" ng-class="{active: ctrl.editor.index === 2}">
 						Pending Invitations ({{ctrl.pendingInvites.length}})
 					</a>
 				</li>
@@ -54,8 +62,10 @@
         <td><span class="ellipsis">{{user.email}}</span></td>
 				<td>{{user.lastSeenAtAge}}</td>
         <td>
-          <select type="text" ng-model="user.role" class="input-medium" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']" ng-change="ctrl.updateOrgUser(user)">
-          </select>
+					<div class="gf-form-select-wrapper width-9">
+						<select type="text" ng-model="user.role" class="gf-form-input" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']" ng-change="ctrl.updateOrgUser(user)">
+						</select>
+					</div>
         </td>
         <td>
           <a ng-click="ctrl.removeUser(user)" class="btn btn-danger btn-mini">

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

@@ -59,7 +59,7 @@ export class DataSourceEditCtrl {
   initNewDatasourceModel() {
     this.isNew = true;
     this.current = angular.copy(defaults);
-    this.navModel.items.push({title: 'New data source'});
+    this.navModel.breadcrumbs.push({text: 'New data source'});
 
     // We are coming from getting started
     if (this.$location.search().gettingstarted) {
@@ -86,7 +86,7 @@ export class DataSourceEditCtrl {
     this.backendSrv.get('/api/datasources/' + id).then(ds => {
       this.isNew = false;
       this.current = ds;
-      this.navModel.items.push({title: ds.name});
+      this.navModel.breadcrumbs.push({text: ds.name});
 
       if (datasourceCreated) {
         datasourceCreated = false;

+ 1 - 2
public/app/features/plugins/partials/ds_list.html

@@ -4,7 +4,7 @@
 	<div class="page-container">
 		<div class="page-header">
 			<h1>
-				<i class="icon-gf icon-gf-datasources"></i>
+				<i class="icon-gf icon-gf-fw icon-gf-datasources"></i>
 				<span>Data Sources</span>
 			</h1>
 
@@ -15,7 +15,6 @@
 		</div>
 
 		<section class="card-section" layout-mode>
-			<layout-selector></layout-selector>
 
 			<ol class="card-list" >
 				<li class="card-item-wrapper" ng-repeat="ds in ctrl.datasources">

+ 1 - 0
public/app/features/plugins/plugin_edit_ctrl.ts

@@ -42,6 +42,7 @@ export class PluginEditCtrl {
     return this.backendSrv.get(`/api/plugins/${this.pluginId}/settings`).then(result => {
       this.model = result;
       this.pluginIcon = this.getPluginIcon(this.model.type);
+      this.navModel.breadcrumbs.push({text: this.model.name});
 
       this.model.dependencies.plugins.forEach(plug => {
         plug.icon = this.getPluginIcon(plug.type);

+ 8 - 2
public/sass/base/_grafana_icons.scss

@@ -18,14 +18,20 @@
     font-variant: normal;
     text-transform: none;
     line-height: 1;
+    display: inline-block;
 
     /* Better Font Rendering =========== */
     -webkit-font-smoothing: antialiased;
     -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-gf-fw {
+  width: 1.2857142857em;
+  text-align: center;
+}
+
 .inline-icon-gf {
-    vertical-align: middle;
+  vertical-align: middle;
 }
 
 .icon-gf-raintank_wordmark:before {
@@ -145,7 +151,7 @@
 }
 .icon-gf-grabber:before {
   content: "\e90b";
-} 
+}
 .icon-gf-users:before {
     content: "\e622";
 }

+ 4 - 1
public/sass/components/_cards.scss

@@ -97,7 +97,7 @@
   color: $text-color-weak;
   text-transform: uppercase;
   font-size: $font-size-sm;
-  font-weight: bold;
+  font-weight: $font-weight-semi-bold;
 }
 
 .card-item-notice {
@@ -158,6 +158,9 @@
     img {
       width: 6rem;
     }
+    .fa, .icon-gf {
+      font-size: 3.5rem;
+    }
   }
 
   .card-item-name {

+ 1 - 1
public/sass/components/_gf-form.scss

@@ -194,7 +194,7 @@ $gf-form-margin: 0.1rem;
   select.gf-form-input {
     text-indent: .01px;
     text-overflow: '';
-    padding-right: $input-padding-x*2;
+    padding-right: $input-padding-x*4;
     -webkit-appearance: none;
     -moz-appearance: menulist-text; // was set to "window" and caused odd display on windos and linux.
     appearance: none;

+ 36 - 36
public/sass/components/_scrollbar.scss

@@ -110,39 +110,39 @@
 // Srollbars
 //
 
-// ::-webkit-scrollbar {
-//   width: 8px;
-//   height: 8px;
-// }
-//
-// ::-webkit-scrollbar:hover {
-//   height: 8px;
-// }
-//
-// ::-webkit-scrollbar-button:start:decrement,
-// ::-webkit-scrollbar-button:end:increment { display: none;  }
-// ::-webkit-scrollbar-button:horizontal:decrement {  display: none; }
-// ::-webkit-scrollbar-button:horizontal:increment {  display: none; }
-// ::-webkit-scrollbar-button:vertical:decrement { display: none; }
-// ::-webkit-scrollbar-button:vertical:increment { display: none; }
-// ::-webkit-scrollbar-button:horizontal:decrement:active { background-image: none; }
-// ::-webkit-scrollbar-button:horizontal:increment:active { background-image: none; }
-// ::-webkit-scrollbar-button:vertical:decrement:active { background-image: none; }
-// ::-webkit-scrollbar-button:vertical:increment:active {background-image: none; }
-// ::-webkit-scrollbar-track-piece { background-color: transparent; }
-//
-// ::-webkit-scrollbar-thumb:vertical {
-//   height: 50px;
-//   background: -webkit-gradient(linear, left top, right top, color-stop(0%, $scrollbarBackground), color-stop(100%, $scrollbarBackground2));
-//   border: 1px solid $scrollbarBorder;
-//   border-top: 1px solid $scrollbarBorder;
-//   border-left: 1px solid $scrollbarBorder;
-// }
-//
-// ::-webkit-scrollbar-thumb:horizontal {
-//   width: 50px;
-//   background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, $scrollbarBackground), color-stop(100%, $scrollbarBackground2));
-//   border: 1px solid $scrollbarBorder;
-//   border-top: 1px solid $scrollbarBorder;
-//   border-left: 1px solid $scrollbarBorder;
-// }
+::-webkit-scrollbar {
+  width: 8px;
+  height: 8px;
+}
+
+::-webkit-scrollbar:hover {
+  height: 8px;
+}
+
+::-webkit-scrollbar-button:start:decrement,
+::-webkit-scrollbar-button:end:increment { display: none;  }
+::-webkit-scrollbar-button:horizontal:decrement {  display: none; }
+::-webkit-scrollbar-button:horizontal:increment {  display: none; }
+::-webkit-scrollbar-button:vertical:decrement { display: none; }
+::-webkit-scrollbar-button:vertical:increment { display: none; }
+::-webkit-scrollbar-button:horizontal:decrement:active { background-image: none; }
+::-webkit-scrollbar-button:horizontal:increment:active { background-image: none; }
+::-webkit-scrollbar-button:vertical:decrement:active { background-image: none; }
+::-webkit-scrollbar-button:vertical:increment:active {background-image: none; }
+::-webkit-scrollbar-track-piece { background-color: transparent; }
+
+::-webkit-scrollbar-thumb:vertical {
+  height: 50px;
+  background: -webkit-gradient(linear, left top, right top, color-stop(0%, $scrollbarBackground), color-stop(100%, $scrollbarBackground2));
+  border: 1px solid $scrollbarBorder;
+  border-top: 1px solid $scrollbarBorder;
+  border-left: 1px solid $scrollbarBorder;
+}
+
+::-webkit-scrollbar-thumb:horizontal {
+  width: 50px;
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, $scrollbarBackground), color-stop(100%, $scrollbarBackground2));
+  border: 1px solid $scrollbarBorder;
+  border-top: 1px solid $scrollbarBorder;
+  border-left: 1px solid $scrollbarBorder;
+}

+ 4 - 4
public/sass/layout/_page.scss

@@ -61,12 +61,12 @@
     margin-bottom: $spacer*1.5;
   }
 
+  a, button {
+    float: right;
+    margin-left: $spacer;
+  }
 }
 
-.page-header__cta {
-  float: right;
-  margin-left: $spacer;
-}
 
 .page-heading {
   font-size: 1.25rem;

+ 1 - 1
public/views/index.html

@@ -82,7 +82,7 @@
     window.grafanaBootData = {
       user:[[.User]],
       settings: [[.Settings]],
-      mainNavLinks: [[.MainNavLinks]]
+      navTree: [[.NavTree]]
     };
     </script>