Просмотр исходного кода

Merge branch 'develop' into develop-light-theme

Patrick O'Carroll 8 лет назад
Родитель
Сommit
a16cfb4b3b
100 измененных файлов с 1541 добавлено и 1513 удалено
  1. 2 0
      pkg/api/dtos/index.go
  2. 50 48
      pkg/api/index.go
  3. 9 0
      pkg/models/dashboards.go
  4. 0 61
      pkg/plugins/dashboard_importer.go
  5. 17 96
      pkg/plugins/dashboard_importer_test.go
  6. 0 10
      pkg/plugins/dashboards.go
  7. 2 0
      public/app/core/angular_wrappers.ts
  8. 72 0
      public/app/core/components/PageHeader.tsx
  9. 10 0
      public/app/core/components/grafana_app.ts
  10. 7 9
      public/app/core/components/navbar/navbar.html
  11. 4 4
      public/app/core/components/navbar/navbar.ts
  12. 8 0
      public/app/core/components/scroll/scroll.ts
  13. 62 72
      public/app/core/components/search/search.html
  14. 3 22
      public/app/core/components/search/search.ts
  15. 6 0
      public/app/core/components/sidemenu/sidemenu.html
  16. 10 0
      public/app/core/components/sidemenu/sidemenu.ts
  17. 33 8
      public/app/core/nav_model_srv.ts
  18. 4 5
      public/app/core/routes/dashboard_loaders.ts
  19. 0 6
      public/app/core/routes/routes.ts
  20. 7 2
      public/app/core/services/context_srv.ts
  21. 3 13
      public/app/features/admin/admin.ts
  22. 1 1
      public/app/features/admin/admin_edit_org_ctrl.ts
  23. 1 1
      public/app/features/admin/admin_edit_user_ctrl.ts
  24. 1 1
      public/app/features/admin/admin_list_orgs_ctrl.ts
  25. 1 1
      public/app/features/admin/admin_list_users_ctrl.ts
  26. 6 30
      public/app/features/admin/partials/admin_home.html
  27. 0 33
      public/app/features/admin/partials/configuration_home.html
  28. 3 5
      public/app/features/admin/partials/edit_org.html
  29. 14 11
      public/app/features/admin/partials/edit_user.html
  30. 3 3
      public/app/features/admin/partials/new_user.html
  31. 8 4
      public/app/features/admin/partials/orgs.html
  32. 16 19
      public/app/features/admin/partials/settings.html
  33. 2 6
      public/app/features/admin/partials/stats.html
  34. 8 12
      public/app/features/admin/partials/users.html
  35. 1 1
      public/app/features/alerting/alert_list_ctrl.ts
  36. 3 2
      public/app/features/alerting/notification_edit_ctrl.ts
  37. 1 1
      public/app/features/alerting/notifications_list_ctrl.ts
  38. 16 22
      public/app/features/alerting/partials/alert_list.html
  39. 5 5
      public/app/features/alerting/partials/notification_edit.html
  40. 7 5
      public/app/features/alerting/partials/notifications_list.html
  41. 1 1
      public/app/features/dashboard/dashboard_list_ctrl.ts
  42. 11 1
      public/app/features/dashboard/dashgrid/AddPanelPanel.tsx
  43. 49 78
      public/app/features/dashboard/dashnav/dashnav.html
  44. 1 1
      public/app/features/dashboard/dashnav/dashnav.ts
  45. 114 146
      public/app/features/dashboard/partials/dashboardList.html
  46. 22 34
      public/app/features/dashboard/timepicker/timepicker.html
  47. 1 0
      public/app/features/org/all.ts
  48. 1 1
      public/app/features/org/change_password_ctrl.ts
  49. 1 1
      public/app/features/org/new_org_ctrl.ts
  50. 1 1
      public/app/features/org/org_api_keys_ctrl.ts
  51. 1 1
      public/app/features/org/org_details_ctrl.ts
  52. 2 3
      public/app/features/org/org_users_ctrl.ts
  53. 5 8
      public/app/features/org/partials/change_password.html
  54. 5 5
      public/app/features/org/partials/newOrg.html
  55. 3 5
      public/app/features/org/partials/orgApiKeys.html
  56. 12 17
      public/app/features/org/partials/orgDetails.html
  57. 55 37
      public/app/features/org/partials/orgUsers.html
  58. 3 6
      public/app/features/org/partials/profile.html
  59. 13 12
      public/app/features/org/partials/user_groups.html
  60. 1 1
      public/app/features/org/profile_ctrl.ts
  61. 1 1
      public/app/features/org/user_groups_ctrl.ts
  62. 6 6
      public/app/features/playlist/partials/playlist.html
  63. 6 6
      public/app/features/playlist/partials/playlists.html
  64. 5 7
      public/app/features/playlist/playlist_edit_ctrl.ts
  65. 1 1
      public/app/features/playlist/playlists_ctrl.ts
  66. 3 5
      public/app/features/plugins/ds_edit_ctrl.ts
  67. 1 1
      public/app/features/plugins/ds_list_ctrl.ts
  68. 0 6
      public/app/features/plugins/import_list/import_list.html
  69. 68 79
      public/app/features/plugins/partials/ds_edit.html
  70. 24 25
      public/app/features/plugins/partials/ds_http_settings.html
  71. 38 40
      public/app/features/plugins/partials/ds_list.html
  72. 19 39
      public/app/features/plugins/partials/plugin_edit.html
  73. 75 59
      public/app/features/plugins/partials/plugin_list.html
  74. 1 1
      public/app/features/plugins/plugin_edit_ctrl.ts
  75. 13 19
      public/app/features/plugins/plugin_list_ctrl.ts
  76. 3 7
      public/app/features/snapshot/partials/snapshots.html
  77. 1 1
      public/app/features/snapshot/snapshot_ctrl.ts
  78. 11 35
      public/app/features/styleguide/styleguide.html
  79. 2 2
      public/app/features/styleguide/styleguide.ts
  80. 1 0
      public/sass/_grafana.scss
  81. 25 71
      public/sass/_old_responsive.scss
  82. 14 6
      public/sass/_variables.dark.scss
  83. 9 1
      public/sass/_variables.light.scss
  84. 20 16
      public/sass/_variables.scss
  85. 13 0
      public/sass/base/_icons.scss
  86. 1 1
      public/sass/components/_dashboard_grid.scss
  87. 2 3
      public/sass/components/_dropdown.scss
  88. 1 1
      public/sass/components/_footer.scss
  89. 16 1
      public/sass/components/_gf-form.scss
  90. 5 8
      public/sass/components/_modals.scss
  91. 56 51
      public/sass/components/_navbar.scss
  92. 159 0
      public/sass/components/_page_header.scss
  93. 30 3
      public/sass/components/_panel_add_panel.scss
  94. 1 1
      public/sass/components/_scrollbar.scss
  95. 54 15
      public/sass/components/_search.scss
  96. 121 30
      public/sass/components/_sidemenu.scss
  97. 4 2
      public/sass/components/_tabbed_view.scss
  98. 11 51
      public/sass/components/_tabs.scss
  99. 6 17
      public/sass/components/_timepicker.scss
  100. 6 17
      public/sass/components/_view_states.scss

+ 2 - 0
pkg/api/dtos/index.go

@@ -24,11 +24,13 @@ type NavLink struct {
 	Id           string     `json:"id,omitempty"`
 	Text         string     `json:"text,omitempty"`
 	Description  string     `json:"description,omitempty"`
+	SubTitle     string     `json:"subTitle,omitempty"`
 	Icon         string     `json:"icon,omitempty"`
 	Img          string     `json:"img,omitempty"`
 	Url          string     `json:"url,omitempty"`
 	Target       string     `json:"target,omitempty"`
 	Divider      bool       `json:"divider,omitempty"`
 	HideFromMenu bool       `json:"hideFromMenu,omitempty"`
+	HideFromTabs bool       `json:"hideFromTabs,omitempty"`
 	Children     []*NavLink `json:"children,omitempty"`
 }

+ 50 - 48
pkg/api/index.go

