Ver Fonte

Merge branch 'develop' of github.com:grafana/grafana into develop

Marcus Efraimsson há 8 anos atrás
pai
commit
cb0dac11a3

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

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

+ 41 - 4
public/app/core/components/PageHeader.tsx → public/app/core/components/PageHeader/PageHeader.tsx

@@ -1,6 +1,7 @@
 import React from 'react';
-import { NavModel, NavModelItem } from '../nav_model_srv';
+import { NavModel, NavModelItem } from '../../nav_model_srv';
 import classNames from 'classnames';
+import appEvents from 'app/core/app_events';
 
 export interface IProps {
   model: NavModel;
@@ -26,8 +27,44 @@ function TabItem(tab: NavModelItem) {
   );
 }
 
-function Tabs({main}: {main: NavModelItem}) {
-  return <ul className="gf-tabs">{main.children.map(TabItem)}</ul>;
+function SelectOption(navItem: NavModelItem) {
+  if (navItem.hideFromTabs) { // TODO: Rename hideFromTabs => hideFromNav
+    return (null);
+  }
+
+  return (
+    <option key={navItem.url} value={navItem.url}>
+      {navItem.text}
+    </option>
+  );
+}
+
+function Navigation({main}: {main: NavModelItem}) {
+  return (<nav>
+    <SelectNav customCss="page-header__select_nav" main={main} />
+    <Tabs customCss="page-header__tabs" main={main} />
+  </nav>);
+}
+
+function SelectNav({main, customCss}: {main: NavModelItem, customCss: string}) {
+  const defaultSelectedItem = main.children.find(navItem => {
+    return navItem.active === true;
+  });
+
+  const gotoUrl = evt => {
+    var element = evt.target;
+    var url = element.options[element.selectedIndex].value;
+    appEvents.emit('location-change', {href: url});
+  };
+
+  return (<select
+    className={`gf-select-nav ${customCss}`}
+    defaultValue={defaultSelectedItem.url}
+    onChange={gotoUrl}>{main.children.map(SelectOption)}</select>);
+}
+
+function Tabs({main, customCss}: {main: NavModelItem, customCss: string}) {
+  return <ul className={`gf-tabs ${customCss}`}>{main.children.map(TabItem)}</ul>;
 }
 
 export default class PageHeader extends React.Component<IProps, any> {
@@ -63,7 +100,7 @@ export default class PageHeader extends React.Component<IProps, any> {
         <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} />}
+            {this.props.model.main.children && <Navigation main={this.props.model.main} />}
           </div>
         </div>
       </div>

+ 2 - 1
public/app/core/components/grafana_app.ts

@@ -12,7 +12,7 @@ import Drop from 'tether-drop';
 export class GrafanaCtrl {
 
   /** @ngInject */
-  constructor($scope, alertSrv, utilSrv, $rootScope, $controller, contextSrv) {
+  constructor($scope, alertSrv, utilSrv, $rootScope, $controller, contextSrv, globalEventSrv) {
 
     $scope.init = function() {
       $scope.contextSrv = contextSrv;
@@ -23,6 +23,7 @@ export class GrafanaCtrl {
       profiler.init(config, $rootScope);
       alertSrv.init();
       utilSrv.init();
+      globalEventSrv.init();
 
       $scope.dashAlerts = alertSrv;
     };

+ 1 - 0
public/app/core/services/all.js

@@ -8,5 +8,6 @@ define([
   './segment_srv',
   './backend_srv',
   './dynamic_directive_srv',
+  './global_event_srv'
 ],
 function () {});

+ 21 - 0
public/app/core/services/global_event_srv.ts

@@ -0,0 +1,21 @@
+import coreModule from 'app/core/core_module';
+import appEvents from 'app/core/app_events';
+
+// This service is for registering global events.
+// Good for communication react > angular and vice verse
+export class GlobalEventSrv {
+
+  /** @ngInject */
+  constructor(private $location, private $timeout) {
+  }
+
+  init() {
+    appEvents.on('location-change', payload => {
+        this.$timeout(() => { // A hack to use timeout when we're changing things (in this case the url) from outside of Angular.
+            this.$location.path(payload.href);
+        });
+    });
+  }
+}
+
+coreModule.service('globalEventSrv', GlobalEventSrv);

+ 0 - 3
public/app/core/utils/react2angular.ts

@@ -1,10 +1,7 @@
 import coreModule from 'app/core/core_module';
 
 export function react2AngularDirective(name: string, component: any, options: any) {
-
   coreModule.directive(name, ['reactDirective', reactDirective => {
     return reactDirective(component, options);
   }]);
-
 }
-

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

@@ -1,6 +1,7 @@
 ///<reference path="../../headers/common.d.ts" />
 
 import coreModule from '../../core/core_module';
+import {appEvents} from 'app/core/core';
 
 export class DataSourcesCtrl {
   datasources: any;
@@ -11,13 +12,24 @@ export class DataSourcesCtrl {
     private $scope,
     private backendSrv,
     private datasourceSrv,
+    private $location,
     private navModelSrv) {
 
     this.navModel = this.navModelSrv.getNav('cfg', 'datasources', 0);
-
+    this.navigateToUrl = this.navigateToUrl.bind(this);
     backendSrv.get('/api/datasources').then(result => {
       this.datasources = result;
     });
+
+    appEvents.on('location-change', payload => {
+      this.navigateToUrl(payload.href);
+    });
+  }
+
+  navigateToUrl(url) {
+    // debugger;
+    this.$location.path(url);
+    this.$location.replace();
   }
 
   removeDataSourceConfirmed(ds) {

+ 57 - 52
public/app/partials/error.html

@@ -1,55 +1,60 @@
-<navbar model="navModel"></navbar>
-
 <div class="page-container">
-
   <div class="page-header">
-    <h1>
-		Page not found (404)
-	</h1>
-	</div>
-	<div class="error-row">
-		<div class="dash-row-menu-grip"><i class="fa fa-ellipsis-v"></i></div>
-		<div class="panel-container error-row">
-			<div class="error-column graph-box">
-				<div class="error-row">
-					<div class="error-column error-space-between graph-percentage">
-						<p>100%</p>
-						<p>80%</p>
-						<p>60%</p>
-						<p>40%</p>
-						<p>20%</p>
-						<p>0%</p>
-					</div>
-					<div class="error-column image-box">
-						<img src="public/img/graph404.svg" width="100%">
-						<div class="error-row error-space-between">
-							<p class="graph-text">Then</p>
-							<p class="graph-text">Now</p>
-						</div>
-					</div>
-				</div>
-			</div>
-			<div class="error-column info-box">
-				<div class="error-row current-box">
-					<p class="current-text">current</p>
-				</div>
-				<div class="error-row" style="flex: 1">
-					<i class="fa fa-minus error-minus"></i>
-					<div class="error-column error-space-between">
-						<div class="error-row error-space-between">
-							<p>Chances you are on the page you are looking for.</p>
-							<p class="left-margin">0%</p>
-						</div>
-						<div>
-							<h3>Sorry for the inconvenience</h3>
-							<p>Please go back to your <a href="{{appSubUrl}}/" class="error-link">home dashboard</a> and try again.</p>
-							<p>If the error persists, seek help on the <a href="https://community.grafana.com" target="_blank" class="error-link">community site</a>.</p>
-						</div>
-					</div>
-				</div>
-			</div>
-			<span class="resize-panel-handle icon-gf icon-gf-grabber" style="cursor: default"></span>
-		</div>
-	</div>
-
+    <div class="page-header__inner">
+      <span class="page-header__logo">
+        <i class="page-header__icon fa fa-fw fa-exclamation-triangle"></i>
+      </span>
+      <div class="page-header__info-block">
+        <h1 class="page-header__title">
+          Page not found
+        </h1>
+        <div class="page-header__sub-title">
+          404 Error
+        </div>
+      </div>
+    </div>
+  </div>
+    <div class="panel-container error-container">
+      <div class="error-column graph-box">
+        <div class="error-row">
+          <div class="error-column error-space-between graph-percentage">
+            <p>100%</p>
+            <p>80%</p>
+            <p>60%</p>
+            <p>40%</p>
+            <p>20%</p>
+            <p>0%</p>
+          </div>
+          <div class="error-column image-box">
+            <img src="public/img/graph404.svg" width="100%">
+            <div class="error-row error-space-between">
+              <p class="graph-text">Then</p>
+              <p class="graph-text">Now</p>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="error-column info-box">
+        <div class="error-row current-box">
+          <p class="current-text">current</p>
+        </div>
+        <div class="error-row" style="flex: 1">
+          <i class="fa fa-minus error-minus"></i>
+          <div class="error-column error-space-between error-full-width">
+            <div class="error-row error-space-between">
+              <p>Chances you are on the page you are looking for.</p>
+              <p class="left-margin">0%</p>
+            </div>
+            <div>
+              <h3>Sorry for the inconvenience</h3>
+              <p>Please go back to your
+                <a href="{{appSubUrl}}/" class="error-link">home dashboard</a> and try again.</p>
+              <p>If the error persists, seek help on the
+                <a href="https://community.grafana.com" target="_blank" class="error-link">community site</a>.</p>
+            </div>
+          </div>
+        </div>
+      </div>
+      <span class="react-resizable-handle" style="cursor: default"></span>
+    </div>
 </div>

+ 1 - 1
public/sass/_variables.scss

@@ -235,5 +235,5 @@ $dashboard-padding: $panel-margin * 2;
 $panel-padding: 0px 10px 5px 10px;
 
 // tabs
-$tabs-padding: 9px 15px 9px;
+$tabs-padding: 10px 15px 9px;
 

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

@@ -8,7 +8,7 @@
   }
 
   .react-grid-item {
-    display: none;
+    display: none !important;
     transition-property: none !important;
   }
 

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

@@ -72,6 +72,21 @@
   text-transform: uppercase;
 }
 
+.page-header__select_nav {
+  margin-bottom: 10px;
+
+  @include media-breakpoint-up(lg) {
+    display: none;
+  }
+}
+
+.page-header__tabs {
+  display: none;
+  @include media-breakpoint-up(lg) {
+    display: block;
+  }
+}
+
 .page-breadcrumbs {
   display: flex;
   padding: 10px 0;

+ 13 - 1
public/sass/components/_tabs.scss

@@ -16,7 +16,7 @@
   position: relative;
   display: block;
   border: solid transparent;
-  border-width: 2px 1px 1px;
+  border-width: 0 1px 1px;
   border-radius: 3px 3px 0 0;
 
   i {
@@ -34,6 +34,18 @@
     border-color: $orange $tab-border-color transparent;
     background: $page-bg;
     color: $link-color;
+    overflow: hidden;
+
+    &::before {
+      display: block;
+      content: ' ';
+      position: absolute;
+      left: 0;
+      right: 0;
+      height: 2px;
+      top: 0;
+      background-image: linear-gradient(to right, #ffd500 0%, #ff4400 99%, #ff4400 100%);
+    }
   }
 }
 

+ 34 - 1
public/sass/pages/_errorpage.scss

@@ -3,6 +3,11 @@
 // Layout
 //
 
+.error-container {
+  display: flex;
+  flex-direction: row;
+}
+
 .error-row {
     display: flex;
     flex-direction: row;
@@ -22,7 +27,7 @@
 
 .info-box {
     width: 38%;
-    padding: 2rem 1rem 6rem;
+    padding: 2rem 1rem 2rem;
 }
 
 .graph-percentage {padding: 0 0 1.5rem;}
@@ -58,3 +63,31 @@
 }
 
 .graph-text {margin: 0;}
+
+@include media-breakpoint-down(sm) {
+  .graph-box {
+    width: 50%;
+  }
+
+  .info-box {
+    width: 50%;
+  }
+}
+
+@include media-breakpoint-down(xs) {
+  .error-container {
+    flex-direction: column;
+  }
+
+  .graph-box {
+    width: 100%;
+  }
+
+  .info-box {
+      width: 100%;
+  }
+
+  .error-full-width {
+    width: 100%;
+  }
+}