From 9e6a8eae5638cd3cdaa606b16c135160fcfef6f8 Mon Sep 17 00:00:00 2001 From: Kyle Knight Date: Thu, 1 Dec 2016 12:57:19 -0600 Subject: [PATCH] Styling User Registration (#529) --- assets/fonts/kolidecons/kolidecons.woff | Bin 12276 -> 12164 bytes assets/images/kolide-logo-condensed.svg | 2 + frontend/components/buttons/Button/Button.tsx | 4 +- .../AdminDetails/AdminDetails.jsx | 65 +++--- .../AdminDetails/AdminDetails.tests.jsx | 21 -- .../RegistrationForm/AdminDetails/helpers.js | 5 - .../ConfirmationPage/ConfirmationPage.jsx | 72 ++++--- .../ConfirmationPage.tests.jsx | 2 - .../ConfirmationPage/_styles.scss | 92 ++++++++ .../KolideDetails/KolideDetails.jsx | 20 +- .../OrgDetails/OrgDetails.jsx | 29 ++- .../RegistrationForm/RegistrationForm.jsx | 139 +++++++++---- .../forms/RegistrationForm/_styles.scss | 196 ++++++++++++++++++ .../forms/fields/Checkbox/Checkbox.jsx | 33 +++ .../forms/fields/Checkbox/Checkbox.tests.jsx | 11 + .../forms/fields/Checkbox/_styles.scss | 45 ++++ .../components/forms/fields/Checkbox/index.js | 1 + .../InputFieldWithIcon/InputFieldWithIcon.jsx | 18 +- .../fields/InputFieldWithIcon/_styles.scss | 24 ++- .../TargetDetails/_styles.scss | 4 +- .../fields/SelectTargetsDropdown/_styles.scss | 2 +- frontend/interfaces/registration_form_data.js | 1 - .../Breadcrumbs/Breadcrumbs.jsx | 25 ++- .../Breadcrumbs/Breadcrumbs.tests.jsx | 18 +- .../RegistrationPage/Breadcrumbs/_styles.scss | 146 +++++++++++++ .../RegistrationPage/RegistrationPage.jsx | 14 +- .../RegistrationPage.tests.jsx | 1 + frontend/pages/RegistrationPage/_styles.scss | 19 ++ frontend/pages/hosts/NewHostPage/_styles.scss | 4 +- frontend/styles/global/_global.scss | 5 +- frontend/styles/global/_icons.scss | 24 +-- frontend/styles/var/mixins.scss | 9 +- frontend/templates/react.tmpl | 1 + 33 files changed, 864 insertions(+), 188 deletions(-) create mode 100644 assets/images/kolide-logo-condensed.svg create mode 100644 frontend/components/forms/RegistrationForm/ConfirmationPage/_styles.scss create mode 100644 frontend/components/forms/RegistrationForm/_styles.scss create mode 100644 frontend/components/forms/fields/Checkbox/Checkbox.jsx create mode 100644 frontend/components/forms/fields/Checkbox/Checkbox.tests.jsx create mode 100644 frontend/components/forms/fields/Checkbox/_styles.scss create mode 100644 frontend/components/forms/fields/Checkbox/index.js create mode 100644 frontend/pages/RegistrationPage/Breadcrumbs/_styles.scss create mode 100644 frontend/pages/RegistrationPage/_styles.scss diff --git a/assets/fonts/kolidecons/kolidecons.woff b/assets/fonts/kolidecons/kolidecons.woff index 62a532bc51b4e973d50e29a6b00f06b10d2671d1..8ae70f97a835a4636720a2ffc9a2c243bfc3ff79 100644 GIT binary patch delta 9820 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 delta 9960 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

3L62kh+jO)UWl6n`$-KWZ#U)gI zBsFKb>;Sy%1&Z6fjSTJh85#|nrm7K13)li<0AxAzyPel8%xR4+mg3??kVHU-5cnTbjtoY5H>6m-O@a)!k6j*gxV zs3%3Q60axyB}6*~Wd@JS0l7mHg|1SLJb<*Tc8CSgA$NbYLz*C7x)JOZ!$H4!82Q|PM5D6#%v;by+GD*~* zwZ9^SBlI9LA$lT?A;}=^Bj+LiMNvQrMd?8~M+Kq5qgkO9q2r^gpx2`BV}xUjU`k<* zVMSuKVSmEb!EV8U!jZxKhFghyjwgnRA8lk7WDANmuoP`nqIeXv7O*&3Hp^;Fw$>CUFqm7`du_DUO9eSTbdMvbhfuuI8cwWyS+ zvE4ON2akCIeI(fxHJ)Z>K5Mj6Pczq~Bl}~`j(ADvVeT5|aH;W^kru0Jlb;k$hg5v~ zu)o2?ocw;)qgjDs-(y@vyH6oB-_u0qFx7^5-pl^Z5jt|cT9Ea&IW%JEr8o*&ok_MMl%000^qXlCL52XRIsrT_o{ diff --git a/assets/images/kolide-logo-condensed.svg b/assets/images/kolide-logo-condensed.svg new file mode 100644 index 0000000000..c089ee022b --- /dev/null +++ b/assets/images/kolide-logo-condensed.svg @@ -0,0 +1,2 @@ + +Asset 3 diff --git a/frontend/components/buttons/Button/Button.tsx b/frontend/components/buttons/Button/Button.tsx index a5920b54f9..b4ad0822fd 100644 --- a/frontend/components/buttons/Button/Button.tsx +++ b/frontend/components/buttons/Button/Button.tsx @@ -8,6 +8,7 @@ interface IButtonProps { disabled: boolean; onClick: (evt: React.MouseEvent) => boolean; size: string; + tabIndex: number; text: string; type: string; variant: string; @@ -37,7 +38,7 @@ class Button extends React.Component { render () { const { handleClick } = this; - const { className, disabled, size, text, type, variant } = this.props; + const { className, disabled, size, tabIndex, text, type, variant } = this.props; const fullClassName = classnames(`${baseClass}--${variant}`, className, { [baseClass]: variant !== 'unstyled', [`${baseClass}--disabled`]: disabled, @@ -49,6 +50,7 @@ class Button extends React.Component { className={fullClassName} disabled={disabled} onClick={handleClick} + tabIndex={tabIndex} type={type} > {text} diff --git a/frontend/components/forms/RegistrationForm/AdminDetails/AdminDetails.jsx b/frontend/components/forms/RegistrationForm/AdminDetails/AdminDetails.jsx index f2718d5b56..45bfa6f60f 100644 --- a/frontend/components/forms/RegistrationForm/AdminDetails/AdminDetails.jsx +++ b/frontend/components/forms/RegistrationForm/AdminDetails/AdminDetails.jsx @@ -6,14 +6,15 @@ import Button from 'components/buttons/Button'; import InputFieldWithIcon from 'components/forms/fields/InputFieldWithIcon'; import helpers from './helpers'; -const formFields = ['name', 'username', 'password', 'password_confirmation', 'email']; +const formFields = ['username', 'password', 'password_confirmation', 'email']; const { validate } = helpers; class AdminDetails extends Component { static propTypes = { + className: PropTypes.string, + currentPage: PropTypes.bool, fields: PropTypes.shape({ email: formFieldInterface.isRequired, - name: formFieldInterface.isRequired, password: formFieldInterface.isRequired, password_confirmation: formFieldInterface.isRequired, username: formFieldInterface.isRequired, @@ -22,40 +23,44 @@ class AdminDetails extends Component { }; render () { - const { fields, handleSubmit } = this.props; + const { className, currentPage, fields, handleSubmit } = this.props; + const tabIndex = currentPage ? 1 : -1; return ( -

- - - - - +
+
+ + + + +
); diff --git a/frontend/components/forms/RegistrationForm/AdminDetails/AdminDetails.tests.jsx b/frontend/components/forms/RegistrationForm/AdminDetails/AdminDetails.tests.jsx index 2d84be00d6..9b8ca04b54 100644 --- a/frontend/components/forms/RegistrationForm/AdminDetails/AdminDetails.tests.jsx +++ b/frontend/components/forms/RegistrationForm/AdminDetails/AdminDetails.tests.jsx @@ -9,24 +9,6 @@ import { fillInFormInput } from 'test/helpers'; describe('AdminDetails - form', () => { afterEach(restoreSpies); - describe('name input', () => { - it('renders an input field', () => { - const form = mount(); - const fullNameField = form.find({ name: 'name' }); - - expect(fullNameField.length).toEqual(1); - }); - - it('updates state when the field changes', () => { - const form = mount(); - const fullNameField = form.find({ name: 'name' }).find('input'); - - fillInFormInput(fullNameField, 'The Gnar Co'); - - expect(form.state().formData).toInclude({ name: 'The Gnar Co' }); - }); - }); - describe('username input', () => { it('renders an input field', () => { const form = mount(); @@ -111,7 +93,6 @@ describe('AdminDetails - form', () => { expect(onSubmitSpy).toNotHaveBeenCalled(); expect(form.state().errors).toInclude({ email: 'Email must be present', - name: 'Full name must be present', password: 'Password must be present', password_confirmation: 'Password confirmation must be present', username: 'Username must be present', @@ -152,14 +133,12 @@ describe('AdminDetails - form', () => { const onSubmitSpy = createSpy(); const form = mount(); const emailField = form.find({ name: 'email' }).find('input'); - const fullNameField = form.find({ name: 'name' }).find('input'); const passwordConfirmationField = form.find({ name: 'password_confirmation' }).find('input'); const passwordField = form.find({ name: 'password' }).find('input'); const usernameField = form.find({ name: 'username' }).find('input'); const submitBtn = form.find('Button'); fillInFormInput(emailField, 'hi@gnar.dog'); - fillInFormInput(fullNameField, 'Gnar Dog'); fillInFormInput(passwordField, 'p@ssw0rd'); fillInFormInput(passwordConfirmationField, 'p@ssw0rd'); fillInFormInput(usernameField, 'gnardog'); diff --git a/frontend/components/forms/RegistrationForm/AdminDetails/helpers.js b/frontend/components/forms/RegistrationForm/AdminDetails/helpers.js index 277b5374dc..8f5f50e87a 100644 --- a/frontend/components/forms/RegistrationForm/AdminDetails/helpers.js +++ b/frontend/components/forms/RegistrationForm/AdminDetails/helpers.js @@ -6,7 +6,6 @@ const validate = (formData) => { const errors = {}; const { email, - name: fullName, password, password_confirmation: passwordConfirmation, username, @@ -20,10 +19,6 @@ const validate = (formData) => { errors.email = 'Email must be present'; } - if (!fullName) { - errors.name = 'Full name must be present'; - } - if (!username) { errors.username = 'Username must be present'; } diff --git a/frontend/components/forms/RegistrationForm/ConfirmationPage/ConfirmationPage.jsx b/frontend/components/forms/RegistrationForm/ConfirmationPage/ConfirmationPage.jsx index 32a6f2d60a..5e7c5f1b2e 100644 --- a/frontend/components/forms/RegistrationForm/ConfirmationPage/ConfirmationPage.jsx +++ b/frontend/components/forms/RegistrationForm/ConfirmationPage/ConfirmationPage.jsx @@ -1,11 +1,16 @@ import React, { Component, PropTypes } from 'react'; +import classnames from 'classnames'; import Button from 'components/buttons/Button'; import formDataInterface from 'interfaces/registration_form_data'; import Icon from 'components/Icon'; +import Checkbox from 'components/forms/fields/Checkbox'; + +const baseClass = 'confirm-user-reg'; class ConfirmationPage extends Component { static propTypes = { + className: PropTypes.string, formData: formDataInterface, handleSubmit: PropTypes.func, }; @@ -20,9 +25,9 @@ class ConfirmationPage extends Component { render () { const { + className, formData: { email, - full_name: fullName, kolide_server_url: kolideWebAddress, org_name: orgName, username, @@ -30,38 +35,47 @@ class ConfirmationPage extends Component { } = this.props; const { onSubmit } = this; + const confirmRegClasses = classnames(className, baseClass); + return ( -
- - - - - - - - - - - - - - - - - - - - - - - - - -
Administrator Configuration
Full Name:{fullName}
Username:{username}
Email:{email}
Organization:{orgName}
Kolide URL:{kolideWebAddress}
+
+
+ + + + + + + + + + + + + + + + + + + + + +
Administrator Configuration
Username:{username}
Email:{email}
Organization:{orgName}
Kolide URL:{kolideWebAddress}
+ +
+ +

I am migrating an existing osquery installation.

+

Take me to the Import Configuration page.

+
+
+
+
); diff --git a/frontend/components/forms/RegistrationForm/ConfirmationPage/ConfirmationPage.tests.jsx b/frontend/components/forms/RegistrationForm/ConfirmationPage/ConfirmationPage.tests.jsx index aed6dd3cf3..ed2897416a 100644 --- a/frontend/components/forms/RegistrationForm/ConfirmationPage/ConfirmationPage.tests.jsx +++ b/frontend/components/forms/RegistrationForm/ConfirmationPage/ConfirmationPage.tests.jsx @@ -9,7 +9,6 @@ describe('ConfirmationPage - form', () => { afterEach(restoreSpies); const formData = { - full_name: 'Jason Meller', username: 'jmeller', email: 'jason@kolide.co', org_name: 'Kolide', @@ -24,7 +23,6 @@ describe('ConfirmationPage - form', () => { /> ); - expect(form.text()).toInclude(formData.full_name); expect(form.text()).toInclude(formData.username); expect(form.text()).toInclude(formData.email); expect(form.text()).toInclude(formData.org_name); diff --git a/frontend/components/forms/RegistrationForm/ConfirmationPage/_styles.scss b/frontend/components/forms/RegistrationForm/ConfirmationPage/_styles.scss new file mode 100644 index 0000000000..fb12290b21 --- /dev/null +++ b/frontend/components/forms/RegistrationForm/ConfirmationPage/_styles.scss @@ -0,0 +1,92 @@ +.confirm-user-reg { + &__wrapper { + padding: 0 35px 25px; + } + + &__icon { + color: $success; + font-size: 120px; + display: block; + text-align: center; + margin: 10px 0 35px; + } + + &__submit { + bottom: 0; + top: auto; + position: absolute; + border-top-left-radius: 0; + border-top-right-radius: 0; + + &:active { + top: auto; + } + } + + &__table { + width: 100%; + + caption { + font-size: 18px; + font-weight: $bold; + line-height: 0.72; + letter-spacing: 0.6px; + color: $text-dark; + text-transform: uppercase; + padding-bottom: 20px; + } + + tr { + vertical-align: bottom; + } + + th { + font-size: 14px; + font-weight: $bold; + line-height: 1.71; + letter-spacing: 0.5px; + color: $text-dark; + text-align: left; + } + + td { + font-size: 14px; + font-weight: $light; + line-height: 1.71; + letter-spacing: 0.5px; + color: $text-dark; + } + } + + &__table-url { + @include ellipsis(90%); + font-family: 'SourceCodePro', $monospace; + vertical-align: bottom; + } + + &__import { + @include user-select(none); + font-size: 14px; + font-weight: $light; + line-height: 1.71; + letter-spacing: 0.5px; + color: $text-dark; + margin: 30px 0 0; + + label { + display: block; + position: relative; + } + + p { + margin: 0; + padding-left: 40px; + } + + .kolide-checkbox__input { + position: absolute; + left: 0; + top: 0; + } + } +} diff --git a/frontend/components/forms/RegistrationForm/KolideDetails/KolideDetails.jsx b/frontend/components/forms/RegistrationForm/KolideDetails/KolideDetails.jsx index 804fff206b..baccf1ef02 100644 --- a/frontend/components/forms/RegistrationForm/KolideDetails/KolideDetails.jsx +++ b/frontend/components/forms/RegistrationForm/KolideDetails/KolideDetails.jsx @@ -11,6 +11,8 @@ const { validate } = helpers; class KolideDetails extends Component { static propTypes = { + className: PropTypes.string, + currentPage: PropTypes.bool, fields: PropTypes.shape({ kolide_server_url: formFieldInterface.isRequired, }).isRequired, @@ -18,18 +20,24 @@ class KolideDetails extends Component { }; render () { - const { fields, handleSubmit } = this.props; + const { className, currentPage, fields, handleSubmit } = this.props; + const tabIndex = currentPage ? 1 : -1; return ( -
- +
+
+ /v1, ' or any other path']} + /> +
); diff --git a/frontend/components/forms/RegistrationForm/OrgDetails/OrgDetails.jsx b/frontend/components/forms/RegistrationForm/OrgDetails/OrgDetails.jsx index 117a470280..abf7755df8 100644 --- a/frontend/components/forms/RegistrationForm/OrgDetails/OrgDetails.jsx +++ b/frontend/components/forms/RegistrationForm/OrgDetails/OrgDetails.jsx @@ -11,6 +11,8 @@ const { validate } = helpers; class OrgDetails extends Component { static propTypes = { + className: PropTypes.string, + currentPage: PropTypes.bool, fields: PropTypes.shape({ org_name: formFieldInterface.isRequired, org_logo_url: formFieldInterface.isRequired, @@ -19,22 +21,29 @@ class OrgDetails extends Component { }; render () { - const { fields, handleSubmit } = this.props; + const { className, currentPage, fields, handleSubmit } = this.props; + const tabIndex = currentPage ? 1 : -1; return ( -
- - +
+
+ + +
); diff --git a/frontend/components/forms/RegistrationForm/RegistrationForm.jsx b/frontend/components/forms/RegistrationForm/RegistrationForm.jsx index b4bfe8d8b0..c5785586ca 100644 --- a/frontend/components/forms/RegistrationForm/RegistrationForm.jsx +++ b/frontend/components/forms/RegistrationForm/RegistrationForm.jsx @@ -1,4 +1,5 @@ import React, { Component, PropTypes } from 'react'; +import classnames from 'classnames'; import AdminDetails from 'components/forms/RegistrationForm/AdminDetails'; import ConfirmationPage from 'components/forms/RegistrationForm/ConfirmationPage'; @@ -12,6 +13,8 @@ const PAGE_HEADER_TEXT = { 4: 'SUCCESS', }; +const baseClass = 'user-registration'; + class RegistrationForm extends Component { static propTypes = { onNextPage: PropTypes.func, @@ -21,8 +24,14 @@ class RegistrationForm extends Component { constructor (props) { super(props); + const { window } = global; - this.state = { errors: {}, formData: {} }; + this.state = { + errors: {}, + formData: { + kolide_server_url: window.location.origin, + }, + }; } onPageFormSubmit = (pageFormData) => { @@ -39,19 +48,40 @@ class RegistrationForm extends Component { return onNextPage(); } - onSubmit = () => { + onSubmitConfirmation = () => { const { formData } = this.state; const { onSubmit: handleSubmit } = this.props; return handleSubmit(formData); } + isCurrentPage = (num) => { + const { page } = this.props; + + if (num === page) { + return true; + } + + return false; + } + + renderHeader = () => { + const { page } = this.props; + const headerText = PAGE_HEADER_TEXT[page]; + + if (headerText) { + return

{headerText}

; + } + + return false; + } + renderDescription = () => { const { page } = this.props; if (page === 1) { return ( -
+

Additional admins can be designated within the Kolide App

Passwords must include 7 characters, at least 1 number (eg. 0-9) and at least 1 symbol (eg. ^&*#)

@@ -60,7 +90,7 @@ class RegistrationForm extends Component { if (page === 2) { return ( -
+

Set your Organization's name (eg. Yahoo! Inc)

Specify the website URL of your organization (eg. Yahoo.com)

@@ -69,7 +99,7 @@ class RegistrationForm extends Component { if (page === 3) { return ( -
+

Define the base URL which osqueryd clients use to connect and register with Kolide.

Note: Please ensure the URL you choose is accessible to all endpoints that need to communicate with Kolide. Otherwise, they will not be able to correctly register. @@ -81,51 +111,82 @@ class RegistrationForm extends Component { return false; } - renderHeader = () => { + renderContent = () => { const { page } = this.props; - const headerText = PAGE_HEADER_TEXT[page]; - - if (headerText) { - return

{headerText}

; - } - - return false; - } - - renderPageForm = () => { const { formData } = this.state; - const { onPageFormSubmit, onSubmit } = this; - const { page } = this.props; - - if (page === 1) { - return ; - } - - if (page === 2) { - return ; - } - - if (page === 3) { - return ; - } + const { + onSubmitConfirmation, + renderDescription, + renderHeader, + } = this; if (page === 4) { - return ; + return ( +
+ {renderHeader()} + +
+ ); } - return false; + return ( +
+ {renderHeader()} + {renderDescription()} +
+ ); } render () { - const { onSubmit } = this.props; - const { renderDescription, renderHeader, renderPageForm } = this; + const { onSubmit, page } = this.props; + const { formData } = this.state; + const { isCurrentPage, onPageFormSubmit, renderContent } = this; + + const containerClass = classnames(`${baseClass}__container`, { + [`${baseClass}__container--complete`]: page > 3, + }); + + const adminDetailsClass = classnames( + `${baseClass}__field-wrapper`, + `${baseClass}__field-wrapper--admin` + ); + + const orgDetailsClass = classnames( + `${baseClass}__field-wrapper`, + `${baseClass}__field-wrapper--org` + ); + + const kolideDetailsClass = classnames( + `${baseClass}__field-wrapper`, + `${baseClass}__field-wrapper--kolide` + ); + + const formSectionClasses = classnames( + `${baseClass}__form`, + { + [`${baseClass}__form--step1-active`]: page === 1, + [`${baseClass}__form--step1-complete`]: page > 1, + [`${baseClass}__form--step2-active`]: page === 2, + [`${baseClass}__form--step2-complete`]: page > 2, + [`${baseClass}__form--step3-active`]: page === 3, + [`${baseClass}__form--step3-complete`]: page > 3, + } + ); return ( -
- {renderHeader()} - {renderDescription()} - {renderPageForm()} -
+
+
+ {renderContent()} + +
+ + + + + + +
+
); } } diff --git a/frontend/components/forms/RegistrationForm/_styles.scss b/frontend/components/forms/RegistrationForm/_styles.scss new file mode 100644 index 0000000000..03d00eeac9 --- /dev/null +++ b/frontend/components/forms/RegistrationForm/_styles.scss @@ -0,0 +1,196 @@ +.user-registration { + @include display(flex); + @include align-content(center); + @include justify-content(center); + @include flex-grow(1); + + &__container { + @include align-self(center); + @include size(500px 520px); + border-radius: 4px; + background-color: $bg-light; + box-shadow: 0 0 30px 0 rgba(0, 0, 0, 0.3); + box-sizing: border-box; + padding: 25px 35px; + margin-top: -55px; + + &--complete { + padding: 0; + + .user-registration__title { + font-size: 24px; + font-weight: $bold; + line-height: 0.54; + letter-spacing: 0.9px; + color: $text-dark; + padding: 25px 35px; + } + } + } + + &__form { + @include transform(translateY(-85px)); + width: 100%; + height: 470px; + position: absolute; + top: 50%; + left: 0; + overflow: hidden; + box-sizing: border-box; + padding: 25px 0; + + @include breakpoint(tablet) { + @include transform(translateY(-100px)); + } + + &--step1-complete { + .user-registration__field-wrapper--admin { + left: -184px; + } + + .user-registration__field-wrapper--org { + left: 50%; + } + + .user-registration__field-wrapper--kolide { + left: calc(100% + 184px); + } + } + + &--step2-complete { + .user-registration__field-wrapper--admin { + left: calc(-50% - 184px); + } + + .user-registration__field-wrapper--org { + left: -184px; + } + + .user-registration__field-wrapper--kolide { + left: 50%; + } + } + + &--step3-complete { + .user-registration__field-wrapper--admin { + left: calc(-100% - 184px); + } + + .user-registration__field-wrapper--org { + left: calc(-50% - 184px); + } + + .user-registration__field-wrapper--kolide { + left: -184px; + } + } + + &::before, + &::after { + background-image: linear-gradient(to right, $accent-dark 50%, transparent 50%); + background-position: left top; + background-repeat: repeat-x; + background-size: 17px 2px; + position: absolute; + top: 100px; + left: 50%; + width: 50%; + height: 2px; + content: ''; + z-index: 1; + } + + &::before { + left: auto; + right: 50%; + } + + &--step1-active { + &::before { + display: none; + } + } + + &--step3-active, + &--step3-complete { + &::after { + display: none; + } + } + } + + &__description { + font-size: 14px; + font-weight: $light; + line-height: 1.43; + letter-spacing: 0.5px; + color: $text-dark; + } + + &__title { + font-size: 18px; + font-weight: $bold; + line-height: 0.72; + letter-spacing: 0.6px; + color: $text-dark; + margin: 0; + padding: 0; + } + + &__field-wrapper { + @include transition(left 300ms ease); + width: 430px; + min-height: 400px; + padding-bottom: 75px; + border-radius: 4px; + background-color: $bg-light; + box-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.3); + margin: 0 auto; + position: absolute; + box-sizing: border-box; + margin-left: -215px; + z-index: 2; + + &--admin { + left: 50%; + } + + &--org { + left: calc(100% + 184px); + } + + &--kolide { + top: 45px; + left: calc(150% + 184px); + } + + input { + background-color: transparent; + } + + .button { + bottom: 0; + top: auto; + position: absolute; + border-top-left-radius: 0; + border-top-right-radius: 0; + + &:active { + top: auto; + } + } + + .registration-fields { + padding: 0 35px 25px; + box-sizing: border-box; + } + } + + &__confirmation { + background-color: $bg-light; + position: relative; + z-index: 2; + width: 500px; + height: 500px; + } +} diff --git a/frontend/components/forms/fields/Checkbox/Checkbox.jsx b/frontend/components/forms/fields/Checkbox/Checkbox.jsx new file mode 100644 index 0000000000..939587582b --- /dev/null +++ b/frontend/components/forms/fields/Checkbox/Checkbox.jsx @@ -0,0 +1,33 @@ +import React, { Component, PropTypes } from 'react'; +import classnames from 'classnames'; +import { noop } from 'lodash'; + +const baseClass = 'kolide-checkbox'; + +class InputField extends Component { + static propTypes = { + children: PropTypes.node, + className: PropTypes.string, + name: PropTypes.string, + onChange: PropTypes.func, + }; + + static defaultProps = { + onChange: noop, + }; + + render () { + const { children, className, name, onChange } = this.props; + const checkBoxClass = classnames(baseClass, className); + + return ( + + ); + } +} + +export default InputField; diff --git a/frontend/components/forms/fields/Checkbox/Checkbox.tests.jsx b/frontend/components/forms/fields/Checkbox/Checkbox.tests.jsx new file mode 100644 index 0000000000..d577e3e530 --- /dev/null +++ b/frontend/components/forms/fields/Checkbox/Checkbox.tests.jsx @@ -0,0 +1,11 @@ +import React from 'react'; +import expect from 'expect'; +import { mount } from 'enzyme'; + +import Checkbox from './Checkbox'; + +describe('Checkbox - component', () => { + it('renders', () => { + expect(mount()).toExist(); + }); +}); diff --git a/frontend/components/forms/fields/Checkbox/_styles.scss b/frontend/components/forms/fields/Checkbox/_styles.scss new file mode 100644 index 0000000000..51262a19c9 --- /dev/null +++ b/frontend/components/forms/fields/Checkbox/_styles.scss @@ -0,0 +1,45 @@ +.kolide-checkbox { + &__input { + visibility: hidden; + margin: 0; + + &:checked + .kolide-checkbox__tick { + &::after { + background-color: $brand; + border: solid 2px $brand; + } + + &::before { + @include transform(rotate(45deg)); + @include position(absolute, 50% null null 50%); + box-sizing: border-box; + display: table; + width: 7px; + height: 13px; + margin: -8px 0 0 -4px; + border: 2px solid $white; + border-top: 0; + border-left: 0; + content: ''; + } + } + } + + &__tick { + @include size(20px); + position: absolute; + display: inline-block; + + &::after { + @include transition(border 75ms ease-in-out, background 75ms ease-in-out); + @include size(20px); + border-radius: 2px; + border: solid 2px $border-medium; + content: ''; + box-sizing: border-box; + display: block; + background-color: $white; + visibility: visible; + } + } +} diff --git a/frontend/components/forms/fields/Checkbox/index.js b/frontend/components/forms/fields/Checkbox/index.js new file mode 100644 index 0000000000..f3d29de1e6 --- /dev/null +++ b/frontend/components/forms/fields/Checkbox/index.js @@ -0,0 +1 @@ +export default from './Checkbox'; diff --git a/frontend/components/forms/fields/InputFieldWithIcon/InputFieldWithIcon.jsx b/frontend/components/forms/fields/InputFieldWithIcon/InputFieldWithIcon.jsx index ba5e299ed7..9b00a76f3c 100644 --- a/frontend/components/forms/fields/InputFieldWithIcon/InputFieldWithIcon.jsx +++ b/frontend/components/forms/fields/InputFieldWithIcon/InputFieldWithIcon.jsx @@ -10,10 +10,12 @@ class InputFieldWithIcon extends InputField { static propTypes = { autofocus: PropTypes.bool, error: PropTypes.string, + hint: PropTypes.oneOfType([PropTypes.array, PropTypes.string]), iconName: PropTypes.string, name: PropTypes.string, onChange: PropTypes.func, placeholder: PropTypes.string, + tabIndex: PropTypes.number, type: PropTypes.string, className: PropTypes.string, }; @@ -33,9 +35,19 @@ class InputFieldWithIcon extends InputField { return
{placeholder}
; } + renderHint = () => { + const { hint } = this.props; + + if (hint) { + return {hint}; + } + + return false; + } + render () { - const { className, error, iconName, name, placeholder, type, value } = this.props; - const { onInputChange } = this; + const { className, error, iconName, name, placeholder, tabIndex, type, value } = this.props; + const { onInputChange, renderHint } = this; const inputClasses = classnames( `${baseClass}__input`, @@ -60,10 +72,12 @@ class InputFieldWithIcon extends InputField { className={inputClasses} placeholder={placeholder} ref={(r) => { this.input = r; }} + tabIndex={tabIndex} type={type} value={value} /> {iconName && } + {renderHint()}
); } diff --git a/frontend/components/forms/fields/InputFieldWithIcon/_styles.scss b/frontend/components/forms/fields/InputFieldWithIcon/_styles.scss index 56941e5d44..168bbcd53d 100644 --- a/frontend/components/forms/fields/InputFieldWithIcon/_styles.scss +++ b/frontend/components/forms/fields/InputFieldWithIcon/_styles.scss @@ -7,7 +7,7 @@ position: absolute; right: 6px; top: 28px; - font-size: 20px; + font-size: 14px; color: $accent-text; &--active { @@ -27,13 +27,18 @@ font-size: 20px; border-bottom-style: solid; border-bottom-color: $brand-ultralight; - color: $accent-text; padding-right: 30px; opacity: 1; text-indent: 1px; position: relative; width: 100%; box-sizing: border-box; + font-family: 'Oxygen', $helvetica; + color: $text-dark; + + @include placeholder { + color: $accent-text; + } &:focus { outline: none; @@ -63,4 +68,19 @@ font-size: $small; text-transform: lowercase; } + + &__hint { + font-size: 14px; + font-weight: $normal; + line-height: 1.57; + letter-spacing: 1px; + color: $accent-text; + + code { + color: $brand-light; + background-color: $accent-light; + padding: 2px; + font-family: 'SourceCodePro', $monospace; + } + } } diff --git a/frontend/components/forms/fields/SelectTargetsDropdown/TargetDetails/_styles.scss b/frontend/components/forms/fields/SelectTargetsDropdown/TargetDetails/_styles.scss index 109a0be625..793f772d16 100644 --- a/frontend/components/forms/fields/SelectTargetsDropdown/TargetDetails/_styles.scss +++ b/frontend/components/forms/fields/SelectTargetsDropdown/TargetDetails/_styles.scss @@ -7,7 +7,7 @@ font-size: $xsmall; display: none; - @include breakpoint(tablet) { + @include breakpoint(ltdesktop) { display: inline-block; position: absolute; top: 10px; @@ -20,7 +20,7 @@ } } - @include breakpoint(tablet) { + @include breakpoint(ltdesktop) { padding-top: $pad-most; } } diff --git a/frontend/components/forms/fields/SelectTargetsDropdown/_styles.scss b/frontend/components/forms/fields/SelectTargetsDropdown/_styles.scss index 89b8bc5199..b011dd57c0 100644 --- a/frontend/components/forms/fields/SelectTargetsDropdown/_styles.scss +++ b/frontend/components/forms/fields/SelectTargetsDropdown/_styles.scss @@ -181,7 +181,7 @@ } } - @include breakpoint(tablet) { + @include breakpoint(ltdesktop) { .Select-menu-outer { .Select-menu { min-width: 665px; diff --git a/frontend/interfaces/registration_form_data.js b/frontend/interfaces/registration_form_data.js index c61c347b56..f9a8fedc41 100644 --- a/frontend/interfaces/registration_form_data.js +++ b/frontend/interfaces/registration_form_data.js @@ -1,7 +1,6 @@ import { PropTypes } from 'react'; export default PropTypes.shape({ - full_name: PropTypes.string, username: PropTypes.string, password: PropTypes.string, password_confirmation: PropTypes.string, diff --git a/frontend/pages/RegistrationPage/Breadcrumbs/Breadcrumbs.jsx b/frontend/pages/RegistrationPage/Breadcrumbs/Breadcrumbs.jsx index b0488f7d8e..e2b794149b 100644 --- a/frontend/pages/RegistrationPage/Breadcrumbs/Breadcrumbs.jsx +++ b/frontend/pages/RegistrationPage/Breadcrumbs/Breadcrumbs.jsx @@ -24,21 +24,26 @@ class Breadcrumbs extends Component { render () { const { onClick } = this; const { page } = this.props; - const page1ClassName = classnames('button--unstyled', 'page-1-btn', { - 'is-active': page >= 1, + const baseClass = 'registration-breadcrumbs'; + const pageBaseClass = `${baseClass}__page`; + const page1ClassName = classnames(pageBaseClass, `${pageBaseClass}--1`, 'button--unstyled', { + [`${pageBaseClass}--active`]: page === 1, + [`${pageBaseClass}--complete`]: page > 1, }); - const page2ClassName = classnames('button--unstyled', 'page-2-btn', { - 'is-active': page >= 2, + const page2ClassName = classnames(pageBaseClass, `${pageBaseClass}--2`, 'button--unstyled', { + [`${pageBaseClass}--active`]: page === 2, + [`${pageBaseClass}--complete`]: page > 2, }); - const page3ClassName = classnames('button--unstyled', 'page-3-btn', { - 'is-active': page >= 3, + const page3ClassName = classnames(pageBaseClass, `${pageBaseClass}--3`, 'button--unstyled', { + [`${pageBaseClass}--active`]: page === 3, + [`${pageBaseClass}--complete`]: page > 3, }); return ( -
- - - +
+ + +
); } diff --git a/frontend/pages/RegistrationPage/Breadcrumbs/Breadcrumbs.tests.jsx b/frontend/pages/RegistrationPage/Breadcrumbs/Breadcrumbs.tests.jsx index 1fb5a6d2d5..566e2b05d0 100644 --- a/frontend/pages/RegistrationPage/Breadcrumbs/Breadcrumbs.tests.jsx +++ b/frontend/pages/RegistrationPage/Breadcrumbs/Breadcrumbs.tests.jsx @@ -14,21 +14,21 @@ describe('Breadcrumbs - component', () => { it('renders page 1 Button as active when the page prop is 1', () => { const component = mount(); - const page1Btn = component.find('button.page-1-btn'); - const page2Btn = component.find('button.page-2-btn'); - const page3Btn = component.find('button.page-3-btn'); + const page1Btn = component.find('button.registration-breadcrumbs__page--1'); + const page2Btn = component.find('button.registration-breadcrumbs__page--2'); + const page3Btn = component.find('button.registration-breadcrumbs__page--3'); - expect(page1Btn.prop('className')).toInclude('is-active'); - expect(page2Btn.prop('className')).toNotInclude('is-active'); - expect(page3Btn.prop('className')).toNotInclude('is-active'); + expect(page1Btn.prop('className')).toInclude('registration-breadcrumbs__page--active'); + expect(page2Btn.prop('className')).toNotInclude('registration-breadcrumbs__page--active'); + expect(page3Btn.prop('className')).toNotInclude('registration-breadcrumbs__page--active'); }); it('calls the onClick prop with the page # when clicked', () => { const onClickSpy = createSpy(); const component = mount(); - const page1Btn = component.find('button.page-1-btn'); - const page2Btn = component.find('button.page-2-btn'); - const page3Btn = component.find('button.page-3-btn'); + const page1Btn = component.find('button.registration-breadcrumbs__page--1'); + const page2Btn = component.find('button.registration-breadcrumbs__page--2'); + const page3Btn = component.find('button.registration-breadcrumbs__page--3'); page1Btn.simulate('click'); diff --git a/frontend/pages/RegistrationPage/Breadcrumbs/_styles.scss b/frontend/pages/RegistrationPage/Breadcrumbs/_styles.scss new file mode 100644 index 0000000000..112452407a --- /dev/null +++ b/frontend/pages/RegistrationPage/Breadcrumbs/_styles.scss @@ -0,0 +1,146 @@ +.registration-breadcrumbs { + @include display(flex); + @include justify-content(space-between); + @include align-content(center); + width: 665px; + height: 125px; + margin: 0 auto; + + @include breakpoint(tablet) { + height: 75px; + } + + &__page { + text-align: center; + width: 145px; + font-size: 14px; + font-weight: $normal; + line-height: 1.53; + letter-spacing: 0.5px; + color: $text-medium; + position: relative; + + &::before { + content: ''; + position: absolute; + width: 235px; + height: 2px; + background-image: linear-gradient(to right, $accent-dark 50%, transparent 50%); + background-position: left top; + background-repeat: repeat-x; + background-size: 17px 2px; + bottom: 43px; + left: 84px; + + @include breakpoint(tablet) { + bottom: 23px; + } + } + + &::after { + @extend %kolidecon; + @include size(24px); + background-color: $white; + display: block; + border-radius: 50%; + content: ''; + font-size: 28px; + margin: 14px auto 0; + position: relative; + z-index: 1; + cursor: pointer; + + @include breakpoint(tablet) { + margin-top: 4px; + } + } + + &:focus { + outline: none; + } + + &--active { + font-weight: $bold; + color: $text-dark; + } + + &--1 { + &::after { + border: solid 2px $success; + } + + &.registration-breadcrumbs__page--active { + &::after { + background-color: $success; + } + } + + &.registration-breadcrumbs__page--complete { + &::before { + background-image: linear-gradient(to right, $success 0%, $link 100%); + background-size: auto; + z-index: 2; + } + + &::after { + @include size(28px); + content: '\f035'; + color: $success; + border: 0; + } + } + } + + &--2 { + &::after { + border: solid 2px $link; + } + + &.registration-breadcrumbs__page--active { + &::after { + background-color: $link; + } + } + + &.registration-breadcrumbs__page--complete { + &::before { + background-image: linear-gradient(to right, $link 0%, $brand-light 100%); + background-size: auto; + z-index: 2; + } + + &::after { + @include size(28px); + content: '\f035'; + color: $link; + border: 0; + } + } + } + + &--3 { + &::before { + display: none; + } + + &::after { + border: solid 2px $brand-light; + } + + &.registration-breadcrumbs__page--active { + &::after { + background-color: $brand-light; + } + } + + &.registration-breadcrumbs__page--complete { + &::after { + @include size(28px); + content: '\f035'; + color: $brand-light; + border: 0; + } + } + } + } +} diff --git a/frontend/pages/RegistrationPage/RegistrationPage.jsx b/frontend/pages/RegistrationPage/RegistrationPage.jsx index 151f4a4751..d744f9bdcd 100644 --- a/frontend/pages/RegistrationPage/RegistrationPage.jsx +++ b/frontend/pages/RegistrationPage/RegistrationPage.jsx @@ -10,6 +10,8 @@ import { setup } from 'redux/nodes/auth/actions'; import { showBackgroundImage } from 'redux/nodes/app/actions'; import userInterface from 'interfaces/user'; +import kolideLogo from '../../../assets/images/kolide-logo-condensed.svg'; + export class RegistrationPage extends Component { static propTypes = { currentUser: userInterface, @@ -70,6 +72,11 @@ export class RegistrationPage extends Component { } onSetPage = (page) => { + const { page: currentPage } = this.state; + if (page >= currentPage) { + return false; + } + this.setState({ page }); return false; @@ -85,7 +92,12 @@ export class RegistrationPage extends Component { } return ( -
+
+ Kolide
diff --git a/frontend/pages/RegistrationPage/RegistrationPage.tests.jsx b/frontend/pages/RegistrationPage/RegistrationPage.tests.jsx index ea8bc05556..3355eb40f6 100644 --- a/frontend/pages/RegistrationPage/RegistrationPage.tests.jsx +++ b/frontend/pages/RegistrationPage/RegistrationPage.tests.jsx @@ -84,6 +84,7 @@ describe('RegistrationPage - component', () => { describe('#onSetPage', () => { it('sets state to the page number', () => { const page = mount(); + page.setState({ page: 3 }); page.node.onSetPage(3); expect(page.state()).toInclude({ page: 3 }); diff --git a/frontend/pages/RegistrationPage/_styles.scss b/frontend/pages/RegistrationPage/_styles.scss new file mode 100644 index 0000000000..0624707c48 --- /dev/null +++ b/frontend/pages/RegistrationPage/_styles.scss @@ -0,0 +1,19 @@ +.registration-page { + @include display(flex); + @include justify-content(center); + @include flex-direction(column); + min-height: calc(100vh - #{$footer-height}); + position: relative; + + &__logo { + @include position(absolute, 15px null null 15px); + width: 200px; + + @include breakpoint(tablet) { + width: 125px; + position: static; + display: block; + margin: 15px 0 0 15px; + } + } +} diff --git a/frontend/pages/hosts/NewHostPage/_styles.scss b/frontend/pages/hosts/NewHostPage/_styles.scss index 9328f3df55..3f9ee7942c 100644 --- a/frontend/pages/hosts/NewHostPage/_styles.scss +++ b/frontend/pages/hosts/NewHostPage/_styles.scss @@ -26,7 +26,7 @@ border: solid 1px $accent-dark; box-shadow: inset 0 0 8px 0 rgba($black, 0.12); box-sizing: border-box; - font-family: Source-codePro, Oxygen; + font-family: SourceCodePro, Oxygen; font-size: $medium; height: 60px; letter-spacing: 1.2px; @@ -100,6 +100,6 @@ code { color: $brand; - font-family: Source-codePro, Oxygen; + font-family: SourceCodePro, Oxygen; } } diff --git a/frontend/styles/global/_global.scss b/frontend/styles/global/_global.scss index 6c0d7672b2..640d0c9563 100644 --- a/frontend/styles/global/_global.scss +++ b/frontend/styles/global/_global.scss @@ -1,6 +1,7 @@ html { position: relative; min-height: 100%; + min-width: $min-width; // Because iOS hates us we must fight to the death! -webkit-tap-highlight-color: rgba(0, 0, 0, 0); // End Apple War @@ -13,6 +14,7 @@ body { font-family: 'Oxygen', sans-serif; font-size: $base; line-height: 1.6; + min-width: $min-width; } h1, @@ -37,6 +39,7 @@ h3 { } input, -textarea { +textarea, +button { font-family: 'Oxygen', sans-serif; } diff --git a/frontend/styles/global/_icons.scss b/frontend/styles/global/_icons.scss index 128a25459b..99cd75c9bd 100644 --- a/frontend/styles/global/_icons.scss +++ b/frontend/styles/global/_icons.scss @@ -112,18 +112,6 @@ content: '\f029'; } - .kolidecon-username:before { - content: '\f02a'; -} - - .kolidecon-password:before { - content: '\f02b'; -} - - .kolidecon-email:before { - content: '\f02c'; -} - .kolidecon-query:before { content: '\f02d'; } @@ -288,6 +276,18 @@ content: '\f03d'; } + .kolidecon-username:before { + content: '\f02a'; +} + + .kolidecon-password:before { + content: '\f02b'; +} + + .kolidecon-email:before { + content: '\f02c'; +} + .sr-only { position: absolute; diff --git a/frontend/styles/var/mixins.scss b/frontend/styles/var/mixins.scss index 9343c705a4..6480d1aa1b 100644 --- a/frontend/styles/var/mixins.scss +++ b/frontend/styles/var/mixins.scss @@ -1,10 +1,15 @@ $min-width: 768px; -$medium-width: 1280px; +$medium-width: 1024px; +$desktop-width: 1280px; $max-width: 2560px; @mixin breakpoint($size: desktop) { @if ($size == tablet) { - @media (min-width: $min-width) and (max-width: $medium-width - 1) { + @media (max-width: $medium-width) { + @content; + } + } @else if ($size == ltdesktop) { + @media (min-width: $min-width) and (max-width: $desktop-width - 1) { @content; } } @else { diff --git a/frontend/templates/react.tmpl b/frontend/templates/react.tmpl index 77716a9ee8..2b01131de0 100644 --- a/frontend/templates/react.tmpl +++ b/frontend/templates/react.tmpl @@ -2,6 +2,7 @@ + Kolide