From 74ceb76ec02ec6761618a655a451122e65d0d139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 30 Nov 2017 15:37:03 +0100 Subject: [PATCH] ux: work on page header --- pkg/api/dtos/index.go | 1 + pkg/api/index.go | 85 +++++++++--------- public/app/core/angular_wrappers.ts | 2 + public/app/core/components/PageHeader.tsx | 88 +++++++++++++++++++ public/app/core/nav_model_srv.ts | 28 ++++-- .../admin/partials/configuration_home.html | 10 +-- .../app/features/alerting/alert_list_ctrl.ts | 3 +- .../alerting/notifications_list_ctrl.ts | 3 +- .../alerting/partials/alert_list.html | 26 +----- .../alerting/partials/notifications_list.html | 25 +----- public/app/features/org/org_details_ctrl.ts | 2 +- .../app/features/org/partials/orgDetails.html | 59 +++++++++---- public/app/features/plugins/ds_list_ctrl.ts | 2 +- .../features/plugins/partials/ds_list.html | 11 +-- public/sass/_variables.dark.scss | 1 + public/sass/base/_icons.scss | 4 + public/sass/components/_page_header.scss | 40 ++++++--- public/sass/layout/_page.scss | 6 ++ public/sass/pages/_plugins.scss | 50 +++-------- 19 files changed, 254 insertions(+), 192 deletions(-) create mode 100644 public/app/core/components/PageHeader.tsx diff --git a/pkg/api/dtos/index.go b/pkg/api/dtos/index.go index 5661ae1df91..8f1cdd9a92d 100644 --- a/pkg/api/dtos/index.go +++ b/pkg/api/dtos/index.go @@ -24,6 +24,7 @@ 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"` diff --git a/pkg/api/index.go b/pkg/api/index.go index 7a954ecdf22..7f30dcf9f8a 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -104,7 +104,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { {Text: "Home", Url: setting.AppSubUrl + "/", Icon: "fa fa-fw fa-home"}, {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"}, + {Text: "Dashboard List", Id: "dashboards", Url: setting.AppSubUrl + "/dashboards", Icon: "fa fa-fw fa-bars"}, } data.NavTree = append(data.NavTree, &dtos.NavLink{ @@ -146,6 +146,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { 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 +203,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", @@ -218,25 +220,6 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { {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", Id: "users", @@ -245,12 +228,32 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { Url: setting.AppSubUrl + "/org/users", }, { - Text: "Groups", + Text: "Teams", Id: "users", 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", + // 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: "Preferences", + Id: "org-settings", + Description: "Organization preferences", + Icon: "fa fa-fw fa-sliders", + Url: setting.AppSubUrl + "/org", + }, + { Text: "API Keys", Id: "apikeys", @@ -261,21 +264,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", - 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"}, - }, - }) - } + // 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", + // 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"}, + // }, + // }) + // } data.NavTree = append(data.NavTree, cfgNode) } diff --git a/public/app/core/angular_wrappers.ts b/public/app/core/angular_wrappers.ts index 7acdc79d55a..00181736119 100644 --- a/public/app/core/angular_wrappers.ts +++ b/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"]); } diff --git a/public/app/core/components/PageHeader.tsx b/public/app/core/components/PageHeader.tsx new file mode 100644 index 00000000000..bc0fbb3f7b9 --- /dev/null +++ b/public/app/core/components/PageHeader.tsx @@ -0,0 +1,88 @@ +import React from 'react'; +import { NavModel } from '../nav_model_srv'; +import classNames from 'classnames'; + +export interface IProps { + model: NavModel; +} + +export default class PageHeader extends React.Component { + constructor(props) { + super(props); + } + + renderBreadcrumb(breadcrumb) { + return ( + + {breadcrumb.text} + + ); + } + + renderTab(tab) { + let tabClasses = classNames({ + 'gf-tabs-link': true, + 'active': tab.active, + }); + + console.log(tab.active); + + return ( +
  • + + + {tab.text} + +
  • + ); + } + + renderHeaderTitle(main) { + return ( +
    + + {main.icon && } + {main.img && } + + +
    +

    {main.text}

    + {main.subTitle &&
    {main.subTitle}
    } + {main.subType && ( +
    + + {main.subType.text} +
    + )} +
    +
    + ); + } + + render() { + return ( +
    +
    +
    +
    + + + + {this.props.model.breadcrumbs.map(this.renderBreadcrumb)} +
    +
    + +
    + {this.renderHeaderTitle(this.props.model.main)} + + {this.props.model.main.children && ( +
      + {this.props.model.main.children.map(this.renderTab)} +
    + )} +
    +
    +
    + ); + } +} diff --git a/public/app/core/nav_model_srv.ts b/public/app/core/nav_model_srv.ts index 964f8f4bd91..017b2c6435f 100644 --- a/public/app/core/nav_model_srv.ts +++ b/public/app/core/nav_model_srv.ts @@ -1,5 +1,3 @@ -/// - import coreModule from 'app/core/core_module'; import config from 'app/core/config'; import _ from 'lodash'; @@ -9,20 +7,18 @@ export interface NavModelItem { url: string; icon?: string; img?: string; + active?: boolean; + children: NavModelItem[]; } export class NavModel { breadcrumbs: NavModelItem[]; - header: NavModelItem; + main: NavModelItem; node: NavModelItem; constructor() { this.breadcrumbs = []; } - - setPageHeaderIndex(index: number) { - this.header = this.breadcrumbs[index]; - } } export class NavModelSrv { @@ -43,13 +39,29 @@ export class NavModelSrv { 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.header = 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; } diff --git a/public/app/features/admin/partials/configuration_home.html b/public/app/features/admin/partials/configuration_home.html index 854e4eb848d..7ebc5127b4a 100644 --- a/public/app/features/admin/partials/configuration_home.html +++ b/public/app/features/admin/partials/configuration_home.html @@ -1,12 +1,4 @@ -
    -
    - - - -
    -
    +
    diff --git a/public/app/features/alerting/alert_list_ctrl.ts b/public/app/features/alerting/alert_list_ctrl.ts index e7a0dbf1298..2f70e9bda59 100644 --- a/public/app/features/alerting/alert_list_ctrl.ts +++ b/public/app/features/alerting/alert_list_ctrl.ts @@ -23,8 +23,7 @@ export class AlertListCtrl { /** @ngInject */ constructor(private backendSrv, private $location, navModelSrv) { - this.navModel = navModelSrv.getNav('alerting', 'alert-list'); - this.navModel.setPageHeaderIndex(0); + this.navModel = navModelSrv.getNav('alerting', 'alert-list', 0); var params = $location.search(); this.filters.state = params.state || null; diff --git a/public/app/features/alerting/notifications_list_ctrl.ts b/public/app/features/alerting/notifications_list_ctrl.ts index 55647857b41..d1edeb35ac2 100644 --- a/public/app/features/alerting/notifications_list_ctrl.ts +++ b/public/app/features/alerting/notifications_list_ctrl.ts @@ -9,8 +9,7 @@ export class AlertNotificationsListCtrl { /** @ngInject */ constructor(private backendSrv, navModelSrv) { this.loadNotifications(); - this.navModel = navModelSrv.getNav('alerting', 'channels'); - this.navModel.setPageHeaderIndex(0); + this.navModel = navModelSrv.getNav('alerting', 'channels', 0); } loadNotifications() { diff --git a/public/app/features/alerting/partials/alert_list.html b/public/app/features/alerting/partials/alert_list.html index df7105d0bfe..9a992dd34a3 100644 --- a/public/app/features/alerting/partials/alert_list.html +++ b/public/app/features/alerting/partials/alert_list.html @@ -1,28 +1,4 @@ -
    - -
    +
    diff --git a/public/app/features/alerting/partials/notifications_list.html b/public/app/features/alerting/partials/notifications_list.html index 064348b64b6..a2f6f723696 100644 --- a/public/app/features/alerting/partials/notifications_list.html +++ b/public/app/features/alerting/partials/notifications_list.html @@ -1,27 +1,4 @@ -
    - -
    +
    diff --git a/public/app/features/org/org_details_ctrl.ts b/public/app/features/org/org_details_ctrl.ts index 63291c346e0..525cb6b8b59 100644 --- a/public/app/features/org/org_details_ctrl.ts +++ b/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() { diff --git a/public/app/features/org/partials/orgDetails.html b/public/app/features/org/partials/orgDetails.html index 69422925dee..8d000a7b8d1 100644 --- a/public/app/features/org/partials/orgDetails.html +++ b/public/app/features/org/partials/orgDetails.html @@ -1,26 +1,51 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -
    - + -

    General

    -
    -
    -
    - Organization name - -
    -
    +
    +

    General

    + +
    +
    + Organization name + +
    +
    - - - - + +
    diff --git a/public/app/features/plugins/ds_list_ctrl.ts b/public/app/features/plugins/ds_list_ctrl.ts index a893ee7475f..5feadb68fe3 100644 --- a/public/app/features/plugins/ds_list_ctrl.ts +++ b/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; diff --git a/public/app/features/plugins/partials/ds_list.html b/public/app/features/plugins/partials/ds_list.html index 5bec4a5d44e..0669beb4129 100644 --- a/public/app/features/plugins/partials/ds_list.html +++ b/public/app/features/plugins/partials/ds_list.html @@ -1,13 +1,4 @@ -
    -
    - - - -
    -
    +
    diff --git a/public/sass/_variables.dark.scss b/public/sass/_variables.dark.scss index 1164f8305e0..437c33d7bbd 100644 --- a/public/sass/_variables.dark.scss +++ b/public/sass/_variables.dark.scss @@ -52,6 +52,7 @@ $critical: #ed2e18; // ------------------------- $body-bg: rgb(23,24,25); $page-bg: rgb(22, 23, 25); + $body-color: $gray-4; $text-color: $gray-4; $text-color-strong: $white; diff --git a/public/sass/base/_icons.scss b/public/sass/base/_icons.scss index d0a9dbebcba..e8dc28c96b6 100644 --- a/public/sass/base/_icons.scss +++ b/public/sass/base/_icons.scss @@ -47,5 +47,9 @@ 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'); +} + diff --git a/public/sass/components/_page_header.scss b/public/sass/components/_page_header.scss index 9c3a7dc31ea..6544e15b935 100644 --- a/public/sass/components/_page_header.scss +++ b/public/sass/components/_page_header.scss @@ -20,27 +20,30 @@ } } +.page-header__inner { + flex-grow: 1; + display: flex; + margin-bottom: 2.5rem; +} + .page-header__title { font-size: $font-size-h2; - flex-grow: 1; - margin-bottom: 2.5rem; - line-height: 50px; + margin-bottom: 1px; + padding-top: $spacer; } .page-header__img { border-radius: 50%; - margin-right: 0.5rem; position: relative; top: -3px; - width: 50px; - height: 50px; + width: 65px; + height: 65px; } .page-header__icon { - font-size: 150%; - margin-right: 0.5rem; - width: 50px; - height: 50px; + font-size: 70px; + width: 65; + height: 65; position: relative; &.fa { @@ -52,10 +55,19 @@ } } -.page-heading { - font-size: 1.25rem; - margin-top: 0; - margin-bottom: $spacer * 0.7; +.page-header__logo { + margin-right: $spacer/2; } +.page-header-info-block { +} + +.page-header__sub-title { + color: $text-muted; +} + +.page-header-stamps-type { + color: $link-color-disabled; + text-transform: uppercase; +} diff --git a/public/sass/layout/_page.scss b/public/sass/layout/_page.scss index b261c091c37..6ea39877311 100644 --- a/public/sass/layout/_page.scss +++ b/public/sass/layout/_page.scss @@ -42,6 +42,12 @@ } } +.page-heading { + font-size: 1.25rem; + margin-top: 0; + margin-bottom: $spacer * 0.7; +} + .page-action-bar { margin-bottom: $spacer * 2; display: flex; diff --git a/public/sass/pages/_plugins.scss b/public/sass/pages/_plugins.scss index c93d94f40b5..edb4e8ade3c 100644 --- a/public/sass/pages/_plugins.scss +++ b/public/sass/pages/_plugins.scss @@ -1,41 +1,3 @@ -.plugin-header { - @include clearfix(); - - padding: $spacer 0 $spacer/2 0; - margin-bottom: 2rem; -} - -.plugin-header-logo { - float: left; - width: 7rem; - img { - width: 7rem; - } - margin-right: $spacer; -} - -.plugin-header-info-block { - float: left; -} - -.plugin-header-author { -} - -.plugin-header-stamps-type { - color: $link-color-disabled; - text-transform: uppercase; -} - -.plugin-info-list-item { - img { - width: 16px; - } - - white-space: nowrap; - max-width: $page-sidebar-width; - text-overflow: ellipsis; - overflow: hidden; -} .get-more-plugins-link { color: $gray-3; @@ -55,3 +17,15 @@ display: none; } } + +.plugin-info-list-item { + img { + width: 16px; + } + + white-space: nowrap; + max-width: $page-sidebar-width; + text-overflow: ellipsis; + overflow: hidden; +} +