Merge remote-tracking branch 'origin/9879-login' into develop-login2

This commit is contained in:
Torkel Ödegaard 2017-12-13 16:06:17 +01:00
commit aa4f1fa971
17 changed files with 6408 additions and 286 deletions

View File

@ -2,9 +2,11 @@ import { react2AngularDirective } from 'app/core/utils/react2angular';
import { PasswordStrength } from './components/PasswordStrength';
import PageHeader from './components/PageHeader/PageHeader';
import EmptyListCTA from './components/EmptyListCTA/EmptyListCTA';
// import { Login } from './components/Login/Login';
export function registerAngularDirectives() {
react2AngularDirective('passwordStrength', PasswordStrength, ['password']);
react2AngularDirective('pageHeader', PageHeader, ['model', 'noTabs']);
react2AngularDirective('emptyListCta', EmptyListCTA, ['model']);
// react2AngularDirective('login', Login, []);
}

File diff suppressed because it is too large Load Diff

View File

@ -113,12 +113,18 @@ export default class PageHeader extends React.Component<IProps, any> {
}
render() {
const { model } = this.props;
if (!model) {
return null;
}
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 && <Navigation main={this.props.model.main} />}
{this.renderHeaderTitle(model.main)}
{model.main.children && <Navigation main={model.main} />}
</div>
</div>
</div>

View File