@@ -101,15 +101,17 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 	}
 
 	dashboardChildNavs := []*dtos.NavLink{
-		{Text: "Home", Url: setting.AppSubUrl + "/", Icon: "fa fa-fw fa-home"},
+		{Text: "Home", Url: setting.AppSubUrl + "/", Icon: "fa fa-fw fa-home", HideFromTabs: true},
+		{Divider: true, HideFromTabs: true},
+		{Text: "Manage", Id: "dashboards", Url: setting.AppSubUrl + "/dashboards", Icon: "fa fa-fw fa-sitemap"},
 		{Text: "Playlists", Id: "playlists", Url: setting.AppSubUrl + "/playlists", Icon: "fa fa-fw fa-film"},
 		{Text: "Snapshots", Id: "snapshots", Url: setting.AppSubUrl + "/dashboard/snapshots", Icon: "icon-gf icon-gf-fw icon-gf-snapshot"},
-		{Text: "Dashboard List", Description: "Manage Dashboards And Folders", Id: "dashboards", Url: setting.AppSubUrl + "/dashboards", Icon: "fa fa-fw fa-bars"},
 	}
 
 	data.NavTree = append(data.NavTree, &dtos.NavLink{
 		Text:     "Dashboards",
 		Id:       "dashboards",
+		SubTitle: "Manage dashboards & folders",
 		Icon:     "gicon gicon-dashboard",
 		Url:      setting.AppSubUrl + "/",
 		Children: dashboardChildNavs,
@@ -117,22 +119,23 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 
 	if c.IsSignedIn {
 		profileNode := &dtos.NavLink{
-			Text:         c.SignedInUser.Login,
+			Text:         c.SignedInUser.Name,
+			SubTitle:     c.SignedInUser.Login,
 			Id:           "profile",
 			Img:          data.User.GravatarUrl,
 			Url:          setting.AppSubUrl + "/profile",
 			HideFromMenu: true,
 			Children: []*dtos.NavLink{
-				{Text: "Your profile", Url: setting.AppSubUrl + "/profile", Icon: "fa fa-fw fa-sliders"},
+				{Text: "Preferences", Id: "profile-settings", Url: setting.AppSubUrl + "/profile", Icon: "fa fa-fw fa-sliders"},
 				{Text: "Change Password", Id: "change-password", Url: setting.AppSubUrl + "/profile/password", Icon: "fa fa-fw fa-lock", HideFromMenu: true},
 			},
 		}
 
 		if !setting.DisableSignoutMenu {
 			// add sign out first
-			profileNode.Children = append([]*dtos.NavLink{
-				{Text: "Sign out", Url: setting.AppSubUrl + "/logout", Icon: "fa fa-fw fa-sign-out", Target: "_self"},
-			}, profileNode.Children...)
+			profileNode.Children = append(profileNode.Children, &dtos.NavLink{
+				Text: "Sign out", Id: "sign-out", Url: setting.AppSubUrl + "/logout", Icon: "fa fa-fw fa-sign-out", Target: "_self",
+			})
 		}
 
 		data.NavTree = append(data.NavTree, profileNode)
@@ -140,12 +143,13 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 
 	if setting.AlertingEnabled && (c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR) {
 		alertChildNavs := []*dtos.NavLink{
-			{Text: "Alert List", Id: "alert-list", Url: setting.AppSubUrl + "/alerting/list", Icon: "fa fa-fw fa-list-ul"},
-			{Text: "Notification channels", Id: "channels", Url: setting.AppSubUrl + "/alerting/notifications", Icon: "fa fa-fw fa-bell-o"},
+			{Text: "Alert Rules", Id: "alert-list", Url: setting.AppSubUrl + "/alerting/list", Icon: "fa fa-fw fa-list-ul"},
+			{Text: "Notification channels", Id: "channels", Url: setting.AppSubUrl + "/alerting/notifications", Icon: "gicon gicon-alert-notification-channel"},
 		}
 
 		data.NavTree = append(data.NavTree, &dtos.NavLink{
 			Text:     "Alerting",
+			SubTitle: "Alert rules & notifications",
 			Id:       "alerting",
 			Icon:     "gicon gicon-alert",
 			Url:      setting.AppSubUrl + "/alerting/list",
@@ -202,10 +206,11 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 
 	if c.OrgRole == m.ROLE_ADMIN {
 		cfgNode := &dtos.NavLink{
-			Id:   "cfg",
-			Text: "Configuration",
-			Icon: "fa fa-fw fa-cogs",
-			Url:  setting.AppSubUrl + "/configuration",
+			Id:       "cfg",
+			Text:     "Configuration",
+			SubTitle: "Organization: " + c.OrgName,
+			Icon:     "fa fa-fw fa-cog",
+			Url:      setting.AppSubUrl + "/datasources",
 			Children: []*dtos.NavLink{
 				{
 					Text:        "Data Sources",
@@ -213,29 +218,6 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 					Description: "Add and configure data sources",
 					Id:          "datasources",
 					Url:         setting.AppSubUrl + "/datasources",
-					Children: []*dtos.NavLink{
-						{Text: "List", Url: setting.AppSubUrl + "/datasources", Icon: "gicon gicon-datasources"},
-						{Text: "New", Url: setting.AppSubUrl + "/datasources", Icon: "fa fa-fw fa-plus"},
-					},
-				},
-				{
-					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-fw 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:        "Members",
@@ -245,12 +227,27 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 					Url:         setting.AppSubUrl + "/org/users",
 				},
 				{
-					Text:        "Groups",
-					Id:          "users",
+					Text:        "Teams",
+					Id:          "teams",
 					Description: "Manage org groups",
-					Icon:        "fa fa-fw fa-users",
+					Icon:        "gicon gicon-user-group",
 					Url:         setting.AppSubUrl + "/org/user-groups",
 				},
+				{
+					Text:        "Plugins",
+					Id:          "plugins",
+					Description: "View and configure plugins",
+					Icon:        "icon-gf icon-gf-fw icon-gf-apps",
+					Url:         setting.AppSubUrl + "/plugins",
+				},
+				{
+					Text:        "Preferences",
+					Id:          "org-settings",
+					Description: "Organization preferences",
+					Icon:        "fa fa-fw fa-sliders",
+					Url:         setting.AppSubUrl + "/org",
+				},
+
 				{
 					Text:        "API Keys",
 					Id:          "apikeys",
@@ -263,16 +260,21 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 
 		if c.IsGrafanaAdmin {
 			cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{
-				Text: "Server Admin",
-				Id:   "admin",
-				Icon: "fa fa-fw fa-shield",
-				Url:  setting.AppSubUrl + "/admin",
+				Divider: true, HideFromTabs: true,
+			})
+			cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{
+				Text:         "Server Admin",
+				HideFromTabs: true,
+				SubTitle:     "Manage all users & orgs",
+				Id:           "admin",
+				Icon:         "fa fa-fw fa-shield",
+				Url:          setting.AppSubUrl + "/admin/users",
 				Children: []*dtos.NavLink{
-					{Text: "Users", Id: "global-users", Url: setting.AppSubUrl + "/admin/users"},
-					{Text: "Orgs", Id: "global-orgs", Url: setting.AppSubUrl + "/admin/orgs"},
-					{Text: "Server Settings", Id: "server-settings", Url: setting.AppSubUrl + "/admin/settings"},
-					{Text: "Server Stats", Id: "server-stats", Url: setting.AppSubUrl + "/admin/stats"},
-					{Text: "Style Guide", Id: "styleguide", Url: setting.AppSubUrl + "/styleguide"},
+					{Text: "Users", Id: "global-users", Url: setting.AppSubUrl + "/admin/users", Icon: "icon-gf icon-gf-fw icon-gf-users"},
+					{Text: "Orgs", Id: "global-orgs", Url: setting.AppSubUrl + "/admin/orgs", Icon: "gicon gicon-org"},
+					{Text: "Settings", Id: "server-settings", Url: setting.AppSubUrl + "/admin/settings", Icon: "fa fa-fw fa-sliders"},
+					{Text: "Stats", Id: "server-stats", Url: setting.AppSubUrl + "/admin/stats", Icon: "fa fa-fw fa-bar-chart"},
+					{Text: "Style Guide", Id: "styleguide", Url: setting.AppSubUrl + "/styleguide", Icon: "fa fa-fw fa-eyedropper"},
 				},
 			})
 		}

+ 9 - 0
pkg/models/dashboards.go

@@ -68,6 +68,15 @@ func NewDashboard(title string) *Dashboard {
 	return dash
 }
 
+// NewDashboardFolder creates a new dashboard folder
+func NewDashboardFolder(title string) *Dashboard {
+	folder := NewDashboard(title)
+	folder.Data.Set("schemaVersion", 16)
+	folder.Data.Set("editable", true)
+	folder.Data.Set("hideControls", true)
+	return folder
+}
+
 // GetTags turns the tags in data json into go string array
 func (dash *Dashboard) GetTags() []string {
 	return dash.Data.Get("tags").MustStringArray()

+ 0 - 61
pkg/plugins/dashboard_importer.go

@@ -49,10 +49,6 @@ func ImportDashboard(cmd *ImportDashboardCommand) error {
 		if dashboard, err = loadPluginDashboard(cmd.PluginId, cmd.Path); err != nil {
 			return err
 		}
-
-		if err = createDashboardFolderForPlugin(cmd, dashboard); err != nil {
-			return err
-		}
 	} else {
 		dashboard = m.NewDashboardFromJson(cmd.Dashboard)
 	}
@@ -93,63 +89,6 @@ func ImportDashboard(cmd *ImportDashboardCommand) error {
 	return nil
 }
 
-func createDashboardFolderForPlugin(cmd *ImportDashboardCommand, dashboard *m.Dashboard) error {
-	var err error
-	var plugin *PluginBase
-
-	if plugin, err = getPlugin(cmd.PluginId); err != nil {
-		return err
-	}
-
-	var pluginType string
-
-	if plugin.Type == "datasource" {
-		pluginType = "Datasource"
-	} else if plugin.Type == "app" {
-		pluginType = "App"
-	}
-
-	folderTitle := fmt.Sprint(pluginType, ": ", plugin.Name)
-
-	folderDash := simplejson.NewFromAny(map[string]interface{}{
-		"schemaVersion": 16,
-		"title":         folderTitle,
-		"editable":      true,
-		"hideControls":  true,
-	})
-
-	saveCmd := m.SaveDashboardCommand{
-		Dashboard: folderDash,
-		OrgId:     cmd.OrgId,
-		UserId:    cmd.UserId,
-		PluginId:  cmd.PluginId,
-		IsFolder:  true,
-	}
-
-	dashModel := saveCmd.GetDashboardModel()
-
-	getDashboardQuery := m.GetDashboardQuery{
-		OrgId: cmd.OrgId,
-		Slug:  dashModel.Slug,
-	}
-
-	if err := bus.Dispatch(&getDashboardQuery); err != nil {
-		return err
-	}
-
-	if getDashboardQuery.Result != nil {
-		dashboard.FolderId = getDashboardQuery.Result.Id
-		return nil
-	}
-
-	if err := bus.Dispatch(&saveCmd); err != nil {
-		return err
-	}
-
-	dashboard.FolderId = saveCmd.Result.Id
-	return nil
-}
-
 type DashTemplateEvaluator struct {
 	template  *simplejson.Json
 	inputs    []ImportDashboardInput

+ 17 - 96
pkg/plugins/dashboard_importer_test.go

@@ -13,98 +13,12 @@ import (
 )
 
 func TestDashboardImport(t *testing.T) {
-
-	Convey("When importing plugin dashboard", t, func() {
-		setting.Cfg = ini.Empty()
-		sec, _ := setting.Cfg.NewSection("plugin.test-app")
-		sec.NewKey("path", "../../tests/test-app")
-		err := Init()
-
-		So(err, ShouldBeNil)
-
-		folderId := int64(1000)
+	pluginScenario("When importing a plugin dashboard", t, func() {
 		var importedDash *m.Dashboard
-		var createdFolder *m.Dashboard
-		bus.AddHandler("test", func(cmd *m.SaveDashboardCommand) error {
-			if cmd.IsFolder {
-				createdFolder = cmd.GetDashboardModel()
-				createdFolder.Id = folderId
-				cmd.Result = createdFolder
-			} else {
-				importedDash = cmd.GetDashboardModel()
-				cmd.Result = importedDash
-			}
-
-			return nil
-		})
-
-		bus.AddHandler("test", func(cmd *m.GetDashboardQuery) error {
-			return nil
-		})
-
-		cmd := ImportDashboardCommand{
-			PluginId: "test-app",
-			Path:     "dashboards/connections.json",
-			OrgId:    1,
-			UserId:   1,
-			Inputs: []ImportDashboardInput{
-				{Name: "*", Type: "datasource", Value: "graphite"},
-			},
-		}
-
-		err = ImportDashboard(&cmd)
-		So(err, ShouldBeNil)
-
-		Convey("should install dashboard", func() {
-			So(importedDash, ShouldNotBeNil)
-
-			resultStr, _ := importedDash.Data.EncodePretty()
-			expectedBytes, _ := ioutil.ReadFile("../../tests/test-app/dashboards/connections_result.json")
-			expectedJson, _ := simplejson.NewJson(expectedBytes)
-			expectedStr, _ := expectedJson.EncodePretty()
-
-			So(string(resultStr), ShouldEqual, string(expectedStr))
-
-			panel := importedDash.Data.Get("rows").GetIndex(0).Get("panels").GetIndex(0)
-			So(panel.Get("datasource").MustString(), ShouldEqual, "graphite")
-
-			So(importedDash.FolderId, ShouldEqual, folderId)
-		})
 
-		Convey("should create app folder", func() {
-			So(createdFolder.Title, ShouldEqual, "App: Test App")
-			So(createdFolder.Id, ShouldEqual, folderId)
-		})
-	})
-
-	Convey("When re-importing plugin dashboard", t, func() {
-		setting.Cfg = ini.Empty()
-		sec, _ := setting.Cfg.NewSection("plugin.test-app")
-		sec.NewKey("path", "../../tests/test-app")
-		err := Init()
-
-		So(err, ShouldBeNil)
-
-		folderId := int64(1000)
-		var importedDash *m.Dashboard
-		var createdFolder *m.Dashboard
 		bus.AddHandler("test", func(cmd *m.SaveDashboardCommand) error {
-			if cmd.IsFolder {
-				cmd.Result = cmd.GetDashboardModel()
-			} else {
-				importedDash = cmd.GetDashboardModel()
-				cmd.Result = importedDash
-			}
-
-			return nil
-		})
-
-		bus.AddHandler("test", func(cmd *m.GetDashboardQuery) error {
-			cmd.Result = &m.Dashboard{
-				Id:    1000,
-				Title: "Something",
-			}
-
+			importedDash = cmd.GetDashboardModel()
+			cmd.Result = importedDash
 			return nil
 		})
 
@@ -118,7 +32,7 @@ func TestDashboardImport(t *testing.T) {
 			},
 		}
 
-		err = ImportDashboard(&cmd)
+		err := ImportDashboard(&cmd)
 		So(err, ShouldBeNil)
 
 		Convey("should install dashboard", func() {
@@ -133,12 +47,6 @@ func TestDashboardImport(t *testing.T) {
 
 			panel := importedDash.Data.Get("rows").GetIndex(0).Get("panels").GetIndex(0)
 			So(panel.Get("datasource").MustString(), ShouldEqual, "graphite")
-
-			So(importedDash.FolderId, ShouldEqual, folderId)
-		})
-
-		Convey("should not create app folder", func() {
-			So(createdFolder, ShouldBeNil)
 		})
 	})
 
@@ -177,3 +85,16 @@ func TestDashboardImport(t *testing.T) {
 	})
 
 }
+
+func pluginScenario(desc string, t *testing.T, fn func()) {
+	Convey("Given a plugin", t, func() {
+		setting.Cfg = ini.Empty()
+		sec, _ := setting.Cfg.NewSection("plugin.test-app")
+		sec.NewKey("path", "../../tests/test-app")
+		err := Init()
+
+		So(err, ShouldBeNil)
+
+		Convey(desc, fn)
+	})
+}

+ 0 - 10
pkg/plugins/dashboards.go

@@ -108,13 +108,3 @@ func loadPluginDashboard(pluginId, path string) (*m.Dashboard, error) {
 
 	return m.NewDashboardFromJson(data), nil
 }
-
-func getPlugin(pluginId string) (*PluginBase, error) {
-	plugin, exists := Plugins[pluginId]
-
-	if !exists {
-		return nil, PluginNotFoundError{pluginId}
-	}
-
-	return plugin, nil
-}

+ 2 - 0
public/app/core/angular_wrappers.ts

@@ -1,8 +1,10 @@
 import { react2AngularDirective } from 'app/core/utils/react2angular';
 import { PasswordStrength } from './components/PasswordStrength';
+import PageHeader from './components/PageHeader';
 
 export function registerAngularDirectives() {
 
   react2AngularDirective('passwordStrength', PasswordStrength, ['password']);
+  react2AngularDirective('pageHeader', PageHeader, ['model', "noTabs"]);
 
 }

+ 72 - 0
public/app/core/components/PageHeader.tsx

@@ -0,0 +1,72 @@
+import React from 'react';
+import { NavModel, NavModelItem } from '../nav_model_srv';
+import classNames from 'classnames';
+
+export interface IProps {
+  model: NavModel;
+}
+
+function TabItem(tab: NavModelItem) {
+  if (tab.hideFromTabs) {
+    return (null);
+  }
+
+  let tabClasses = classNames({
+    'gf-tabs-link': true,
+    active: tab.active,
+  });
+
+  return (
+    <li className="gf-tabs-item" key={tab.url}>
+      <a className={tabClasses} href={tab.url}>
+        <i className={tab.icon} />
+        {tab.text}
+      </a>
+    </li>
+  );
+}
+
+function Tabs({main}: {main: NavModelItem}) {
+  return <ul className="gf-tabs">{main.children.map(TabItem)}</ul>;
+}
+
+export default class PageHeader extends React.Component<IProps, any> {
+  constructor(props) {
+    super(props);
+  }
+
+  renderHeaderTitle(main) {
+    return (
+      <div className="page-header__inner">
+        <span className="page-header__logo">
+          {main.icon && <i className={`page-header__icon ${main.icon}`} />}
+          {main.img && <img className="page-header__img" src={main.img} />}
+        </span>
+
+        <div className="page-header__info-block">
+          <h1 className="page-header__title">{main.text}</h1>
+          {main.subTitle && <div className="page-header__sub-title">{main.subTitle}</div>}
+          {main.subType && (
+            <div className="page-header__stamps">
+              <i className={main.subType.icon} />
+              {main.subType.text}
+            </div>
+          )}
+        </div>
+      </div>
+    );
+  }
+
+  render() {
+    return (
+      <div className="page-header-canvas">
+        <div className="page-container">
+          <div className="page-header">
+            {this.renderHeaderTitle(this.props.model.main)}
+            {this.props.model.main.children && <Tabs main={this.props.model.main} />}
+          </div>
+        </div>
+      </div>
+    );
+  }
+}

+ 10 - 0
public/app/core/components/grafana_app.ts

@@ -85,6 +85,16 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
         }
       });
 
+      let sidemenuOpenSmallBreakpoint = scope.contextSrv.sidemenuSmallBreakpoint;
+      body.toggleClass('sidemenu-open--xs', sidemenuOpenSmallBreakpoint);
+
+      scope.$watch('contextSrv.sidemenuSmallBreakpoint', newVal => {
+        if (sidemenuOpenSmallBreakpoint !== scope.contextSrv.sidemenuSmallBreakpoint) {
+          sidemenuOpenSmallBreakpoint = scope.contextSrv.sidemenuSmallBreakpoint;
+          body.toggleClass('sidemenu-open--xs', scope.contextSrv.sidemenuSmallBreakpoint);
+        }
+      });
+
       // tooltip removal fix
       // manage page classes
       var pageClass;

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

@@ -1,13 +1,11 @@
 <div class="page-nav">
-  <div class="container">
-    <div class="page-breadcrumbs">
-      <a class="breadcrumb-item active" href="/">
-        <i class="fa fa-home"></i>
-      </a>
-      <a class="breadcrumb-item" ng-href="{{::item.url}}" ng-repeat="item in ctrl.model.breadcrumbs">
-        {{::item.text}}
-      </a>
-    </div>
+  <div class="page-breadcrumbs">
+    <a class="breadcrumb-item active" href="/">
+      <i class="fa fa-home"></i>
+    </a>
+    <a class="breadcrumb-item" ng-href="{{::item.url}}" ng-repeat="item in ctrl.model.breadcrumbs">
+      {{::item.text}}
+    </a>
   </div>
 </div>
 

+ 4 - 4
public/app/core/components/navbar/navbar.ts

@@ -39,10 +39,10 @@ export function pageH1() {
   return {
     restrict: 'E',
     template: `
-    <h1>
-    <i class="{{::model.node.icon}}" ng-if="::model.node.icon"></i>
-    <img ng-src="{{::model.node.img}}" ng-if="::model.node.img"></i>
-    {{model.node.text}}
+    <h1 class="page-header__title">
+      <i class="page-header__icon {{::model.header.icon}}" ng-if="::model.header.icon"></i>
+      <img class="page-header__img" ng-src="{{::model.header.img}}" ng-if="::model.header.img"></i>
+      {{model.header.text}}
     </h1>
     `,
     scope: {

+ 8 - 0
public/app/core/components/scroll/scroll.ts

@@ -8,6 +8,14 @@ export function geminiScrollbar() {
 
       let scrollbar = new PerfectScrollbar(elem[0]);
 
+      scope.$on('$routeChangeSuccess', () => {
+        elem[0].scrollTop = 0;
+      });
+
+      scope.$on('$routeUpdate', () => {
+        elem[0].scrollTop = 0;
+      });
+
       scope.$on('$destroy', () => {
         scrollbar.destroy();
       });

+ 62 - 72
public/app/core/components/search/search.html

@@ -15,84 +15,74 @@
 						ng-blur="ctrl.searchInputBlur()"
 						/>
 
-		<div class="search-switches">
-			<i class="fa fa-filter"></i>
-			<a class="pointer" href="javascript:void 0;" ng-click="ctrl.showStarred()" tabindex="2">
-				<i class="fa fa-remove" ng-show="ctrl.query.starred"></i>
-				starred
-			</a> |
-			<a class="pointer" href="javascript:void 0;" ng-click="ctrl.getTags()" tabindex="3">
-				<i class="fa fa-remove" ng-show="ctrl.tagsMode"></i>
-				tags
-			</a>
-			<span ng-if="ctrl.query.tag.length">
-				|
-				<span ng-repeat="tagName in ctrl.query.tag">
-					<a ng-click="ctrl.removeTag(tagName, $event)" tag-color-from-name="tagName" class="label label-tag">
-						<i class="fa fa-remove"></i>
-						{{tagName}}
-					</a>
-				</span>
-			</span>
-		</div>
-
 		<div class="search-field-spacer"></div>
 	</div>
 
-	<div class="search-dropdown" ng-class="{'search-dropdown--fade-in': ctrl.openCompleted}">
-		<div class="search-results-container" ng-if="ctrl.tagsMode">
-			<div ng-repeat="tag in ctrl.results" class="pointer" style="width: 180px; float: left;"
-																												ng-class="{'selected': $index === ctrl.selectedIndex }"
-														ng-click="ctrl.filterByTag(tag.term, $event)">
-				<a class="search-result-tag label label-tag" tag-color-from-name="tag.term">
-					<i class="fa fa-tag"></i>
-					<span>{{tag.term}} &nbsp;({{tag.count}})</span>
-				</a>
-			</div>
-		</div>
-
-		<div class="search-results-container" ng-if="!ctrl.tagsMode" grafana-scrollbar>
-			<h6 ng-show="!ctrl.isLoading && results.length">No dashboards matching your query were found.</h6>
+	<div class="search-dropdown">
+    <div class="search-dropdown__col_1">
+      <div class="search-results-container" grafana-scrollbar>
+        <h6 ng-show="!ctrl.isLoading && results.length">No dashboards matching your query were found.</h6>
 
-			<div ng-repeat="section in ctrl.results" class="search-section">
-				<a class="search-section__header pointer" ng-hide="section.hideHeader" ng-click="ctrl.toggleFolder(section)">
-					<i class="search-section__header__icon" ng-class="section.icon"></i>
-					<span class="search-section__header__text">{{::section.title}}</span>
-					<i class="fa fa-minus search-section__header__toggle" ng-show="section.expanded"></i>
-					<i class="fa fa-plus search-section__header__toggle" ng-hide="section.expanded"></i>
-				</a>
+        <div ng-repeat="section in ctrl.results" class="search-section">
+          <a class="search-section__header pointer" ng-hide="section.hideHeader" ng-click="ctrl.toggleFolder(section)">
+            <i class="search-section__header__icon" ng-class="section.icon"></i>
+            <span class="search-section__header__text">{{::section.title}}</span>
+            <i class="fa fa-minus search-section__header__toggle" ng-show="section.expanded"></i>
+            <i class="fa fa-plus search-section__header__toggle" ng-hide="section.expanded"></i>
+          </a>
 
-				<div ng-if="section.expanded">
-					<a ng-repeat="item in section.items" class="search-item" ng-class="{'selected': item.selected}" ng-href="{{::item.url}}">
-						<span class="search-item__icon">
-							<i class="fa fa-th-large"></i>
-						</span>
-						<span class="search-item__body">
-							<div class="search-item__body-title">{{::item.title}}</div>
-							<div class="search-item__body-sub-title" ng-show="item.folderTitle && section.hideHeader">
-								{{::item.folderTitle}}
-							</div>
-						</span>
-						<span class="search-item__tags">
-							<span ng-click="ctrl.filterByTag(tag, $event)" ng-repeat="tag in item.tags" tag-color-from-name="tag"  class="label label-tag">
-								{{tag}}
-							</span>
-						</span>
-						<span class="search-item__actions">
-              <span class="search-item__actions__item" ng-click="ctrl.toggleStar()">
-                <i class="fa" ng-class="{'fa-star': item.isStarred, 'fa-star-o': !item.isStarred}"></i>
+          <div ng-if="section.expanded">
+            <a ng-repeat="item in section.items" class="search-item" ng-class="{'selected': item.selected}" ng-href="{{::item.url}}">
+              <span class="search-item__icon">
+                <i class="fa fa-th-large"></i>
+              </span>
+              <span class="search-item__body">
+                <div class="search-item__body-title">{{::item.title}}</div>
+                <div class="search-item__body-sub-title" ng-show="item.folderTitle && section.hideHeader">
+                  {{::item.folderTitle}}
+                </div>
+              </span>
+              <span class="search-item__tags">
+                <span ng-click="ctrl.filterByTag(tag, $event)" ng-repeat="tag in item.tags" tag-color-from-name="tag" class="label label-tag">
+                  {{tag}}
+                </span>
               </span>
-						</span>
-					</a>
-				</div>
-			</div>
-		</div>
+            </a>
+          </div>
+        </div>
+      </div>
+    </div>
 
-		<div class="search-button-row">
-			<a class="search-button-row-explore-link" target="_blank" href="https://grafana.com/dashboards?utm_source=grafana_search">
-				Find <img src="public/img/icn-dashboard-tiny.svg" width="14" /> dashboards on Grafana.com
-			</a>
-		</div>
-	</div>
+    <div class="search-dropdown__col_2">
+      <div class="search-filter-box">
+        <div class="search-filter-box__header">
+          <i class="fa fa-filter"></i>
+          Filter by:
+          <a class="pointer pull-right small">
+            <i class="fa fa-remove"></i> Clear
+          </a>
+        </div>
+
+        <div class="gf-form">
+          <folder-picker initial-title="ctrl.initialFolderFilterTitle"
+                         on-change="ctrl.onFolderChange($folder)"
+                         label-class="width-4">
+          </folder-picker>
+        </div>
+
+        <div class="gf-form">
+          <label class="gf-form-label width-4">Tags</label>
+          <bootstrap-tagsinput ng-model="ctrl.dashboard.tags" tagclass="label label-tag" placeholder="add tags">
+          </bootstrap-tagsinput>
+        </div>
+      </div>
+
+      <div class="search-filter-box">
+        <a class="search-button-row-explore-link" target="_blank" href="https://grafana.com/dashboards?utm_source=grafana_search">
+          <img src="public/img/icn-dashboard-tiny.svg" width="20" /> Find  dashboards on Grafana.com
+        </a>
+      </div>
+    </div>
+  </div>
 </div>
 

+ 3 - 22
public/app/core/components/search/search.ts

@@ -9,16 +9,18 @@ export class SearchCtrl {
   selectedIndex: number;
   results: any;
   currentSearchId: number;
-  tagsMode: boolean;
   showImport: boolean;
   dismiss: any;
   ignoreClose: any;
   isLoading: boolean;
+  initialFolderFilterTitle: string;
 
   /** @ngInject */
   constructor($scope, private $location, private $timeout, private searchSrv: SearchSrv, $rootScope) {
     $rootScope.onAppEvent('show-dash-search', this.openSearch.bind(this), $scope);
     $rootScope.onAppEvent('hide-dash-search', this.closeSearch.bind(this), $scope);
+
+    this.initialFolderFilterTitle = "All";
   }
 
   closeSearch() {
@@ -44,14 +46,6 @@ export class SearchCtrl {
       this.query.starred = true;
     }
 
-    if (payload && payload.tagsMode) {
-      return this.$timeout(() => {
-        this.ignoreClose = false;
-        this.giveSearchFocus = this.giveSearchFocus + 1;
-        this.getTags();
-      }, 100);
-    }
-
     this.$timeout(() => {
       this.ignoreClose = false;
       this.giveSearchFocus = this.giveSearchFocus + 1;
@@ -70,14 +64,6 @@ export class SearchCtrl {
       this.moveSelection(-1);
     }
     if (evt.keyCode === 13) {
-      if (this.tagsMode) {
-        var tag = this.results[this.selectedIndex];
-        if (tag) {
-          this.filterByTag(tag.term, null);
-        }
-        return;
-      }
-
       var selectedDash = this.results[this.selectedIndex];
       if (selectedDash) {
         this.$location.search({});
@@ -93,7 +79,6 @@ export class SearchCtrl {
   }
 
   searchDashboards() {
-    this.tagsMode = false;
     this.currentSearchId = this.currentSearchId + 1;
     var localSearchId = this.currentSearchId;
 
@@ -129,12 +114,8 @@ export class SearchCtrl {
 
   getTags() {
     return this.searchSrv.getDashboardTags().then((results) => {
-      this.tagsMode = !this.tagsMode;
       this.results = results;
       this.giveSearchFocus = this.giveSearchFocus + 1;
-      if ( !this.tagsMode ) {
-        this.search();
-      }
     });
   }
 

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

@@ -2,6 +2,12 @@
 	<img src="public/img/grafana_icon.svg"></img>
 </a>
 
+<a class="sidemenu__logo_small_breakpoint" ng-click="ctrl.toggleSideMenuSmallBreakpoint()">
+  <img src="public/img/grafana_icon.svg"></img>
+  <p class="sidemenu__close"><i class="fa fa-times"></i>&nbsp;Close</p>
+</a>
+
+
 <div class="sidemenu__top">
 	<div ng-repeat="item in ::ctrl.mainLinks" class="sidemenu-item dropdown">
 		<a href="{{::item.url}}" class="sidemenu-link" target="{{::item.target}}">

+ 10 - 0
public/app/core/components/sidemenu/sidemenu.ts

@@ -11,6 +11,7 @@ export class SideMenuCtrl {
   bottomNav: any;
   loginUrl: string;
   isSignedIn: boolean;
+  smallBPSideMenuOpen = false;
 
   /** @ngInject */
   constructor(private $scope, private $rootScope, private $location, private contextSrv, private $timeout) {
@@ -28,6 +29,10 @@ export class SideMenuCtrl {
     }
 
     this.$scope.$on('$routeChangeSuccess', () => {
+      if (this.smallBPSideMenuOpen) {
+        this.contextSrv.setSideMenuForSmallBreakpoint(false, true);
+        this.smallBPSideMenuOpen = false;
+      }
       this.loginUrl = 'login?redirect=' + encodeURIComponent(this.$location.path());
     });
   }
@@ -39,6 +44,11 @@ export class SideMenuCtrl {
     });
   }
 
+  toggleSideMenuSmallBreakpoint() {
+    this.smallBPSideMenuOpen = !this.smallBPSideMenuOpen;
+    this.contextSrv.setSideMenuForSmallBreakpoint(this.smallBPSideMenuOpen, false);
+  }
+
   switchOrg() {
     this.$rootScope.appEvent('show-modal', {
       templateHtml: '<org-switcher dismiss="dismiss()"></org-switcher>',

+ 33 - 8
public/app/core/nav_model_srv.ts

@@ -1,19 +1,27 @@
-///<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;
+  text: string;
   url: string;
   icon?: string;
-  iconUrl?: string;
+  img?: string;
+  id: string;
+  active?: boolean;
+  hideFromTabs?: boolean;
+  divider?: boolean;
+  children: NavModelItem[];
 }
 
-export interface NavModel {
-  section: NavModelItem;
-  menu: NavModelItem[];
+export class NavModel {
+  breadcrumbs: NavModelItem[];
+  main: NavModelItem;
+  node: NavModelItem;
+
+  constructor() {
+    this.breadcrumbs = [];
+  }
 }
 
 export class NavModelSrv {
@@ -31,15 +39,32 @@ export class NavModelSrv {
 
   getNav(...args) {
     var children = this.navItems;
-    var nav = {breadcrumbs: [], node: null};
+    var nav = new NavModel();
 
     for (let id of args) {
+      // if its a number then it's the index to use for main
+      if (_.isNumber(id)) {
+        nav.main = nav.breadcrumbs[id];
+        break;
+      }
+
       let node = _.find(children, {id: id});
       nav.breadcrumbs.push(node);
       nav.node = node;
+      nav.main = node;
       children = node.children;
     }
 
+    if (nav.main.children) {
+      for (let item of nav.main.children) {
+        item.active = false;
+
+        if (item.url === nav.node.url) {
+          item.active = true;
+        }
+      }
+    }
+
     return nav;
   }
 

+ 4 - 5
public/app/core/routes/dashboard_loaders.ts

@@ -36,12 +36,11 @@ export class NewDashboardCtrl {
       meta: { canStar: false, canShare: false, isNew: true },
       dashboard: {
         title: "New dashboard",
-        rows: [
+        panels: [
           {
-            title: 'Dashboard Row',
-            height: '350px',
-            panels: [],
-            isNew: true,
+            type: 'add-panel',
+            gridPos: {x: 0, y: 0, w: 12, h: 9},
+            title: 'Panel Title',
           }
         ]
       },

+ 0 - 6
public/app/core/routes/routes.ts

@@ -48,12 +48,6 @@ function setupAngularRoutes($routeProvider, $locationProvider) {
     reloadOnSearch: false,
     pageClass: 'page-dashboard',
   })
-  .when('/configuration', {
-    templateUrl: 'public/app/features/admin/partials/configuration_home.html',
-    controller : 'ConfigurationHomeCtrl',
-    controllerAs: 'ctrl',
-    resolve: loadAdminBundle,
-  })
   .when('/datasources', {
     templateUrl: 'public/app/features/plugins/partials/ds_list.html',
     controller : 'DataSourcesCtrl',

+ 7 - 2
public/app/core/services/context_srv.ts

@@ -27,9 +27,10 @@ export class ContextSrv {
   isGrafanaAdmin: any;
   isEditor: any;
   sidemenu: any;
+  sidemenuSmallBreakpoint = false;
 
   constructor() {
-    this.sidemenu = store.getBool('grafana.sidemenu', false);
+    this.sidemenu = store.getBool('grafana.sidemenu', true);
 
     if (!config.buildInfo) {
       config.buildInfo = {};
@@ -55,7 +56,11 @@ export class ContextSrv {
 
   toggleSideMenu() {
     this.sidemenu = !this.sidemenu;
-    store.set('grafana.sidemenu',this.sidemenu);
+    store.set('grafana.sidemenu', this.sidemenu);
+  }
+
+  setSideMenuForSmallBreakpoint(show: boolean, persistToggle: boolean) {
+    this.sidemenuSmallBreakpoint = show;
   }
 }
 

+ 3 - 13
public/app/features/admin/admin.ts

@@ -10,7 +10,7 @@ class AdminSettingsCtrl {
 
   /** @ngInject **/
   constructor($scope, backendSrv, navModelSrv) {
-    this.navModel = navModelSrv.getNav('cfg', 'admin', 'server-settings');
+    this.navModel = navModelSrv.getNav('cfg', 'admin', 'server-settings', 1);
 
     backendSrv.get('/api/admin/settings').then(function(settings) {
       $scope.settings = settings;
@@ -24,7 +24,7 @@ class AdminHomeCtrl {
 
   /** @ngInject **/
   constructor(navModelSrv) {
-    this.navModel = navModelSrv.getNav('cfg', 'admin');
+    this.navModel = navModelSrv.getNav('cfg', 'admin', 1);
   }
 }
 
@@ -34,7 +34,7 @@ export class AdminStatsCtrl {
 
   /** @ngInject */
   constructor(backendSrv: any, navModelSrv) {
-    this.navModel = navModelSrv.getNav('cfg', 'admin', 'server-stats');
+    this.navModel = navModelSrv.getNav('cfg', 'admin', 'server-stats', 1);
 
     backendSrv.get('/api/admin/stats').then(stats => {
       this.stats = stats;
@@ -42,16 +42,6 @@ export class AdminStatsCtrl {
   }
 }
 
-export class ConfigurationHomeCtrl {
-  navModel: any;
-
-  /** @ngInject */
-  constructor(navModelSrv) {
-    this.navModel = navModelSrv.getNav('cfg');
-  }
-}
-
-coreModule.controller('ConfigurationHomeCtrl', ConfigurationHomeCtrl);
 coreModule.controller('AdminSettingsCtrl', AdminSettingsCtrl);
 coreModule.controller('AdminHomeCtrl', AdminHomeCtrl);
 coreModule.controller('AdminStatsCtrl', AdminStatsCtrl);

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

@@ -5,7 +5,7 @@ export class AdminEditOrgCtrl {
   /** @ngInject */
   constructor($scope, $routeParams, backendSrv, $location, navModelSrv) {
     $scope.init = function() {
-      $scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs');
+      $scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs', 1);
 
       if ($routeParams.id) {
         $scope.getOrg($routeParams.id);

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

@@ -8,7 +8,7 @@ export class AdminEditUserCtrl {
     $scope.user = {};
     $scope.newOrg = { name: '', role: 'Editor' };
     $scope.permissions = {};
-    $scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-users');
+    $scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-users', 1);
 
     $scope.init = function() {
       if ($routeParams.id) {

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

@@ -5,7 +5,7 @@ export class AdminListOrgsCtrl {
   /** @ngInject */
   constructor($scope, backendSrv, navModelSrv) {
     $scope.init = function() {
-      $scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs');
+      $scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs', 1);
       $scope.getOrgs();
     };
 

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

@@ -10,7 +10,7 @@ export default class AdminListUsersCtrl {
 
   /** @ngInject */
   constructor(private $scope, private backendSrv, navModelSrv) {
-    this.navModel = navModelSrv.getNav('cfg', 'admin', 'global-users');
+    this.navModel = navModelSrv.getNav('cfg', 'admin', 'global-users', 1);
     this.query = '';
     this.getUsers();
   }

+ 6 - 30
public/app/features/admin/partials/admin_home.html

@@ -1,35 +1,11 @@
-<navbar model="ctrl.navModel"></navbar>
+<page-header model="ctrl.navModel"></page-header>
 
-<div class="page-container">
-	<div class="page-header">
-		<page-h1 model="ctrl.navModel"></page-h1>
-	</div>
+<div class="page-container page-body">
 
-	<section class="card-section card-list-layout-grid">
-		<ol class="card-list" >
-			<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">
-						</div>
-					</div>
-					<div class="card-item-body">
-						<figure class="card-item-figure">
-							<i class="{{navItem.icon}}"></i>
-						</figure>
-						<div class="card-item-details">
-							<div class="card-item-name">
-								{{navItem.text}}
-							</div>
-							<div class="card-item-sub-name">
-								{{navItem.description}}
-							</div>
-						</div>
-					</div>
-				</a>
-			</li>
-		</ol>
-	</section>
+  <div class="grafana-info-box span8">
+    Grafana is a multi-tenant system where most can be configured per organization. These
+    admin pages are for server admins where you can manage orgs, & all users across all orgs.
+  </div>
 
 </div>
 

+ 0 - 33
public/app/features/admin/partials/configuration_home.html

@@ -1,33 +0,0 @@
-<div class="scroll-canvas" grafana-scrollbar>
-	<navbar model="ctrl.navModel"></navbar>
-	<div class="page-container">
-		<div class="page-header">
-			<page-h1 model="ctrl.navModel"></page-h1>
-		</div>
-
-		<section class="card-section card-list-layout-grid">
-			<ol class="card-list" >
-				<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">
-							</div>
-						</div>
-						<div class="card-item-body">
-							<figure class="card-item-figure">
-								<i class="{{navItem.icon}}"></i>
-							</figure>
-							<div class="card-item-details">
-								<div class="card-item-name">
-									{{navItem.text}}
-								</div>
-								<div class="card-item-sub-name">
-									{{navItem.description}}
-								</div>
-							</div>
-						</div>
-					</a>
-				</li>
-			</ol>
-		</section>
-	</div>

+ 3 - 5
public/app/features/admin/partials/edit_org.html

@@ -1,9 +1,7 @@
-<navbar model="navModel"></navbar>
+<page-header model="navModel"></page-header>
 
-<div class="page-container">
-	<div class="page-header">
-		<h1>Edit Organization</h1>
-	</div>
+<div class="page-container page-body">
+	<h2 class="page-sub-heading">Edit Organization</h2>
 
 	<form name="orgDetailsForm" class="gf-form-group">
 		<div class="gf-form">

+ 14 - 11
public/app/features/admin/partials/edit_user.html

@@ -1,8 +1,9 @@
-<navbar model="navModel"></navbar>
+<page-header model="navModel"></page-header>
 
-<div class="page-container">
-	<div class="page-header">
-		<h1>Edit User</h1>
+<div class="page-container page-body">
+
+	<div class="page-sub-heading">
+		<h2>Edit User</h2>
 	</div>
 
 	<form name="userForm" class="gf-form-group">
@@ -54,7 +55,7 @@
 	<form name="addOrgForm" class="gf-form-group">
 		<div class="gf-form-inline">
 			<div class="gf-form">
-				<span class="gf-form-label width-12">Add organization</span>
+				<span class="gf-form-label">Add</span>
 				<input type="text" ng-model="newOrg.name" bs-typeahead="searchOrgs"	required class="gf-form-input max-width-20" placeholder="organization name">
 			</div>
 			<div class="gf-form">
@@ -67,12 +68,14 @@
 		</div>
 	</form>
 
-	<table class="grafana-options-table">
-		<tr>
-			<th>Name</th>
-			<th>Role</th>
-			<th></th>
-		</tr>
+	<table class="filter-table">
+		<thead>
+			<tr>
+				<th>Name</th>
+				<th>Role</th>
+				<th></th>
+			</tr>
+		</thead>
 		<tr ng-repeat="org in orgs">
 			<td>
 				{{org.name}} <span class="label label-info" ng-show="org.orgId === user.orgId">Current</span>

+ 3 - 3
public/app/features/admin/partials/new_user.html

@@ -1,7 +1,7 @@
-<navbar model="navModel"></navbar>
+<page-header model="navModel"></page-header>
 
-<div class="page-container">
-	<div class="page-header">
+<div class="page-container page-body">
+	<div class="page-sub-heading">
 		<h1>Add new user</h1>
 	</div>
 

+ 8 - 4
public/app/features/admin/partials/orgs.html

@@ -1,8 +1,12 @@
-<navbar model="navModel"></navbar>
+<page-header model="navModel"></page-header>
 
-<div class="page-container">
-	<div class="page-header">
-		<h1>Organizations</h1>
+<div class="page-container page-body">
+	<div class="page-action-bar">
+    <div class="page-action-bar__spacer"></div>
+    <a class="page-header__cta btn btn-success" href="org/new">
+      <i class="fa fa-plus"></i>
+      New Org
+    </a>
 	</div>
 
 	<table class="filter-table form-inline">

+ 16 - 19
public/app/features/admin/partials/settings.html

@@ -1,25 +1,22 @@
-<navbar model="ctrl.navModel"></navbar>
+<page-header model="ctrl.navModel"></page-header>
 
-<div class="page-container">
-	<div class="page-header">
-		<h1>Server settings</h1>
-	</div>
+<div class="page-container page-body">
 
-		<div class="grafana-info-box span8" style="margin: 20px 0 25px 0">
-			These system settings are defined in grafana.ini or custom.ini (or overridden in ENV variables).
-			To change these you currently need to restart grafana.
-		</div>
+	<div class="grafana-info-box span8" style="margin: 20px 0 25px 0">
+		These system settings are defined in grafana.ini or custom.ini (or overridden in ENV variables).
+		To change these you currently need to restart grafana.
+	</div>
 
-		<table class="grafana-options-table">
-			<tr ng-repeat-start="(secName, secValue) in settings">
-				<td class="admin-settings-section">{{secName}}</td>
-				<td></td>
-			</tr>
-			<tr ng-repeat="(keyName, keyValue) in secValue" ng-repeat-end>
-				<td style="padding-left: 25px;">{{keyName}}</td>
-				<td>{{keyValue}}</td>
-			</tr>
-		</table>
+	<table class="filter-table">
+		<tr ng-repeat-start="(secName, secValue) in settings">
+			<td class="admin-settings-section">{{secName}}</td>
+			<td></td>
+		</tr>
+		<tr ng-repeat="(keyName, keyValue) in secValue" ng-repeat-end>
+			<td style="padding-left: 25px;">{{keyName}}</td>
+			<td>{{keyValue}}</td>
+		</tr>
+	</table>
 </div>
 
 

+ 2 - 6
public/app/features/admin/partials/stats.html

@@ -1,10 +1,6 @@
-<navbar model="ctrl.navModel"></navbar>
-
-<div class="page-container">
-	<div class="page-header">
-		<h1>Stats</h1>
-	</div>
+<page-header model="ctrl.navModel"></page-header>
 
+<div class="page-container page-body">
 	<table class="filter-table form-inline">
 		<thead>
 			<tr>

+ 8 - 12
public/app/features/admin/partials/users.html

@@ -1,22 +1,18 @@
-<navbar model="ctrl.navModel"></navbar>
-
-<div class="page-container">
-  <div class="page-header">
-    <h1>Users</h1>
+<page-header model="ctrl.navModel"></page-header>
 
+<div class="page-container page-body">
+	<div class="page-action-bar">
+		<div class="gf-form">
+			<label class="gf-form-label">Search</label>
+			<input class="gf-form-input width-15" type="text" placeholder="Find user by name/login/email" tabindex="1" give-focus="true" ng-model="ctrl.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.getUsers()" />
+		</div>
+		<div class="page-action-bar__spacer"></div>
     <a class="btn btn-success" href="admin/users/create">
       <i class="fa fa-plus"></i>
       Add new user
     </a>
   </div>
 
-  <div class="gf-form pull-right gf-form-group">
-		<label class="gf-form-label">Search</label>
-    <span style="position: relative;">
-      <input class="gf-form-input width-15" type="text" placeholder="Find user by name/login/email" tabindex="1" give-focus="true" ng-model="ctrl.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.getUsers()" />
-    </span>
-  </div>
-
   <div class="admin-list-table">
     <table class="filter-table form-inline">
       <thead>

+ 1 - 1
public/app/features/alerting/alert_list_ctrl.ts

@@ -23,7 +23,7 @@ export class AlertListCtrl {
 
   /** @ngInject */
   constructor(private backendSrv, private $location, navModelSrv) {
-    this.navModel = navModelSrv.getNav('alerting');
+    this.navModel = navModelSrv.getNav('alerting', 'alert-list', 0);
 
     var params = $location.search();
     this.filters.state = params.state || null;

+ 3 - 2
public/app/features/alerting/notification_edit_ctrl.ts

@@ -9,7 +9,7 @@ export class AlertNotificationEditCtrl {
   testSeverity = "critical";
   notifiers: any;
   notifierTemplateId: string;
-
+  isNew: boolean;
   model: any;
   defaults: any = {
     type: 'email',
@@ -23,7 +23,8 @@ export class AlertNotificationEditCtrl {
 
   /** @ngInject */
   constructor(private $routeParams, private backendSrv, private $location, private $templateCache, navModelSrv) {
-    this.navModel = navModelSrv.getNav('alerting', 'channels');
+    this.navModel = navModelSrv.getNav('alerting', 'channels', 0);
+    this.isNew = !this.$routeParams.id;
 
     this.backendSrv.get(`/api/alert-notifiers`).then(notifiers => {
       this.notifiers = notifiers;

+ 1 - 1
public/app/features/alerting/notifications_list_ctrl.ts

@@ -9,7 +9,7 @@ export class AlertNotificationsListCtrl {
   /** @ngInject */
   constructor(private backendSrv, navModelSrv) {
     this.loadNotifications();
-    this.navModel = navModelSrv.getNav('alerting', 'channels');
+    this.navModel = navModelSrv.getNav('alerting', 'channels', 0);
   }
 
   loadNotifications() {

+ 16 - 22
public/app/features/alerting/partials/alert_list.html

@@ -1,29 +1,23 @@
-<navbar model="ctrl.navModel"></navbar>
+<page-header model="ctrl.navModel"></page-header>
 
-<div class="page-container" >
-	<div class="page-header">
-    <page-h1 model="ctrl.navModel"></page-h1>
+<div class="page-container page-body">
 
-    <a class="btn btn-secondary" ng-click="ctrl.openHowTo()">
-			<i class="fa fa-info-circle"></i>
-			How to add an alert
-		</a>
-    <a class="btn btn-inverse" href="alerting/notifications" >
-			<i class="fa fa-bell"></i>
-			Notification channels
-		</a>
-	</div>
-
-  <div class="gf-form-group">
-    <div class="gf-form-inline">
-      <div class="gf-form">
-        <label class="gf-form-label">Filter by state</label>
-        <div class="gf-form-select-wrapper width-13">
-          <select class="gf-form-input" ng-model="ctrl.filters.state" ng-options="f.value as f.text for f in ctrl.stateFilters" ng-change="ctrl.filtersChanged()">
-          </select>
-        </div>
+  <div class="page-action-bar">
+    <div class="gf-form">
+      <label class="gf-form-label">Filter by state</label>
+      <div class="gf-form-select-wrapper width-13">
+        <select class="gf-form-input" ng-model="ctrl.filters.state" ng-options="f.value as f.text for f in ctrl.stateFilters" ng-change="ctrl.filtersChanged()">
+        </select>
       </div>
     </div>
+
+    <div class="page-action-bar__spacer">
+    </div>
+
+    <a class="btn btn-secondary" ng-click="ctrl.openHowTo()">
+      <i class="fa fa-info-circle"></i>
+      How to add an alert
+    </a>
   </div>
 
   <section class="card-section card-list-layout-list">

+ 5 - 5
public/app/features/alerting/partials/notification_edit.html

@@ -1,9 +1,9 @@
-<navbar model="ctrl.navModel"></navbar>
+<page-header model="ctrl.navModel"></page-header>
 
-<div class="page-container">
-  <div class="page-header">
-    <page-h1 model="ctrl.navModel"></page-h1>
-  </div>
+<div class="page-container page-body">
+
+  <h3 class="page-sub-heading" ng-hide="ctrl.isNew">Edit Notification Channel</h3>
+  <h3 class="page-sub-heading" ng-show="ctrl.isNew">New Notification Channel</h3>
 
   <form name="ctrl.theForm" ng-if="ctrl.notifiers">
     <div class="gf-form-group">

+ 7 - 5
public/app/features/alerting/partials/notifications_list.html

@@ -1,10 +1,12 @@
-<navbar model="ctrl.navModel"></navbar>
+<page-header model="ctrl.navModel"></page-header>
 
-<div class="page-container" >
-	<div class="page-header">
-    <page-h1 model="ctrl.navModel"></page-h1>
+<div class="page-container page-body">
+	<div class="page-action-bar">
+    <div class="page-action-bar__spacer">
+    </div>
 
-    <a href="alerting/notification/new" class="btn btn-success pull-right">
+    <a href="alerting/notification/new" class="btn btn-success">
+      <i class="fa fa-plus"></i>
       New Channel
     </a>
   </div>

+ 1 - 1
public/app/features/dashboard/dashboard_list_ctrl.ts

@@ -17,7 +17,7 @@ export class DashboardListCtrl {
 
   /** @ngInject */
   constructor(private backendSrv, navModelSrv, private $q, private searchSrv: SearchSrv) {
-    this.navModel = navModelSrv.getNav('dashboards', 'dashboards');
+    this.navModel = navModelSrv.getNav('dashboards', 'dashboards', 0);
     this.query = {query: '', mode: 'tree', tag: [], starred: false};
     this.selectedStarredFilter = this.starredFilterOptions[0];
 

+ 11 - 1
public/app/features/dashboard/dashgrid/AddPanelPanel.tsx

@@ -72,8 +72,18 @@ export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelP
   render() {
     return (
       <div className="panel-container">
-        <div className="add-panel">{this.state.panelPlugins.map(this.renderPanelItem.bind(this))}</div>
+        <div className="add-panel">
+          <div className="add-panel__header">
+            <i className="gicon gicon-add-panel"></i>
+            <span className="add-panel__title">New Panel</span>
+            <span className="add-panel__sub-title">Select a visualization</span>
+          </div>
+          <div className="add-panel__items">
+            {this.state.panelPlugins.map(this.renderPanelItem.bind(this))}
+          </div>
+        </div>
       </div>
     );
   }
 }
+

+ 49 - 78
public/app/features/dashboard/dashnav/dashnav.html

@@ -1,95 +1,66 @@
 <div class="navbar">
-	<div class="navbar-inner">
+
+	<div>
 		<a class="navbar-page-btn" ng-click="ctrl.showSearch()">
 			<i class="gicon gicon-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>
+		<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 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 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>
+	<div class="navbar__spacer"></div>
 
-			<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>
+	<div class="navbar-buttons navbar-buttons--actions">
+		<button class="btn navbar-button navbar-button--add-panel" ng-show="::ctrl.dashboard.meta.canSave" bs-tooltip="'Add panel'" data-placement="bottom" ng-click="ctrl.addPanel()">
+			<i class="gicon gicon-add-panel"></i>
+		</button>
 
-			<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>
-				</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>
-			<li class="navbar-mini-btn-wrapper" ng-show="::ctrl.dashboard.meta.canSave">
-				<button class="btn btn-secondary btn-mini" ng-click="ctrl.addPanel()">
-					<i class="fa fa-plus-circle"></i> Add Panel
-				</button>
-			</li>
-		</ul>
+		<button class="btn navbar-button" 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>
 
-		<div class="nav nav--grow">
-		</div>
+		<button class="btn navbar-button" 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>
+		</button>
+
+		<button class="btn navbar-button" 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>
 
-		<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 ng-if="!ctrl.dashboard.timepicker.hidden">
-				<gf-time-picker dashboard="ctrl.dashboard"></gf-time-picker>
-			</li>
-		</ul>
+		<button class="btn navbar-button" ng-if="::ctrl.dashboard.snapshot.originalUrl" ng-href="{{ctrl.dashboard.snapshot.originalUrl}}" bs-tooltip="'Open original dashboard'" data-placement="bottom">
+			<i class="fa fa-link"></i>
+		</button>
+
+		<div class="dropdown">
+			<button class="btn navbar-button" data-toggle="dropdown" bs-tooltip="'Settings'" data-placement="bottom">
+				<i class="fa fa-cog"></i>
+			</button>
+
+			<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>
+		</div>
 	</div>
 
+	<gf-time-picker class="gf-timepicker-nav" dashboard="ctrl.dashboard" ng-if="!ctrl.dashboard.timepicker.hidden"></gf-time-picker>
+
 </div>
 
 <dashboard-search></dashboard-search>

+ 1 - 1
public/app/features/dashboard/dashnav/dashnav.ts

@@ -150,7 +150,7 @@ export class DashNavCtrl {
       this.dashboard.addPanel({
         type: 'add-panel',
         gridPos: {x: 0, y: 0, w: 12, h: 9},
-        title: 'New Graph',
+        title: 'Panel Title',
       });
     }
 

+ 114 - 146
public/app/features/dashboard/partials/dashboardList.html

@@ -1,163 +1,131 @@
-<div class="scroll-canvas" grafana-scrollbar>
-  <navbar model="ctrl.navModel"></navbar>
-  <div class="page-container" style="height: 95%">
-    <div class="page-header">
-      <h1>Dashboards</h1>
+<page-header model="ctrl.navModel"></page-header>
 
-      <a class="btn btn-inverse" href="/dashboard/new">
-        <i class="gicon gicon-dashboard-new"></i>
-        Dashboard
-      </a>
-      <a class="btn btn-inverse" href="/dashboard/new/?editview=new-folder">
-        <i class="gicon gicon-folder-new"></i>
-        Folder
-      </a>
-    </div>
-    <div class="gf-form-group">
-      <div class="gf-form width-15">
-        <span style="position: relative;">
-          <input type="text" class="gf-form-input" placeholder="Find Dashboard by name" tabindex="1" give-focus="true"
-            ng-model="ctrl.query.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.onQueryChange()" />
-        </span>
-      </div>
+<div class="page-container page-body">
+  <div class="page-action-bar">
+    <div class="gf-form gf-form--grow">
+      <label class="gf-form-label">Search</label>
+      <input type="text" class="gf-form-input max-width-30" placeholder="Find Dashboard by name" tabindex="1" give-focus="true" ng-model="ctrl.query.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.onQueryChange()" />
     </div>
+    <div class="page-action-bar__spacer"></div>
+    <a class="btn btn-success" href="/dashboard/new">
+      <i class="fa fa-plus"></i>
+      Dashboard
+    </a>
+    <a class="btn btn-success" href="/dashboard/new/?editview=new-folder">
+      <i class="fa fa-plus"></i>
+      Folder
+    </a>
+  </div>
 
-    <div class="gf-form" ng-if="ctrl.query.tag.length">
-      Filters:
-      <span ng-repeat="tagName in ctrl.query.tag">
-        <a ng-click="ctrl.removeTag(tagName, $event)" tag-color-from-name="tagName" class="label label-tag">
-          <i class="fa fa-remove"></i>
-          {{tagName}}
-        </a>
-      </span>
-    </div>
+  <div class="gf-form" ng-if="ctrl.query.tag.length">
+    Filters:
+    <span ng-repeat="tagName in ctrl.query.tag">
+      <a ng-click="ctrl.removeTag(tagName, $event)" tag-color-from-name="tagName" class="label label-tag">
+        <i class="fa fa-remove"></i>
+        {{tagName}}
+      </a>
+    </span>
+  </div>
 
-    <div class="gf-form">
-        <div class="gf-form-button-row"
-          ng-show="ctrl.hasFilters">
-          <button
-            type="button"
-            class="btn gf-form-button btn-inverse btn-small"
-            ng-click="ctrl.clearFilters()">
-            <i class="fa fa-close"></i> Clear current search query and filters
-        </button>
-        </div>
+  <div class="gf-form">
+      <div class="gf-form-button-row"
+        ng-show="ctrl.hasFilters">
+        <button
+          type="button"
+          class="btn gf-form-button btn-inverse btn-small"
+          ng-click="ctrl.clearFilters()">
+          <i class="fa fa-close"></i> Clear current search query and filters
+      </button>
+      </div>
+  </div>
+
+  <div class="gf-form-group">
+    <div class="gf-form-button-row">
+      <button	type="button"
+          class="btn gf-form-button btn-secondary"
+          ng-disabled="!ctrl.canMove"
+          ng-click="ctrl.moveTo()"
+          bs-tooltip="ctrl.canMove ? '' : 'Select a dashboard to move (cannot move folders)'" data-placement="bottom">
+        <i class="fa fa-exchange"></i>&nbsp;&nbsp;Move to...
+      </button>
+      <button  type="button"
+          class="btn gf-form-button btn-inverse"
+          ng-click="ctrl.delete()"
+          ng-disabled="!ctrl.canDelete">
+          <i class="fa fa-trash"></i>&nbsp;&nbsp;Delete
+      </button>
     </div>
+  </div>
 
-    <div class="gf-form-group">
-      <div class="gf-form-button-row">
-        <button	type="button"
-            class="btn gf-form-button btn-secondary"
-            ng-disabled="!ctrl.canMove"
-            ng-click="ctrl.moveTo()"
-            bs-tooltip="ctrl.canMove ? '' : 'Select a dashboard to move (cannot move folders)'" data-placement="bottom">
-          <i class="fa fa-exchange"></i>&nbsp;&nbsp;Move to...
-        </button>
-        <button  type="button"
-            class="btn gf-form-button btn-inverse"
-            ng-click="ctrl.delete()"
-            ng-disabled="!ctrl.canDelete">
-            <i class="fa fa-trash"></i>&nbsp;&nbsp;Delete
-        </button>
+  <div class="dashboard-list">
+    <div class="search-results-filter-row">
+      <gf-form-switch
+        on-change="ctrl.onSelectAllChanged()"
+        checked="ctrl.selectAllChecked"
+      />
+      <div class="search-results-filter-row__filters">
+        <select
+          class="search-results-filter-row__filters-item gf-form-input"
+          ng-model="ctrl.selectedStarredFilter"
+          ng-options="t.text disable when t.disabled for t in ctrl.starredFilterOptions"
+          ng-change="ctrl.onStarredFilterChange()"
+        />
+        <select
+          class="search-results-filter-row__filters-item gf-form-input"
+          ng-model="ctrl.selectedTagFilter"
+          ng-options="t.term disable when t.disabled for t in ctrl.tagFilterOptions"
+          ng-change="ctrl.onTagFilterChange()"
+        />
       </div>
     </div>
+    <div class="search-results-container" ng-show="ctrl.sections.length > 0" grafana-scrollbar>
+      <div ng-repeat="section in ctrl.sections" class="search-section">
 
-      <div class="dashboard-list">
-        <div class="search-results-filter-row">
-            <gf-form-switch
-              on-change="ctrl.onSelectAllChanged()"
-              checked="ctrl.selectAllChecked"
-            />
-          <div class="search-results-filter-row__filters">
-            <select
-              class="search-results-filter-row__filters-item gf-form-input"
-              ng-model="ctrl.selectedStarredFilter"
-              ng-options="t.text disable when t.disabled for t in ctrl.starredFilterOptions"
-              ng-change="ctrl.onStarredFilterChange()"
-            />
-            <select
-              class="search-results-filter-row__filters-item gf-form-input"
-              ng-model="ctrl.selectedTagFilter"
-              ng-options="t.term disable when t.disabled for t in ctrl.tagFilterOptions"
-              ng-change="ctrl.onTagFilterChange()"
-            />
-          </div>
+        <div class="search-section__header__with-checkbox" ng-hide="section.hideHeader">
+          <gf-form-switch
+            on-change="ctrl.selectionChanged()"
+            checked="section.checked">
+          </gf-form-switch>
+          <a  class="search-section__header pointer" ng-click="ctrl.toggleFolder(section)" ng-hide="section.hideHeader">
+            <i class="search-section__header__icon" ng-class="section.icon"></i>
+            <span class="search-section__header__text">{{::section.title}}</span>
+            <i class="fa fa-minus search-section__header__toggle" ng-show="section.expanded"></i>
+            <i class="fa fa-plus search-section__header__toggle" ng-hide="section.expanded"></i>
+          </a>
         </div>
-        <div class="search-results-container" ng-show="ctrl.sections.length > 0" grafana-scrollbar>
-          <div ng-repeat="section in ctrl.sections" class="search-section">
-
-            <div class="search-section__header__with-checkbox" ng-hide="section.hideHeader">
-              <gf-form-switch
-                on-change="ctrl.selectionChanged()"
-                checked="section.checked">
-              </gf-form-switch>
-              <a  class="search-section__header pointer" ng-click="ctrl.toggleFolder(section)" ng-hide="section.hideHeader">
-                <i class="search-section__header__icon" ng-class="section.icon"></i>
-                <span class="search-section__header__text">{{::section.title}}</span>
-                <i class="fa fa-minus search-section__header__toggle" ng-show="section.expanded"></i>
-                <i class="fa fa-plus search-section__header__toggle" ng-hide="section.expanded"></i>
-              </a>
-            </div>
 
-            <div ng-if="section.expanded">
-              <div ng-repeat="item in section.items" class="search-item__with-checkbox" ng-class="{'selected': item.selected}">
-                <gf-form-switch
-                  on-change="ctrl.selectionChanged()"
-                  checked="item.checked" />
-                <a ng-href="{{::item.url}}" class="search-item">
-                  <span class="search-item__icon">
-                    <i class="fa fa-th-large"></i>
-                  </span>
-                  <span class="search-item__body">
-                    <div class="search-item__body-title">{{::item.title}}</div>
-                    <div class="search-item__body-sub-title" ng-show="item.folderTitle && section.hideHeader">
-                      <i class="fa fa-folder-o"></i>
-                      {{::item.folderTitle}}
-                    </div>
-                  </span>
-                  <span class="search-item__tags">
-                    <span ng-click="ctrl.filterByTag(tag, $event)" ng-repeat="tag in item.tags" tag-color-from-name="tag"  class="label label-tag">
-                      {{tag}}
-                    </span>
-                  </span>
-                  <span class="search-item__actions">
-                    <i class="fa" ng-class="{'fa-star': item.isStarred, 'fa-star-o': !item.isStarred}"></i>
-                  </span>
-                </a>
-              </div>
-            </div>
-          </div>
-
-            <!-- <div bindonce class="search-section" ng-repeat="dashboard in ctrl.dashboards">
-                <gf-form-switch
-                    switch-class="gf-form-switch--table-cell"
-                    on-change="ctrl.selectionChanged()"
-                    checked="dashboard.checked">
-                </gf-form-switch>
-                <a class="search-item pointer "
-                  bo-href-i="{{dashboard.url}}">
-                  <span class="search-item__icon">
-                    <i class="fa fa-th-large"></i>
-                  </span>
-                  <span class="search-result-tags">
-                    <span ng-click="ctrl.filterByTag(tag, $event)" bindonce ng-repeat="tag in dashboard.tags" tag-color-from-name="tag"  class="label label-tag">
-                      {{tag}}
-                    </span>
-                    <i class="fa" bo-class="{'fa-star': dashboard.isStarred, 'fa-star-o': !dashboard.isStarred}"></i>
-                  </span>
-                  <span class="search-result-link">
-                    <i class="fa search-result-icon"></i>
-                    <span bo-text="dashboard.title" />
-                  </span>
-                </a>
-            </div> -->
+        <div ng-if="section.expanded">
+          <div ng-repeat="item in section.items" class="search-item__with-checkbox" ng-class="{'selected': item.selected}">
+            <gf-form-switch
+              on-change="ctrl.selectionChanged()"
+              checked="item.checked" />
+            <a ng-href="{{::item.url}}" class="search-item">
+              <span class="search-item__icon">
+                <i class="fa fa-th-large"></i>
+              </span>
+              <span class="search-item__body">
+                <div class="search-item__body-title">{{::item.title}}</div>
+                <div class="search-item__body-sub-title" ng-show="item.folderTitle && section.hideHeader">
+                  <i class="fa fa-folder-o"></i>
+                  {{::item.folderTitle}}
+                </div>
+              </span>
+              <span class="search-item__tags">
+                <span ng-click="ctrl.filterByTag(tag, $event)" ng-repeat="tag in item.tags" tag-color-from-name="tag"  class="label label-tag">
+                  {{tag}}
+                </span>
+              </span>
+              <span class="search-item__actions">
+                <i class="fa" ng-class="{'fa-star': item.isStarred, 'fa-star-o': !item.isStarred}"></i>
+              </span>
+            </a>
           </div>
         </div>
       </div>
-
-    <em class="muted" ng-hide="ctrl.sections.length > 0">
-      No Dashboards or Folders found.
-    </em>
+    </div>
   </div>
 </div>
 
+<em class="muted" ng-hide="ctrl.sections.length > 0">
+  No Dashboards or Folders found.
+</em>

+ 22 - 34
public/app/features/dashboard/timepicker/timepicker.html

@@ -1,38 +1,26 @@
-<ul class="nav gf-timepicker-nav">
+<div class="navbar-buttons navbar-buttons--zoom">
+	<button class="btn navbar-button navbar-button--tight" ng-click='ctrl.move(-1)'>
+		<i class="fa fa-chevron-left"></i>
+	</button>
 
-  <li class="dashnav-move-timeframe gf-timepicker-time-control" bs-tooltip="'Shift time backward <br> (left arrow key)'" data-placement="bottom">
-    <a ng-click='ctrl.move(-1)'>
-      <i class="fa fa-chevron-left"></i>
-    </a>
-  </li>
-  <li class="dashnav-zoom-out gf-timepicker-time-control" bs-tooltip="'Time range zoom out <br> CTRL+Z'" data-placement="bottom">
-    <a ng-click='ctrl.zoom(2)'>Zoom Out</a>
-  </li>
-  </li>
-  <li class="dashnav-move-timeframe gf-timepicker-time-control" bs-tooltip="'Shift time forward <br> (right arrow key)'" data-placement="bottom">
-    <a ng-click='ctrl.move(1)'>
-      <i class="fa fa-chevron-right"></i>
-    </a>
-  </li>
+	<button class="btn navbar-button" bs-tooltip="'Time range zoom out <br> CTRL+Z'" data-placement="bottom" ng-click='ctrl.zoom(2)'>
+		<i class="fa fa-search-minus"></i>
+	</button>
 
-  <li>
-    <a bs-tooltip="ctrl.tooltip" data-placement="bottom" ng-click="ctrl.openDropdown()" class="gf-timepicker-nav-btn">
-      <i class="fa fa-clock-o"></i>
-      <span ng-bind="ctrl.rangeString"></span>
-      <span ng-show="ctrl.isUtc" class="gf-timepicker-utc">
-        UTC
-      </span>
+	<button class="btn navbar-button navbar-button--tight" ng-click='ctrl.move(1)'>
+		<i class="fa fa-chevron-right"></i>
+	</button>
+</div>
 
-      <span ng-show="ctrl.dashboard.refresh" class="text-warning">
-        &nbsp; Refresh every {{ctrl.dashboard.refresh}}
-      </span>
-    </a>
-  </li>
+<div class="navbar-buttons">
+	<button bs-tooltip="ctrl.tooltip" data-placement="bottom" ng-click="ctrl.openDropdown()" class="btn navbar-button gf-timepicker-nav-btn">
+		<i class="fa fa-clock-o"></i>
+		<span ng-bind="ctrl.rangeString"></span>
+		<span ng-show="ctrl.isUtc" class="gf-timepicker-utc">UTC</span>
+		<span ng-show="ctrl.dashboard.refresh" class="text-warning">&nbsp; Refresh every {{ctrl.dashboard.refresh}}</span>
+	</button>
 
-  <li class="dashnav-refresh-action">
-    <a ng-click="ctrl.timeSrv.refreshDashboard()">
-      <i class="fa fa-refresh"></i>
-    </a>
-  </li>
-
-</ul>
+	<button class="btn navbar-button navbar-button--refresh" ng-click="ctrl.timeSrv.refreshDashboard()">
+		<i class="fa fa-refresh"></i>
+	</button>
+</div>

+ 1 - 0
public/app/features/org/all.ts

@@ -5,6 +5,7 @@ import './select_org_ctrl';
 import './change_password_ctrl';
 import './new_org_ctrl';
 import './user_invite_ctrl';
+import './user_groups_ctrl';
 import './org_api_keys_ctrl';
 import './org_details_ctrl';
 import './prefs_control';

+ 1 - 1
public/app/features/org/change_password_ctrl.ts

@@ -8,7 +8,7 @@ export class ChangePasswordCtrl {
     $scope.command = {};
     $scope.authProxyEnabled = config.authProxyEnabled;
     $scope.ldapEnabled = config.ldapEnabled;
-    $scope.navModel = navModelSrv.getNav('profile', 'change-password');
+    $scope.navModel = navModelSrv.getNav('profile', 'change-password', 0);
 
     $scope.changePassword = function() {
       if (!$scope.userForm.$valid) { return; }

+ 1 - 1
public/app/features/org/new_org_ctrl.ts

@@ -5,7 +5,7 @@ export class NewOrgCtrl {
 
   /** @ngInject **/
   constructor($scope, $http, backendSrv, navModelSrv) {
-    $scope.navModel = navModelSrv.getOrgNav(0);
+    $scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs', 1);
     $scope.newOrg = {name: ''};
 
     $scope.createOrg = function() {

+ 1 - 1
public/app/features/org/org_api_keys_ctrl.ts

@@ -4,7 +4,7 @@ export class OrgApiKeysCtrl {
 
   /** @ngInject **/
   constructor ($scope, $http, backendSrv, navModelSrv) {
-    $scope.navModel = navModelSrv.getNav('cfg', 'apikeys');
+    $scope.navModel = navModelSrv.getNav('cfg', 'apikeys', 0);
 
     $scope.roleTypes = ['Viewer', 'Editor', 'Admin'];
     $scope.token = { role: 'Viewer' };

+ 1 - 1
public/app/features/org/org_details_ctrl.ts

@@ -6,7 +6,7 @@ export class OrgDetailsCtrl {
   constructor($scope, $http, backendSrv, contextSrv, navModelSrv) {
     $scope.init = function() {
       $scope.getOrgInfo();
-      $scope.navModel = navModelSrv.getNav('cfg', 'org');
+      $scope.navModel = navModelSrv.getNav('cfg', 'org-settings', 0);
     };
 
     $scope.getOrgInfo = function() {

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

@@ -23,7 +23,7 @@ export class OrgUsersCtrl {
       role: 'Viewer',
     };
 
-    this.navModel = navModelSrv.getNav('cfg', 'users');
+    this.navModel = navModelSrv.getNav('cfg', 'users', 0);
 
     this.get();
     this.editor = { index: 0 };
@@ -44,8 +44,7 @@ export class OrgUsersCtrl {
     if (this.externalUserMngLinkName) {
       return this.externalUserMngLinkName;
     }
-
-    return "Add Members";
+    return "Add Member";
   }
 
   get() {

+ 5 - 8
public/app/features/org/partials/change_password.html

@@ -1,15 +1,12 @@
-<navbar model="navModel"></navbar>
+<page-header model="navModel"></page-header>
 
-<div class="page-container">
-	<div class="page-header">
-		<page-h1 model="navModel"></page-h1>
-	</div>
+<div class="page-container page-body">
+	<h2 class="page-sub-heading">
+		Change your password
+	</h2>
 
 	<div ng-if="ldapEnabled || authProxyEnabled">
 		You cannot change password when ldap or auth proxy authentication is enabled.
-		<br>
-		<br>
-		<a class="btn-text" href="profile">Back to profile</a>
 	</div>
 
 	<form name="userForm" class="gf-form-group" ng-hide="ldapEnabled || authProxyEnabled">

+ 5 - 5
public/app/features/org/partials/newOrg.html

@@ -1,9 +1,9 @@
-<navbar model="navModel"></navbar>
+<page-header model="navModel"></page-header>
 
-<div class="page-container" ng-form="playlistEditForm">
-	<div class="page-header">
-		<h1>New Organization</h1>
-	</div>
+<div class="page-container page-body" ng-form="playlistEditForm">
+	<h2 class="page-sub-heading">
+		New Organization
+	</h2>
 
 	<p class="playlist-description">Each organization contains their own dashboards, data sources and configuration, and cannot be shared between orgs. While users may belong to more than one, mutiple organization are most frequently used in multi-tenant deployments. </p>
 

+ 3 - 5
public/app/features/org/partials/orgApiKeys.html

@@ -1,11 +1,9 @@
-<navbar model="navModel"></navbar>
+<page-header model="navModel"></page-header>
 
-<div class="page-container">
-	<div class="page-header">
-		<page-h1 model="navModel"></page-h1>
-	</div>
+<div class="page-container page-body">
 
 	<h3 class="page-heading">Add new</h3>
+
 	<form name="addTokenForm" class="gf-form-group">
 		<div class="gf-form-inline">
 			<div class="gf-form max-width-21">

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

@@ -1,26 +1,21 @@
-<navbar model="navModel"></navbar>
+<page-header model="navModel"></page-header>
 
-<div class="page-container">
-	<div class="page-header">
-		<page-h1 model="navModel"></page-h1>
-	</div>
+<div class="page-container page-body">
+  <h3 class="page-sub-heading">Organization profile</h3>
 
-	<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">Organization name</span>
-				<input class="gf-form-input" type="text" required ng-model="org.name">
-			</div>
-		</div>
+  <form name="orgForm" class="gf-form-group">
+    <div class="gf-form-inline">
+      <div class="gf-form max-width-28">
+        <span class="gf-form-label">Organization name</span>
+        <input class="gf-form-input" type="text" required ng-model="org.name">
+      </div>
+    </div>
 
     <div class="gf-form-button-row">
       <button type="submit" class="btn btn-success" ng-click="update()">Save</button>
     </div>
-	</form>
-
-	<prefs-control mode="org"></prefs-control>
-
+  </form>
+  <prefs-control mode="org"></prefs-control>
 </div>
 
 

+ 55 - 37
public/app/features/org/partials/orgUsers.html

@@ -1,34 +1,52 @@
-<navbar model="ctrl.navModel"></navbar>
+<!-- <navbar model="ctrl.navModel"></navbar> -->
+<!--  -->
+<!-- <div class="page&#45;container"> -->
+<!-- 	<div class="page&#45;header"> -->
+<!-- 		<page&#45;h1 model="ctrl.navModel"></page&#45;h1> -->
+<!--  -->
+<!-- 		<button class="btn btn&#45;success" ng&#45;click="ctrl.openAddUsersView()" ng&#45;hide="ctrl.externalUserMngLinkUrl"> -->
+<!-- 			<span>{{ctrl.addUsersBtnName}}</span> -->
+<!-- 		</button> -->
+<!--  -->
+<!-- 		<div class="page&#45;header&#45;tabs"> -->
+<!--  -->
+<!-- 			<a class="btn btn&#45;inverse" ng&#45;href="{{ctrl.externalUserMngLinkUrl}}" target="_blank" ng&#45;if="ctrl.externalUserMngLinkUrl"> -->
+<!-- 				<i class="fa fa&#45;external&#45;link&#45;square"></i> -->
+<!-- 				{{ctrl.addUsersBtnName}} -->
+<!--       </a> -->
+<!--  -->
+<!-- 			<ul class="gf&#45;tabs"> -->
+<!-- 				<li class="gf&#45;tabs&#45;item"> -->
+<!-- 					<a class="gf&#45;tabs&#45;link" ng&#45;click="ctrl.editor.index = 0" ng&#45;class="{active: ctrl.editor.index === 0}"> -->
+<!-- 						Users ({{ctrl.users.length}}) -->
+<!-- 					</a> -->
+<!-- 				</li> -->
+<!-- 				<li class="gf&#45;tabs&#45;item" ng&#45;show="ctrl.pendingInvites.length"> -->
+<!-- 					<a class="gf&#45;tabs&#45;link" ng&#45;click="ctrl.editor.index = 1" ng&#45;class="{active: ctrl.editor.index === 1}"> -->
+<!-- 						Pending Invites ({{ctrl.pendingInvites.length}}) -->
+<!-- 					</a> -->
+<!-- 				</li> -->
+<!-- 			</ul> -->
+<!-- 		</div> -->
+<!-- 	</div> -->
 
-<div class="page-container">
-	<div class="page-header">
-		<page-h1 model="ctrl.navModel"></page-h1>
+<page-header model="ctrl.navModel"></page-header>
 
+<div class="page-container page-body">
+  <div class="page-action-bar">
+    <div class="page-action-bar__spacer"></div>
+    <button class="btn btn-inverse" ng-show="ctrl.pendingInvites.length" ng-click="ctrl.editor.index = 1">
+      Pending Invites ({{ctrl.pendingInvites.length}})
+    </button>
 		<button class="btn btn-success" ng-click="ctrl.openAddUsersView()" ng-hide="ctrl.externalUserMngLinkUrl">
+      <i class="fa fa-plus"></i>
 			<span>{{ctrl.addUsersBtnName}}</span>
 		</button>
-
-		<div class="page-header-tabs">
-
-			<a class="btn btn-inverse" ng-href="{{ctrl.externalUserMngLinkUrl}}" target="_blank" ng-if="ctrl.externalUserMngLinkUrl">
-				<i class="fa fa-external-link-square"></i>
-				{{ctrl.addUsersBtnName}}
-      </a>
-
-			<ul class="gf-tabs">
-				<li class="gf-tabs-item">
-					<a class="gf-tabs-link" ng-click="ctrl.editor.index = 0" ng-class="{active: ctrl.editor.index === 0}">
-						Users ({{ctrl.users.length}})
-					</a>
-				</li>
-				<li class="gf-tabs-item" ng-show="ctrl.pendingInvites.length">
-					<a class="gf-tabs-link" ng-click="ctrl.editor.index = 1" ng-class="{active: ctrl.editor.index === 1}">
-						Pending Invites ({{ctrl.pendingInvites.length}})
-					</a>
-				</li>
-			</ul>
-		</div>
-	</div>
+    <a class="btn btn-inverse" ng-href="{{ctrl.externalUserMngLinkUrl}}" target="_blank" ng-if="ctrl.externalUserMngLinkUrl">
+      <i class="fa fa-external-link-square"></i>
+      {{ctrl.addUsersBtnName}}
+    </a>
+  </div>
 
   <div class="grafana-info-box" ng-if="ctrl.externalUserMngInfo">
     <span ng-bind-html="ctrl.externalUserMngInfo"></span>
@@ -41,26 +59,26 @@
           <th></th>
           <th>Login</th>
           <th>Email</th>
-					<th>
-						Seen
-						<tip>Time since user was seen using Grafana</tip>
-					</th>
+          <th>
+            Seen
+            <tip>Time since user was seen using Grafana</tip>
+          </th>
           <th>Role</th>
           <th style="width: 34px;"></th>
         </tr>
       </thead>
       <tr ng-repeat="user in ctrl.users">
         <td class="width-4 text-center">
-					<img class="filter-table__avatar" ng-src="{{user.avatarUrl}}"></img>
-				</td>
+          <img class="filter-table__avatar" ng-src="{{user.avatarUrl}}"></img>
+        </td>
         <td>{{user.login}}</td>
         <td><span class="ellipsis">{{user.email}}</span></td>
-				<td>{{user.lastSeenAtAge}}</td>
+        <td>{{user.lastSeenAtAge}}</td>
         <td>
-					<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>
+          <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">

+ 3 - 6
public/app/features/org/partials/profile.html

@@ -1,12 +1,9 @@
-<navbar model="ctrl.navModel"></navbar>
+<page-header model="ctrl.navModel"></page-header>
 
-<div class="page-container">
-	<div class="page-header">
-		<page-h1 model="ctrl.navModel"></page-h1>
-	</div>
+<div class="page-container page-body">
+  <h3 class="page-sub-heading">User Profile</h3>
 
 	<form name="ctrl.userForm" class="gf-form-group">
-		<h3 class="page-heading">Information</h3>
 
 		<div class="gf-form max-width-30">
 			<span class="gf-form-label width-8">Name</span>

+ 13 - 12
public/app/features/org/partials/user_groups.html

@@ -1,20 +1,22 @@
-<navbar model="ctrl.navModel"></navbar>
+<page-header model="ctrl.navModel"></page-header>
 
-<div class="page-container">
-	<div class="page-header">
-		<h1>User Groups</h1>
+<div class="page-container page-body">
+	<div class="page-action-bar">
+
+    <div class="gf-form gf-form--grow">
+      <label class="gf-form-label">Search</label>
+      <input type="text" class="gf-form-input max-width-20" placeholder="Find User Group by name" tabindex="1" give-focus="true"
+          ng-model="ctrl.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.get()" />
+    </div>
+
+    <div class="page-action-bar__spacer"></div>
 
     <a class="btn btn-success" ng-click="ctrl.openUserGroupModal()">
       <i class="fa fa-plus"></i>
-      Create User Group
+			Add Team
     </a>
   </div>
-    <div class="gf-form width-15 gf-form-group">
-      <span style="position: relative;">
-        <input type="text" class="gf-form-input" placeholder="Find User Group by name" tabindex="1" give-focus="true"
-          ng-model="ctrl.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.get()" />
-      </span>
-    </div>
+
   <div class="admin-list-table">
     <table class="filter-table form-inline" ng-show="ctrl.userGroups.length > 0">
       <thead>
@@ -42,7 +44,6 @@
           </td>
         </tr>
       </tbody>
-
     </table>
   </div>
 

+ 1 - 1
public/app/features/org/profile_ctrl.ts

@@ -14,7 +14,7 @@ export class ProfileCtrl {
   constructor(private backendSrv, private contextSrv, private $location, navModelSrv) {
     this.getUser();
     this.getUserOrgs();
-    this.navModel = navModelSrv.getNav('profile');
+    this.navModel = navModelSrv.getNav('profile', 'profile-settings', 0);
   }
 
   getUser() {

+ 1 - 1
public/app/features/org/user_groups_ctrl.ts

@@ -15,7 +15,7 @@ export class UserGroupsCtrl {
 
   /** @ngInject */
   constructor(private backendSrv, navModelSrv) {
-    this.navModel = navModelSrv.getNav('cfg', 'users');
+    this.navModel = navModelSrv.getNav('cfg', 'teams', 0);
     this.get();
   }
 

+ 6 - 6
public/app/features/playlist/partials/playlist.html

@@ -1,9 +1,9 @@
-<navbar model="ctrl.navModel"></navbar>
+<page-header model="ctrl.navModel"></page-header>
 
-<div class="page-container" ng-form="playlistEditForm">
-	<div class="page-header">
-		<page-h1 model="ctrl.navModel"></page-h1>
-	</div>
+<div class="page-container page-body" ng-form="playlistEditForm">
+
+  <h3 class="page-sub-heading" ng-hide="ctrl.isNew">Edit Playlist</h3>
+  <h3 class="page-sub-heading" ng-show="ctrl.isNew">New Playlist</h3>
 
 	<p class="playlist-description">A playlist rotates through a pre-selected list of Dashboards. A Playlist can be a great way to build situational awareness, or just show off your metrics to your team or visitors.</p>
 
@@ -103,7 +103,7 @@
 	<div class="clearfix"></div>
 
 	<div class="gf-form-button-row">
-		<a class="btn btn-success " ng-show="ctrl.isNew()"
+		<a class="btn btn-success " ng-show="ctrl.isNew"
 			ng-disabled="ctrl.playlistEditForm.$invalid || ctrl.isPlaylistEmpty()"
 			ng-click="ctrl.savePlaylist(ctrl.playlist, ctrl.playlistItems)">Create new playlist</a>
 		<a class="btn btn-success" ng-show="!ctrl.isNew()"

+ 6 - 6
public/app/features/playlist/partials/playlists.html

@@ -1,15 +1,15 @@
-<navbar model="ctrl.navModel"></navbar>
+<page-header model="ctrl.navModel"></page-header>
 
-<div class="page-container">
-  <div class="page-header">
-		<page-h1 model="ctrl.navModel"></page-h1>
-    <a class="btn btn-primary pull-right" href="playlists/create">
+<div class="page-container page-body">
+  <div class="page-action-bar">
+    <div class="page-action-bar__spacer"></div>
+    <a class="btn btn-success pull-right" href="playlists/create">
       <i class="fa fa-plus"></i>
       New Playlist
     </a>
   </div>
 
-  <table class="filter-table" style="margin-top: 20px">
+  <table class="filter-table">
     <thead>
       <th><strong>Name</strong></th>
       <th><strong>Start url</strong></th>

+ 5 - 7
public/app/features/playlist/playlist_edit_ctrl.ts

@@ -1,5 +1,3 @@
-///<reference path="../../headers/common.d.ts" />
-
 import _ from 'lodash';
 import coreModule from '../../core/core_module';
 
@@ -11,10 +9,12 @@ export class PlaylistEditCtrl {
   playlist: any = {
     interval: '5m',
   };
+
   playlistItems: any = [];
   dashboardresult: any = [];
   tagresult: any = [];
   navModel: any;
+  isNew: boolean;
 
   /** @ngInject */
   constructor(
@@ -24,7 +24,9 @@ export class PlaylistEditCtrl {
     $route,
     navModelSrv
   ) {
-    this.navModel = navModelSrv.getNav('dashboards', 'playlists');
+
+    this.navModel = navModelSrv.getNav('dashboards', 'playlists', 0);
+    this.isNew = $route.current.params.id;
 
     if ($route.current.params.id) {
       var playlistId = $route.current.params.id;
@@ -104,10 +106,6 @@ export class PlaylistEditCtrl {
       });
   }
 
-  isNew() {
-    return !this.playlist.id;
-  }
-
   isPlaylistEmpty() {
     return !this.playlistItems.length;
   }

+ 1 - 1
public/app/features/playlist/playlists_ctrl.ts

@@ -9,7 +9,7 @@ export class PlaylistsCtrl {
 
   /** @ngInject */
   constructor(private $scope, private backendSrv, navModelSrv) {
-    this.navModel = navModelSrv.getNav('dashboards', 'playlists');
+    this.navModel = navModelSrv.getNav('dashboards', 'playlists', 0);
 
     backendSrv.get('/api/playlists').then(result => {
       this.playlists = result;

+ 3 - 5
public/app/features/plugins/ds_edit_ctrl.ts

@@ -41,7 +41,7 @@ export class DataSourceEditCtrl {
     navModelSrv,
   ) {
 
-    this.navModel = navModelSrv.getNav('cfg', 'datasources');
+    this.navModel = navModelSrv.getNav('cfg', 'datasources', 0);
     this.datasources = [];
     this.tabIndex = 0;
 
@@ -58,9 +58,7 @@ export class DataSourceEditCtrl {
     this.isNew = true;
     this.current = _.cloneDeep(defaults);
 
-    // add to nav & breadcrumbs
-    this.navModel.node = {text: 'New data source', icon: 'icon-gf icon-gf-fw icon-gf-datasources'};
-    this.navModel.breadcrumbs.push(this.navModel.node);
+    this.navModel.breadcrumbs.push({text: 'New'});
 
     // We are coming from getting started
     if (this.$location.search().gettingstarted) {
@@ -87,7 +85,7 @@ export class DataSourceEditCtrl {
     this.backendSrv.get('/api/datasources/' + id).then(ds => {
       this.isNew = false;
       this.current = ds;
-      this.navModel.node = {text: ds.name, icon: 'icon-gf icon-gf-fw icon-gf-datasources'};
+      this.navModel.node = {text: ds.name, icon: 'icon-gf icon-gf-fw icon-gf-datasources', id: 'ds-new'};
       this.navModel.breadcrumbs.push(this.navModel.node);
 
       if (datasourceCreated) {

+ 1 - 1
public/app/features/plugins/ds_list_ctrl.ts

@@ -13,7 +13,7 @@ export class DataSourcesCtrl {
     private datasourceSrv,
     private navModelSrv) {
 
-    this.navModel = this.navModelSrv.getNav('cfg', 'datasources');
+    this.navModel = this.navModelSrv.getNav('cfg', 'datasources', 0);
 
     backendSrv.get('/api/datasources').then(result => {
       this.datasources = result;

+ 0 - 6
public/app/features/plugins/import_list/import_list.html

@@ -13,12 +13,6 @@
 						{{dash.title}}
 					</span>
 				</td>
-				<td>
-          <span>
-            Revision: {{dash.revision}}
-            <span ng-if="dash.imported" class="small">(Imported: {{dash.importedRevision}})</span>
-          <span>
-				</td>
 				<td style="text-align: right">
 					<button class="btn btn-secondary btn-small" ng-click="ctrl.import(dash, false)" ng-show="!dash.imported">
 						Import

+ 68 - 79
public/app/features/plugins/partials/ds_edit.html

@@ -1,91 +1,80 @@
-<div class="scroll-canvas" grafana-scrollbar>
-	<navbar model="ctrl.navModel"></navbar>
-	<div class="page-container">
-		<div class="page-header">
-			<page-h1 model="ctrl.navModel"></page-h1>
+<page-header model="ctrl.navModel"></page-header>
 
-			<div ng-if="ctrl.current.readOnly" class="grafana-info-box span8">Disclaimer. This datasource was added by config and cannot be modified using the UI. Please contact your server admin to update this datasource.</div>
+<div class="page-container page-body">
 
-			<div class="page-header-tabs" ng-show="ctrl.hasDashboards">
-				<ul class="gf-tabs">
-					<li class="gf-tabs-item">
-						<a class="gf-tabs-link" ng-click="ctrl.tabIndex = 0" ng-class="{active: ctrl.tabIndex === 0}">
-							Config
-						</a>
-					</li>
-					<li class="gf-tabs-item">
-						<a class="gf-tabs-link" ng-click="ctrl.tabIndex = 1" ng-class="{active: ctrl.tabIndex === 1}">
-							Dashboards
-						</a>
-					</li>
-				</ul>
-			</div>
-		</div>
-
-		<div ng-if="ctrl.tabIndex === 0" class="tab-content">
-
-			<form name="ctrl.editForm" ng-if="ctrl.current">
-				<div class="gf-form-group">
-					<div class="gf-form-inline">
-						<div class="gf-form max-width-30">
-							<span class="gf-form-label width-7">Name</span>
-							<input class="gf-form-input max-width-23" type="text" ng-model="ctrl.current.name" placeholder="name" required>
-							<info-popover offset="0px -135px" mode="right-absolute">
-								The name is used when you select the data source in panels.
-								The <em>Default</em> data source is preselected in new
-								panels.
-							</info-popover>
-						</div>
-						<gf-form-switch class="gf-form" label="Default" checked="ctrl.current.isDefault" switch-class="max-width-6"></gf-form-switch>
-					</div>
+  <div ng-if="ctrl.current.readOnly"  class="page-action-bar">
+    <div class="grafana-info-box span8">
+      Disclaimer. This datasource was added by config and cannot be modified using the UI. Please contact your server admin to update this datasource.
+    </div>
+  </div>
 
-					<div class="gf-form">
-						<span class="gf-form-label width-7">Type</span>
-						<div class="gf-form-select-wrapper max-width-23">
-							<select class="gf-form-input" ng-model="ctrl.current.type" ng-options="v.id as v.name for v in ctrl.types" ng-change="ctrl.userChangedType()"></select>
-						</div>
-					</div>
-				</div>
+  <h3 class="page-sub-heading" ng-hide="ctrl.isNew">Edit Data Source</h3>
+  <h3 class="page-sub-heading" ng-show="ctrl.isNew">New Data Source</h3>
 
-				<div class="alert alert-info gf-form-group" ng-if="ctrl.datasourceMeta.state === 'alpha'">
-					This plugin is marked as being in alpha state, which means it is in early development phase and
-					updates will include breaking changes.
-				</div>
+  <form name="ctrl.editForm" ng-if="ctrl.current">
+    <div class="gf-form-group">
+      <div class="gf-form-inline">
+        <div class="gf-form max-width-30">
+          <span class="gf-form-label width-7">Name</span>
+          <input class="gf-form-input max-width-23" type="text" ng-model="ctrl.current.name" placeholder="name" required>
+          <info-popover offset="0px -135px" mode="right-absolute">
+            The name is used when you select the data source in panels.
+            The <em>Default</em> data source is preselected in new
+            panels.
+          </info-popover>
+        </div>
+        <gf-form-switch class="gf-form" label="Default" checked="ctrl.current.isDefault" switch-class="max-width-6"></gf-form-switch>
+      </div>
 
-				<rebuild-on-change property="ctrl.datasourceMeta.id">
-					<plugin-component type="datasource-config-ctrl">
-					</plugin-component>
-				</rebuild-on-change>
+      <div class="gf-form">
+        <span class="gf-form-label width-7">Type</span>
+        <div class="gf-form-select-wrapper max-width-23">
+          <select class="gf-form-input" ng-model="ctrl.current.type" ng-options="v.id as v.name for v in ctrl.types" ng-change="ctrl.userChangedType()"></select>
+        </div>
+      </div>
+    </div>
 
-				<div ng-if="ctrl.testing" class="gf-form-group section">
-					<h5 ng-show="!ctrl.testing.done">Testing.... <i class="fa fa-spiner fa-spin"></i></h5>
-					<div class="alert-{{ctrl.testing.status}} alert" ng-show="ctrl.testing.done">
-						<div class="alert-icon">
-							<i class="fa fa-exclamation-triangle" ng-show="ctrl.testing.status === 'error'"></i>
-							<i class="fa fa-check" ng-show="ctrl.testing.status !== 'error'"></i>
-						</div>
-						<div class="alert-body">
-							<div class="alert-title">{{ctrl.testing.message}}</div>
-						</div>
-					</div>
-				</div>
+    <div class="alert alert-info gf-form-group" ng-if="ctrl.datasourceMeta.state === 'alpha'">
+      This plugin is marked as being in alpha state, which means it is in early development phase and
+      updates will include breaking changes.
+    </div>
 
-				<div class="gf-form-button-row">
-					<button type="submit" class="btn btn-success" ng-disabled="ctrl.current.readOnly"  ng-click="ctrl.saveChanges()">Save</button>
-					<button type="submit" class="btn btn-danger" ng-disabled="ctrl.current.readOnly"  ng-show="!ctrl.isNew" ng-click="ctrl.delete()">
-						Delete
-					</button>
-					<a class="btn btn-link" href="datasources">Cancel</a>
-				</div>
+    <rebuild-on-change property="ctrl.datasourceMeta.id">
+      <plugin-component type="datasource-config-ctrl">
+      </plugin-component>
+    </rebuild-on-change>
 
-				<br />
-				<br />
-				<br />
+    <div ng-if="ctrl.hasDashboards">
+      <h3 class="section-heading">Bundled Plugin Dashboards</h3>
+      <div class="section">
+        <dashboard-import-list plugin="ctrl.datasourceMeta" datasource="ctrl.current"></dashboard-import-list>
+      </div>
+    </div>
 
-			</form>
+    <div ng-if="ctrl.testing" class="gf-form-group section">
+      <h5 ng-show="!ctrl.testing.done">Testing.... <i class="fa fa-spiner fa-spin"></i></h5>
+      <div class="alert-{{ctrl.testing.status}} alert" ng-show="ctrl.testing.done">
+        <div class="alert-icon">
+          <i class="fa fa-exclamation-triangle" ng-show="ctrl.testing.status === 'error'"></i>
+          <i class="fa fa-check" ng-show="ctrl.testing.status !== 'error'"></i>
+        </div>
+        <div class="alert-body">
+          <div class="alert-title">{{ctrl.testing.message}}</div>
+        </div>
+      </div>
     </div>
-    <div ng-if="ctrl.tabIndex === 1" class="tab-content">
-      <dashboard-import-list plugin="ctrl.datasourceMeta" datasource="ctrl.current"></dashboard-import-list>
+
+    <div class="gf-form-button-row">
+      <button type="submit" class="btn btn-success" ng-disabled="ctrl.current.readOnly"  ng-click="ctrl.saveChanges()">Save</button>
+      <button type="submit" class="btn btn-danger" ng-disabled="ctrl.current.readOnly"  ng-show="!ctrl.isNew" ng-click="ctrl.delete()">
+        Delete
+      </button>
+      <a class="btn btn-link" href="datasources">Cancel</a>
     </div>
-  </div>
+
+    <br />
+    <br />
+    <br />
+
+  </form>
 </div>

+ 24 - 25
public/app/features/plugins/partials/ds_http_settings.html

@@ -1,7 +1,7 @@
 
 
 <div class="gf-form-group">
-  <h3 class="page-heading">HTTP settings</h3>
+  <h3 class="page-heading">HTTP</h3>
   <div class="gf-form-group">
     <div class="gf-form-inline">
       <div class="gf-form max-width-30">
@@ -38,39 +38,38 @@
     </div>
   </div>
 
-  <h3 class="page-heading">HTTP Auth</h3>
-    <div class="gf-form-group">
-      <div class="gf-form-inline">
-        <gf-form-switch class="gf-form" label="Basic Auth" checked="current.basicAuth" label-class="width-8" switch-class="max-width-6"></gf-form-switch>
-        <gf-form-switch class="gf-form" label="With Credentials" tooltip="Whether credentials such as cookies or auth headers should be sent with cross-site requests." checked="current.withCredentials" label-class="width-11" switch-class="max-width-6"></gf-form-switch>
-      </div>
-      <div class="gf-form-inline">
-        <gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="TLS Client Auth" label-class="width-8" checked="current.jsonData.tlsAuth" switch-class="max-width-6"></gf-form-switch>
-        <gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="With CA Cert" tooltip="Needed for verifing self-signed TLS Certs" checked="current.jsonData.tlsAuthWithCACert" label-class="width-11" switch-class="max-width-6"></gf-form-switch>
-      </div>
+  <h3 class="page-heading">Auth</h3>
+  <div class="gf-form-group">
+    <div class="gf-form-inline">
+      <gf-form-switch class="gf-form" label="Basic Auth" checked="current.basicAuth" label-class="width-8" switch-class="max-width-6"></gf-form-switch>
+      <gf-form-switch class="gf-form" label="With Credentials" tooltip="Whether credentials such as cookies or auth headers should be sent with cross-site requests." checked="current.withCredentials" label-class="width-11" switch-class="max-width-6"></gf-form-switch>
     </div>
-
     <div class="gf-form-inline">
-      <gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="Skip TLS Verification (Insecure)" label-class="width-16" checked="current.jsonData.tlsSkipVerify" switch-class="max-width-6"></gf-form-switch>
+      <gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="TLS Client Auth" label-class="width-8" checked="current.jsonData.tlsAuth" switch-class="max-width-6"></gf-form-switch>
+      <gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="With CA Cert" tooltip="Needed for verifing self-signed TLS Certs" checked="current.jsonData.tlsAuthWithCACert" label-class="width-11" switch-class="max-width-6"></gf-form-switch>
     </div>
   </div>
+
+  <div class="gf-form-inline">
+    <gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="Skip TLS Verification (Insecure)" label-class="width-16" checked="current.jsonData.tlsSkipVerify" switch-class="max-width-6"></gf-form-switch>
+  </div>
 </div>
 
 <div class="gf-form-group" ng-if="current.basicAuth">
   <h6>Basic Auth Details</h6>
-	<div class="gf-form" ng-if="current.basicAuth">
-		<span class="gf-form-label width-7">
-			User
-		</span>
-		<input class="gf-form-input max-width-21" type="text"  ng-model='current.basicAuthUser' placeholder="user" required></input>
-	</div>
+  <div class="gf-form" ng-if="current.basicAuth">
+    <span class="gf-form-label width-7">
+      User
+    </span>
+    <input class="gf-form-input max-width-21" type="text"  ng-model='current.basicAuthUser' placeholder="user" required></input>
+  </div>
 
-	<div class="gf-form">
-		<span class="gf-form-label width-7">
-			Password
-		</span>
-		<input class="gf-form-input max-width-21" type="password" ng-model='current.basicAuthPassword' placeholder="password" required></input>
-	</div>
+  <div class="gf-form">
+    <span class="gf-form-label width-7">
+      Password
+    </span>
+    <input class="gf-form-input max-width-21" type="password" ng-model='current.basicAuthPassword' placeholder="password" required></input>
+  </div>
 </div>
 
 <div class="gf-form-group" ng-if="(current.jsonData.tlsAuth || current.jsonData.tlsAuthWithCACert) && current.access=='proxy'">

+ 38 - 40
public/app/features/plugins/partials/ds_list.html

@@ -1,48 +1,46 @@
-<div class="scroll-canvas" grafana-scrollbar>
-	<navbar model="ctrl.navModel"></navbar>
-	<div class="page-container">
-		<div class="page-header">
-			<page-h1 model="ctrl.navModel"></page-h1>
+<page-header model="ctrl.navModel"></page-header>
 
-			<a class="page-header__cta btn btn-success" href="datasources/new">
-				Add data source
-			</a>
-		</div>
-
-		<section class="card-section" layout-mode>
-			<layout-selector></layout-selector>
+<div class="page-container page-body">
+  <div class="page-action-bar">
+    <div class="page-action-bar__spacer"></div>
+    <a class="page-header__cta btn btn-success" href="datasources/new">
+      <i class="fa fa-plus"></i>
+      Add data source
+    </a>
+	</div>
 
-			<ol class="card-list" >
-				<li class="card-item-wrapper" ng-repeat="ds in ctrl.datasources">
-					<a class="card-item" href="datasources/edit/{{ds.id}}/">
-						<div class="card-item-header">
-							<div class="card-item-type">
-								{{ds.type}}
-							</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">
+				<a class="card-item" href="datasources/edit/{{ds.id}}/">
+					<div class="card-item-header">
+						<div class="card-item-type">
+							{{ds.type}}
 						</div>
-						<div class="card-item-body">
-							<figure class="card-item-figure">
-								<img ng-src="{{ds.typeLogoUrl}}">
-							</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>
-								</div>
-								<div class="card-item-sub-name">
-									{{ds.url}}
-								</div>
+					</div>
+					<div class="card-item-body">
+						<figure class="card-item-figure">
+							<img ng-src="{{ds.typeLogoUrl}}">
+						</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>
+							</div>
+							<div class="card-item-sub-name">
+								{{ds.url}}
 							</div>
 						</div>
-					</a>
-				</li>
-			</ol>
-		</section>
+					</div>
+				</a>
+			</li>
+		</ol>
+	</section>
 
-		<div ng-if="ctrl.datasources.length === 0">
-			<em>No data sources defined</em>
-		</div>
+	<div ng-if="ctrl.datasources.length === 0">
+		<em>No data sources defined</em>
 	</div>
 </div>

+ 19 - 39
public/app/features/plugins/partials/plugin_edit.html

@@ -1,62 +1,42 @@
-<navbar model="ctrl.navModel"></navbar>
-
-<div class="page-container" ng-init="ctrl.init()">
-  <div class="page-header">
-    <div class="plugin-header">
-      <span class="plugin-header-logo">
-        <img ng-src="{{ctrl.model.info.logos.large}}">
-      </span>
-
-      <div class="plugin-header-info-block">
-        <h1 class="plugin-header-name">{{ctrl.model.name}}</h1>
-        <div class="plugin-header-author">By {{ctrl.model.info.author.name}}</div>
-        <div class="plugin-header-stamps">
-          <span class="plugin-header-stamps-type">
-            <i class="{{ctrl.pluginIcon}}"></i> {{ctrl.model.type}}
-          </span>
-        </div>
-      </div>
-    </div>
-
-    <ul class="gf-tabs">
-      <li class="gf-tabs-item" ng-repeat="tab in ctrl.tabs">
-        <a class="gf-tabs-link" ng-click="ctrl.tabIndex = $index" ng-class="{active: ctrl.tabIndex === $index}">
-          {{::tab}}
-        </a>
-      </li>
-    </ul>
+<page-header model="ctrl.navModel"></page-header>
 
+<div class="page-container page-body" ng-init="ctrl.init()">
+  <div class="page-action-bar">
+    <button class="btn" ng-repeat="tab in ctrl.tabs" ng-class="{'btn-secondary': ctrl.tabIndex === $index, 'btn-inverse': ctrl.tabIndex !== $index}" ng-click="ctrl.tabIndex = $index">
+      {{tab}}
+    </button>
   </div>
 
-  <div class="page-body">
-    <div class="tab-content page-content-with-sidebar" ng-if="ctrl.tabs[ctrl.tabIndex] === 'Readme'">
+  <div class="sidebar-container">
+
+    <div class="tab-content sidebar-content" ng-if="ctrl.tabs[ctrl.tabIndex] === 'Readme'">
       <div ng-bind-html="ctrl.readmeHtml" class="markdown-html">
       </div>
     </div>
 
-    <div class="tab-content page-content-with-sidebar" ng-if="ctrl.tabs[ctrl.tabIndex] === 'Config'">
+    <div class="tab-content sidebar-content" ng-if="ctrl.tabs[ctrl.tabIndex] === 'Config'">
       <div ng-if="ctrl.model.id">
         <plugin-component type="app-config-ctrl"></plugin-component>
 
-	      <div class="gf-form-button-row">
-					<button type="submit" class="btn btn-success" ng-click="ctrl.enable()" ng-show="!ctrl.model.enabled">Enable</button>
-					<button type="submit" class="btn btn-success" ng-click="ctrl.update()" ng-show="ctrl.model.enabled">Update</button>
-					<button type="submit" class="btn btn-danger" ng-click="ctrl.disable()" ng-show="ctrl.model.enabled">Disable</button>
-				</div>
+        <div class="gf-form-button-row">
+          <button type="submit" class="btn btn-success" ng-click="ctrl.enable()" ng-show="!ctrl.model.enabled">Enable</button>
+          <button type="submit" class="btn btn-success" ng-click="ctrl.update()" ng-show="ctrl.model.enabled">Update</button>
+          <button type="submit" class="btn btn-danger" ng-click="ctrl.disable()" ng-show="ctrl.model.enabled">Disable</button>
+        </div>
       </div>
     </div>
 
-    <div class="tab-content page-content-with-sidebar" ng-if="ctrl.tabs[ctrl.tabIndex] === 'Dashboards'">
-			<dashboard-import-list plugin="ctrl.model"></dashboard-import-list>
+    <div class="tab-content sidebar.content" ng-if="ctrl.tabs[ctrl.tabIndex] === 'Dashboards'">
+      <dashboard-import-list plugin="ctrl.model"></dashboard-import-list>
     </div>
 
     <aside class="page-sidebar">
       <section class="page-sidebar-section">
         <h4>Version</h4>
         <span>{{ctrl.model.info.version}}</span>
-				<div ng-show="ctrl.model.hasUpdate">
+        <div ng-show="ctrl.model.hasUpdate">
           <a ng-click="ctrl.updateAvailable()" bs-tooltip="ctrl.model.latestVersion">Update Available!</a>
-				</div>
+        </div>
       </section>
       <section class="page-sidebar-section" ng-show="ctrl.model.type === 'app'">
         <h5>Includes</h4>

+ 75 - 59
public/app/features/plugins/partials/plugin_list.html

@@ -1,65 +1,81 @@
-<div class="scroll-canvas" grafana-scrollbar>
-	<navbar model="ctrl.navModel"></navbar>
+<page-header model="ctrl.navModel"></page-header>
 
-	<div class="page-container">
-		<div class="page-header">
-			<h1>
-				<i class="icon-gf icon-gf-apps"></i>
-				Plugins <span class="muted small">(currently installed)</span>
-			</h1>
+<!-- <div class="page&#45;header&#45;canvas"> -->
+<!--   <div class="page&#45;container"> -->
+<!--     <navbar model="ctrl.navModel"></navbar> -->
+<!--  -->
+<!--     <div class="page&#45;header"> -->
+<!-- 		  <page&#45;h1 model="ctrl.navModel"></page&#45;h1> -->
+<!--  -->
+<!--       <div class="page&#45;header&#45;tabs"> -->
+<!--         <ul class="gf&#45;tabs"> -->
+<!--           <li class="gf&#45;tabs&#45;item"> -->
+<!--             <a class="gf&#45;tabs&#45;link" href="plugins?type=panel" ng&#45;class="{active: ctrl.tabIndex === 0}"> -->
+<!--               <i class="icon&#45;gf icon&#45;gf&#45;panel"></i> -->
+<!--               Panels -->
+<!--             </a> -->
+<!--           </li> -->
+<!--           <li class="gf&#45;tabs&#45;item"> -->
+<!--             <a class="gf&#45;tabs&#45;link" href="plugins?type=datasource" ng&#45;class="{active: ctrl.tabIndex === 1}"> -->
+<!--               <i class="gicon gicon&#45;datasources"></i> -->
+<!--               Data sources -->
+<!--             </a> -->
+<!--           </li> -->
+<!--           <li class="gf&#45;tabs&#45;item"> -->
+<!--             <a class="gf&#45;tabs&#45;link" href="plugins?type=app" ng&#45;class="{active: ctrl.tabIndex === 2}"> -->
+<!--               <i class="icon&#45;gf icon&#45;gf&#45;apps"></i> -->
+<!--               Apps -->
+<!--             </a> -->
+<!--           </li> -->
+<!--         </ul> -->
+<!--  -->
+<!--         <a class="get&#45;more&#45;plugins&#45;link pull&#45;right" href="https://grafana.com/plugins?utm_source=grafana_plugin_list" target="_blank"> -->
+<!--           Find more <img src="public/img/icn&#45;plugins&#45;tiny.svg" />plugins on Grafana.com -->
+<!--         </a> -->
+<!--       </div> -->
+<!--     </div> -->
+<!--   </div> -->
+<!-- </div> -->
 
-			<div class="page-header-tabs">
-				<ul class="gf-tabs">
-					<li class="gf-tabs-item">
-						<a class="gf-tabs-link" href="plugins?type=panel" ng-class="{active: ctrl.tabIndex === 0}">
-							Panels
-						</a>
-					</li>
-					<li class="gf-tabs-item">
-						<a class="gf-tabs-link" href="plugins?type=datasource" ng-class="{active: ctrl.tabIndex === 1}">
-							Data sources
-						</a>
-					</li>
-					<li class="gf-tabs-item">
-						<a class="gf-tabs-link" href="plugins?type=app" ng-class="{active: ctrl.tabIndex === 2}">
-							Apps
-						</a>
-					</li>
-				</ul>
+<div class="page-container page-body">
+  <div class="page-action-bar">
+    <div class="gf-form">
+      <label class="gf-form-label">Search</label>
+      <input type="text" class="gf-form-input width-20" ng-model="ctrl.searchQuery" ng-change="ctrl.onQueryUpdated()" />
+    </div>
 
-				<a class="get-more-plugins-link" href="https://grafana.com/plugins?utm_source=grafana_plugin_list" target="_blank">
-					Find more <img src="public/img/icn-plugins-tiny.svg" />plugins on Grafana.com
-				</a>
-			</div>
-		</div>
+    <div class="page-action-bar__spacer"></div>
+    <a class="btn btn-success" href="https://grafana.com/plugins?utm_source=grafana_plugin_list" target="_blank">
+      Find more plugins on Grafana.com
+    </a>
+	</div>
 
-		<section class="card-section" layout-mode>
-			<layout-selector></layout-selector>
+  <section class="card-section" layout-mode>
+    <layout-selector></layout-selector>
 
-			<ol class="card-list" >
-				<li class="card-item-wrapper" ng-repeat="plugin in ctrl.plugins">
-					<a class="card-item" href="plugins/{{plugin.id}}/edit">
-						<div class="card-item-header">
-							<div class="card-item-type">
-								<i class="icon-gf icon-gf-{{plugin.type}}"></i>
-								{{plugin.type}}
-							</div>
-							<div class="card-item-notice" ng-show="plugin.hasUpdate">
-								<span bs-tooltip="plugin.latestVersion">Update available!</span>
-							</div>
-						</div>
-						<div class="card-item-body">
-							<figure class="card-item-figure">
-								<img ng-src="{{plugin.info.logos.small}}">
-							</figure>
-							<div class="card-item-details">
-								<div class="card-item-name">{{plugin.name}}</div>
-								<div class="card-item-sub-name">By {{plugin.info.author.name}}</div>
-							</div>
-						</div>
-					</a>
-				</li>
-			</ol>
-		</section>
-	</div>
+    <ol class="card-list" >
+      <li class="card-item-wrapper" ng-repeat="plugin in ctrl.plugins">
+        <a class="card-item" href="plugins/{{plugin.id}}/edit">
+          <div class="card-item-header">
+            <div class="card-item-type">
+              <i class="icon-gf icon-gf-{{plugin.type}}"></i>
+              {{plugin.type}}
+            </div>
+            <div class="card-item-notice" ng-show="plugin.hasUpdate">
+              <span bs-tooltip="plugin.latestVersion">Update available!</span>
+            </div>
+          </div>
+          <div class="card-item-body">
+            <figure class="card-item-figure">
+              <img ng-src="{{plugin.info.logos.small}}">
+            </figure>
+            <div class="card-item-details">
+              <div class="card-item-name">{{plugin.name}}</div>
+              <div class="card-item-sub-name">By {{plugin.info.author.name}}</div>
+            </div>
+          </div>
+        </a>
+      </li>
+    </ol>
+  </section>
 </div>

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

@@ -27,7 +27,7 @@ export class PluginEditCtrl {
     $routeParams,
     navModelSrv,
   ) {
-    this.navModel = navModelSrv.getNav('cfg', 'plugins');
+    this.navModel = navModelSrv.getNav('cfg', 'plugins', 0);
     this.model = {};
     this.pluginId = $routeParams.pluginId;
     this.tabIndex = 0;

+ 13 - 19
public/app/features/plugins/plugin_list_ctrl.ts

@@ -1,34 +1,28 @@
-///<reference path="../../headers/common.d.ts" />
-
 import angular from 'angular';
+import _ from 'lodash';
 
 export class PluginListCtrl {
   plugins: any[];
   tabIndex: number;
   navModel: any;
+  searchQuery: string;
+  allPlugins: any[];
 
   /** @ngInject */
   constructor(private backendSrv: any, $location, navModelSrv) {
     this.tabIndex = 0;
-    this.navModel = navModelSrv.getNav('cfg', 'plugins');
-
-    var pluginType = $location.search().type || 'panel';
-    switch (pluginType) {
-      case "datasource":  {
-        this.tabIndex = 1;
-        break;
-      }
-      case "app": {
-        this.tabIndex = 2;
-        break;
-      }
-      case "panel":
-      default:
-        this.tabIndex = 0;
-    }
+    this.navModel = navModelSrv.getNav('cfg', 'plugins', 0);
 
-    this.backendSrv.get('api/plugins', {embedded: 0, type: pluginType}).then(plugins => {
+    this.backendSrv.get('api/plugins', {embedded: 0}).then(plugins => {
       this.plugins = plugins;
+      this.allPlugins = plugins;
+    });
+  }
+
+  onQueryUpdated() {
+    let regex = new RegExp(this.searchQuery, 'ig');
+    this.plugins = _.filter(this.allPlugins, item => {
+      return regex.test(item.name) || regex.test(item.type);
     });
   }
 }

+ 3 - 7
public/app/features/snapshot/partials/snapshots.html

@@ -1,11 +1,7 @@
-<navbar model="ctrl.navModel"></navbar>
+<page-header model="ctrl.navModel"></page-header>
 
-<div class="page-container">
-  <div class="page-header">
-		<page-h1 model="ctrl.navModel"></page-h1>
-  </div>
-
-   <table class="filter-table" style="margin-top: 20px">
+<div class="page-container page-body">
+   <table class="filter-table">
     <thead>
       <th><strong>Name</strong></th>
       <th><strong>Snapshot url</strong></th>

+ 1 - 1
public/app/features/snapshot/snapshot_ctrl.ts

@@ -9,7 +9,7 @@ export class SnapshotsCtrl {
 
   /** @ngInject */
   constructor(private $rootScope, private backendSrv, navModelSrv) {
-    this.navModel = navModelSrv.getNav('dashboards', 'snapshots');
+    this.navModel = navModelSrv.getNav('dashboards', 'snapshots', 0);
     this.backendSrv.get('/api/dashboard/snapshots').then(result => {
       this.snapshots = result;
     });

+ 11 - 35
public/app/features/styleguide/styleguide.html

@@ -1,34 +1,10 @@
-<navbar model="ctrl.navModel"></navbar>
-
-<div class="page-container">
-	<div class="page-header">
-    <page-h1 model="ctrl.navModel"></page-h1>
-
-		<a class="btn btn-success" ng-click="ctrl.switchTheme()">
-			<i class="fa fa-random"></i>
-			Switch theme
-		</a>
-
-		<div class="page-header-tabs">
-			<ul class="gf-tabs">
-				<li class="gf-tabs-item" ng-repeat="page in ctrl.pages">
-					<a class="gf-tabs-link" href="styleguide/{{page}}" ng-class="{active: ctrl.page[page]}">{{page}}</a>
-				</li>
-			</ul>
-		</div>
+<page-header model="ctrl.navModel"></page-header>
 
-	</div>
+<div class="page-container page-body">
 
-	<div class="tab-pane" ng-if="ctrl.page.colors">
-		<ul>
-			<li class="style-guide-color-card" ng-repeat="color in ctrl.colors" style="background-color: {{color.value}}">
-				<strong>${{color.name}}</strong>
-				<em>{{color.value}}</em>
-			</li>
-		</ul>
-	</div>
+	<h3 class="page-heading">Buttons</h3>
 
-	<div class="tab-pane" ng-if="ctrl.page.buttons">
+	<div class="tab-pane">
 		<div ng-repeat="variant in ctrl.buttonVariants" class="row">
 			<div ng-repeat="btnSize in ctrl.buttonSizes" class="style-guide-button-list p-a-2 col-md-4">
 				<button ng-repeat="buttonName in ctrl.buttonNames" class="btn btn{{variant}}{{buttonName}} {{btnSize}}">
@@ -38,7 +14,7 @@
 		</div>
 	</div>
 
-	<div class="tab-pane style-guide-icon-list" ng-if="ctrl.page.icons">
+	<div class="tab-pane style-guide-icon-list">
 		<div class="row">
 			<div ng-repeat="icon in ctrl.icons" class="col-md-2 col-sm-3 col-xs-4">
 				<i class="icon-gf icon-gf-{{icon}}" bs-tooltip="'icon-gf icon-gf-{{icon}}'"></i>
@@ -46,13 +22,13 @@
 		</div>
 	</div>
 
-	<div class="tab-pane style-guide-plugin-authoring" ng-if="ctrl.page.plugins">
-		<p>From grafana 3.0 it's very easy to develop your own plugins and share them with other grafana users.</p>
-		<p>More information about plugin development can be found at <a href="http://docs.grafana.org/plugins/developing/development/" target="_blank">docs.grafana.org</a></p>
-	</div>
+	<h3 class="page-heading">Forms</h3>
 
-	<div class="tab-pane" ng-if="ctrl.page.forms">
-		forms
+	<div class="gf-form-inline">
+		<div class="gf-form">
+			<label class="gf-form-label">Label</label>
+			<input type="text" class="gf-form-input" />
+		</div>
 	</div>
 
 </div>

+ 2 - 2
public/app/features/styleguide/styleguide.ts

@@ -8,7 +8,7 @@ class StyleGuideCtrl {
   theme: string;
   buttonNames = ['primary', 'secondary', 'inverse', 'success', 'warning', 'danger'];
   buttonSizes = ['btn-small', '', 'btn-large'];
-  buttonVariants = ['-', '-outline-'];
+  buttonVariants = ['-'];
   icons: any = [];
   page: any;
   pages = ['colors', 'buttons', 'icons', 'plugins'];
@@ -16,7 +16,7 @@ class StyleGuideCtrl {
 
   /** @ngInject **/
   constructor(private $http, private $routeParams, private backendSrv, navModelSrv) {
-    this.navModel = navModelSrv.getNav('cfg', 'admin', 'styleguide');
+    this.navModel = navModelSrv.getNav('cfg', 'admin', 'styleguide', 1);
     this.theme = config.bootData.user.lightTheme ? 'light': 'dark';
     this.page = {};
 

+ 1 - 0
public/sass/_grafana.scss

@@ -85,6 +85,7 @@
 @import "components/code_editor";
 @import "components/dashboard_grid";
 @import "components/dashboard_list";
+@import "components/page_header";
 
 
 // PAGES

+ 25 - 71
public/sass/_old_responsive.scss

@@ -1,95 +1,49 @@
 
-.dashnav-back-to-dashboard  {
+.navbar-buttons--zoom {
   display: none;
 }
 
-// Media queries
-// ---------------------
-
-@include media-breakpoint-down(sm) {
-  // div.panel {
-  //   width: 100% !important;
-  //   padding: 0px !important;
-  // }
-  // .panel-margin {
-  //   margin-right: 0;
-  //   margin-left: 0;
-  // }
-  body {
-    padding: 0;
-  }
-  .page-dashboard .navbar-page-btn {
-    max-width: 200px;
-  }
-  .gf-timepicker-nav-btn {
-    max-width: 120px;
-  }
-  .dashnav-zoom-out,
-  .dashnav-move-timeframe,
-  .dashnav-action-icons {
-    display: none;
-  }
-  .page-container {
-    padding: ($spacer * 1) ($spacer * 2);
-  }
+.navbar-page-btn {
+  max-width: 200px;
+}
 
-  .dash-row-menu-container {
-    display: none;
-  }
+.gf-timepicker-nav-btn {
+  max-width: 120px;
 }
 
-@include media-breakpoint-down(xs) {
-  .page-dashboard .navbar-page-btn {
-    max-width: 250px;
-  }
+.navbar-buttons--actions {
+  display: none;
 }
 
-// form styles
-@include media-breakpoint-up(md) {
-  .page-dashboard .navbar-page-btn {
-    max-width: 280px;
-  }
-  .gf-timepicker-nav-btn {
-    max-width: 120px;
-  }
+// Media queries
+// ---------------------
 
-  .dashnav-move-timeframe {
-    display: none;
+@include media-breakpoint-up(sm) {
+  .navbar-page-btn {
+    max-width: 250px;
   }
-
-  .panel-in-fullscreen {
-    .dashnav-action-icons {
-      display: none;
-    }
-    .dashnav-back-to-dashboard  {
-      display: block;
-    }
+  .gf-timepicker-nav-btn {
+    max-width: 200px;
   }
 }
 
-@include media-breakpoint-up(lg) {
-  .page-dashboard .navbar-page-btn {
-    max-width: 290px;
+@include media-breakpoint-up(md) {
+  .navbar-buttons--actions {
+    display: flex;
+  }
+  .navbar-page-btn {
+    max-width: 325px;
   }
   .gf-timepicker-nav-btn {
     max-width: 240px;
   }
-  .dashnav-zoom-out {
-    display: block;
-  }
-  .dashnav-move-timeframe {
-    display: block;
-  }
 }
 
-@include media-breakpoint-up(xl) {
-  .panel-in-fullscreen {
-    .dashnav-action-icons {
-      display: block;
-    }
+@include media-breakpoint-up(lg) {
+  .navbar-buttons--zoom {
+    display: flex;
   }
-
-  .page-dashboard .navbar-page-btn {
+  .navbar-page-btn {
     max-width: none;
   }
   .gf-timepicker-nav-btn {

+ 14 - 6
public/sass/_variables.dark.scss

@@ -15,7 +15,7 @@ $dark-3:           #262628;
 $dark-4:           #333333;
 $dark-5:           #444444;
 $gray-1:           #555555;
-$gray-2:           #7B7B7B;
+$gray-2:           #8e8e8e;
 $gray-3:           #b3b3b3;
 $gray-4:           #D8D9DA;
 $gray-5:           #ECECEC;
@@ -51,7 +51,8 @@ $critical:              #ed2e18;
 // Scaffolding
 // -------------------------
 $body-bg:  			   	    rgb(23,24,25);
-$page-bg:  			   	    $dark-2;
+$page-bg:  			   	    rgb(22, 23, 25);
+
 $body-color:   		 	    $gray-4;
 $text-color:   	   		  $gray-4;
 $text-color-strong: 	  $white;
@@ -64,7 +65,7 @@ $text-shadow-faint: 1px 1px 4px rgb(45, 45, 45);
 
 // gradients
 $brand-gradient: linear-gradient(to right, rgba(255,213,0,0.7) 0%, rgba(255,68,0,0.7) 99%, rgba(255,68,0,0.7) 100%);
-$page-gradient: linear-gradient(180deg, #222426 10px, rgba(15, 15, 16, .03) 100px, rgba(10, 10, 11, .03));
+$page-gradient: linear-gradient(180deg, #222426 10px, rgb(22, 23, 25) 100px);
 
 // Links
 // -------------------------
@@ -97,6 +98,11 @@ $panel-drop-zone-bg:    repeating-linear-gradient(-128deg, #111, #111 10px, #191
 $panel-header-hover-bg:       $dark-4;
 $panel-header-menu-hover-bg:  $dark-5;
 
+// page header
+$page-header-bg: linear-gradient(90deg, #292a2d, black);
+$page-header-shadow: inset 0px -4px 14px $dark-2;
+$page-header-border-color: $dark-4;
+
 $divider-border-color:        #555;
 
 // Graphite Target Editor
@@ -121,8 +127,9 @@ $list-item-link-color: $text-color;
 $list-item-shadow:     $card-shadow;
 
 // Scrollbars
-$scrollbarBackground: #3a3a3a;
+$scrollbarBackground: #404357;
 $scrollbarBackground2: #3a3a3a;
+
 $scrollbarBorder: black;
 
 // Tables
@@ -180,6 +187,7 @@ $input-invalid-border-color:     lighten($red, 5%);
 
 // Search
 $search-shadow: 0 0 35px 0 $body-bg;
+$search-filter-box-bg: $gray-blue;
 
 // Dropdowns
 // -------------------------
@@ -274,7 +282,7 @@ $alert-warning-bg:        linear-gradient(90deg, #d44939, #e0603d);
 $alert-info-bg:           linear-gradient(100deg, #1a4552, #00374a);
 
 // popover
-$popover-bg:              $panel-bg;
+$popover-bg:              $page-bg;
 $popover-color:           $text-color;
 $popover-border-color:    $dark-4;
 $popover-shadow:          0 0 20px black;
@@ -300,7 +308,7 @@ $checkboxImageUrl: '../img/checkbox.png';
 $info-box-background: linear-gradient(100deg, #1a4552, #00374a);
 
 // footer
-$footer-link-color:   $gray-1;
+$footer-link-color:   $gray-2;
 $footer-link-hover:   $gray-4;
 
 // collapse box

+ 9 - 1
public/sass/_variables.light.scss

@@ -102,6 +102,8 @@ $brand-gradient: linear-gradient(to right, rgba(255,213,0,1.0) 0%, rgba(255,68,0
 //$page-gradient: linear-gradient(120deg, transparent 40%, darken($gray-6, 4%) 98%);
 $page-gradient: linear-gradient(120deg, $gray-7 40%, $gray-6 98%);
 //$page-gradient: $gray-7;
+// $page-gradient: linear-gradient(-60deg, transparent 70%, darken($page-bg, 4%) 98%);
+$page-header-bg: linear-gradient(90deg, #292a2d, black);
 
 // Links
 // -------------------------
@@ -135,6 +137,11 @@ $panel-drop-zone-bg: repeating-linear-gradient(-128deg, $body-bg, $body-bg 10px,
 $panel-header-hover-bg:       $gray-6;
 $panel-header-menu-hover-bg:  $gray-4;
 
+// Page header
+$page-header-bg: linear-gradient(90deg, #292a2d, black);
+$page-header-shadow: inset 0px -4px 14px $dark-2;
+$page-header-border-color: $dark-4;
+
 $divider-border-color:	      $gray-2;
 
 // Graphite Target Editor
@@ -238,6 +245,7 @@ $breadcrumb-hover-hl:       #d9dadd;
 
 // search
 $search-shadow: 0 5px 30px 0 $gray-4;
+$search-filter-box-bg: $gray-4;
 
 // Dropdowns
 // -------------------------
@@ -322,7 +330,7 @@ $alert-warning-bg:        linear-gradient(90deg, #d44939, #e04d3d);
 $alert-info-bg:           $blue-dark;
 
 // popover
-$popover-bg:              $panel-bg;
+$popover-bg:              $page-bg;
 $popover-color:           $text-color;
 $popover-border-color:    $gray-5;
 $popover-shadow:          0 0 20px $white;

+ 20 - 16
public/sass/_variables.scss

@@ -86,11 +86,12 @@ $font-family-monospace:    Menlo, Monaco, Consolas, "Courier New", monospace;
 $font-family-base:         $font-family-sans-serif !default;
 
 $font-size-root: 14px !default;
+$font-size-base: 13px !default;
 
-$font-size-base: 1rem !default;
-$font-size-lg:   1.25rem !default;
-$font-size-sm:   .875rem !default;
-$font-size-xs:   .75rem !default;
+$font-size-lg:   18px !default;
+$font-size-md:   15px !default;
+$font-size-sm:   11px !default;
+$font-size-xs:   9px !default;
 
 $line-height-base: 1.5 !default;
 $font-weight-semi-bold: 500;
@@ -159,9 +160,9 @@ $table-cell-padding:            4px 10px !default;
 $table-sm-cell-padding:         .3rem !default;
 
 // Forms
-$input-padding-x:                .75rem !default;
-$input-padding-y:                .6rem !default;
-$input-line-height:              1.35rem !default;
+$input-padding-x:                10px !default;
+$input-padding-y:                8px !default;
+$input-line-height:              19px !default;
 
 $input-btn-border-width:         1px;
 $input-border-radius:            0 $border-radius $border-radius 0 !default;
@@ -172,11 +173,11 @@ $label-border-radius:            $border-radius 0 0 $border-radius !default;
 $label-border-radius-lg:         $border-radius-lg 0 0 $border-radius-lg !default;
 $label-border-radius-sm:         $border-radius-sm 0 0 $border-radius-sm !default;
 
-$input-padding-x-sm:             .5rem !default;
-$input-padding-y-sm:             .25rem !default;
+$input-padding-x-sm:             7px !default;
+$input-padding-y-sm:             4px !default;
 
-$input-padding-x-lg:             1.5rem !default;
-$input-padding-y-lg:             .75rem !default;
+$input-padding-x-lg:             20px !default;
+$input-padding-y-lg:             10px !default;
 
 $input-height:                   (($font-size-base * $line-height-base) + ($input-padding-y * 2)) !default;
 $input-height-lg:                (($font-size-lg * $line-height-lg) + ($input-padding-y-lg * 2)) !default;
@@ -197,10 +198,14 @@ $form-icon-danger: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www
 // Used for a bird's eye view of components dependent on the z-axis
 // Try to avoid customizing these :)
 $zindex-dropdown:          1000;
-$zindex-tooltip:           1020;
-$zindex-navbar-fixed:      1030;
+$zindex-navbar-fixed:      1020;
+$zindex-tooltip:           1030;
 $zindex-modal-backdrop:    1040;
 $zindex-modal:             1050;
+$zindex-typeahead:         1060;
+$zindex-sidemenu : $zindex-navbar-fixed + 5;
+
+
 
 // Buttons
 //
@@ -224,9 +229,8 @@ $side-menu-width:  60px;
 // dashboard
 $panel-margin: 10px;
 $dashboard-padding: $panel-margin * 2;
+$panel-padding: 0px 10px 5px 10px;
 
 // tabs
-$tabs-padding-top: 0.6rem;
-$tabs-padding-bottom: 0.4rem;
-$tabs-top-margin: 0.5rem;
+$tabs-padding: 9px 15px 9px;
 

+ 13 - 0
public/sass/base/_icons.scss

@@ -43,5 +43,18 @@
   background-image: url('../img/icons_#{$theme-name}_theme/icon_add_panel.svg');
 }
 
+.gicon-alert-notification-channel {
+  background-image: url('../img/icons_#{$theme-name}_theme/icon_notification_channels.svg');
+}
 
+.gicon-user-group {
+  background-image: url('../img/icons_#{$theme-name}_theme/icon_user_group.svg');
+}
 
+.gicon-org {
+  background-image: url('../img/icons_#{$theme-name}_theme/icon_org.svg');
+}
+
+.gicon-zoom-out {
+  background-image: url('../img/icons_#{$theme-name}_theme/icon_zoom_out.svg');
+}

+ 1 - 1
public/sass/components/_dashboard_grid.scss

@@ -21,7 +21,7 @@
   }
 }
 
-@include media-breakpoint-down(md) {
+@include media-breakpoint-down(sm) {
   .react-grid-layout {
     height: 100% !important;
   }

+ 2 - 3
public/sass/components/_dropdown.scss

@@ -18,7 +18,7 @@
   position: relative;
   top: -3px;
   width: 250px;
-  font-size: 80%;
+  font-size: $font-size-sm;
   margin-left: 22px;
   color: $gray-2;
   white-space: normal;
@@ -91,7 +91,6 @@
         color: $link-color-disabled;
         position: relative;
         top: 3px;
-        padding-left: 5px;
       }
 
       .gicon {
@@ -300,7 +299,7 @@
 // Typeahead
 // ---------
 .typeahead {
-  z-index: 1051;
+  z-index: $zindex-typeahead;
   margin-top: 2px; // give it some space to breathe
 }
 

+ 1 - 1
public/sass/components/_footer.scss

@@ -5,7 +5,7 @@
 .footer {
   color: $footer-link-color;
   padding: 5rem 0 1rem 0;
-  font-size: $font-size-xs;
+  font-size: $font-size-sm;
   width: 98%;  /* was causing horiz scrollbars - need to examine */
 
   a {

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

@@ -1,4 +1,5 @@
 $gf-form-margin: 3px;
+$input-border: 1px solid $input-border-color;
 
 .gf-form {
   margin-bottom: $gf-form-margin;
@@ -20,6 +21,15 @@ $gf-form-margin: 3px;
   &--flex-end {
     justify-content: flex-end;
   }
+
+  &--alt {
+    flex-direction: column;
+    align-items: flex-start;
+
+    .gf-form-label {
+      padding: 4px 0;
+    }
+  }
 }
 
 .gf-form-disabled {
@@ -115,7 +125,7 @@ $gf-form-margin: 3px;
   background-color: $input-bg;
   background-image: none;
   background-clip: padding-box;
-  border: 1px solid $input-border-color;
+  border: $input-border;
   @include border-radius($input-border-radius-sm);
   @include box-shadow($input-box-shadow);
   white-space: nowrap;
@@ -268,6 +278,7 @@ $gf-form-margin: 3px;
   position: relative;
   background-color: $input-bg;
   padding-right: $input-padding-x;
+  border: $input-border;
 
   &::after {
     position: absolute;
@@ -279,6 +290,10 @@ $gf-form-margin: 3px;
     content: '\f0d7';
     pointer-events: none;
   }
+
+  .gf-form-input {
+    border: none;
+  }
 }
 
 .gf-form-help-icon {

+ 5 - 8
public/sass/components/_modals.scss

@@ -23,7 +23,7 @@
   position: fixed;
   z-index: $zindex-modal;
   width: 100%;
-	background-color: $panel-bg;
+	background: $page-bg;
   @include box-shadow(0 3px 7px rgba(0,0,0,0.3));
   @include background-clip(padding-box);
   outline: none;
@@ -37,13 +37,10 @@
 }
 
 .modal-header {
-  background-color: $body-bg;
-	@include brand-bottom-border();
-	@include clearfix();
-
-  .gf-tabs-link.active {
-    background-color: $panel-bg;
-  }
+  background: $page-header-bg;
+  box-shadow: $page-header-shadow;
+  border-bottom: 1px solid $page-header-border-color;
+  @include clearfix();
 }
 
 .modal-header-title {

+ 56 - 51
public/sass/components/_navbar.scss

@@ -1,19 +1,14 @@
 
 .navbar {
-  display: block;
-  overflow: visible;
   position: relative;
   padding-left: $side-menu-width;
-  box-shadow: $navbarShadow;
-  z-index: 1;
-  background: $navbarBackground;
-}
-
-.navbar-inner {
-  min-height: $navbarHeight;
+  // box-shadow: $navbarShadow;
+  z-index: $zindex-navbar-fixed;
+  // background: $navbarBackground;
+  height: $navbarHeight;
   padding-right: $spacer;
   display: flex;
-  @include clearfix();
+  flex-grow: 1;
 }
 
 .sidemenu-open {
@@ -22,47 +17,6 @@
   }
 }
 
-.navbar .nav {
-  position: relative;
-  left: 0;
-  float: left;
-
-  &--grow {
-    flex-grow: 1;
-  }
-}
-
-
-.navbar .nav > li {
-  float: left;
-}
-
-// Links
-.navbar .nav > li > a {
-  float: none;
-  padding: 17px 13px 13px;
-  color: $navbarLinkColor;
-  text-decoration: none;
-
-  .fa { font-size: 115%; }
-}
-
-// Hover/focus
-.navbar .nav > li > a:focus,
-.navbar .nav > li > a:hover {
-  color: $navbarLinkColorHover;
-  text-decoration: none;
-}
-
-// Active nav items
-.navbar .nav > .active > a,
-.navbar .nav > .active > a:hover,
-.navbar .nav > .active > a:focus {
-  color: $navbarLinkColorActive;
-  text-decoration: none;
-  background-color: $navbarLinkBackgroundActive;
-}
-
 .navbar-page-btn {
   text-overflow: ellipsis;
   overflow: hidden;
@@ -106,3 +60,54 @@
 .navbar-mini-btn-wrapper {
   padding: 15px;
 }
+
+.navbar-buttons {
+  height: $navbarHeight;
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  margin-right: $spacer;
+}
+
+.navbar__spacer {
+  flex-grow: 1;
+}
+
+.navbar-button {
+  @include buttonBackground($btn-inverse-bg, $btn-inverse-bg-hl, $btn-inverse-text-color);
+
+  display: inline-block;
+  font-weight: $btn-font-weight;
+  padding: 8px 11px;
+  line-height: 16px;
+  color: $text-muted;
+  border: 1px solid #151515;
+  margin-right: 1px;
+  white-space: nowrap;
+
+  .gicon {
+    font-size: 16px;
+  }
+
+  .fa {
+    font-size: 16px;
+  }
+
+  &--add-panel {
+    padding: 5px 10px;
+
+    .gicon {
+      font-size: 22px;
+    }
+  }
+
+  &--tight {
+    padding: 9px 4px;
+
+    .fa {
+      font-size: 14px;
+      position: relative;
+      top: 2px;
+    }
+  }
+}

+ 159 - 0
public/sass/components/_page_header.scss

@@ -0,0 +1,159 @@
+
+.page-header-canvas {
+  background: $page-header-bg;
+  box-shadow: $page-header-shadow;
+  border-bottom: 1px solid $page-header-border-color;
+}
+
+.page-header {
+  padding: 2.5rem 0 0 0;
+
+  .btn {
+    float: right;
+    margin-left: 1rem;
+
+    // better align icons
+    .fa {
+      position: relative;
+      top: 1px;
+    }
+  }
+}
+
+.page-header__inner {
+  flex-grow: 1;
+  display: flex;
+  margin-bottom: 2.5rem;
+}
+
+.page-header__title {
+  font-size: $font-size-h2;
+  margin-bottom: 1px;
+  padding-top: $spacer;
+}
+
+.page-header__img {
+  border-radius: 50%;
+  position: relative;
+  top: 10px;
+  width: 50px;
+  height: 50px;
+}
+
+.page-header__icon {
+  font-size: 50px;
+  width: 50px;
+  height: 50px;
+  position: relative;
+
+  &.fa {
+    top: 10px;
+  }
+
+  &.gicon {
+    top: 10px;
+  }
+
+  &.icon-gf {
+    top: 3px;
+  }
+}
+
+.page-header__logo {
+  margin: 0 $spacer;
+}
+
+.page-header__sub-title {
+  color: $text-muted;
+}
+
+.page-header-stamps-type {
+  color: $link-color-disabled;
+  text-transform: uppercase;
+}
+
+.page-breadcrumbs {
+  display: flex;
+  padding: 10px 0;
+  line-height: 0.5;
+}
+
+.breadcrumb {
+  display: inline-block;
+  box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.35);
+  overflow: hidden;
+  border-radius: 5px;
+  counter-reset: flag;
+}
+
+.breadcrumb-item {
+  @include gradientBar($btn-inverse-bg, $btn-inverse-bg-hl, $btn-inverse-text-color);
+
+  text-decoration: none;
+  outline: none;
+  display: block;
+  float: left;
+  font-size: 12px;
+  line-height: 30px;
+  padding: 0 7px 0 37px;
+  position: relative;
+  box-shadow: $card-shadow;
+
+  &:first-child {
+    padding-left: 10px;
+    border-radius: 5px 0 0 5px; /*to match with the parent's radius*/
+    font-size: 18px;
+  }
+
+  &:first-child::before {
+    left: 14px;
+  }
+
+  &:last-child {
+    border-radius: 0 5px 5px 0; /*this was to prevent glitches on hover*/
+    padding-right: 20px;
+  }
+
+  &.active,
+  &:hover {
+    background: #333;
+    background: linear-gradient(#333, #000);
+  }
+
+  &.active::after,
+  &:hover::after {
+    background: #333;
+    background: linear-gradient(135deg, #333, #000);
+  }
+
+  &::after {
+    content: '';
+    position: absolute;
+    top: 0;
+    right: -14px; // half of square's length
+
+    // same dimension as the line-height of .breadcrumb-item
+    width: 30px;
+    height: 30px;
+
+    transform: scale(0.707) rotate(45deg);
+    // we need to prevent the arrows from getting buried under the next link
+    z-index: 1;
+
+    // background same as links but the gradient will be rotated to compensate with the transform applied
+    background: linear-gradient(135deg, $btn-inverse-bg, $btn-inverse-bg-hl);
+
+    // stylish arrow design using box shadow
+    box-shadow: 2px -2px 0 2px rgb(35, 31, 31), 3px -3px 0 2px rgba(255, 255, 255, 0.1);
+
+    // 5px - for rounded arrows and
+    // 50px - to prevent hover glitches on the border created using shadows*/
+    border-radius: 0 5px 0 50px;
+  }
+
+  // we dont need an arrow after the last link
+  &:last-child::after {
+    content: none;
+  }
+}
+

+ 30 - 3
public/sass/components/_panel_add_panel.scss

@@ -1,20 +1,47 @@
 
 .add-panel {
+  height: 100%;
+}
+
+.add-panel__header {
+  padding: 5px 15px;
+  display: flex;
+  align-items: center;
+
+  i {
+    font-size: 30px;
+    margin-right: $spacer;
+  }
+}
+
+.add-panel__title {
+  font-size: $font-size-md;
+  margin-right: $spacer/2;
+}
+
+.add-panel__sub-title {
+  font-style: italic;
+  color: $text-muted;
+  position: relative;
+  top: 1px;
+}
+
+.add-panel__items {
+  padding: 3px 8px;
   display: flex;
   flex-direction: row;
   flex-wrap: wrap;
   overflow: auto;
-  height: 100%;
+  height: calc(100% - 43px);
   align-content: flex-start;
   justify-content: space-around;
-  padding: 3px 0;
 }
 
 .add-panel__item {
   background: $card-background;
   box-shadow: $card-shadow;
 
-  border: $panel-border;
+  border-radius: 3px;
   padding: $spacer/3 $spacer;
   width: 31%;
   height: 60px;

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

@@ -71,7 +71,7 @@
 }
 
 .ps__thumb-y {
-  @include gradient-vertical($blue, lighten($blue, 20%));
+  @include gradient-vertical($scrollbarBackground, $scrollbarBackground2);
   border-radius: 6px;
   width: 6px;
   /* there must be 'right' for ps__thumb-y */

+ 54 - 15
public/sass/components/_search.scss

@@ -6,7 +6,7 @@
   top: $navbarHeight;
   z-index: $zindex-modal-backdrop;
   background-color: $black;
-  @include opacity(70);
+  @include opacity(75);
 }
 
 .search-container {
@@ -44,12 +44,6 @@
   flex-grow: 1;
 }
 
-.search-switches {
-  flex-grow: 1;
-  padding: 1rem 1rem 0.75rem 1rem;
-  white-space: nowrap;
-}
-
 .search-field-icon {
   font-size: $font-size-lg;
   padding: 1rem 1rem 0.75rem 1.5rem;
@@ -57,18 +51,45 @@
 
 .search-dropdown {
   display: flex;
-  flex-direction: column;
-  max-width: 800px;
-  background: $page-bg;
+  flex-direction: row;
   height: calc(100% - #{$navbarHeight});
 }
 
+.search-dropdown__col_1 {
+  background: $page-bg;
+  max-width: 700px;
+  display: flex;
+  flex-direction: column;
+  flex-grow: 1;
+}
+
+.search-dropdown__col_2 {
+  flex-grow: 1;
+  height: 100%;
+  padding-top: 16px;
+}
+
+.search-filter-box {
+  background: $search-filter-box-bg;
+  border-radius: 2px;
+  padding: $spacer*1.5;
+  max-width: 340px;
+  margin-bottom: $spacer * 1.5;
+  margin-left: $spacer * 1.5;
+}
+
+.search-filter-box__header {
+  border-bottom: 1px solid $dark-5;
+  margin-bottom: $spacer * 1.5;
+}
+
 .search-results-container {
   height: 100%;
   display: block;
   padding: $spacer;
   position: relative;
   flex-grow: 10;
+  margin-bottom: 1rem;
 
   .label-tag {
     margin-left: 6px;
@@ -84,9 +105,17 @@
   }
 }
 
+.search-section {
+  background: $panel-bg;
+  border: $panel-border;
+  padding: $panel-padding;
+  margin-bottom: 3px;
+  border-radius: 5px;
+}
+
 .search-section__header {
   font-size: $font-size-h6;
-  padding: 0.6rem 0;
+  padding: 8px 0 2px 0;
   color: $text-color-weak;
   display: flex;
   flex-grow: 1;
@@ -105,7 +134,7 @@
 }
 
 .search-section__header__icon {
-  padding: 3px 10px;
+  padding: 5px 10px;
 }
 
 .search-section__header__toggle {
@@ -170,24 +199,34 @@
 }
 
 .search-item__tags {
-  padding: 8px;
+  padding: 10px;
 }
 
 .search-item__actions {
   flex: 0 0 auto;
+  padding: 0 10px 0 0;
 }
 
 .search-item__actions__item {
-  display: none;
+  display: inline-block;
+  opacity: 0;
+  width: 0;
+  transition: all 0.2s ease-in-out;
+  .fa-star, .fa-star-o {
+    color: $orange;
+    line-height: 37px;
+  }
 }
 
 .search-item:hover {
   .search-item__actions__item {
-    opacity: 0.8;
+    width: 15px;
+    opacity: 1;
   }
 }
 
 .search-button-row {
   text-align: center;
   padding: $spacer*2 $spacer;
+  background: $panel-bg;
 }

+ 121 - 30
public/sass/components/_sidemenu.scss

@@ -4,26 +4,34 @@
   flex-flow: column;
   flex-direction: column;
   width: $side-menu-width;
-  background: $navbarBackground;
-  z-index: 10;
-
+  z-index: $zindex-sidemenu;
   a:focus {
     text-decoration: none;
   }
-}
 
-.sidemenu-open {
-  .sidemenu {
-    background: $side-menu-bg;
-    position: initial;
-    height: auto;
-    box-shadow: $side-menu-shadow;
-    position: relative;
-    z-index: 2;
+  .sidemenu__logo_small_breakpoint {
+    display: none;
+  }
+
+  .sidemenu__close {
+    display: none;
   }
-  .sidemenu__top,
-  .sidemenu__bottom {
-    display: block;
+}
+
+@include media-breakpoint-up(sm) {
+  .sidemenu-open {
+    .sidemenu {
+      background: $side-menu-bg;
+      position: initial;
+      height: auto;
+      box-shadow: $side-menu-shadow;
+      position: relative;
+      z-index: $zindex-sidemenu;
+    }
+    .sidemenu__top,
+    .sidemenu__bottom {
+      display: block;
+    }
   }
 }
 
@@ -42,21 +50,23 @@
   position: relative;
   @include left-brand-border();
 
-  &.active,
-  &:hover {
-    background-color: $side-menu-item-hover-bg;
-    @include left-brand-border-gradient();
+  @include media-breakpoint-up(sm) {
+    &.active,
+    &:hover {
+      background-color: $side-menu-item-hover-bg;
+      @include left-brand-border-gradient();
 
-    .dropdown-menu {
-      margin: 0;
-      display: block;
-      opacity: 0;
-      top: 0px;
-      // important to overlap it otherwise it can be hidden
-      // again by the mouse getting outside the hover space
-      left: $side-menu-width - 2px;
-      @include animation('dropdown-anim 150ms ease-in-out 100ms forwards');
-      z-index: 1;
+      .dropdown-menu {
+        margin: 0;
+        display: block;
+        opacity: 0;
+        top: 0px;
+        // important to overlap it otherwise it can be hidden
+        // again by the mouse getting outside the hover space
+        left: $side-menu-width - 2px;
+        @include animation('dropdown-anim 150ms ease-in-out 100ms forwards');
+        z-index:  $zindex-sidemenu;
+      }
     }
   }
 }
@@ -154,7 +164,7 @@ li.sidemenu-org-switcher {
   }
 }
 
-.sidemenu__logo {
+.sidemenu__logo, .sidemenu__logo_small_breakpoint {
   display: block;
   padding: 0.4rem 1.0rem 0.4rem 0.65rem;
   min-height: $navbarHeight;
@@ -172,3 +182,84 @@ li.sidemenu-org-switcher {
   }
 }
 
+@include media-breakpoint-down(xs) {
+  .sidemenu-open {
+    .navbar {
+      padding-left: 60px !important;
+    }
+  }
+
+  .sidemenu-open--xs {
+    .sidemenu {
+      width: 100%;
+      background: $side-menu-bg;
+      position: initial;
+      height: auto;
+      box-shadow: $side-menu-shadow;
+      position: relative;
+      z-index: $zindex-sidemenu;
+    }
+
+    .sidemenu__close {
+      display: block;
+      font-size: $font-size-md;
+    }
+
+    .sidemenu__top,
+    .sidemenu__bottom {
+      display: block;
+    }
+  }
+
+  .sidemenu {
+    .sidemenu__logo {
+      display: none;
+    }
+    .sidemenu__logo_small_breakpoint {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: baseline;
+
+      &:hover {
+        background: transparent;
+      }
+    }
+
+    .sidemenu__top {
+      padding-top: 0rem;
+    }
+
+    .side-menu-header {
+      padding-left: 10px;
+    }
+
+    .sidemenu-link {
+      text-align: left;
+    }
+
+    .sidemenu-icon {
+      display: none
+    }
+
+    .dropdown-menu--sidemenu {
+      display: block;
+      position: unset;
+      width: 100%;
+      float: none;
+      margin-top: 0.5rem;
+      margin-bottom: 0.5rem;
+
+      > li > a {
+        padding-left: 15px;
+      }
+    }
+
+    .sidemenu__bottom {
+      .dropdown-menu--sidemenu {
+        display: flex;
+        flex-direction: column-reverse;
+      }
+    }
+  }
+}

+ 4 - 2
public/sass/components/_tabbed_view.scss

@@ -12,8 +12,10 @@
 }
 
 .tabbed-view-header {
+  background: $page-header-bg;
+  box-shadow: $page-header-shadow;
+  border-bottom: 1px solid $page-header-border-color;
   @include clearfix();
-  @include brand-bottom-border();
 }
 
 .tabbed-view-title {
@@ -34,7 +36,7 @@
   margin: 0;
   background-color: transparent;
   border: none;
-  padding: ($tabs-padding-top + $tabs-top-margin) $spacer $tabs-padding-bottom;
+  padding: $tabs-padding;
   color: $text-color;
   i {
     font-size: 120%;

+ 11 - 51
public/sass/components/_tabs.scss

@@ -1,41 +1,8 @@
-.nav-tabs-alt {
-	& > li > a {
-	  color: darken($link-color, 20%);
-	}
-
-	li > a:hover {
-    border-bottom: none;
-	}
-
-	li.active > a,
-	li.active > a:focus,
-	li.active > a:hover {
-    @include border-radius(3px);
-	  border: 1px solid $divider-border-color;
-	  background-color: transparent;
-	  border-bottom: 1px solid $page-bg;
-	  color: $link-color;
-	}
-
-	li.disabled > a {
-		color: $text-color;
-	}
-
-	.open .dropdown-toggle {
-		background-color: #060606;
-		border-color: transparent;
-	}
-
-  .tab-content {
-    padding: 10px;
-    background-color: $panel-bg;
-  }
-}
-
 .gf-tabs {
   @include clearfix();
   float: left;
-  margin: $tabs-top-margin 0 0 0;
+  position: relative;
+  top: 1px;
 }
 
 .gf-tabs-item {
@@ -44,13 +11,17 @@
 }
 
 .gf-tabs-link {
-  padding: $tabs-padding-top $spacer $tabs-padding-bottom $spacer;
+  padding: $tabs-padding;
   margin-right: $spacer/2;
-  border: 1px solid transparent;
   position: relative;
   display: block;
+  border: solid transparent;
+  border-width: 2px 1px 1px;
+  border-radius: 3px 3px 0 0;
 
-  @include border-radius(2px 2px 0 0);
+  i {
+    margin-right: 5px;
+  }
 
   &:hover,
   &:focus {
@@ -60,20 +31,9 @@
   &.active,
   &.active:hover,
   &.active:focus {
-    @include border-radius(3px);
-    border-color: rgba(216, 131, 40, 0.77);
-    border-bottom: 1px solid $page-bg;
+    border-color: $orange $dark-4 transparent;
+    background: $page-bg;
     color: $link-color;
-    position: relative;
-    top: 1px;
   }
 }
 
-.form-tabs-wrapper {
-  @include brand-bottom-border();
-  @include clearfix();
-}
-
-.form-tabs-content {
-  padding: $spacer*2 $spacer;
-}

+ 6 - 17
public/sass/components/_timepicker.scss

@@ -1,15 +1,15 @@
-.nav.gf-timepicker-nav {
-  margin-right: 0;
-}
-
 .timepicker-timestring {
   font-weight: normal;
 }
 
+.gf-timepicker-nav {
+  flex-wrap: nowrap;
+  display: flex;
+}
+
 .gf-timepicker-nav-btn {
-  overflow: hidden;
   text-overflow: ellipsis;
-  white-space: nowrap;
+  overflow: hidden;
 }
 
 .gf-timepicker-dropdown {
@@ -118,14 +118,3 @@
   @extend .fa-chevron-left;
 }
 
-.gf-timepicker-time-control {
-  font-size: $font-size-sm;
-  a {
-    padding: 18px 7px 13px !important;
-  }
-}
-
-.dashnav-move-timeframe  {
-  position: relative;
-  top: 1px;
-}

+ 6 - 17
public/sass/components/_view_states.scss

@@ -21,33 +21,22 @@
 
 .playlist-active,
 .user-activity-low {
+  .react-resizable-handle
   .add-row-panel-hint,
   .dash-row-menu-container,
-  .panel-drop-zone
-  .dashnav-refresh-action,
-  .dashnav-zoom-out,
+  .navbar-button--refresh,
+  .navbar-buttons--zoom,
+  .navbar-buttons--actions,
   .panel-menu-container,
-  .dashnav-action-icons,
   .panel-info-corner--info,
-  .panel-info-corner--links,
-  .dashnav-move-timeframe  {
+  .panel-info-corner--links {
     opacity: 0;
     transition: all 1.5s ease-in-out 1s;
   }
 
-  // navbar buttons
-  .navbar {
-    border-color: transparent;
-    background: transparent;
-    transition: all 1.5s ease-in-out 1s;
-    .fa {
-      opacity: 0;
-      transition: all 1.5s ease-in-out 1s;
-    }
-  }
-
   .navbar {
     box-shadow: none;
+    background: transparent;
   }
 
   .navbar-page-btn {

Некоторые файлы не были показаны из-за большого количества измененных файлов