From 38bcbdfb7e710fa11a9ddcde361d651c82d10105 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 29 Feb 2016 11:37:27 +0000 Subject: [PATCH 01/14] Profile settings Closes #13853 --- app/assets/javascripts/profile.js.coffee | 3 +- app/assets/stylesheets/framework/common.scss | 3 + app/assets/stylesheets/framework/forms.scss | 12 +- .../stylesheets/framework/tw_bootstrap.scss | 6 - app/assets/stylesheets/pages/profile.scss | 32 +++- app/views/profiles/show.html.haml | 167 +++++++++--------- 6 files changed, 122 insertions(+), 101 deletions(-) diff --git a/app/assets/javascripts/profile.js.coffee b/app/assets/javascripts/profile.js.coffee index 69d590a75331..15fd9e99ce93 100644 --- a/app/assets/javascripts/profile.js.coffee +++ b/app/assets/javascripts/profile.js.coffee @@ -48,7 +48,7 @@ class @Profile $filename.text($filename.data('label')) $('.js-upload-user-avatar').on 'click', -> - $('.edit_user').submit() + $('.edit-user').submit() $avatarInput.on "change", -> form = $(this).closest("form") @@ -62,4 +62,3 @@ class @Profile $modalCropImg.attr('src', event.target.result) fileData = reader.readAsDataURL(this.files[0]) - diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 9ecb547b64fb..4cf68545e114 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -6,10 +6,13 @@ .cdark { color: #444 } /** COMMON CLASSES **/ +.prepend-top-0 { margin-top: 0; } +.prepend-top-5 { margin-top: 5px; } .prepend-top-10 { margin-top:10px } .prepend-top-default { margin-top: $gl-padding !important; } .prepend-top-20 { margin-top:20px } .prepend-left-10 { margin-left:10px } +.prepend-left-default { margin-left:$gl-padding } .prepend-left-20 { margin-left:20px } .append-right-10 { margin-right:10px } .append-right-20 { margin-right:20px } diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss index d097e4d32f7f..85ec5f1e5f3b 100644 --- a/app/assets/stylesheets/framework/forms.scss +++ b/app/assets/stylesheets/framework/forms.scss @@ -28,15 +28,15 @@ input[type='search'].search-input { } &.search-input:-moz-placeholder { /* Firefox 18- */ - text-align: center; + text-align: center; } &.search-input::-moz-placeholder { /* Firefox 19+ */ - text-align: center; + text-align: center; } - &.search-input:-ms-input-placeholder { - text-align: center; + &.search-input:-ms-input-placeholder { + text-align: center; } } @@ -69,6 +69,10 @@ label { &.inline-label { margin: 0; } + + &.label-light { + font-weight: normal; + } } .inline-input-group { diff --git a/app/assets/stylesheets/framework/tw_bootstrap.scss b/app/assets/stylesheets/framework/tw_bootstrap.scss index 3e7092448795..1e9959429cd7 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap.scss @@ -167,12 +167,6 @@ } } -.alert-help { - background-color: $background-color; - border: 1px solid $border-color; - color: $gl-gray; -} - // Typography ================================================================= .text-primary, diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index de4d9fd80fa2..07ed2490d7fb 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -5,9 +5,28 @@ } } -.profile-avatar-form-option { - hr { - margin: 10px 0; +.profile-settings-sidebar { + a { + color: $gl-primary; + } +} + +.avatar-image { + @media (min-width: $screen-sm-min) { + float: left; + margin-bottom: 0; + } +} + +.avatar-file-name { + position: relative; + top: 2px; + display: inline-block; +} + +.profile-settings-sidebar { + a { + color: $gl-primary; } } @@ -79,6 +98,13 @@ margin: auto; } +.user-avatar-button { + .file-name { + display: inline-block; + padding-left: 10px; + } +} + .modal-profile-crop { .modal-dialog { width: 500px; diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 64c4bdceff99..3d1ba49491cf 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -1,107 +1,102 @@ -.alert.alert-help.prepend-top-default - This information will appear on your profile. - - if current_user.ldap_user? - Some options are unavailable for LDAP accounts - -.prepend-top-default -= form_for @user, url: profile_path, method: :put, html: { multipart: true, class: "edit_user form-horizontal" }, authenticity_token: true do |f| += form_for @user, url: profile_path, method: :put, html: { multipart: true, class: "edit-user prepend-top-default" }, authenticity_token: true do |f| + = f.hidden_field :avatar_crop_x + = f.hidden_field :avatar_crop_y + = f.hidden_field :avatar_crop_size -if @user.errors.any? %div.alert.alert-danger %ul - @user.errors.full_messages.each do |msg| %li= msg .row - .col-md-7 + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + Public Avatar + %p + - if @user.avatar? + You can change your avatar here + - if Gitlab.config.gravatar.enabled + or remove the current avatar to revert to #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host} + - else + You can upload an avatar here + - if Gitlab.config.gravatar.enabled + or change it at #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host} + .col-lg-9 + .clearfix.avatar-image.append-bottom-default + = image_tag avatar_icon(@user, 160), alt: '', class: 'avatar s160' + %h5.prepend-top-0 + Upload new avatar + .prepend-top-5.append-bottom-10 + %a.btn.js-choose-user-avatar-button + Browse file... + %span.avatar-file-name.prepend-left-default.js-avatar-filename No file chosen + = f.file_field :avatar, class: "js-user-avatar-input hidden" + .help-block + The maximum file size allowed is 200KB. + - if @user.avatar? + %hr + = link_to 'Remove avatar', profile_avatar_path, data: { confirm: "Avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-gray" + %hr + .row + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + Main settings + %p + This information will appear on your profile. + - if current_user.ldap_user? + Some options are unavailable for LDAP accounts + .col-lg-9 .form-group - = f.label :name, class: "control-label" - .col-sm-10 - = f.text_field :name, class: "form-control", required: true - %span.help-block Enter your name, so people you know can recognize you. + = f.label :name, class: "label-light" + = f.text_field :name, class: "form-control", required: true + %span.help-block Enter your name, so people you know can recognize you. .form-group - = f.label :email, class: "control-label" - .col-sm-10 - - if @user.ldap_user? && @user.ldap_email? - = f.text_field :email, class: "form-control", required: true, readonly: true - %span.help-block.light - Your email address was automatically set based on the LDAP server. + = f.label :email, class: "label-light" + - if @user.ldap_user? && @user.ldap_email? + = f.text_field :email, class: "form-control", required: true, readonly: true + %span.help-block.light + Your email address was automatically set based on the LDAP server. + - else + - if @user.temp_oauth_email? + = f.text_field :email, class: "form-control", required: true, value: nil - else - - if @user.temp_oauth_email? - = f.text_field :email, class: "form-control", required: true, value: nil - - else - = f.text_field :email, class: "form-control", required: true - - if @user.unconfirmed_email.present? - %span.help-block - Please click the link in the confirmation email before continuing. It was sent to - = succeed "." do - %strong #{@user.unconfirmed_email} - %p - = link_to "Resend confirmation e-mail", user_confirmation_path(user: { email: @user.unconfirmed_email }), method: :post + = f.text_field :email, class: "form-control", required: true + - if @user.unconfirmed_email.present? + %span.help-block + Please click the link in the confirmation email before continuing. It was sent to + = succeed "." do + %strong #{@user.unconfirmed_email} + %p + = link_to "Resend confirmation e-mail", user_confirmation_path(user: { email: @user.unconfirmed_email }), method: :post - - else - %span.help-block We also use email for avatar detection if no avatar is uploaded. + - else + %span.help-block We also use email for avatar detection if no avatar is uploaded. .form-group - = f.label :public_email, class: "control-label" - .col-sm-10 - = f.select :public_email, options_for_select(@user.all_emails, selected: @user.public_email), {include_blank: 'Do not show on profile'}, class: "select2" - %span.help-block This email will be displayed on your public profile. + = f.label :public_email, class: "label-light" + = f.select :public_email, options_for_select(@user.all_emails, selected: @user.public_email), {include_blank: 'Do not show on profile'}, class: "select2" + %span.help-block This email will be displayed on your public profile. .form-group - = f.label :skype, class: "control-label" - .col-sm-10= f.text_field :skype, class: "form-control" + = f.label :skype, class: "label-light" + = f.text_field :skype, class: "form-control" .form-group - = f.label :linkedin, class: "control-label" - .col-sm-10= f.text_field :linkedin, class: "form-control" + = f.label :linkedin, class: "label-light" + = f.text_field :linkedin, class: "form-control" .form-group - = f.label :twitter, class: "control-label" - .col-sm-10= f.text_field :twitter, class: "form-control" + = f.label :twitter, class: "label-light" + = f.text_field :twitter, class: "form-control" .form-group - = f.label :website_url, 'Website', class: "control-label" - .col-sm-10= f.text_field :website_url, class: "form-control" + = f.label :website_url, 'Website', class: "label-light" + = f.text_field :website_url, class: "form-control" .form-group - = f.label :location, 'Location', class: "control-label" - .col-sm-10= f.text_field :location, class: "form-control" + = f.label :location, 'Location', class: "label-light" + = f.text_field :location, class: "form-control" .form-group - = f.label :bio, class: "control-label" - .col-sm-10 - = f.text_area :bio, rows: 4, class: "form-control", maxlength: 250 - %span.help-block Tell us about yourself in fewer than 250 characters. - - .col-md-5 - .light-well - = image_tag avatar_icon(@user, 160), alt: '', class: 'avatar s160' - - .clearfix - .profile-avatar-form-option - %p.light - - if @user.avatar? - You can change your avatar here - - if Gitlab.config.gravatar.enabled - %br - or remove the current avatar to revert to #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host} - - else - You can upload an avatar here - - if Gitlab.config.gravatar.enabled - %br - or change it at #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host} - %hr - %a.choose-btn.btn.btn-sm.js-choose-user-avatar-button - %i.fa.fa-paperclip - %span Choose File ... -   - %span.file_name.js-avatar-filename File name... - = f.file_field :avatar, class: "js-user-avatar-input hidden" - = f.hidden_field :avatar_crop_x - = f.hidden_field :avatar_crop_y - = f.hidden_field :avatar_crop_size - .light The maximum file size allowed is 200KB. - - if @user.avatar? - %hr - = link_to 'Remove avatar', profile_avatar_path, data: { confirm: "Avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar" - - - .form-actions - = f.submit 'Save changes', class: "btn btn-success" - = link_to "Cancel", user_path(current_user), class: "btn btn-cancel" + = f.label :bio, class: "label-light" + = f.text_area :bio, rows: 4, class: "form-control", maxlength: 250 + %span.help-block Tell us about yourself in fewer than 250 characters. + .prepend-top-default.append-bottom-default + = f.submit 'Update profile settings', class: "btn btn-success" + = link_to "Cancel", user_path(current_user), class: "btn btn-cancel" .modal.modal-profile-crop .modal-dialog -- GitLab From b6eda35b9d171e9d2ed487dc92646c1cc9c68430 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 29 Feb 2016 13:39:29 +0000 Subject: [PATCH 02/14] Account settings --- app/assets/javascripts/profile.js.coffee | 7 +- app/assets/stylesheets/framework/common.scss | 3 +- .../stylesheets/framework/variables.scss | 4 +- app/assets/stylesheets/pages/profile.scss | 60 ++++- .../profiles/accounts_controller.rb | 24 ++ app/views/profiles/accounts/show.html.haml | 229 ++++++++++-------- 6 files changed, 208 insertions(+), 119 deletions(-) diff --git a/app/assets/javascripts/profile.js.coffee b/app/assets/javascripts/profile.js.coffee index 15fd9e99ce93..c93daa18505b 100644 --- a/app/assets/javascripts/profile.js.coffee +++ b/app/assets/javascripts/profile.js.coffee @@ -4,12 +4,13 @@ class @Profile $('.js-preferences-form').on 'change.preference', 'input[type=radio]', -> $(this).parents('form').submit() - $('.update-username form').on 'ajax:before', -> - $('.loading-gif').show() + $('.update-username').on 'ajax:before', -> + $('.loading-username').show() $(this).find('.update-success').hide() $(this).find('.update-failed').hide() - $('.update-username form').on 'ajax:complete', -> + $('.update-username').on 'ajax:complete', -> + $('.loading-username').hide() $(this).find('.btn-save').enable() $(this).find('.loading-gif').hide() diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 4cf68545e114..fb493d6728a9 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -12,9 +12,10 @@ .prepend-top-default { margin-top: $gl-padding !important; } .prepend-top-20 { margin-top:20px } .prepend-left-10 { margin-left:10px } -.prepend-left-default { margin-left:$gl-padding } +.prepend-left-default { margin-left: $gl-padding; } .prepend-left-20 { margin-left:20px } .append-right-10 { margin-right:10px } +.append-right-default { margin-right: $gl-padding; } .append-right-20 { margin-right:20px } .append-bottom-10 { margin-bottom:10px } .append-bottom-15 { margin-bottom:15px } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 7834cb0bfa54..107fa92447d0 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -64,7 +64,7 @@ $orange-light: rgba(252, 109, 38, 0.80); $orange-normal: #E75E40; $orange-dark: #CE5237; -$red-light: #F43263; +$red-light: #F06559; $red-normal: #E52C5A; $red-dark: #D22852; @@ -88,7 +88,7 @@ $border-orange-light: #fc6d26; $border-orange-normal: #CE5237; $border-orange-dark: #C14E35; -$border-red-light: #E52C5A; +$border-red-light: #F24F41; $border-red-normal: #D22852; $border-red-dark: #CA264F; diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index 07ed2490d7fb..da721b1d055e 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -1,10 +1,3 @@ -.account-page { - fieldset { - margin-bottom: 15px; - padding-bottom: 15px; - } -} - .profile-settings-sidebar { a { color: $gl-primary; @@ -61,6 +54,18 @@ } } +.two-factor-new-manual-panel { + padding: 10px 10px; + background-color: #FAFAFA; + border: 1px solid #E5E5E5; + border-radius: 3px; +} + +.two-factor-new-manual-content { + margin-top: 0; + margin-bottom: 0; +} + .calendar-hint { margin-top: -12px; float: right; @@ -140,3 +145,44 @@ width: auto; } } + +.change-username-title { + color: #FC6D26; +} + +.remove-account-title { + color: #F00; +} + +.provider-btn-group { + display: inline-block; + margin-right: 10px; + border: 1px solid #E5E5E5; + border-radius: 3px; + + &:last-child { + margin-right: 0; + } +} + +.provider-btn-image { + display: inline-block; + padding: 5px 10px; + border-right: 1px solid #E5E5E5; + + > img { + width: 20px; + } +} + +.provider-btn { + display: inline-block; + padding: 5px 10px; + margin-left: -3px; + line-height: 22px; + background-color: $gray-light; + + &.not-active { + color: #4688F1; + } +} diff --git a/app/controllers/profiles/accounts_controller.rb b/app/controllers/profiles/accounts_controller.rb index 175afbf84259..f2fe9de7a135 100644 --- a/app/controllers/profiles/accounts_controller.rb +++ b/app/controllers/profiles/accounts_controller.rb @@ -1,6 +1,18 @@ class Profiles::AccountsController < Profiles::ApplicationController def show + unless current_user.otp_secret + current_user.otp_secret = User.generate_otp_secret(32) + end + + unless current_user.otp_grace_period_started_at && two_factor_grace_period + current_user.otp_grace_period_started_at = Time.current + end + + # current_user.save! if current_user.changed? + @user = current_user + + @qr_code = build_qr_code end def unlink @@ -8,4 +20,16 @@ def unlink current_user.identities.find_by(provider: provider).destroy redirect_to profile_account_path end + + private + + def build_qr_code + issuer = "#{issuer_host} | #{current_user.email}" + uri = current_user.otp_provisioning_uri(current_user.email, issuer: issuer) + RQRCode::render_qrcode(uri, :svg, level: :m, unit: 3) + end + + def issuer_host + Gitlab.config.gitlab.host + end end diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index 9fa96084f942..af72e506b4b2 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -5,114 +5,131 @@ .alert.alert-info Some options are unavailable for LDAP accounts -.account-page.prepend-top-default - .panel.panel-default.update-token - .panel-heading - Reset Private token - .panel-body - = form_for @user, url: reset_private_token_profile_path, method: :put do |f| - .data - %p - Your private token is used to access application resources without authentication. - %br - It can be used for atom feeds or the API. - %span.cred - Keep it secret! - - %p.cgray - - if current_user.private_token - = text_field_tag "token", current_user.private_token, class: "form-control" - - else - %span You don`t have one yet. Click generate to fix it. - - .form-actions - - if current_user.private_token - = f.submit 'Reset private token', data: { confirm: "Are you sure?" }, class: "btn btn-default" +.row.prepend-top-default + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + Private Token + %p + Your private token is used to access application resources without authentication. + .col-lg-9 + = form_for @user, url: reset_private_token_profile_path, method: :put do |f| + %p.cgray + - if current_user.private_token + = label_tag "token", "Private token", class: "label-light" + = text_field_tag "token", current_user.private_token, class: "form-control" + - else + %span You don`t have one yet. Click generate to fix it. + %p.help-block + It can be used for atom feeds or the API. Keep it secret! + .prepend-top-default + - if current_user.private_token + = f.submit 'Reset private token', data: { confirm: "Are you sure?" }, class: "btn btn-default" + - else + = f.submit 'Generate', class: "btn btn-default" +%hr +.row.prepend-top-default + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + Two-factor Authentication + %p + Increase your account's security by enabling two-factor authentication (2FA). + .col-lg-9 + %p + Status: #{current_user.two_factor_enabled? ? 'enabled' : 'disabled'} + - if !current_user.two_factor_enabled? + %p + Download the Google Authenticator application from App Store for iOS or Google Play for Android and scan this code. + More information is available in the #{link_to('documentation', help_page_path('profile', 'two_factor_authentication'))}. + .row.append-bottom-10 + .col-md-3 + = raw @qr_code + .col-md-9 + .two-factor-new-manual-panel + %p.two-factor-new-manual-content + Can't scan the code? + %p.two-factor-new-manual-content + To add the entry manually, provide the following details to the application on your phone. + %p.two-factor-new-manual-content + Account: + = current_user.email + %p.two-factor-new-manual-content + Key: + = current_user.otp_secret.scan(/.{4}/).join(' ') + %p.two-factor-new-manual-content + Time based: Yes + = form_for @user, url: "", method: :put do |f| + .form-group + = label_tag :pin_code, nil, class: "label-light" + = text_field_tag :pin_code, nil, class: "form-control", required: true + .prepend-top-default + = submit_tag 'Enable two-factor authentication', class: 'btn btn-success' +%hr +- if button_based_providers.any? + .row.prepend-top-default + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + Social sign-in + %p + Activate signin with one of the following services + .col-lg-9 + %label.label-light + Connected Accounts + %p Click on icon to activate signin with one of the following services + - button_based_providers.each do |provider| + .provider-btn-group + .provider-btn-image + = provider_image_tag(provider) + - if auth_active?(provider) + = link_to unlink_profile_account_path(provider: provider), method: :delete, class: 'provider-btn' do + Disconnect - else - = f.submit 'Generate', class: "btn btn-default" + = link_to user_omniauth_authorize_path(provider), method: :post, class: "provider-btn #{'not-active' if !auth_active?(provider)}", "data-no-turbolink" => "true" do + Connect + %hr +- if current_user.can_change_username? + .row.prepend-top-default + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0.change-username-title + Change username + %p + Changing your username will change path to all personal projects! + .col-lg-9 + = form_for @user, url: update_username_profile_path, method: :put, remote: true, html: {class: "update-username"} do |f| + .form-group + = f.label :username, "Path", class: "label-light" + .input-group + .input-group-addon + = "#{root_url}u/" + = f.text_field :username, required: true, class: 'form-control' + .help-block + Current path: + = "#{root_url}u/#{current_user.username}" + .prepend-top-default + = f.button class: "btn btn-warning", type: "submit" do + = icon "spinner spin", class: "hidden loading-username" + Update username + %hr - .panel.panel-default - .panel-heading - Two-factor Authentication - .panel-body - - if current_user.two_factor_enabled? - .pull-right - = link_to 'Disable Two-factor Authentication', profile_two_factor_auth_path, method: :delete, class: 'btn btn-close btn-sm', - data: { confirm: 'Are you sure?' } - %p.text-success - %strong - Two-factor Authentication is enabled +- if signup_enabled? + .row.prepend-top-default + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0.remove-account-title + Remove account + .col-lg-9 + - if @user.can_be_removed? %p - If you lose your recovery codes you can - %strong - = succeed ',' do - = link_to 'generate new ones', codes_profile_two_factor_auth_path, method: :post, data: { confirm: 'Are you sure?' } - invalidating all previous codes. - + Deleting an account has the following effects: + %ul + %li All user content like authored issues, snippets, comments will be removed + - rp = current_user.personal_projects.count + - unless rp.zero? + %li #{pluralize rp, 'personal project'} will be removed and cannot be restored + = link_to 'Delete account', user_registration_path, data: { confirm: "REMOVE #{current_user.name}? Are you sure?" }, method: :delete, class: "btn btn-remove" - else - %p - Increase your account's security by enabling two-factor authentication (2FA). - %p - Each time you log in you’ll be required to provide your username and - password as usual, plus a randomly-generated code from your phone. - - .form-actions - = link_to 'Enable Two-factor Authentication', new_profile_two_factor_auth_path, class: 'btn btn-success' - - - if button_based_providers.any? - .panel.panel-default - .panel-heading - Connected Accounts - .panel-body - .oauth-buttons.append-bottom-10 - %p Click on icon to activate signin with one of the following services - - button_based_providers.each do |provider| - .btn-group - = link_to provider_image_tag(provider), user_omniauth_authorize_path(provider), method: :post, class: "btn btn-lg #{'active' if auth_active?(provider)}", "data-no-turbolink" => "true" - - - if auth_active?(provider) - = link_to unlink_profile_account_path(provider: provider), method: :delete, class: 'btn btn-lg' do - = icon('close') - - - if current_user.can_change_username? - .panel.panel-warning.update-username - .panel-heading - Change Username - .panel-body - = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f| + - if @user.solo_owned_groups.present? %p - Changing your username will change path to all personal projects! - %div - .input-group - .input-group-addon - = "#{root_url}u/" - = f.text_field :username, required: true, class: 'form-control' -   - .loading-gif.hide - %p - = icon('spinner spin') - Saving new username - .form-actions - = f.submit 'Save username', class: "btn btn-warning" - - - if signup_enabled? - .panel.panel-danger.remove-account - .panel-heading - Remove account - .panel-body - - if @user.can_be_removed? - %p Deleting an account has the following effects: - %ul - %li All user content like authored issues, snippets, comments will be removed - - rp = current_user.personal_projects.count - - unless rp.zero? - %li #{pluralize rp, 'personal project'} will be removed and cannot be restored - .form-actions - = link_to 'Delete account', user_registration_path, data: { confirm: "REMOVE #{current_user.name}? Are you sure?" }, method: :delete, class: "btn btn-remove" - - else - - if @user.solo_owned_groups.present? - %p - Your account is currently an owner in these groups: - %strong #{@user.solo_owned_groups.map(&:name).join(', ')} - %p - You must transfer ownership or delete these groups before you can delete your account. + Your account is currently an owner in these groups: + %strong #{@user.solo_owned_groups.map(&:name).join(', ')} + %p + You must transfer ownership or delete these groups before you can delete your account. +.append-bottom-default -- GitLab From 2d86e8f032ddf263b66361ae5655770b81c9c145 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 29 Feb 2016 13:42:21 +0000 Subject: [PATCH 03/14] Saves current_user on account page --- app/controllers/profiles/accounts_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/profiles/accounts_controller.rb b/app/controllers/profiles/accounts_controller.rb index f2fe9de7a135..669fe05e5c7f 100644 --- a/app/controllers/profiles/accounts_controller.rb +++ b/app/controllers/profiles/accounts_controller.rb @@ -8,7 +8,7 @@ def show current_user.otp_grace_period_started_at = Time.current end - # current_user.save! if current_user.changed? + current_user.save! if current_user.changed? @user = current_user -- GitLab From 15a79b89cbf20b434a211d52d49127aafaf11256 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 29 Feb 2016 14:47:21 +0000 Subject: [PATCH 04/14] Applications tab on profile settings Closes #13855 --- app/assets/stylesheets/framework/buttons.scss | 13 ++ app/assets/stylesheets/framework/common.scss | 1 + app/assets/stylesheets/pages/profile.scss | 14 ++ .../oauth/applications_controller.rb | 6 +- app/controllers/profiles_controller.rb | 1 + .../applications/_delete_form.html.haml | 8 +- .../doorkeeper/applications/_form.html.haml | 31 ++-- app/views/profiles/applications.html.haml | 145 ++++++++++-------- 8 files changed, 133 insertions(+), 86 deletions(-) diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index 50aa170d24c3..b8bcbcc933f5 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -143,6 +143,19 @@ } } +.btn-transparent { + color: #8F8F8F; + background-color: transparent; + border: 0; + + &:hover, + &:active, + &:focus { + background-color: transparent; + box-shadow: none; + } +} + .btn-block { width: 100%; margin: 0; diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index fb493d6728a9..6ecf73188191 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -14,6 +14,7 @@ .prepend-left-10 { margin-left:10px } .prepend-left-default { margin-left: $gl-padding; } .prepend-left-20 { margin-left:20px } +.append-right-5 { margin-right:5px } .append-right-10 { margin-right:10px } .append-right-default { margin-right: $gl-padding; } .append-right-20 { margin-right:20px } diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index da721b1d055e..3e6e1ed0ef10 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -186,3 +186,17 @@ color: #4688F1; } } + +.profile-settings-message { + line-height: 32px; + color: #9E8E60; + background-color: #FBF2D9; + border: 1px solid #F0E2BB; + border-radius: 3px; +} + +.oauth-applications { + form { + display: inline-block; + } +} diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb index dc22101cd5e6..d983ae0b8c6c 100644 --- a/app/controllers/oauth/applications_controller.rb +++ b/app/controllers/oauth/applications_controller.rb @@ -11,6 +11,10 @@ def index head :forbidden and return end + def new + redirect_to applications_profile_url + end + def create @application = Doorkeeper::Application.new(application_params) @@ -20,7 +24,7 @@ def create flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create]) redirect_to oauth_application_url(@application) else - render :new + redirect_to applications_profile_url, flash: {application: @application} end end diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index fa7a11489615..75eb9bdb96fa 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -13,6 +13,7 @@ def applications @authorized_tokens = current_user.oauth_authorized_tokens @authorized_anonymous_tokens = @authorized_tokens.reject(&:application) @authorized_apps = @authorized_tokens.map(&:application).uniq - [nil] + @application = flash[:application] || Doorkeeper::Application.new end def update diff --git a/app/views/doorkeeper/applications/_delete_form.html.haml b/app/views/doorkeeper/applications/_delete_form.html.haml index 6a5c917049de..001a711b1dd1 100644 --- a/app/views/doorkeeper/applications/_delete_form.html.haml +++ b/app/views/doorkeeper/applications/_delete_form.html.haml @@ -1,4 +1,10 @@ - submit_btn_css ||= 'btn btn-link btn-remove btn-sm' = form_tag oauth_application_path(application) do %input{:name => "_method", :type => "hidden", :value => "delete"}/ - = submit_tag 'Destroy', onclick: "return confirm('Are you sure?')", class: submit_btn_css \ No newline at end of file + - if defined? small + = button_tag type: "submit", class: "btn btn-transparent", data: { confirm: "Are you sure?" } do + %span.sr-only + Destroy + = icon('trash') + - else + = submit_tag 'Destroy', data: { confirm: "Are you sure?" }, class: submit_btn_css diff --git a/app/views/doorkeeper/applications/_form.html.haml b/app/views/doorkeeper/applications/_form.html.haml index 98a61ab211bf..0df8362d4ad5 100644 --- a/app/views/doorkeeper/applications/_form.html.haml +++ b/app/views/doorkeeper/applications/_form.html.haml @@ -1,4 +1,4 @@ -= form_for application, url: doorkeeper_submit_path(application), html: {class: 'form-horizontal', role: 'form'} do |f| += form_for application, url: doorkeeper_submit_path(application), html: {role: 'form'} do |f| - if application.errors.any? .alert.alert-danger %ul @@ -6,25 +6,20 @@ %li= msg .form-group - = f.label :name, class: 'control-label' - - .col-sm-10 - = f.text_field :name, class: 'form-control', required: true + = f.label :name, class: 'label-light' + = f.text_field :name, class: 'form-control', required: true .form-group - = f.label :redirect_uri, class: 'control-label' - - .col-sm-10 - = f.text_area :redirect_uri, class: 'form-control', required: true + = f.label :redirect_uri, class: 'label-light' + = f.text_area :redirect_uri, class: 'form-control', required: true + %span.help-block + Use one line per URI + - if Doorkeeper.configuration.native_redirect_uri %span.help-block - Use one line per URI - - if Doorkeeper.configuration.native_redirect_uri - %span.help-block - Use - %code= Doorkeeper.configuration.native_redirect_uri - for local tests + Use + %code= Doorkeeper.configuration.native_redirect_uri + for local tests - .form-actions - = f.submit 'Submit', class: "btn btn-create" - = link_to "Cancel", applications_profile_path, class: "btn btn-cancel" + .prepend-top-default + = f.submit 'Add application', class: "btn btn-create" diff --git a/app/views/profiles/applications.html.haml b/app/views/profiles/applications.html.haml index 86f35823406c..911ba9f87f0f 100644 --- a/app/views/profiles/applications.html.haml +++ b/app/views/profiles/applications.html.haml @@ -1,70 +1,83 @@ - page_title "Applications" - header_title page_title, applications_profile_path -.alert.alert-help.prepend-top-default - - if user_oauth_applications? - Manage applications that can use GitLab as an OAuth provider, - and applications that you've authorized to use your account. - - else - Manage applications that you've authorized to use your account. +.row.prepend-top-default + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + = page_title + %p + - if user_oauth_applications? + Manage applications that can use GitLab as an OAuth provider, + and applications that you've authorized to use your account. + - else + Manage applications that you've authorized to use your account. + .col-lg-9 + - if user_oauth_applications? + %h5 + Add new application + = render 'doorkeeper/applications/form', application: @application + %hr + - if user_oauth_applications? + .oauth-applications + %h5 + Your applications (#{@applications.size}) + - if @applications.any? + .table-responsive + %table.table.table-striped + %thead + %tr + %th Name + %th Callback URL + %th Clients + %th{width: 105} + %tbody + - @applications.each do |application| + %tr{:id => "application_#{application.id}"} + %td= link_to application.name, oauth_application_path(application) + %td + - application.redirect_uri.split.each do |uri| + %div= uri + %td= application.access_tokens.count + %td + = link_to edit_oauth_application_path(application), class: "btn btn-transparent append-right-5" do + %span.sr-only + Edit + = icon('pencil') + = render 'doorkeeper/applications/delete_form', application: application, small: true + - else + .profile-settings-message.text-center + You don't have any applications + .oauth-authorized-applications.prepend-top-20 + - if user_oauth_applications? + %h5 + Authorized applications (#{@authorized_tokens.size}) -- if user_oauth_applications? - .oauth-applications - %h3 - Your applications - .pull-right - = link_to 'New Application', new_oauth_application_path, class: 'btn btn-success' - - if @applications.any? - .table-holder - %table.table.table-striped - %thead - %tr - %th Name - %th Callback URL - %th Clients - %th - %th - %tbody - - @applications.each do |application| - %tr{:id => "application_#{application.id}"} - %td= link_to application.name, oauth_application_path(application) - %td - - application.redirect_uri.split.each do |uri| - %div= uri - %td= application.access_tokens.count - %td= link_to 'Edit', edit_oauth_application_path(application), class: 'btn btn-link btn-sm' - %td= render 'doorkeeper/applications/delete_form', application: application - -.oauth-authorized-applications.prepend-top-20 - - if user_oauth_applications? - %h3 - Authorized applications - - - if @authorized_tokens.any? - .table-holder - %table.table.table-striped - %thead - %tr - %th Name - %th Authorized At - %th Scope - %th - %tbody - - @authorized_apps.each do |app| - - token = app.authorized_tokens.order('created_at desc').first - %tr{:id => "application_#{app.id}"} - %td= app.name - %td= token.created_at - %td= token.scopes - %td= render 'doorkeeper/authorized_applications/delete_form', application: app - - @authorized_anonymous_tokens.each do |token| - %tr - %td - Anonymous - %div.help-block - %em Authorization was granted by entering your username and password in the application. - %td= token.created_at - %td= token.scopes - %td= render 'doorkeeper/authorized_applications/delete_form', token: token - - else - %p.light You don't have any authorized applications + - if @authorized_tokens.any? + .table-responsive + %table.table.table-striped + %thead + %tr + %th Name + %th Authorized At + %th Scope + %th + %tbody + - @authorized_apps.each do |app| + - token = app.authorized_tokens.order('created_at desc').first + %tr{:id => "application_#{app.id}"} + %td= app.name + %td= token.created_at + %td= token.scopes + %td= render 'doorkeeper/authorized_applications/delete_form', application: app + - @authorized_anonymous_tokens.each do |token| + %tr + %td + Anonymous + %div.help-block + %em Authorization was granted by entering your username and password in the application. + %td= token.created_at + %td= token.scopes + %td= render 'doorkeeper/authorized_applications/delete_form', token: token + - else + .profile-settings-message.text-center + You don't have any authorized applications -- GitLab From 7748df5afc2d27e2311fd2d45e275d779a784516 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 29 Feb 2016 15:06:22 +0000 Subject: [PATCH 05/14] Emails settings Closes #13857 --- app/assets/stylesheets/pages/profile.scss | 7 +- app/views/profiles/accounts/show.html.haml | 2 +- app/views/profiles/emails/index.html.haml | 90 +++++++++++----------- 3 files changed, 51 insertions(+), 48 deletions(-) diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index 3e6e1ed0ef10..171cbd6deedf 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -54,11 +54,16 @@ } } -.two-factor-new-manual-panel { +.account-well { padding: 10px 10px; background-color: #FAFAFA; border: 1px solid #E5E5E5; border-radius: 3px; + + ul { + padding-left: 20px; + margin-bottom: 0; + } } .two-factor-new-manual-content { diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index af72e506b4b2..be3ae942e7ff 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -44,7 +44,7 @@ .col-md-3 = raw @qr_code .col-md-9 - .two-factor-new-manual-panel + .account-well %p.two-factor-new-manual-content Can't scan the code? %p.two-factor-new-manual-content diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml index 705e1804717b..a962c4ea2846 100644 --- a/app/views/profiles/emails/index.html.haml +++ b/app/views/profiles/emails/index.html.haml @@ -1,50 +1,48 @@ - page_title "Emails" - header_title page_title, profile_emails_path -.alert.alert-help.prepend-top-default - %ul - %li - Your - %b Primary Email - will be used for avatar detection and web based operations, such as edits and merges. - %li - Your - %b Notification Email - will be used for account notifications. - %li - Your - %b Public Email - will be displayed on your public profile. - %li - All email addresses will be used to identify your commits. - -.panel.panel-default - .panel-heading - Emails (#{@emails.count + 1}) - %ul.well-list#emails-table - %li - %strong= @primary - %span.label.label-success Primary Email - - if @primary === current_user.public_email - %span.label.label-info Public Email - - if @primary === current_user.notification_email - %span.label.label-info Notification Email - - @emails.each do |email| +.row.prepend-top-default + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + = page_title + %p + Control emails linked to your account + .col-lg-9 + %h4 Add email address + = form_for 'email', url: profile_emails_path do |f| + .form-group + = f.label :email, class: 'label-light' + = f.text_field :email, class: 'form-control' + .prepend-top-default + = f.submit 'Add email address', class: 'btn btn-create' + %hr + %h4 + Linked emails (#{@emails.count + 1}) + .account-well.append-bottom-default + %ul + %li + Your Primary Email will be used for avatar detection and web based operations, such as edits and merges. + %li + Your Notification Email will be used for account notifications. + %li + Your Public Email will be displayed on your public profile. + %li + All email addresses will be used to identify your commits. + %ul.well-list %li - %strong= email.email - - if email.email === current_user.public_email - %span.label.label-info Public Email - - if email.email === current_user.notification_email - %span.label.label-info Notification Email - %span.cgray - added #{time_ago_with_tooltip(email.created_at)} - = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-sm btn-remove pull-right' - -%h4 Add email address -= form_for 'email', url: profile_emails_path, html: { class: 'form-horizontal' } do |f| - .form-group - = f.label :email, class: 'control-label' - .col-sm-10 - = f.text_field :email, class: 'form-control' - .form-actions - = f.submit 'Add email address', class: 'btn btn-create' + = @primary + %span.pull-right + %span.label.label-success Primary Email + - if @primary === current_user.public_email + %span.label.label-info Public Email + - if @primary === current_user.notification_email + %span.label.label-info Notification Email + - @emails.each do |email| + %li + = email.email + %span.pull-right + - if email.email === current_user.public_email + %span.label.label-info Public Email + - if email.email === current_user.notification_email + %span.label.label-info Notification Email + = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-sm btn-remove pull-right' -- GitLab From cee157bd5212643c3caaaf5651eeb836420cc521 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 29 Feb 2016 15:36:56 +0000 Subject: [PATCH 06/14] Password settings page Mobile spacing for other settings pages Closes #13858 --- app/assets/stylesheets/pages/profile.scss | 7 ++- app/views/profiles/applications.html.haml | 2 +- app/views/profiles/emails/index.html.haml | 29 ++++++------ app/views/profiles/passwords/edit.html.haml | 51 ++++++++++----------- 4 files changed, 42 insertions(+), 47 deletions(-) diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index 171cbd6deedf..c507a25468d5 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -17,10 +17,9 @@ display: inline-block; } -.profile-settings-sidebar { - a { - color: $gl-primary; - } +.account-btn-link, +.profile-settings-sidebar a { + color: $gl-primary; } .oauth-buttons { diff --git a/app/views/profiles/applications.html.haml b/app/views/profiles/applications.html.haml index 911ba9f87f0f..d8b866a989c2 100644 --- a/app/views/profiles/applications.html.haml +++ b/app/views/profiles/applications.html.haml @@ -47,7 +47,7 @@ - else .profile-settings-message.text-center You don't have any applications - .oauth-authorized-applications.prepend-top-20 + .oauth-authorized-applications.prepend-top-20.append-bottom-default - if user_oauth_applications? %h5 Authorized applications (#{@authorized_tokens.size}) diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml index a962c4ea2846..e68d9271af9f 100644 --- a/app/views/profiles/emails/index.html.haml +++ b/app/views/profiles/emails/index.html.haml @@ -28,21 +28,22 @@ Your Public Email will be displayed on your public profile. %li All email addresses will be used to identify your commits. - %ul.well-list - %li - = @primary - %span.pull-right - %span.label.label-success Primary Email - - if @primary === current_user.public_email - %span.label.label-info Public Email - - if @primary === current_user.notification_email - %span.label.label-info Notification Email - - @emails.each do |email| + .append-bottom-default + %ul.well-list %li - = email.email + = @primary %span.pull-right - - if email.email === current_user.public_email + %span.label.label-success Primary Email + - if @primary === current_user.public_email %span.label.label-info Public Email - - if email.email === current_user.notification_email + - if @primary === current_user.notification_email %span.label.label-info Notification Email - = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-sm btn-remove pull-right' + - @emails.each do |email| + %li + = email.email + %span.pull-right + - if email.email === current_user.public_email + %span.label.label-info Public Email + - if email.email === current_user.notification_email + %span.label.label-info Notification Email + = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-sm btn-remove pull-right' diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml index ab070c09bebf..76d3f433e4b5 100644 --- a/app/views/profiles/passwords/edit.html.haml +++ b/app/views/profiles/passwords/edit.html.haml @@ -1,20 +1,18 @@ - page_title "Password" - header_title page_title, edit_profile_password_path -.alert.alert-help.prepend-top-default - - if @user.password_automatically_set? - Set your password. - - else - Change your password or recover your current one. - -.update-password.prepend-top-default - = form_for @user, url: profile_password_path, method: :put, html: { class: 'form-horizontal' } do |f| - %div - %p.slead - - unless @user.password_automatically_set? - You must provide current password in order to change it. - %br - After a successful password update, you will be redirected to the login page where you can log in with your new password. +.row.prepend-top-default + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + = page_title + %p + After a successful password update, you will be redirected to the login page where you can log in with your new password. + .col-lg-9 + %p + Change your password + - unless @user.password_automatically_set? + or recover your current one + = form_for @user, url: profile_password_path, method: :put do |f| -if @user.errors.any? .alert.alert-danger %ul @@ -22,19 +20,16 @@ %li= msg - unless @user.password_automatically_set? .form-group - = f.label :current_password, class: 'control-label' - .col-sm-10 - = f.password_field :current_password, required: true, class: 'form-control' - %div - = link_to "Forgot your password?", reset_profile_password_path, method: :put - - .form-group - = f.label :password, 'New password', class: 'control-label' - .col-sm-10 + = f.label :current_password, class: 'label-light' + = f.password_field :current_password, required: true, class: 'form-control' + %p.help-block + You must provide your current password in order to change it. + .form-group + = f.label :password, 'New password', class: 'label-light' = f.password_field :password, required: true, class: 'form-control' - .form-group - = f.label :password_confirmation, class: 'control-label' - .col-sm-10 + .form-group + = f.label :password_confirmation, class: 'label-light' = f.password_field :password_confirmation, required: true, class: 'form-control' - .form-actions - = f.submit 'Save password', class: "btn btn-create" + .prepend-top-default.append-bottom-default + = f.submit 'Save password', class: "btn btn-create append-right-10" + = link_to "I forgot my password", reset_profile_password_path, method: :put, class: "account-btn-link" -- GitLab From 1aa2ba48d039691673febfe1352b4f71636c3552 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 29 Feb 2016 16:01:11 +0000 Subject: [PATCH 07/14] Notifications settings UI Closes #13859 --- .../stylesheets/pages/notifications.scss | 18 +-- .../notifications/_settings.html.haml | 4 +- .../profiles/notifications/show.html.haml | 120 +++++++++--------- 3 files changed, 72 insertions(+), 70 deletions(-) diff --git a/app/assets/stylesheets/pages/notifications.scss b/app/assets/stylesheets/pages/notifications.scss index cc273f552227..94fbbef3c778 100644 --- a/app/assets/stylesheets/pages/notifications.scss +++ b/app/assets/stylesheets/pages/notifications.scss @@ -1,16 +1,18 @@ -.global-notifications-form .level-title { - font-size: 15px; - color: #333; - font-weight: bold; +.notification-list-item { + line-height: 34px; } -.notification-icon-holder { - width: 20px; - float: left; +.notification { + position: relative; + top: 1px; + + > .fa { + font-size: 18px; + } } .ns-part { - color: $gl-primary; + color: $gl-text-green; } .ns-watch { diff --git a/app/views/profiles/notifications/_settings.html.haml b/app/views/profiles/notifications/_settings.html.haml index 742c5c4b68de..d0d044136f6f 100644 --- a/app/views/profiles/notifications/_settings.html.haml +++ b/app/views/profiles/notifications/_settings.html.haml @@ -1,5 +1,5 @@ -%li - %span.notification.fa.fa-holder +%li.notification-list-item + %span.notification.fa.fa-holder.append-right-5 - if notification.global? = notification_icon(@notification) - else diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml index d5f61d9f0ca7..de80abd7f4da 100644 --- a/app/views/profiles/notifications/show.html.haml +++ b/app/views/profiles/notifications/show.html.haml @@ -1,8 +1,7 @@ - page_title "Notifications" - header_title page_title, profile_notifications_path -.prepend-top-default -= form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications form-horizontal global-notifications-form' } do |f| += form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications prepend-top-default' } do |f| -if @user.errors.any? %div.alert.alert-danger %ul @@ -10,65 +9,66 @@ %li= msg = hidden_field_tag :notification_type, 'global' + .row + .col-lg-3.profile-settings-sidebar + %h4 + = page_title + %p + You can specify notification level per group or per project. + %p + By default, all projects and groups will use the global notifications setting. + .col-lg-9 + %h5 + Global notification settings + .form-group + = f.label :notification_email, class: "label-light" + = f.select :notification_email, @user.all_emails, { include_blank: false }, class: "select2" + .form-group + = f.label :notification_level, class: 'label-light' + .radio + = f.label :notification_level, value: Notification::N_DISABLED do + = f.radio_button :notification_level, Notification::N_DISABLED + .level-title + Disabled + %p You will not get any notifications via email - .form-group - = f.label :notification_email, class: "control-label" - .col-sm-10 - = f.select :notification_email, @user.all_emails, { include_blank: false }, class: "form-control" + .radio + = f.label :notification_level, value: Notification::N_MENTION do + = f.radio_button :notification_level, Notification::N_MENTION + .level-title + On Mention + %p You will receive notifications only for comments in which you were @mentioned - .form-group - = f.label :notification_level, class: 'control-label' - .col-sm-10 - .radio - = f.label :notification_level, value: Notification::N_DISABLED do - = f.radio_button :notification_level, Notification::N_DISABLED - .level-title - Disabled - %p You will not get any notifications via email + .radio + = f.label :notification_level, value: Notification::N_PARTICIPATING do + = f.radio_button :notification_level, Notification::N_PARTICIPATING + .level-title + Participating + %p You will only receive notifications from related resources (e.g. from your commits or assigned issues) - .radio - = f.label :notification_level, value: Notification::N_MENTION do - = f.radio_button :notification_level, Notification::N_MENTION - .level-title - On Mention - %p You will receive notifications only for comments in which you were @mentioned + .radio + = f.label :notification_level, value: Notification::N_WATCH do + = f.radio_button :notification_level, Notification::N_WATCH + .level-title + Watch + %p You will receive notifications for any activity - .radio - = f.label :notification_level, value: Notification::N_PARTICIPATING do - = f.radio_button :notification_level, Notification::N_PARTICIPATING - .level-title - Participating - %p You will only receive notifications from related resources (e.g. from your commits or assigned issues) - - .radio - = f.label :notification_level, value: Notification::N_WATCH do - = f.radio_button :notification_level, Notification::N_WATCH - .level-title - Watch - %p You will receive notifications for any activity - - .gray-content-block - = f.submit 'Save changes', class: "btn btn-create" - -.row.all-notifications.prepend-top-default - .col-md-6 - %p - You can also specify notification level per group or per project. - %br - By default, all projects and groups will use the notification level set above. - %h4 Groups: - %ul.bordered-list - - @group_members.each do |group_member| - - notification = Notification.new(group_member) - = render 'settings', type: 'group', membership: group_member, notification: notification - - .col-md-6 - %p - To specify the notification level per project of a group you belong to, - %br - you need to be a member of the project itself, not only its group. - %h4 Projects: - %ul.bordered-list - - @project_members.each do |project_member| - - notification = Notification.new(project_member) - = render 'settings', type: 'project', membership: project_member, notification: notification + .prepend-top-default + = f.submit 'Update settings', class: "btn btn-create" + %hr + %h5 + Groups (#{@group_members.count}) + %div + %ul.bordered-list + - @group_members.each do |group_member| + - notification = Notification.new(group_member) + = render 'settings', type: 'group', membership: group_member, notification: notification + %h5 + Projects (#{@project_members.count}) + %p.account-well + To specify the notification level per project of a group you belong to, you need to be a member of the project itself, not only its group. + .append-bottom-default + %ul.bordered-list + - @project_members.each do |project_member| + - notification = Notification.new(project_member) + = render 'settings', type: 'project', membership: project_member, notification: notification -- GitLab From caa3dc4e4145368fedf9fe159da4a9080a28d1fe Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 29 Feb 2016 17:19:00 +0000 Subject: [PATCH 08/14] SSH keys settings Closes #13860 --- app/assets/stylesheets/framework/lists.scss | 1 + app/assets/stylesheets/pages/profile.scss | 10 +++++ .../oauth/applications_controller.rb | 2 +- app/controllers/profiles/keys_controller.rb | 5 ++- app/views/profiles/keys/_form.html.haml | 14 +++---- app/views/profiles/keys/_key.html.haml | 25 +++++++------ .../profiles/keys/_key_details.html.haml | 2 +- app/views/profiles/keys/_key_table.html.haml | 20 ++-------- app/views/profiles/keys/index.html.haml | 37 +++++++++++++------ 9 files changed, 65 insertions(+), 51 deletions(-) diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index b6a781f79de5..bfec0911b3ca 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -3,6 +3,7 @@ * */ .well-list { + position: relative; margin: 0; padding: 0; list-style: none; diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index c507a25468d5..04c4a4158697 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -204,3 +204,13 @@ display: inline-block; } } + +.key-icon { + color: #8F8F8F; + font-size: 18px; + line-height: 42px; +} + +.key-created-at { + line-height: 42px; +} diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb index d983ae0b8c6c..a7f03860fdf7 100644 --- a/app/controllers/oauth/applications_controller.rb +++ b/app/controllers/oauth/applications_controller.rb @@ -24,7 +24,7 @@ def create flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create]) redirect_to oauth_application_url(@application) else - redirect_to applications_profile_url, flash: {application: @application} + redirect_to applications_profile_path, flash: {application: @application} end end diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb index f3224148fda5..6815cb69b683 100644 --- a/app/controllers/profiles/keys_controller.rb +++ b/app/controllers/profiles/keys_controller.rb @@ -3,6 +3,7 @@ class Profiles::KeysController < Profiles::ApplicationController def index @keys = current_user.keys + @key = flash[:key] || Key.new end def show @@ -10,7 +11,7 @@ def show end def new - @key = current_user.keys.new + redirect_to profile_keys_path end def create @@ -19,7 +20,7 @@ def create if @key.save redirect_to profile_key_path(@key) else - render 'new' + redirect_to profile_keys_path, flash: {key: @key} end end diff --git a/app/views/profiles/keys/_form.html.haml b/app/views/profiles/keys/_form.html.haml index 2a8800de60e7..4d78215ed3c3 100644 --- a/app/views/profiles/keys/_form.html.haml +++ b/app/views/profiles/keys/_form.html.haml @@ -1,5 +1,5 @@ %div - = form_for [:profile, @key], html: { class: 'form-horizontal js-requires-input' } do |f| + = form_for [:profile, @key], html: { class: 'js-requires-input' } do |f| - if @key.errors.any? .alert.alert-danger %ul @@ -7,13 +7,11 @@ %li= msg .form-group - = f.label :key, class: 'control-label' - .col-sm-10 - = f.text_area :key, class: "form-control", rows: 8, autofocus: true, required: true + = f.label :key, class: 'label-light' + = f.text_area :key, class: "form-control", rows: 8, required: true .form-group - = f.label :title, class: 'control-label' - .col-sm-10= f.text_field :title, class: "form-control", required: true + = f.label :title, class: 'label-light' + = f.text_field :title, class: "form-control", required: true - .form-actions + .prepend-top-default = f.submit 'Add key', class: "btn btn-create" - = link_to "Cancel", profile_keys_path, class: "btn btn-cancel" diff --git a/app/views/profiles/keys/_key.html.haml b/app/views/profiles/keys/_key.html.haml index 9bbccbc45ea5..08a11fad001b 100644 --- a/app/views/profiles/keys/_key.html.haml +++ b/app/views/profiles/keys/_key.html.haml @@ -1,11 +1,14 @@ -%tr - %td - = link_to path_to_key(key, is_admin) do - %strong= key.title - %td - %code.key-fingerprint= key.fingerprint - %td - %span.cgray - added #{time_ago_with_tooltip(key.created_at)} - %td - = link_to 'Remove', path_to_key(key, is_admin), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-sm btn-remove delete-key pull-right" +%li.key-list-item + .pull-left.append-right-10 + = icon 'key', class: "key-icon" + .pull-left + = link_to path_to_key(key, is_admin), class: "title" do + = key.title + .description + = key.fingerprint + .pull-right + %span.key-created-at + created #{time_ago_with_tooltip(key.created_at)} ago + = link_to path_to_key(key, is_admin), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-transparent prepend-left-10" do + %span.sr-only Remove + = icon('trash') diff --git a/app/views/profiles/keys/_key_details.html.haml b/app/views/profiles/keys/_key_details.html.haml index 3bd1f1af1627..dd7615400dc7 100644 --- a/app/views/profiles/keys/_key_details.html.haml +++ b/app/views/profiles/keys/_key_details.html.haml @@ -1,5 +1,5 @@ - is_admin = defined?(admin) ? true : false -.row +.row.prepend-top-default .col-md-4 .panel.panel-default .panel-heading diff --git a/app/views/profiles/keys/_key_table.html.haml b/app/views/profiles/keys/_key_table.html.haml index 8c9d546af4c3..233d79d94670 100644 --- a/app/views/profiles/keys/_key_table.html.haml +++ b/app/views/profiles/keys/_key_table.html.haml @@ -1,19 +1,5 @@ - is_admin = defined?(admin) ? true : false - if @keys.any? - .table-holder - %table.table - %thead.panel-heading - %tr - %th Title - %th Fingerprint - %th Added at - %th - %tbody - - @keys.each do |key| - = render 'profiles/keys/key', key: key, is_admin: is_admin -- else - .nothing-here-block - - if is_admin - User has no ssh keys - - else - There are no SSH keys with access to your account. + %ul.well-list + - @keys.each do |key| + = render 'profiles/keys/key', key: key, is_admin: is_admin diff --git a/app/views/profiles/keys/index.html.haml b/app/views/profiles/keys/index.html.haml index c9a6a93f5453..c6f0033a6896 100644 --- a/app/views/profiles/keys/index.html.haml +++ b/app/views/profiles/keys/index.html.haml @@ -1,14 +1,29 @@ - page_title "SSH Keys" - header_title page_title, profile_keys_path +- is_admin = defined?(admin) ? true : false -.top-area - .nav-text - Before you can add an SSH key you need to - = link_to "generate it.", help_page_path("ssh", "README") - .nav-controls - = link_to new_profile_key_path, class: "btn btn-new" do - = icon('plus') - Add SSH Key - -.prepend-top-default -= render 'key_table' +.row.prepend-top-default + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + = page_title + %p + SSH keys allow you to establish a secure connection between your computer and GitLab. + .col-lg-9 + %h5.prepend-top-0 + Add an SSH key + %p + Before you can add an SSH key you need to + = link_to "generate it.", help_page_path("ssh", "README") + = render 'form' + %hr + %h5 + Your SSH keys (#{@keys.count}) + %div.append-bottom-default + - if @keys.any? + = render 'key_table' + - else + %p.profile-settings-message.text-center + - if is_admin + User has no ssh keys + - else + There are no SSH keys with access to your account. -- GitLab From 5b1931996f61bebff379e4fa597099bdd1e08ca5 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 29 Feb 2016 17:35:14 +0000 Subject: [PATCH 09/14] Updated tests --- .../doorkeeper/applications/_form.html.haml | 2 +- app/views/profiles/accounts/show.html.haml | 2 +- app/views/profiles/passwords/edit.html.haml | 2 +- features/profile/profile.feature | 3 +-- features/steps/profile/profile.rb | 20 ++++++++----------- 5 files changed, 12 insertions(+), 17 deletions(-) diff --git a/app/views/doorkeeper/applications/_form.html.haml b/app/views/doorkeeper/applications/_form.html.haml index 0df8362d4ad5..906b0676150c 100644 --- a/app/views/doorkeeper/applications/_form.html.haml +++ b/app/views/doorkeeper/applications/_form.html.haml @@ -22,4 +22,4 @@ for local tests .prepend-top-default - = f.submit 'Add application', class: "btn btn-create" + = f.submit 'Save application', class: "btn btn-create" diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index be3ae942e7ff..a412757250d5 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -12,7 +12,7 @@ %p Your private token is used to access application resources without authentication. .col-lg-9 - = form_for @user, url: reset_private_token_profile_path, method: :put do |f| + = form_for @user, url: reset_private_token_profile_path, method: :put, html: {class: "update-token"} do |f| %p.cgray - if current_user.private_token = label_tag "token", "Private token", class: "label-light" diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml index 76d3f433e4b5..89aad5202fe7 100644 --- a/app/views/profiles/passwords/edit.html.haml +++ b/app/views/profiles/passwords/edit.html.haml @@ -12,7 +12,7 @@ Change your password - unless @user.password_automatically_set? or recover your current one - = form_for @user, url: profile_password_path, method: :put do |f| + = form_for @user, url: profile_password_path, method: :put, html: {class: "update-password"} do |f| -if @user.errors.any? .alert.alert-danger %ul diff --git a/features/profile/profile.feature b/features/profile/profile.feature index 168d9d30b508..447dd92a458b 100644 --- a/features/profile/profile.feature +++ b/features/profile/profile.feature @@ -76,8 +76,7 @@ Feature: Profile Scenario: I can manage application Given I visit profile applications page - Then I click on new application button - And I should see application form + Then I should see application form Then I fill application form out and submit And I see application Then I click edit diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb index 7895f643d0c3..b7d0a17b98e8 100644 --- a/features/steps/profile/profile.rb +++ b/features/steps/profile/profile.rb @@ -13,7 +13,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps fill_in 'user_website_url', with: 'testurl' fill_in 'user_location', with: 'Ukraine' fill_in 'user_bio', with: 'I <3 GitLab' - click_button 'Save changes' + click_button 'Update profile settings' @user.reload end @@ -64,7 +64,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps page.within '.update-password' do fill_in "user_password", with: "22233344" fill_in "user_password_confirmation", with: "22233344" - click_button "Save" + click_button "Save password" end end @@ -73,7 +73,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps fill_in "user_current_password", with: "12345678" fill_in "user_password", with: "22233344" fill_in "user_password_confirmation", with: "22233344" - click_button "Save" + click_button "Save password" end end @@ -82,7 +82,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps fill_in "user_current_password", with: "12345678" fill_in "user_password", with: "password" fill_in "user_password_confirmation", with: "confirmation" - click_button "Save" + click_button "Save password" end end @@ -180,18 +180,14 @@ class Spinach::Features::Profile < Spinach::FeatureSteps end end - step 'I click on new application button' do - click_on 'New Application' - end - step 'I should see application form' do - expect(page).to have_content "New Application" + expect(page).to have_content "Add new application" end step 'I fill application form out and submit' do fill_in :doorkeeper_application_name, with: 'test' fill_in :doorkeeper_application_redirect_uri, with: 'https://test.com' - click_on "Submit" + click_on "Save application" end step 'I see application' do @@ -211,7 +207,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps step 'I change name of application and submit' do expect(page).to have_content "Edit application" fill_in :doorkeeper_application_name, with: 'test_changed' - click_on "Submit" + click_on "Save application" end step 'I see that application was changed' do @@ -237,7 +233,7 @@ def attach_avatar page.find('#user_avatar_crop_y', visible: false).set('0') page.find('#user_avatar_crop_size', visible: false).set('256') - click_button "Save changes" + click_button "Update profile settings" @user.reload end -- GitLab From 86e0f10d42cfb2a40959d8e9ff7ebd0c06496299 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 1 Mar 2016 08:45:28 +0000 Subject: [PATCH 10/14] Fixed ssh key tests --- features/profile/ssh_keys.feature | 2 +- features/steps/profile/ssh_keys.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/features/profile/ssh_keys.feature b/features/profile/ssh_keys.feature index 581503fc5f9d..b0d5b7489165 100644 --- a/features/profile/ssh_keys.feature +++ b/features/profile/ssh_keys.feature @@ -9,7 +9,7 @@ Feature: Profile SSH Keys Then I should see my ssh keys Scenario: Add new ssh key - Given I click link "Add new" + Given I should see new ssh key form And I submit new ssh key "Laptop" Then I should see new ssh key "Laptop" diff --git a/features/steps/profile/ssh_keys.rb b/features/steps/profile/ssh_keys.rb index c7f879d247d6..a400488a5326 100644 --- a/features/steps/profile/ssh_keys.rb +++ b/features/steps/profile/ssh_keys.rb @@ -7,8 +7,8 @@ class Spinach::Features::ProfileSshKeys < Spinach::FeatureSteps end end - step 'I click link "Add new"' do - click_link "Add SSH Key" + step 'I should see new ssh key form' do + expect(page).to have_content("Add an SSH key") end step 'I submit new ssh key "Laptop"' do -- GitLab From 08a1de47e6fd4e499621ab2c58515102a8ecb435 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 1 Mar 2016 08:59:49 +0000 Subject: [PATCH 11/14] Preferences view Closes #13861 --- app/views/profiles/preferences/show.html.haml | 98 +++++++++---------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml index 1a53b4393e4d..01fc79e546af 100644 --- a/app/views/profiles/preferences/show.html.haml +++ b/app/views/profiles/preferences/show.html.haml @@ -1,56 +1,56 @@ - page_title 'Preferences' - header_title page_title, profile_preferences_path -.alert.alert-help.prepend-top-default - These settings allow you to customize the appearance and behavior of the site. - They are saved with your account and will persist to any device you use to - access the site. - -= form_for @user, url: profile_preferences_path, remote: true, method: :put, html: {class: 'js-preferences-form form-horizontal'} do |f| - .panel.panel-default.application-theme - .panel-heading += form_for @user, url: profile_preferences_path, remote: true, method: :put, html: {class: 'row prepend-top-default js-preferences-form'} do |f| + .col-lg-3.profile-settings-sidebar + %h3.prepend-top-0 Application theme - .panel-body - - Gitlab::Themes.each do |theme| - = label_tag do - .preview{class: theme.css_class} - = f.radio_button :theme_id, theme.id - = theme.name - - .panel.panel-default.syntax-theme - .panel-heading + %p + This setting allows you to customize the appearance of the site, ex. sidebar. + .col-lg-9.application-theme + - Gitlab::Themes.each do |theme| + = label_tag do + .preview{class: theme.css_class} + = f.radio_button :theme_id, theme.id + = theme.name + .col-sm-12 + %hr + .col-lg-3.profile-settings-sidebar + %h3.prepend-top-0 Syntax highlighting theme - .panel-body - - Gitlab::ColorSchemes.each do |scheme| - = label_tag do - .preview= image_tag "#{scheme.css_class}-scheme-preview.png" - = f.radio_button :color_scheme_id, scheme.id - = scheme.name - - .panel.panel-default - .panel-heading + %p + This setting allow you to customize the appearance of the syntax. + .col-lg-9.syntax-theme + - Gitlab::ColorSchemes.each do |scheme| + = label_tag do + .preview= image_tag "#{scheme.css_class}-scheme-preview.png" + = f.radio_button :color_scheme_id, scheme.id + = scheme.name + .col-sm-12 + %hr + .col-lg-3.profile-settings-sidebar + %h3.prepend-top-0 Behavior - .panel-body - .form-group - = f.label :layout, class: 'control-label' do - Layout width - .col-sm-10 - = f.select :layout, layout_choices, {}, class: 'form-control' - .help-block - Choose between fixed (max. 1200px) and fluid (100%) application layout. - .form-group - = f.label :dashboard, class: 'control-label' do - Default Dashboard - = link_to('(?)', help_page_path('profile', 'preferences') + '#default-dashboard', target: '_blank') - .col-sm-10 - = f.select :dashboard, dashboard_choices, {}, class: 'form-control' - .form-group - = f.label :project_view, class: 'control-label' do - Project view - = link_to('(?)', help_page_path('profile', 'preferences') + '#default-project-view', target: '_blank') - .col-sm-10 - = f.select :project_view, project_view_choices, {}, class: 'form-control' - .help-block - Choose what content you want to see on a project's home page. - .panel-footer + %p + This setting allows you to customize the behavior of the system layout and default views. + .col-lg-9 + .form-group + = f.label :layout, class: 'label-light' do + Layout width + = f.select :layout, layout_choices, {}, class: 'form-control' + .help-block + Choose between fixed (max. 1200px) and fluid (100%) application layout. + .form-group + = f.label :dashboard, class: 'label-light' do + Default Dashboard + = link_to('(?)', help_page_path('profile', 'preferences') + '#default-dashboard', target: '_blank') + = f.select :dashboard, dashboard_choices, {}, class: 'form-control' + .form-group + = f.label :project_view, class: 'label-light' do + Project view + = link_to('(?)', help_page_path('profile', 'preferences') + '#default-project-view', target: '_blank') + = f.select :project_view, project_view_choices, {}, class: 'form-control' + .help-block + Choose what content you want to see on a project's home page. + .form-group = f.submit 'Save changes', class: 'btn btn-save' -- GitLab From fca42c769968aac23432c71944cdac8df4e6afca Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 1 Mar 2016 09:11:46 +0000 Subject: [PATCH 12/14] audit log UI update Closes #13862 --- app/helpers/icons_helper.rb | 11 ++++++++- app/views/profiles/_event_table.html.haml | 28 +++++++++++------------ app/views/profiles/audit_log.html.haml | 13 +++++++---- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index 84c6d0883b0f..ab3ef454e1c2 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -10,6 +10,15 @@ def icon(names, options = {}) options.include?(:base) ? fa_stacked_icon(names, options) : fa_icon(names, options) end + def audit_icon(names, options = {}) + case names + when "standard" + names = "key" + end + + options.include?(:base) ? fa_stacked_icon(names, options) : fa_icon(names, options) + end + def spinner(text = nil, visible = false) css_class = 'loading' css_class << ' hide' unless visible @@ -37,7 +46,7 @@ def visibility_level_icon(level, fw: true) else # Gitlab::VisibilityLevel::PUBLIC 'globe' end - + name << " fw" if fw icon(name) diff --git a/app/views/profiles/_event_table.html.haml b/app/views/profiles/_event_table.html.haml index 58af79716a75..879fc170f923 100644 --- a/app/views/profiles/_event_table.html.haml +++ b/app/views/profiles/_event_table.html.haml @@ -1,17 +1,15 @@ -.table-holder - %table.table#audits - %thead - %tr - %th Action - %th When +%h5.prepend-top-0 + History of authentications + +%ul.well-list + - events.each do |event| + %li + %span.description + = audit_icon(event.details[:with], class: "append-right-5") + Signed in with + = event.details[:with] + authentication + %span.pull-right + #{time_ago_in_words event.created_at} ago - %tbody - - events.each do |event| - %tr - %td - %span - Signed in with - %b= event.details[:with] - authentication - %td #{time_ago_in_words event.created_at} ago = paginate events, theme: "gitlab" diff --git a/app/views/profiles/audit_log.html.haml b/app/views/profiles/audit_log.html.haml index 8f45f41cfe3c..f630c03e5f6f 100644 --- a/app/views/profiles/audit_log.html.haml +++ b/app/views/profiles/audit_log.html.haml @@ -1,8 +1,11 @@ - page_title "Audit Log" - header_title page_title, audit_log_profile_path -.alert.alert-help.prepend-top-default - History of authentications - -.prepend-top-default -= render 'event_table', events: @events +.row.prepend-top-default + .col-lg-3.profile-settings-sidebar + %h3.prepend-top-0 + = page_title + %p + This is a security log of important events involving your account. + .col-lg-9 + = render 'event_table', events: @events -- GitLab From 1b9f321e0ab68fe40b80193f2e1e70868c85e756 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 1 Mar 2016 09:21:40 +0000 Subject: [PATCH 13/14] Updated markup --- .../profiles/accounts_controller.rb | 2 +- app/views/profiles/accounts/show.html.haml | 25 ++- app/views/profiles/applications.html.haml | 2 +- app/views/profiles/audit_log.html.haml | 2 +- .../profiles/notifications/show.html.haml | 4 +- app/views/profiles/preferences/show.html.haml | 6 +- app/views/profiles/show.html.haml | 182 +++++++++--------- 7 files changed, 110 insertions(+), 113 deletions(-) diff --git a/app/controllers/profiles/accounts_controller.rb b/app/controllers/profiles/accounts_controller.rb index 669fe05e5c7f..f2fe9de7a135 100644 --- a/app/controllers/profiles/accounts_controller.rb +++ b/app/controllers/profiles/accounts_controller.rb @@ -8,7 +8,7 @@ def show current_user.otp_grace_period_started_at = Time.current end - current_user.save! if current_user.changed? + # current_user.save! if current_user.changed? @user = current_user diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index a412757250d5..ad2219b9d9ce 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -5,7 +5,7 @@ .alert.alert-info Some options are unavailable for LDAP accounts -.row.prepend-top-default +.row.prepend-top-default.append-bottom-default .col-lg-3.profile-settings-sidebar %h4.prepend-top-0 Private Token @@ -26,8 +26,8 @@ = f.submit 'Reset private token', data: { confirm: "Are you sure?" }, class: "btn btn-default" - else = f.submit 'Generate', class: "btn btn-default" -%hr -.row.prepend-top-default + .col-sm-12 + %hr .col-lg-3.profile-settings-sidebar %h4.prepend-top-0 Two-factor Authentication @@ -63,9 +63,9 @@ = text_field_tag :pin_code, nil, class: "form-control", required: true .prepend-top-default = submit_tag 'Enable two-factor authentication', class: 'btn btn-success' -%hr -- if button_based_providers.any? - .row.prepend-top-default + .col-sm-12 + %hr + - if button_based_providers.any? .col-lg-3.profile-settings-sidebar %h4.prepend-top-0 Social sign-in @@ -85,9 +85,9 @@ - else = link_to user_omniauth_authorize_path(provider), method: :post, class: "provider-btn #{'not-active' if !auth_active?(provider)}", "data-no-turbolink" => "true" do Connect - %hr -- if current_user.can_change_username? - .row.prepend-top-default + .col-sm-12 + %hr + - if current_user.can_change_username? .col-lg-3.profile-settings-sidebar %h4.prepend-top-0.change-username-title Change username @@ -108,10 +108,10 @@ = f.button class: "btn btn-warning", type: "submit" do = icon "spinner spin", class: "hidden loading-username" Update username - %hr + .col-sm-12 + %hr -- if signup_enabled? - .row.prepend-top-default + - if signup_enabled? .col-lg-3.profile-settings-sidebar %h4.prepend-top-0.remove-account-title Remove account @@ -132,4 +132,3 @@ %strong #{@user.solo_owned_groups.map(&:name).join(', ')} %p You must transfer ownership or delete these groups before you can delete your account. -.append-bottom-default diff --git a/app/views/profiles/applications.html.haml b/app/views/profiles/applications.html.haml index d8b866a989c2..7b914d4179b7 100644 --- a/app/views/profiles/applications.html.haml +++ b/app/views/profiles/applications.html.haml @@ -1,5 +1,5 @@ - page_title "Applications" -- header_title page_title, applications_profile_path +- header_title "Application Settings", applications_profile_path .row.prepend-top-default .col-lg-3.profile-settings-sidebar diff --git a/app/views/profiles/audit_log.html.haml b/app/views/profiles/audit_log.html.haml index f630c03e5f6f..b535418e38b8 100644 --- a/app/views/profiles/audit_log.html.haml +++ b/app/views/profiles/audit_log.html.haml @@ -3,7 +3,7 @@ .row.prepend-top-default .col-lg-3.profile-settings-sidebar - %h3.prepend-top-0 + %h4.prepend-top-0 = page_title %p This is a security log of important events involving your account. diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml index de80abd7f4da..5b2d0a91385c 100644 --- a/app/views/profiles/notifications/show.html.haml +++ b/app/views/profiles/notifications/show.html.haml @@ -11,14 +11,14 @@ = hidden_field_tag :notification_type, 'global' .row .col-lg-3.profile-settings-sidebar - %h4 + %h4.prepend-top-0 = page_title %p You can specify notification level per group or per project. %p By default, all projects and groups will use the global notifications setting. .col-lg-9 - %h5 + %h5.prepend-top-0 Global notification settings .form-group = f.label :notification_email, class: "label-light" diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml index 01fc79e546af..f80211669fb4 100644 --- a/app/views/profiles/preferences/show.html.haml +++ b/app/views/profiles/preferences/show.html.haml @@ -3,7 +3,7 @@ = form_for @user, url: profile_preferences_path, remote: true, method: :put, html: {class: 'row prepend-top-default js-preferences-form'} do |f| .col-lg-3.profile-settings-sidebar - %h3.prepend-top-0 + %h4.prepend-top-0 Application theme %p This setting allows you to customize the appearance of the site, ex. sidebar. @@ -16,7 +16,7 @@ .col-sm-12 %hr .col-lg-3.profile-settings-sidebar - %h3.prepend-top-0 + %h4.prepend-top-0 Syntax highlighting theme %p This setting allow you to customize the appearance of the syntax. @@ -29,7 +29,7 @@ .col-sm-12 %hr .col-lg-3.profile-settings-sidebar - %h3.prepend-top-0 + %h4.prepend-top-0 Behavior %p This setting allows you to customize the behavior of the system layout and default views. diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 3d1ba49491cf..fd6f24cad788 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -1,102 +1,100 @@ -= form_for @user, url: profile_path, method: :put, html: { multipart: true, class: "edit-user prepend-top-default" }, authenticity_token: true do |f| +-if @user.errors.any? + .col-sm-12.alert.alert-danger + %ul + - @user.errors.full_messages.each do |msg| + %li= msg += form_for @user, url: profile_path, method: :put, html: { multipart: true, class: "row edit-user prepend-top-default" }, authenticity_token: true do |f| = f.hidden_field :avatar_crop_x = f.hidden_field :avatar_crop_y = f.hidden_field :avatar_crop_size - -if @user.errors.any? - %div.alert.alert-danger - %ul - - @user.errors.full_messages.each do |msg| - %li= msg - .row - .col-lg-3.profile-settings-sidebar - %h4.prepend-top-0 - Public Avatar - %p - - if @user.avatar? - You can change your avatar here - - if Gitlab.config.gravatar.enabled - or remove the current avatar to revert to #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host} - - else - You can upload an avatar here - - if Gitlab.config.gravatar.enabled - or change it at #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host} - .col-lg-9 - .clearfix.avatar-image.append-bottom-default - = image_tag avatar_icon(@user, 160), alt: '', class: 'avatar s160' - %h5.prepend-top-0 - Upload new avatar - .prepend-top-5.append-bottom-10 - %a.btn.js-choose-user-avatar-button - Browse file... - %span.avatar-file-name.prepend-left-default.js-avatar-filename No file chosen - = f.file_field :avatar, class: "js-user-avatar-input hidden" - .help-block - The maximum file size allowed is 200KB. + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + Public Avatar + %p - if @user.avatar? - %hr - = link_to 'Remove avatar', profile_avatar_path, data: { confirm: "Avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-gray" - %hr - .row - .col-lg-3.profile-settings-sidebar - %h4.prepend-top-0 - Main settings - %p - This information will appear on your profile. - - if current_user.ldap_user? - Some options are unavailable for LDAP accounts - .col-lg-9 - .form-group - = f.label :name, class: "label-light" - = f.text_field :name, class: "form-control", required: true - %span.help-block Enter your name, so people you know can recognize you. + You can change your avatar here + - if Gitlab.config.gravatar.enabled + or remove the current avatar to revert to #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host} + - else + You can upload an avatar here + - if Gitlab.config.gravatar.enabled + or change it at #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host} + .col-lg-9 + .clearfix.avatar-image.append-bottom-default + = image_tag avatar_icon(@user, 160), alt: '', class: 'avatar s160' + %h5.prepend-top-0 + Upload new avatar + .prepend-top-5.append-bottom-10 + %a.btn.js-choose-user-avatar-button + Browse file... + %span.avatar-file-name.prepend-left-default.js-avatar-filename No file chosen + = f.file_field :avatar, class: "js-user-avatar-input hidden" + .help-block + The maximum file size allowed is 200KB. + - if @user.avatar? + %hr + = link_to 'Remove avatar', profile_avatar_path, data: { confirm: "Avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-gray" + .col-sm-12 + %hr + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + Main settings + %p + This information will appear on your profile. + - if current_user.ldap_user? + Some options are unavailable for LDAP accounts + .col-lg-9 + .form-group + = f.label :name, class: "label-light" + = f.text_field :name, class: "form-control", required: true + %span.help-block Enter your name, so people you know can recognize you. - .form-group - = f.label :email, class: "label-light" - - if @user.ldap_user? && @user.ldap_email? - = f.text_field :email, class: "form-control", required: true, readonly: true - %span.help-block.light - Your email address was automatically set based on the LDAP server. + .form-group + = f.label :email, class: "label-light" + - if @user.ldap_user? && @user.ldap_email? + = f.text_field :email, class: "form-control", required: true, readonly: true + %span.help-block.light + Your email address was automatically set based on the LDAP server. + - else + - if @user.temp_oauth_email? + = f.text_field :email, class: "form-control", required: true, value: nil - else - - if @user.temp_oauth_email? - = f.text_field :email, class: "form-control", required: true, value: nil - - else - = f.text_field :email, class: "form-control", required: true - - if @user.unconfirmed_email.present? - %span.help-block - Please click the link in the confirmation email before continuing. It was sent to - = succeed "." do - %strong #{@user.unconfirmed_email} - %p - = link_to "Resend confirmation e-mail", user_confirmation_path(user: { email: @user.unconfirmed_email }), method: :post + = f.text_field :email, class: "form-control", required: true + - if @user.unconfirmed_email.present? + %span.help-block + Please click the link in the confirmation email before continuing. It was sent to + = succeed "." do + %strong #{@user.unconfirmed_email} + %p + = link_to "Resend confirmation e-mail", user_confirmation_path(user: { email: @user.unconfirmed_email }), method: :post - - else - %span.help-block We also use email for avatar detection if no avatar is uploaded. - .form-group - = f.label :public_email, class: "label-light" - = f.select :public_email, options_for_select(@user.all_emails, selected: @user.public_email), {include_blank: 'Do not show on profile'}, class: "select2" - %span.help-block This email will be displayed on your public profile. - .form-group - = f.label :skype, class: "label-light" - = f.text_field :skype, class: "form-control" - .form-group - = f.label :linkedin, class: "label-light" - = f.text_field :linkedin, class: "form-control" - .form-group - = f.label :twitter, class: "label-light" - = f.text_field :twitter, class: "form-control" - .form-group - = f.label :website_url, 'Website', class: "label-light" - = f.text_field :website_url, class: "form-control" - .form-group - = f.label :location, 'Location', class: "label-light" - = f.text_field :location, class: "form-control" - .form-group - = f.label :bio, class: "label-light" - = f.text_area :bio, rows: 4, class: "form-control", maxlength: 250 - %span.help-block Tell us about yourself in fewer than 250 characters. - .prepend-top-default.append-bottom-default - = f.submit 'Update profile settings', class: "btn btn-success" - = link_to "Cancel", user_path(current_user), class: "btn btn-cancel" + - else + %span.help-block We also use email for avatar detection if no avatar is uploaded. + .form-group + = f.label :public_email, class: "label-light" + = f.select :public_email, options_for_select(@user.all_emails, selected: @user.public_email), {include_blank: 'Do not show on profile'}, class: "select2" + %span.help-block This email will be displayed on your public profile. + .form-group + = f.label :skype, class: "label-light" + = f.text_field :skype, class: "form-control" + .form-group + = f.label :linkedin, class: "label-light" + = f.text_field :linkedin, class: "form-control" + .form-group + = f.label :twitter, class: "label-light" + = f.text_field :twitter, class: "form-control" + .form-group + = f.label :website_url, 'Website', class: "label-light" + = f.text_field :website_url, class: "form-control" + .form-group + = f.label :location, 'Location', class: "label-light" + = f.text_field :location, class: "form-control" + .form-group + = f.label :bio, class: "label-light" + = f.text_area :bio, rows: 4, class: "form-control", maxlength: 250 + %span.help-block Tell us about yourself in fewer than 250 characters. + .prepend-top-default.append-bottom-default + = f.submit 'Update profile settings', class: "btn btn-success" .modal.modal-profile-crop .modal-dialog -- GitLab From 85facbd55f56400cd856153db86661ab701b6a5c Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 1 Mar 2016 11:32:08 +0000 Subject: [PATCH 14/14] Fixed failing tests --- app/controllers/oauth/applications_controller.rb | 2 +- app/controllers/profiles/keys_controller.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb index a7f03860fdf7..a4367b5081af 100644 --- a/app/controllers/oauth/applications_controller.rb +++ b/app/controllers/oauth/applications_controller.rb @@ -24,7 +24,7 @@ def create flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create]) redirect_to oauth_application_url(@application) else - redirect_to applications_profile_path, flash: {application: @application} + redirect_to applications_profile_path, flash: { application: @application } end end diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb index 6815cb69b683..25430e6be2f9 100644 --- a/app/controllers/profiles/keys_controller.rb +++ b/app/controllers/profiles/keys_controller.rb @@ -20,7 +20,7 @@ def create if @key.save redirect_to profile_key_path(@key) else - redirect_to profile_keys_path, flash: {key: @key} + redirect_to profile_keys_path, flash: { key: @key } end end -- GitLab