@ -11,15 +11,20 @@ export class PasswordStrength extends React.Component<IProps, any> {
}
render() {
const { password } = this.props;
let strengthText = "strength: strong like a bull.";
let strengthClass = "password-strength-good";
if (this.props.password.length <= 8) {
if (!password) {
return null;
}
if (password.length <= 8) {
strengthText = "strength: you can do better.";
strengthClass = "password-strength-ok";
}
if (this.props.password.length < 4) {
if (password.length < 4) {
strengthText = "strength: weak sauce.";
strengthClass = "password-strength-bad";
}

View File

@ -14,6 +14,17 @@ export class ResetPasswordCtrl {
$scope.formModel.code = params.code;
}
$scope.navModel = {
main: {
icon: 'gicon gicon-branding',
subTitle: 'Reset your Grafana password',
breadcrumbs: [
{ title: 'Login', uri: '/login' },
{ title: 'Reset Password' },
]
}
};
$scope.sendResetEmail = function() {
if (!$scope.sendResetForm.$valid) {
return;

View File

@ -26,6 +26,17 @@ export class SignUpCtrl {
$scope.verifyEmailEnabled = false;
$scope.autoAssignOrg = false;
$scope.navModel = {
main: {
icon: 'gicon gicon-branding',
subTitle: 'Register your Grafana account',
breadcrumbs: [
{ title: 'Login', uri: '/login' },
{ title: 'Sign Up' },
]
}
};
backendSrv.get('/api/user/signup/options').then(options => {
$scope.verifyEmailEnabled = options.verifyEmailEnabled;
$scope.autoAssignOrg = options.autoAssignOrg;

View File

@ -3,9 +3,9 @@
<div class="signup-page-background">
</div>
<div class="login-box">
<div class="login-content">
<div class="login-box-logo">
<div class="login-branding">
<img src="img/logo_transparent_200x75.png">
</div>

View File

@ -1,85 +1,73 @@
<div class="login-container container">
<div class="login-box">
<div class="login-box-logo">
<img class="logo-icon" src="public/img/grafana_icon.svg"></img><br>
<div class="login container">
<div class="login-content">
<div class="login-branding">
<img class="logo-icon" src="public/img/grafana_icon.svg" alt="Grafana" />
<i class="icon-gf icon-gf-grafana_wordmark"></i>
</div>
<div class="login-inner-box">
<div class="login-tab-header">
<button class="btn-login-tab" ng-click="loginMode = true;" ng-class="{active: loginMode}">
Log in
<form name="loginForm" class="login-form-group gf-form-group" ng-hide="disableLoginForm">
<div class="login-form">
<input type="text" name="username" class="gf-form-input login-form-input" required ng-model='formModel.user' placeholder={{loginHint}}
autofocus>
</div>
<div class="login-form">
<input type="password" name="password" class="gf-form-input login-form-input" required ng-model="formModel.password" id="inputPassword"
placeholder="password">
</div>
<div class="login-button-group">
<button type="submit" class="btn btn-large p-x-2" ng-click="submit();" ng-class="{'btn-inverse': !loginForm.$valid, 'btn-primary': loginForm.$valid}">
Log In
</button>
<button class="btn-login-tab" ng-click="loginMode = false;" ng-class="{active: !loginMode}" ng-show="!disableUserSignUp">
Sign up
</button>
</div>
<form name="loginForm" class="login-form gf-form-group" ng-hide="disableLoginForm">
<div class="gf-form" ng-if="loginMode">
<span class="gf-form-label width-7">User</span>
<input type="text" name="username" class="gf-form-input max-width-14" required ng-model='formModel.user' placeholder={{loginHint}} autofocus>
</div>
<div class="gf-form" ng-if="loginMode">
<span class="gf-form-label width-7">Password</span>
<input type="password" name="password" class="gf-form-input max-width-14" required ng-model="formModel.password" id="inputPassword" placeholder="password">
</div>
<div class="gf-form" ng-if="!loginMode">
<span class="gf-form-label width-7">Email</span>
<input type="email" class="gf-form-input max-width-14" required ng-model='formModel.email' placeholder="email">
</div>
<div class="gf-form-button-row">
<button type="submit" class="btn btn-large p-x-3" ng-click="submit();" ng-class="{'btn-inverse': !loginForm.$valid, 'btn-primary': loginForm.$valid}">
{{submitBtnText}}
</button>
</div>
</form>
<div ng-if="loginMode">
<div class="text-center login-divider" ng-show="oauthEnabled">
<div class="login-divider-line">
<span class="login-divider-text">
<span ng-hide="disableLoginForm">Or</span> Login With
</span>
</div>
</div>
<div class="clearfix"></div>
<div class="login-oauth text-center" ng-show="oauthEnabled">
<a class="btn btn-large btn-google" href="login/google" target="_self" ng-if="oauth.google">
<i class="fa fa-google"></i>
Google
</a>
<a class="btn btn-large btn-github" href="login/github" target="_self" ng-if="oauth.github">
<i class="fa fa-github"></i>
GitHub
</a>
<a class="btn btn-large btn-grafana-com" href="login/grafana_com" target="_self" ng-if="oauth.grafana_com">
<img src="public/img/grafana_com_auth_icon.svg"></img>
<span>Grafana.com</span>
</a>
<a class="btn btn-large btn-generic-oauth" href="login/generic_oauth" target="_self" ng-if="oauth.generic_oauth">
<i class="fa fa-gear"></i>
{{oauth.generic_oauth.name}}
</a>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="text-center password-recovery" ng-hide="disableLoginForm">
<div class="text-center">
<div class="small login-button-forgot-password">
<a href="user/password/send-reset-email">
Forgot your password?
</a>
</div>
</div>
</form>
<div class="text-center login-divider" ng-show="oauthEnabled">
<div>
<div class="login-divider-line">
</div>
</div>
<div>
<span class="login-divider-text">
<span ng-hide="disableLoginForm">or</span>
</span>
</div>
<div>
<div class="login-divider-line">
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="login-oauth text-center" ng-show="oauthEnabled">
<a class="btn btn-medium btn-service btn-service--google login-btn" href="login/google" target="_self" ng-if="oauth.google">
<i class="btn-service-icon fa fa-google"></i>
Sign in with Google
</a>
<a class="btn btn-medium btn-service btn-service--github login-btn" href="login/github" target="_self" ng-if="oauth.github">
<i class="btn-service-icon fa fa-github"></i>
Sign in with GitHub
</a>
<a class="btn btn-medium btn-inverse btn-service btn-service--grafanacom login-btn" href="login/grafana_com" target="_self" ng-if="oauth.grafana_com">
<i class="btn-service-icon"></i>
Sign in with Grafana.com
</a>
<a class="btn btn-medium btn-inverse btn-service btn-service--oauth login-btn" href="login/generic_oauth" target="_self" ng-if="oauth.generic_oauth">
<i class="btn-service-icon fa fa-sign-in"></i>
Sign in with {{oauth.generic_oauth.name}}
</a>
</div>
<div class="login-signup-box">
<div class="login-signup-title p-r-1">
New to Grafana?
</div>
<a href="/signup" class="btn btn-medium btn-signup btn-p-x-2">
Sign Up
</a>
</div>
</div>
<div class="clearfix"></div>
</div>
</div>

View File

@ -1,71 +1,31 @@
<div class="login-container container">
<div class="login-box">
<div class="login-box-logo">
<img class="logo-icon" src="public/img/grafana_icon.svg"></img><br>
<i class="icon-gf icon-gf-grafana_wordmark"></i>
</div>
<div class="login-inner-box">
<div class="login-tab-header">
<button class="btn-login-tab" class="active">
Reset password
</button>
</div>
<page-header model="navModel"></page-header>
<div class="page-container page-body">
<div class="signup">
<h3 class="p-b-1">Reset password</h3>
<form name="sendResetForm" class="login-form gf-form-group" ng-show="mode === 'send'">
<div class="gf-form">
<span class="gf-form-label width-7">User</span>
<input type="text" name="username" class="gf-form-input max-width-14" required ng-model='formModel.userOrEmail' placeholder="email or username">
</div>
<div class="gf-form-button-row">
<br />
<br />
<button type="submit" class="btn btn-large" ng-click="sendResetEmail();" ng-class="{'btn-inverse': !sendResetForm.$valid, 'btn-primary': sendResetForm.$valid}">
<button type="submit" class="btn btn-success" ng-click="sendResetEmail();" ng-disabled="!sendResetForm.$valid">
Reset Password
</button>
<a href="/login" class="btn btn-inverse">
Back
</a>
</div>
</form>
<div style="text-align: center; padding: 20px;" ng-if="mode === 'email-sent'">
<div ng-if="mode === 'email-sent'">
An email with a reset link as been sent to the email address. <br>
You should receive it shortly.
</div>
<br />
<br />
<form name="resetForm" class="login-form gf-form-group" ng-show="mode === 'reset'">
<div class="gf-form">
<span class="gf-form-label width-10">New Password</span>
<input type="password" name="NewPassword" class="gf-form-input max-width-14" required ng-minlength="4" ng-model='formModel.newPassword' placeholder="password" watch-change="formModel.newPassword = inputValue;">
</div>
<div class="gf-form">
<span class="gf-form-label width-10">Confirm Password</span>
<input type="password" name="ConfirmPassword" class="gf-form-input max-width-14" required ng-minlength="4" ng-model='formModel.confirmPassword' placeholder="confirm password">
</div>
<div style="margin-left: 141px; width: 207px;">
<password-strength password="formModel.newPassword"></password-strength>
</div>
<div class="gf-form-button-row">
<button type="submit" class="btn" ng-click="submitReset();" ng-class="{'btn-inverse': !resetForm.$valid, 'btn-primary': resetForm.$valid}">
Reset Password
</button>
</div>
</form>
<div style="margin-top: 20px">
<div class="text-center">
<a href="login">Back to login</a>
<div class="p-t-1">
<a href="/login" class="btn btn-success p-t-1">
Login
</a>
</div>
</div>
</div>
</div>
</div>

View File

@ -3,10 +3,10 @@
<div class="signup-page-background">
</div>
<div class="login-box">
<div class="login-content">
<div class="login-box-logo">
<img class="logo-icon" src="public/img/grafana_icon.svg"></img><br>
<div class="login-branding">
<img class="logo-icon" src="public/img/grafana_icon.svg" alt="Grafana" />
<i class="icon-gf icon-gf-grafana_wordmark"></i>
</div>

View File

@ -1,35 +1,12 @@
<div class="container">
<page-header model="navModel"></page-header>
<div class="signup-page-background">
</div>
<div class="login-box">
<div class="login-box-logo">
<img class="logo-icon" src="public/img/grafana_icon.svg"></img><br>
<i class="icon-gf icon-gf-grafana_wordmark"></i>
</div>
<div class="invite-box">
<h3>
You're almost there.
</h3>
<div class="modal-tagline">
<div class="page-container page-body">
<div class="signup">
<h3 class="p-b-1">You're almost there.</h3>
<div class="p-b-1">
We just need a couple of more bits of<br> information to finish creating your account.
</div>
<div style="display: inline-block; margin-top: 25px; width: 300px">
<div class="editor-option">
<label class="small">Your email:</label>
<span class="large">{{formModel.email}}</span>
</div>
</div>
<br>
<br>
<form name="signUpForm" class="login-form gf-form-group">
<div class="gf-form" ng-if="verifyEmailEnabled">
<span class="gf-form-label width-9">
Email code<tip>Email verification code (sent to your email)</tip>
@ -39,35 +16,34 @@
<div class="gf-form" ng-if="!autoAssignOrg">
<span class="gf-form-label width-9">Org. name</span>
<input type="text" name="orgName" class="gf-form-input max-width-14" ng-model='formModel.orgName' placeholder="Name your organization">
<input type="text" name="orgName" class="gf-form-input max-width-14" ng-model="formModel.orgName" placeholder="Name your organization">
</div>
<div class="gf-form">
<span class="gf-form-label width-9">Your name</span>
<input type="text" name="name" class="gf-form-input max-width-14" ng-model='formModel.name' placeholder="(optional)">
<input type="text" name="name" class="gf-form-input max-width-14" ng-model="formModel.name" placeholder="(optional)">
</div>
<div class="gf-form">
<span class="gf-form-label width-9">Username</span>
<input type="text" class="gf-form-input max-width-14" required ng-model='formModel.username' placeholder="Username" autocomplete="off">
<span class="gf-form-label width-9">Email</span>
<input type="text" class="gf-form-input max-width-14" required ng-model="formModel.username" placeholder="Email" autocomplete="off">
</div>
<div class="gf-form">
<span class="gf-form-label width-9">Password</span>
<input type="password" class="gf-form-input max-width-14" required ng-model="formModel.password" id="inputPassword" placeholder="password" autocomplete="off">
</div>
<div style="margin-left: 9rem; width: 194px;">
<div class="signup__password-strength">
<password-strength password="formModel.password"></password-strength>
</div>
<div class="gf-form-button-row">
<button type="submit" class="btn" ng-click="ctrl.submit();" ng-class="{'btn-inverse': !signUpForm.$valid, 'btn-primary': signUpForm.$valid}">
Continue
<div class="gf-form-button-row p-t-3">
<button type="submit" class="btn btn-success" ng-click="ctrl.submit();" ng-disabled="!signUpForm.$valid">
Sign Up
</button>
<a href="/login" class="btn btn-inverse">
Back
</a>
</div>
</form>
</div>
</div>
</div>

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 266 KiB

View File

@ -224,6 +224,8 @@ $btn-padding-y-xl: 11px !default;
$btn-border-radius: 2px;
$btn-semi-transparent: rgba(0,0,0,0.2) !default;
// sidemenu
$side-menu-width: 60px;
@ -235,3 +237,25 @@ $panel-padding: 0px 10px 5px 10px;
// tabs
$tabs-padding: 10px 15px 9px;
$external-services: (
github: (
bgColor: #464646,
borderColor: #393939,
icon: ''
),
google: (
bgColor: #e84d3c,
borderColor: #b83e31,
icon: ''
),
grafanacom: (
bgColor: inherit,
borderColor: #393939,
icon: ''
),
oauth: (
bgColor: inherit,
borderColor: #393939,
icon: ''
)
) !default;

View File

@ -63,6 +63,10 @@
background-image: url('../img/icons_#{$theme-name}_theme/icon_zoom_out.svg');
}
.gicon-branding {
background-image: url('../img/grafana_icon.svg');
}
.sidemenu {
.gicon-dashboard {
background-image: url('../img/icons_dark_theme/icon_dashboard.svg');
@ -71,5 +75,3 @@
background-image: url('../img/icons_dark_theme/icon_alert.svg');
}
}

View File

@ -92,6 +92,7 @@
.btn-warning {
@include buttonBackground($btn-warning-bg, $btn-warning-bg-hl);
}
// Danger and error appear as red
.btn-danger {
@include buttonBackground($btn-danger-bg, $btn-danger-bg-hl);
@ -142,4 +143,57 @@
}
}
// Extra padding
.btn-p-x-2 {
padding-left: 20px;
padding-right: 20px;
}
// External services
// Usage:
// <div class="btn btn-service btn-service--facebook">Button text</div>
$btn-service-icon-width: 35px;
.btn-service {
position: relative;
}
@each $service, $data in $external-services {
$serviceBgColor: map-get($data, bgColor);
$serviceBorderColor: map-get($data, borderColor);
.btn-service--#{$service} {
background-color: $serviceBgColor;
border: 1px solid $serviceBorderColor;
.btn-service-icon {
font-size: 24px; // Override
border-right: 1px solid $serviceBorderColor;
}
}
}
.btn-service-icon {
position: absolute;
left: 0;
height: 100%;
top: 0;
padding-left: .5rem;
padding-right: .5rem;
width: $btn-service-icon-width;
text-align: center;
&::before {
position: relative;
top: 4px;
}
}
.btn-service--grafanacom {
.btn-service-icon {
background-image: url(/public/img/grafana_mask_icon_white.svg);
background-repeat: no-repeat;
background-position: 50%;
background-size: 60%;
}
}

View File

@ -1,42 +1,111 @@
.login-container {
background-position: left;
background-size: 60%;
$login-border: #8daac5;
.login {
background-position: center;
min-height: 85vh;
background-repeat: no-repeat;
min-width: 100%;
margin-left: 0;
margin-top: -26px; /* BAD HACK - experiement to see how it looks */
padding-top: $spacer * 5; /* BAD HACK - experiement to see how it looks */
background-color: $black;
display: flex;
align-items: center;
justify-content: center;
background-image: url(../img/heatmap_bg_test.svg);
background-size: cover;
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill,
textarea:-webkit-autofill,
textarea:-webkit-autofill:hover,
textarea:-webkit-autofill:focus,
select:-webkit-autofill,
select:-webkit-autofill:hover,
select:-webkit-autofill:focus {
-webkit-box-shadow: 0 0 0px 1000px $black inset;
-webkit-text-fill-color: $gray-7 !important;
}
.login-form-group {
display: flex;
flex-direction: column;
width: 100%;
align-items: center;
margin-bottom: 1rem;
}
.login-form {
display: inline-block;
max-width: 24rem;
margin-bottom: 1rem;
width: 100%;
}
.login-box {
.login-form-input {
border: 1px solid $login-border;
border-radius: 4px;
opacity: .6;
&:focus {
border: 1px solid $login-border;
}
}
.login-button-group {
display: flex;
flex-direction: column;
align-items: center;
justify-content:space-between;
width: 100%;
margin-top: .5rem
}
.login-button-forgot-password {
padding-top: 1rem;
}
.login-text {
font-size: $font-size-sm;
}
.login-content {
max-width: 700px;
margin: 0 auto; /* was $spacer * 2 auto 0 auto; */
display: flex;
align-items: stretch;
flex-direction: column;
}
.login-box-logo {
text-align: center;
margin-bottom: $spacer * 2;
img {
width: 6rem;
.login-branding {
width: 100%;
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
justify-content: center;
flex-grow: 0;
.logo-icon {
width: 70px;
margin-bottom: 15px;
}
.icon-gf-grafana_wordmark {
color: $link-color;
position: relative;
top: -4.5rem;
font-size: 2.5rem;
text-shadow: 3px 3px 5px black;
font-size: 2rem;
text-shadow: 2px 2px 5px rgba(0,0,0,0.3);
}
}
.login-inner-box {
background: $panel-bg;
text-align: center;
padding-bottom: 3rem;
padding: 2rem 4rem;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex-grow: 1;
max-width: 415px;
}
.login-tab-header {
@ -45,6 +114,12 @@
margin-bottom: 3rem;
}
.btn-signup {
color: $white;
border: 1px solid $login-border;
background-color: $btn-semi-transparent;
}
.btn-login-tab {
background: transparent;
border: none;
@ -98,30 +173,7 @@
}
.login-oauth {
.btn {
margin: 5px;
}
.btn-google {
background: #dd4b39;
color: white;
}
.btn-github {
background: #555;
color: white;
}
.btn-grafana-com {
@include buttonBackground($btn-inverse-bg, $btn-inverse-bg-hl, $btn-inverse-text-color);
box-shadow: $card-shadow;
img {
width: 19px;
vertical-align: sub;
}
}
width: 100%;
}
.password-recovery {
@ -134,13 +186,15 @@
.login-divider {
float: left;
width: 50%;
margin: 5px 25% 25px 25%;
width: 100%;
margin: 0 25% 1rem 25%;
display: flex;
justify-content: space-between;
.login-divider-line {
width: 100%;
width: 110px;
height: 10px;
border-bottom: 1px solid $gray-1;
border-bottom: 1px solid $login-border;
.login-divider-text {
background-color: $panel-bg;
@ -150,6 +204,25 @@
}
}
.login-signup-box {
display: flex;
align-items: center;
justify-content: flex-end;
width: 100%;
margin-top: 1rem
}
.login-signup-title {
justify-self: flex-start;
flex: 1;
text-align: left;
}
.login-btn {
width: 100%;
margin: 0 0 1rem;
}
.signup-page-background {
position: fixed;
top: 0;
@ -190,14 +263,171 @@
}
}
@include media-breakpoint-up(sm) {
.login-content {
flex-direction: row;
}
.login-branding {
width: 35%;
padding: 4rem 2rem;
border-right: 1px solid $login-border;
justify-content: flex-start;
}
.login-inner-box {
width: 65%;
padding: 1rem 2rem;
}
.login-branding {
.logo-icon {
width: 80px;
}
}
}
@include media-breakpoint-up(md) {
.login-box-logo {
img {
width: 125px;
.login-branding {
width: 45%;
padding: 2rem 4rem;
.logo-icon {
width: 100px;
}
.icon-gf-grafana_wordmark {
top: -5px;
font-size: 3rem;
font-size: 3.2rem;
}
}
.login-inner-box {
width: 55%;
padding: 1rem 4rem;
}
.login-button-group {
flex-direction: row;
}
.login-button-forgot-password {
padding-top: 0;
padding-left: 10px;
}
}
@include media-breakpoint-up(lg) {
.login {
min-height: 100vh;
}
.login-form-input {
min-width: 300px;
}
}
login-bg {
position: absolute;
top: 0;
left: 0;
right: 0;
perspective: 1000px;
.login-bg {
width: 4%;
height: 10px;
// background: hotpink;
// border:1px solid #0F1926;
float: left;
transition: 1s ease-in-out;
z-index: 1;
transform-style: preserve-3d;
&.login-bg-flip {
transform: rotateY(180deg);
}
&:before, &:after {
backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
right: 0;
height: 100%;
content: '';
display: block;
}
&:before {
z-index: 2;
transform: rotateY(0deg);
background-color: #215392;
}
&:after {
transform: rotateY(180deg);
background-color: rgb(25, 50, 80);
}
&:nth-child(3n+0) {
&:before {
background-color: #0f253c;
}
&:after {
background-color: blue;
}
}
&:nth-child(3n+1) {
&:before {
background-color: #102438;
}
&:after {
background-color: blue;
}
}
&:nth-child(3n+2) {
&:before {
background-color: #19314e;
}
&:after {
background-color: blue;
}
}
&:nth-child(3n+3) {
&:before {
background-color: #215392;
}
&:after {
background-color: blue;
}
}
// &:nth-child(3n+5) {
// &:before {
// background-color: hotpink;
// }
// &:after {
// background-color: blue;
// }
// }
}
}
login-bg-fx {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 100%;
background-image: -webkit-radial-gradient(center center, ellipse farthest-corner, transparent 0%, transparent 10%, rgba(18, 22, 29, 1) 100%);
z-index:2;
}

View File

@ -15,3 +15,8 @@
}
}
.signup__password-strength {
position: absolute;
margin-left: 9rem;
width: 194px;
}