فهرست منبع

dashboard acl modal

Torkel Ödegaard 8 سال پیش
والد
کامیت
3edd209736

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

@@ -8,9 +8,9 @@
 		<i class="fa fa-chevron-left"></i>
 	</a>
 
-  <!-- <a class="navbar&#45;page&#45;btn navbar&#45;page&#45;btn&#45;&#45;search" ng&#45;click="ctrl.showSearch()"> -->
-	<!-- 	<i class="fa fa&#45;search"></i> -->
-	<!-- </a> -->
+  <a class="navbar-page-btn navbar-page-btn--search" ng-click="ctrl.showSearch()">
+		<i class="fa fa-search"></i>
+	</a>
 
 	<div ng-if="::!ctrl.hasMenu">
 		<a href="{{::ctrl.section.url}}" class="navbar-page-btn">

+ 13 - 7
public/app/core/directives/dash_edit_link.js

@@ -2,8 +2,9 @@ define([
   'jquery',
   'angular',
   '../core_module',
+  'lodash',
 ],
-function ($, angular, coreModule) {
+function ($, angular, coreModule, _) {
   'use strict';
 
   var editViewMap = {
@@ -12,7 +13,8 @@ function ($, angular, coreModule) {
     'templating':  { src: 'public/app/features/templating/partials/editor.html'},
     'history':     { html: '<gf-dashboard-history dashboard="dashboard"></gf-dashboard-history>'},
     'timepicker':  { src: 'public/app/features/dashboard/timepicker/dropdown.html' },
-    'import':      { html: '<dash-import></dash-import>' }
+    'import':      { html: '<dash-import dismiss="dismiss()"></dash-import>', isModal: true },
+    'permissions': { html: '<dash-acl-modal dismiss="dismiss()"></dash-acl-modal>', isModal: true }
   };
 
   coreModule.default.directive('dashEditorView', function($compile, $location, $rootScope) {
@@ -31,8 +33,7 @@ function ($, angular, coreModule) {
 
         function showEditorPane(evt, options) {
           if (options.editview) {
-            options.src = editViewMap[options.editview].src;
-            options.html = editViewMap[options.editview].html;
+            _.defaults(options, editViewMap[options.editview]);
           }
 
           if (lastEditView && lastEditView === options.editview) {
@@ -61,19 +62,24 @@ function ($, angular, coreModule) {
               var urlParams = $location.search();
               if (options.editview === urlParams.editview) {
                 delete urlParams.editview;
-                $location.search(urlParams);
+                // hack for consistently updating url
+                setTimeout(function() {
+                  $rootScope.$apply(function() {
+                    $location.search(urlParams);
+                  });
+                });
               }
             }
           };
 
-          if (options.editview === 'import') {
+          if (options.isModal) {
             var modalScope = $rootScope.$new();
             modalScope.$on("$destroy", function() {
               editorScope.dismiss();
             });
 
             $rootScope.appEvent('show-modal', {
-              templateHtml: '<dash-import></dash-import>',
+              templateHtml: options.html,
               scope: modalScope,
               backdrop: 'static'
             });

+ 7 - 1
public/app/core/nav_model_srv.ts

@@ -168,6 +168,12 @@ export class NavModelSrv {
         clickHandler: () => dashNavCtrl.openEditView('annotations')
       });
 
+      menu.push({
+        title: 'Permissions...',
+        icon: 'fa fa-fw fa-lock',
+        clickHandler: () => dashNavCtrl.openEditView('permissions')
+      });
+
       if (!dashboard.meta.isHome) {
         menu.push({
           title: 'Version history',
@@ -199,7 +205,7 @@ export class NavModelSrv {
 
     if (this.contextSrv.isEditor && !dashboard.meta.isFolder) {
       menu.push({
-        title: 'Save As ...',
+        title: 'Save As...',
         icon: 'fa fa-fw fa-save',
         clickHandler: () => dashNavCtrl.saveDashboardAs()
       });

+ 129 - 68
public/app/features/dashboard/acl/acl.html

@@ -1,74 +1,135 @@
-<div class="editor-row">
-	<h5 class="section-heading">Add New Permission</h5>
-	<form name="addPermission" class="gf-form-group">
-		<div class="gf-form-inline">
-      <div class="gf-form">
-				<span class="gf-form-label">Type</span>
-				<select class="gf-form-input gf-size-auto" ng-model="ctrl.type" ng-options="r for r in ['User Group', 'User']"></select>
-			</div>
-      <div class="gf-form" ng-show="ctrl.type === 'User'">
-        <span class="gf-form-label">User</span>
-        <user-picker user-id="ctrl.userId"></user-picker>
+<div class="modal-body modal-body--with-overflow">
+  <div class="modal-header">
+    <h2 class="modal-header-title">
+      <i class="fa fa-lock"></i>
+      <span class="p-l-1">Permissions</span>
+    </h2>
+
+    <a class="modal-header-close" ng-click="ctrl.dismiss();">
+      <i class="fa fa-remove"></i>
+    </a>
+  </div>
+
+  <form ng-submit="ctrl.save()" class="modal-content" novalidate>
+    <!-- <h5 class="section&#45;heading">Add New Permission</h5> -->
+    <!-- <form name="addPermission" class="gf&#45;form&#45;group"> -->
+    <!-- 	<div class="gf&#45;form&#45;inline"> -->
+    <!--     <div class="gf&#45;form"> -->
+    <!-- 			<span class="gf&#45;form&#45;label">Type</span> -->
+    <!-- 			<select class="gf&#45;form&#45;input gf&#45;size&#45;auto" ng&#45;model="ctrl.type" ng&#45;options="r for r in ['User Group', 'User']"></select> -->
+    <!-- 		</div> -->
+    <!--     <div class="gf&#45;form" ng&#45;show="ctrl.type === 'User'"> -->
+    <!--       <span class="gf&#45;form&#45;label">User</span> -->
+    <!--       <user&#45;picker user&#45;id="ctrl.userId"></user&#45;picker> -->
+    <!--     </div> -->
+    <!--     <div class="gf&#45;form" ng&#45;show="ctrl.type === 'User Group'"> -->
+    <!--       <span class="gf&#45;form&#45;label">User Group</span> -->
+    <!--       <user&#45;group&#45;picker user&#45;group&#45;id="ctrl.userGroupId"></user&#45;group&#45;picker> -->
+    <!--     </div> -->
+    <!-- 		<div class="gf&#45;form"> -->
+    <!-- 			<span class="gf&#45;form&#45;label">Permission</span> -->
+    <!-- 			<select class="gf&#45;form&#45;input gf&#45;size&#45;auto" ng&#45;model="ctrl.permission" ng&#45;options="p.value as p.text for p in ctrl.permissionTypeOptions"></select> -->
+    <!-- 		</div> -->
+    <!-- 		<div class="gf&#45;form"> -->
+    <!-- 			<button class="btn gf&#45;form&#45;btn btn&#45;success" ng&#45;click="ctrl.addPermission()">Add</button> -->
+    <!-- 		</div> -->
+    <!-- 	</div> -->
+    <!-- </form> -->
+
+    <div>
+      <div class="section">
+        <h5 class="section-heading">Groups & Users</h5>
+        <div class="gf-form" ng-repeat="acl in ctrl.userAcl">
+          <span class="gf-form-label width-15">
+            <i class="fa fa-fw fa-user"></i>
+            {{acl.userLogin}}
+          </span>
+          <div class="gf-form-select-wrapper">
+            <select class="gf-form-input gf-size-auto" ng-model="acl.permissions" ng-options="p.value as p.text for p in ctrl.permissionTypeOptions" ng-change="ctrl.updatePermission(permission)"></select>
+          </div>
+          <button class="btn btn-inverse gf-form-btn" ng-click="ctrl.addQuery()" ng-hide="ctrl.current.meta.mixed">
+            <i class="fa fa-remove"></i>
+          </button>
+        </div>
+        <div class="gf-form">
+          <button class="btn btn-inverse gf-form-btn" ng-click="ctrl.addQuery()" ng-hide="ctrl.current.meta.mixed">
+            <i class="fa fa-fw fa-plus"></i>
+            Add Permission
+          </button>
+        </div>
       </div>
-      <div class="gf-form" ng-show="ctrl.type === 'User Group'">
-        <span class="gf-form-label">User Group</span>
-        <user-group-picker user-group-id="ctrl.userGroupId"></user-group-picker>
+      <div class="section pull-right">
+        <h5 class="section-heading">Built-in roles</h5>
+        <div class="gf-form" ng-repeat="roleAcl in ctrl.roles">
+          <span class="gf-form-label width-5">
+            {{roleAcl.name}}
+          </span>
+          <div class="gf-form-select-wrapper">
+            <select class="gf-form-input gf-size-auto" ng-model="roleAcl.permissions" ng-options="p.value as p.text for p in ctrl.roleOptions" ng-change="ctrl.updatePermission(permission)"></select>
+          </div>
+        </div>
       </div>
-			<div class="gf-form">
-				<span class="gf-form-label">Permission</span>
-				<select class="gf-form-input gf-size-auto" ng-model="ctrl.permission" ng-options="p.value as p.text for p in ctrl.permissionTypeOptions"></select>
-			</div>
-			<div class="gf-form">
-				<button class="btn gf-form-btn btn-success" ng-click="ctrl.addPermission()">Add</button>
-			</div>
-		</div>
-	</form>
+    </div>
 
-  <div class="permissionlist">
-    <div class="permissionlist__section">
-      <div class="permissionlist__section-header">
-        <h6>Permissions</h6>
-      </div>
-      <table class="filter-table form-inline">
-        <thead>
-          <tr>
-            <th style="width: 50px;"></th>
-            <th>Name</th>
-            <th style="width: 220px;">Permission</th>
-            <th style="width: 120px"></th>
-          </tr>
-        </thead>
-        <tbody>
-          <tr ng-repeat="permission in ctrl.userPermissions" class="permissionlist__item">
-            <td><i class="fa fa-fw fa-user"></i></td>
-            <td>{{permission.userLogin}}</td>
-            <td><select class="gf-form-input gf-size-auto" ng-model="permission.permissions" ng-options="p.value as p.text for p in ctrl.permissionTypeOptions" ng-change="ctrl.updatePermission(permission)"></select></td>
-            <td class="text-right">
-              <a ng-click="ctrl.removePermission(permission)" class="btn btn-danger btn-small">
-                <i class="fa fa-remove"></i>
-              </a>
-            </td>
-          </tr>
-          <tr ng-repeat="permission in ctrl.userGroupPermissions" class="permissionlist__item">
-            <td><i class="fa fa-fw fa-users"></i></td>
-            <td>{{permission.userGroup}}</td>
-            <td><select class="gf-form-input gf-size-auto" ng-model="permission.permissions" ng-options="p.value as p.text for p in ctrl.permissionTypeOptions" ng-change="ctrl.updatePermission(permission)"></select></td>
-            <td class="text-right">
-              <a ng-click="ctrl.removePermission(permission)" class="btn btn-danger btn-small">
-                <i class="fa fa-remove"></i>
-              </a>
-            </td>
-          </tr>
-          <tr ng-repeat="role in ctrl.roles" class="permissionlist__item">
-            <td></td>
-            <td>{{role.name}}</td>
-            <td><select class="gf-form-input gf-size-auto" ng-model="role.permissions" ng-options="p.value as p.text for p in ctrl.roleOptions" ng-change="ctrl.updatePermission(role)"></select></td>
-            <td class="text-right">
+    <div class="clearfix"></div>
 
-            </td>
-          </tr>
-        </tbody>
-      </table>
+    <div class="gf-form-button-row text-center">
+      <button type="submit" class="btn btn-danger" ng-disabled="!ctrl.canUpdate">Update Permissions</button>
+      <a class="btn-text" ng-click="ctrl.dismiss();">Close</a>
     </div>
-  </div>
+
+  </form>
 </div>
+
+<!-- <br> -->
+<!-- <br> -->
+<!-- <br> -->
+<!--  -->
+<!-- <div class="permissionlist"> -->
+<!--   <div class="permissionlist__section"> -->
+<!--     <div class="permissionlist__section&#45;header"> -->
+<!--       <h6>Permissions</h6> -->
+<!--     </div> -->
+<!--     <table class="filter&#45;table form&#45;inline"> -->
+<!--       <thead> -->
+<!--         <tr> -->
+<!--           <th style="width: 50px;"></th> -->
+<!--           <th>Name</th> -->
+<!--           <th style="width: 220px;">Permission</th> -->
+<!--           <th style="width: 120px"></th> -->
+<!--         </tr> -->
+<!--       </thead> -->
+<!--       <tbody> -->
+<!--         <tr ng&#45;repeat="permission in ctrl.userPermissions" class="permissionlist__item"> -->
+<!--           <td><i class="fa fa&#45;fw fa&#45;user"></i></td> -->
+<!--           <td>{{permission.userLogin}}</td> -->
+<!--           <td><select class="gf&#45;form&#45;input gf&#45;size&#45;auto" ng&#45;model="permission.permissions" ng&#45;options="p.value as p.text for p in ctrl.permissionTypeOptions" ng&#45;change="ctrl.updatePermission(permission)"></select></td> -->
+<!--           <td class="text&#45;right"> -->
+<!--             <a ng&#45;click="ctrl.removePermission(permission)" class="btn btn&#45;danger btn&#45;small"> -->
+<!--               <i class="fa fa&#45;remove"></i> -->
+<!--             </a> -->
+<!--           </td> -->
+<!--         </tr> -->
+<!--         <tr ng&#45;repeat="permission in ctrl.userGroupPermissions" class="permissionlist__item"> -->
+<!--           <td><i class="fa fa&#45;fw fa&#45;users"></i></td> -->
+<!--           <td>{{permission.userGroup}}</td> -->
+<!--           <td><select class="gf&#45;form&#45;input gf&#45;size&#45;auto" ng&#45;model="permission.permissions" ng&#45;options="p.value as p.text for p in ctrl.permissionTypeOptions" ng&#45;change="ctrl.updatePermission(permission)"></select></td> -->
+<!--           <td class="text&#45;right"> -->
+<!--             <a ng&#45;click="ctrl.removePermission(permission)" class="btn btn&#45;danger btn&#45;small"> -->
+<!--               <i class="fa fa&#45;remove"></i> -->
+<!--             </a> -->
+<!--           </td> -->
+<!--         </tr> -->
+<!--         <tr ng&#45;repeat="role in ctrl.roles" class="permissionlist__item"> -->
+<!--           <td></td> -->
+<!--           <td>{{role.name}}</td> -->
+<!--           <td><select class="gf&#45;form&#45;input gf&#45;size&#45;auto" ng&#45;model="role.permissions" ng&#45;options="p.value as p.text for p in ctrl.roleOptions" ng&#45;change="ctrl.updatePermission(role)"></select></td> -->
+<!--           <td class="text&#45;right"> -->
+  <!--  -->
+  <!--           </td> -->
+  <!--         </tr> -->
+  <!--       </tbody> -->
+  <!--     </table> -->
+  <!--   </div> -->
+<!--   </div> -->
+<!-- </div> -->

+ 30 - 30
public/app/features/dashboard/acl/acl.ts

@@ -5,21 +5,20 @@ import appEvents from 'app/core/app_events';
 import _ from 'lodash';
 
 export class AclCtrl {
-  tabIndex: any;
   dashboard: any;
-  userPermissions: Permission[];
-  userGroupPermissions: Permission[];
+  userAcl: DashboardAcl[];
+  groupAcl: DashboardAcl[];
   permissionTypeOptions = [
     {value: 1, text: 'View'},
-    {value: 2, text: 'Read-only Edit'},
-    {value: 4, text: 'Edit'}
+    {value: 2, text: 'Edit'},
+    {value: 4, text: 'Admin'}
   ];
 
   roleOptions = [
-    {value: 0, text: 'None'},
+    {value: 0, text: 'No Access'},
     {value: 1, text: 'View'},
-    {value: 2, text: 'Read-only Edit'},
-    {value: 4, text: 'Edit'}
+    {value: 2, text: 'Edit'},
+    {value: 4, text: 'Admin'}
   ];
 
   roles = [];
@@ -30,28 +29,27 @@ export class AclCtrl {
   userGroupId: number;
 
   /** @ngInject */
-  constructor(private backendSrv, private $scope) {
-    this.tabIndex = 0;
-    this.userPermissions = [];
-    this.userGroupPermissions = [];
+  constructor(private backendSrv, private dashboardSrv) {
+    this.userAcl = [];
+    this.groupAcl = [];
+    this.dashboard = dashboardSrv.getCurrent();
     this.get(this.dashboard.id);
   }
 
   get(dashboardId: number) {
     return this.backendSrv.get(`/api/dashboards/id/${dashboardId}/acl`)
       .then(result => {
-        this.userPermissions = _.filter(result, p => { return p.userId > 0;});
-        this.userGroupPermissions = _.filter(result, p => { return p.userGroupId > 0;});
+        this.userAcl = _.filter(result, p => { return p.userId > 0;});
+        this.groupAcl = _.filter(result, p => { return p.userGroupId > 0;});
         this.roles = this.setRoles(result);
       });
   }
 
   setRoles(result: any) {
     return [
-      {name: 'Org Viewer', permissions: 1},
-      {name: 'Org Read Only Editor', permissions: 2},
-      {name: 'Org Editor', permissions: 4},
-      {name: 'Org Admin', permissions: 4}
+      {name: 'Viewer', permissions: 1},
+      {name: 'Editor', permissions: 2},
+      {name: 'Admin', permissions: 4}
     ];
   }
 
@@ -76,21 +74,21 @@ export class AclCtrl {
     }
   }
 
-  addOrUpdateUserPermission(userId: number, permissionType: number) {
+  addOrUpdateUserPermission(userId: number, permissions: number) {
     return this.backendSrv.post(`/api/dashboards/id/${this.dashboard.id}/acl`, {
       userId: userId,
-      permissions: permissionType
+      permissions: permissions
     });
   }
 
-  addOrUpdateUserGroupPermission(userGroupId: number, permissionType: number) {
+  addOrUpdateUserGroupPermission(userGroupId: number, permissions: number) {
     return this.backendSrv.post(`/api/dashboards/id/${this.dashboard.id}/acl`, {
       userGroupId: userGroupId,
-      permissions: permissionType
+      permissions: permissions
     });
   }
 
-  updatePermission(permission: any) {
+  updatePermission(permission: DashboardAcl) {
     if (permission.userId > 0) {
       return this.addOrUpdateUserPermission(permission.userId, permission.permissions);
     } else {
@@ -101,21 +99,23 @@ export class AclCtrl {
     }
   }
 
-  removePermission(permission: Permission) {
+  removePermission(permission: DashboardAcl) {
     return this.backendSrv.delete(`/api/dashboards/id/${permission.dashboardId}/acl/${permission.id}`).then(() => {
       return this.get(permission.dashboardId);
     });
   }
 }
 
-export function aclSettings() {
+export function dashAclModal() {
   return {
     restrict: 'E',
     templateUrl: 'public/app/features/dashboard/acl/acl.html',
     controller: AclCtrl,
     bindToController: true,
     controllerAs: 'ctrl',
-    scope: { dashboard: "=" }
+    scope: {
+      dismiss: "&"
+    }
   };
 }
 
@@ -126,7 +126,7 @@ export interface FormModel {
   PermissionType: number;
 }
 
-export interface Permission {
+export interface DashboardAcl {
   id: number;
   orgId: number;
   dashboardId: number;
@@ -137,8 +137,8 @@ export interface Permission {
   userEmail: string;
   userGroupId: number;
   userGroup: string;
-  permissions: string[];
-  permissionType: number[];
+  permissions: number;
+  permissionName: string;
 }
 
-coreModule.directive('aclSettings', aclSettings);
+coreModule.directive('dashAclModal', dashAclModal);

+ 52 - 83
public/app/features/dashboard/dashnav/dashnav.html

@@ -1,95 +1,64 @@
-<div class="navbar">
-	<div class="navbar-inner">
-		<a class="navbar-brand-btn pointer" ng-click="ctrl.toggleSideMenu()">
-			<span class="navbar-brand-btn-background">
-				<img src="public/img/grafana_icon.svg"></img>
-			</span>
-			<i class="icon-gf icon-gf-grafana_wordmark"></i>
-			<i class="fa fa-caret-down"></i>
-			<i class="fa fa-chevron-left"></i>
-		</a>
+<navbar model="ctrl.navModel">
 
-		<div class="navbar-section-wrapper">
-			<a class="navbar-page-btn" ng-click="ctrl.showSearch()">
-				<i class="icon-gf icon-gf-dashboard"></i>
-				{{ctrl.dashboard.title}}
-				<i class="fa fa-caret-down"></i>
-			</a>
-		</div>
+<ul class="nav dash-playlist-actions" ng-if="ctrl.playlistSrv.isPlaying">
+	<li>
+		<a ng-click="ctrl.playlistSrv.prev()"><i class="fa fa-step-backward"></i></a>
+	</li>
+	<li>
+		<a ng-click="ctrl.playlistSrv.stop()"><i class="fa fa-stop"></i></a>
+	</li>
+	<li>
+		<a ng-click="ctrl.playlistSrv.next()"><i class="fa fa-step-forward"></i></a>
+	</li>
+</ul>
 
-		<ul class="nav dash-playlist-actions" ng-if="ctrl.playlistSrv.isPlaying">
-			<li>
-				<a ng-click="ctrl.playlistSrv.prev()"><i class="fa fa-step-backward"></i></a>
-			</li>
+<ul class="nav pull-left dashnav-action-icons">
+	<li ng-show="::ctrl.dashboard.meta.canStar">
+		<a class="pointer" ng-click="ctrl.starDashboard()">
+			<i class="fa" ng-class="{'fa-star-o': !ctrl.dashboard.meta.isStarred, 'fa-star': ctrl.dashboard.meta.isStarred}" style="color: orange;"></i>
+		</a>
+	</li>
+	<li ng-show="::ctrl.dashboard.meta.canShare" class="dropdown">
+		<a class="pointer" ng-click="ctrl.hideTooltip($event)" bs-tooltip="'Share dashboard'" data-placement="bottom" data-toggle="dropdown"><i class="fa fa-share-square-o"></i></a>
+		<ul class="dropdown-menu">
 			<li>
-				<a ng-click="ctrl.playlistSrv.stop()"><i class="fa fa-stop"></i></a>
+				<a class="pointer" ng-click="ctrl.shareDashboard(0)">
+					<i class="fa fa-link"></i> Link to Dashboard
+					<div class="dropdown-desc">Share an internal link to the current dashboard. Some configuration options available.</div>
+				</a>
 			</li>
 			<li>
-				<a ng-click="ctrl.playlistSrv.next()"><i class="fa fa-step-forward"></i></a>
-			</li>
-		</ul>
-
-		<ul class="nav pull-left dashnav-action-icons">
-			<li ng-show="::ctrl.dashboard.meta.canStar">
-				<a class="pointer" ng-click="ctrl.starDashboard()">
-					<i class="fa" ng-class="{'fa-star-o': !ctrl.dashboard.meta.isStarred, 'fa-star': ctrl.dashboard.meta.isStarred}" style="color: orange;"></i>
+				<a class="pointer" ng-click="ctrl.shareDashboard(1)">
+					<i class="icon-gf icon-gf-snapshot"></i>Snapshot
+					<div class="dropdown-desc">Interactive, publically accessible dashboard. Sensitive data is stripped out.</div>
 				</a>
 			</li>
-			<li ng-show="::ctrl.dashboard.meta.canShare" class="dropdown">
-				<a class="pointer" ng-click="ctrl.hideTooltip($event)" bs-tooltip="'Share dashboard'" data-placement="bottom" data-toggle="dropdown"><i class="fa fa-share-square-o"></i></a>
-				<ul class="dropdown-menu">
-					<li>
-						<a class="pointer" ng-click="ctrl.shareDashboard(0)">
-							<i class="fa fa-link"></i> Link to Dashboard
-							<div class="dropdown-desc">Share an internal link to the current dashboard. Some configuration options available.</div>
-						</a>
-					</li>
-					<li>
-						<a class="pointer" ng-click="ctrl.shareDashboard(1)">
-							<i class="icon-gf icon-gf-snapshot"></i>Snapshot
-							<div class="dropdown-desc">Interactive, publically accessible dashboard. Sensitive data is stripped out.</div>
-						</a>
-					</li>
-					<li>
-						<a class="pointer" ng-click="ctrl.shareDashboard(2)">
-							<i class="fa fa-cloud-upload"></i>Export
-							<div class="dropdown-desc">Export the dashboard to a JSON file for others and to share on Grafana.com</div>
-						</a>
-					</li>
-				</ul>
-			</li>
-			<li ng-show="::ctrl.dashboard.meta.canSave">
-				<a ng-click="ctrl.saveDashboard()" bs-tooltip="'Save dashboard <br> CTRL+S'" data-placement="bottom"><i class="fa fa-save"></i></a>
-			</li>
-			<li ng-if="::ctrl.dashboard.snapshot.originalUrl">
-				<a ng-href="{{ctrl.dashboard.snapshot.originalUrl}}" bs-tooltip="'Open original dashboard'" data-placement="bottom"><i class="fa fa-link"></i></a>
-			</li>
-			<li class="dropdown">
-				<a class="pointer" data-toggle="dropdown">
-					<i class="fa fa-cog"></i>
+			<li>
+				<a class="pointer" ng-click="ctrl.shareDashboard(2)">
+					<i class="fa fa-cloud-upload"></i>Export
+					<div class="dropdown-desc">Export the dashboard to a JSON file for others and to share on Grafana.com</div>
 				</a>
-				<ul class="dropdown-menu dropdown-menu--navbar">
-					<li ng-repeat="navItem in ::ctrl.navModel.menu" ng-class="{active: navItem.active}">
-						<a class="pointer" ng-href="{{::navItem.url}}" ng-click="ctrl.navItemClicked(navItem, $event)">
-							<i class="{{::navItem.icon}}" ng-show="::navItem.icon"></i>
-							{{::navItem.title}}
-						</a>
-					</li>
-				</ul>
 			</li>
 		</ul>
+	</li>
+	<li ng-show="::ctrl.dashboard.meta.canSave">
+		<a ng-click="ctrl.saveDashboard()" bs-tooltip="'Save dashboard <br> CTRL+S'" data-placement="bottom"><i class="fa fa-save"></i></a>
+	</li>
+	<li ng-if="::ctrl.dashboard.snapshot.originalUrl">
+		<a ng-href="{{ctrl.dashboard.snapshot.originalUrl}}" bs-tooltip="'Open original dashboard'" data-placement="bottom"><i class="fa fa-link"></i></a>
+	</li>
+</ul>
 
-		<ul class="nav pull-right">
-			<li ng-show="ctrl.dashboard.meta.fullscreen" class="dashnav-back-to-dashboard">
-				<a ng-click="ctrl.exitFullscreen()">
-					Back to dashboard
-				</a>
-			</li>
-			<li>
-				<gf-time-picker dashboard="ctrl.dashboard"></gf-time-picker>
-			</li>
-		</ul>
-	</div>
-</div>
+<ul class="nav pull-right">
+	<li ng-show="ctrl.dashboard.meta.fullscreen" class="dashnav-back-to-dashboard">
+		<a ng-click="ctrl.exitFullscreen()">
+			Back to dashboard
+		</a>
+	</li>
+	<li>
+		<gf-time-picker dashboard="ctrl.dashboard"></gf-time-picker>
+	</li>
+</ul>
+
+</navbar>
 
-<dashboard-search></dashboard-search>

+ 0 - 11
public/app/features/dashboard/dashnav/dashnav.ts

@@ -143,17 +143,6 @@ export class DashNavCtrl {
     onFolderChange(parentId) {
       this.dashboard.parentId = parentId;
     }
-
-    showSearch() {
-      this.$rootScope.appEvent('show-dash-search');
-    }
-
-    navItemClicked(navItem, evt) {
-      if (navItem.clickHandler) {
-        navItem.clickHandler();
-        evt.preventDefault();
-      }
-    }
 }
 
 export function dashNavDirective() {

+ 0 - 1
public/app/features/dashboard/import/dash_import.html

@@ -1,4 +1,3 @@
-<div class="modal-body">
 
 	<div class="modal-header">
 		<h2 class="modal-header-title">