summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG1
-rw-r--r--app/assets/javascripts/application.js.coffee8
-rw-r--r--app/assets/javascripts/merge_request_tabs.js.coffee3
-rw-r--r--app/assets/javascripts/notes.js.coffee73
-rw-r--r--app/assets/javascripts/profile.js.coffee7
-rw-r--r--app/assets/stylesheets/framework/common.scss4
-rw-r--r--app/assets/stylesheets/framework/variables.scss8
-rw-r--r--app/assets/stylesheets/pages/profile.scss52
-rw-r--r--app/views/profiles/accounts/show.html.haml211
-rw-r--r--app/views/profiles/two_factor_auths/new.html.haml78
-rw-r--r--app/views/projects/issues/_discussion.html.haml4
-rw-r--r--app/views/projects/issues/show.html.haml2
-rw-r--r--app/views/projects/merge_requests/_discussion.html.haml4
-rw-r--r--app/views/projects/merge_requests/show/_mr_title.html.haml2
-rw-r--r--app/views/projects/notes/_form.html.haml5
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml2
-rw-r--r--features/steps/profile/profile.rb4
-rw-r--r--features/steps/project/issues/award_emoji.rb2
-rw-r--r--features/steps/project/issues/issues.rb2
-rw-r--r--features/steps/project/merge_requests.rb6
-rw-r--r--features/steps/project/snippets.rb2
-rw-r--r--features/steps/project/source/browse_files.rb2
-rw-r--r--features/steps/shared/diff_note.rb4
-rw-r--r--features/steps/shared/issuable.rb2
-rw-r--r--features/steps/shared/note.rb6
-rw-r--r--lib/ci/gitlab_ci_yaml_processor.rb2
-rw-r--r--spec/features/notes_on_merge_requests_spec.rb6
-rw-r--r--spec/lib/ci/gitlab_ci_yaml_processor_spec.rb39
28 files changed, 338 insertions, 203 deletions
diff --git a/CHANGELOG b/CHANGELOG
index fa634cc20db..57fc61a6e22 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -45,6 +45,7 @@ v 8.5.3
- Sort starred projects on dashboard based on last activity by default
- Show commit message in JIRA mention comment
- Makes issue page and merge request page usable on mobile browsers.
+ - Improved UI for profile settings
v 8.5.2
- Fix sidebar overlapping content when screen width was below 1200px
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 321da10a009..1212e89975b 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -220,17 +220,17 @@ $ ->
.off 'breakpoint:change'
.on 'breakpoint:change', (e, breakpoint) ->
if breakpoint is 'sm' or breakpoint is 'xs'
- $gutterIcon = $('aside .gutter-toggle').find('i')
+ $gutterIcon = $('.js-sidebar-toggle').find('i')
if $gutterIcon.hasClass('fa-angle-double-right')
$gutterIcon.closest('a').trigger('click')
$(document)
- .off 'click', 'aside .gutter-toggle'
- .on 'click', 'aside .gutter-toggle', (e, triggered) ->
+ .off 'click', '.js-sidebar-toggle'
+ .on 'click', '.js-sidebar-toggle', (e, triggered) ->
e.preventDefault()
$this = $(this)
$thisIcon = $this.find 'i'
- $allGutterToggleIcons = $('.gutter-toggle i')
+ $allGutterToggleIcons = $('.js-sidebar-toggle i')
if $thisIcon.hasClass('fa-angle-double-right')
$allGutterToggleIcons
.removeClass('fa-angle-double-right')
diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee
index 58373ba87a5..8322b4c46ad 100644
--- a/app/assets/javascripts/merge_request_tabs.js.coffee
+++ b/app/assets/javascripts/merge_request_tabs.js.coffee
@@ -189,7 +189,7 @@ class @MergeRequestTabs
$('.container-fluid').removeClass('container-limited')
shrinkView: ->
- $gutterIcon = $('.gutter-toggle i')
+ $gutterIcon = $('.js-sidebar-toggle i')
# Wait until listeners are set
setTimeout( ->
@@ -197,4 +197,3 @@ class @MergeRequestTabs
if $gutterIcon.is('.fa-angle-double-right')
$gutterIcon.closest('a').trigger('click',[true])
, 0)
-
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index 863a4edfad7..75d7f52bbb6 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -30,6 +30,9 @@ class @Notes
$(document).on "ajax:success", ".js-main-target-form", @addNote
$(document).on "ajax:success", ".js-discussion-note-form", @addDiscussionNote
+ # catch note ajax errors
+ $(document).on "ajax:error", ".js-main-target-form", @addNoteError
+
# change note in UI after update
$(document).on "ajax:success", "form.edit-note", @updateNote
@@ -51,6 +54,9 @@ class @Notes
$(document).on "ajax:complete", ".js-main-target-form", @reenableTargetFormSubmitButton
$(document).on "ajax:success", ".js-main-target-form", @resetMainTargetForm
+ # reset main target form when clicking discard
+ $(document).on "click", ".js-note-discard", @resetMainTargetForm
+
# update the file name when an attachment is selected
$(document).on "change", ".js-note-attachment-input", @updateFormAttachment
@@ -85,6 +91,7 @@ class @Notes
$(document).off "keyup", ".js-note-text"
$(document).off "click", ".js-note-target-reopen"
$(document).off "click", ".js-note-target-close"
+ $(document).off "click", ".js-note-discard"
$('.note .js-task-list-container').taskList('disable')
$(document).off 'tasklist:changed', '.note .js-task-list-container'
@@ -219,7 +226,7 @@ class @Notes
Resets text and preview.
Resets buttons.
###
- resetMainTargetForm: ->
+ resetMainTargetForm: (e) =>
form = $(".js-main-target-form")
# remove validation errors
@@ -231,6 +238,8 @@ class @Notes
form.find(".js-note-text").data("autosave").reset()
+ @updateTargetButtons(e)
+
reenableTargetFormSubmitButton: ->
form = $(".js-main-target-form")
@@ -274,8 +283,10 @@ class @Notes
form.removeClass "js-new-note-form"
form.find('.div-dropzone').remove()
+ # hide discard button
+ form.find('.js-note-discard').hide()
+
# setup preview buttons
- form.find(".js-md-write-button, .js-md-preview-button").tooltip placement: "left"
previewButton = form.find(".js-md-preview-button")
textarea = form.find(".js-note-text")
@@ -309,6 +320,10 @@ class @Notes
addNote: (xhr, note, status) =>
@renderNote(note)
+ addNoteError: (xhr, note, status) =>
+ flash = new Flash('Your comment could not be submitted! Please check your network connection and try again.', 'alert')
+ flash.pinTo('.md-area')
+
###
Called in response to the new note form being submitted
@@ -469,6 +484,11 @@ class @Notes
form.find("#note_line_code").val dataHolder.data("lineCode")
form.find("#note_noteable_type").val dataHolder.data("noteableType")
form.find("#note_noteable_id").val dataHolder.data("noteableId")
+ form.find('.js-note-discard')
+ .show()
+ .removeClass('js-note-discard')
+ .addClass('js-close-discussion-note-form')
+ .text(form.find('.js-close-discussion-note-form').data('cancel-text'))
@setupNoteForm form
form.find(".js-note-text").focus()
form.addClass "js-discussion-note-form"
@@ -568,21 +588,52 @@ class @Notes
updateCloseButton: (e) =>
textarea = $(e.target)
form = textarea.parents('form')
- form.find('.js-note-target-close').text('Close')
+ closebtn = form.find('.js-note-target-close')
+ closebtn.text(closebtn.data('original-text'))
updateTargetButtons: (e) =>
textarea = $(e.target)
form = textarea.parents('form')
+ reopenbtn = form.find('.js-note-target-reopen')
+ closebtn = form.find('.js-note-target-close')
+ discardbtn = form.find('.js-note-discard')
+
if textarea.val().trim().length > 0
- form.find('.js-note-target-reopen').text('Comment & reopen')
- form.find('.js-note-target-close').text('Comment & close')
- form.find('.js-note-target-reopen').addClass('btn-comment-and-reopen')
- form.find('.js-note-target-close').addClass('btn-comment-and-close')
+ reopentext = reopenbtn.data('alternative-text')
+ closetext = closebtn.data('alternative-text')
+
+ if reopenbtn.text() isnt reopentext
+ reopenbtn.text(reopentext)
+
+ if closebtn.text() isnt closetext
+ closebtn.text(closetext)
+
+ if reopenbtn.is(':not(.btn-comment-and-reopen)')
+ reopenbtn.addClass('btn-comment-and-reopen')
+
+ if closebtn.is(':not(.btn-comment-and-close)')
+ closebtn.addClass('btn-comment-and-close')
+
+ if discardbtn.is(':hidden')
+ discardbtn.show()
else
- form.find('.js-note-target-reopen').text('Reopen')
- form.find('.js-note-target-close').text('Close')
- form.find('.js-note-target-reopen').removeClass('btn-comment-and-reopen')
- form.find('.js-note-target-close').removeClass('btn-comment-and-close')
+ reopentext = reopenbtn.data('original-text')
+ closetext = closebtn.data('original-text')
+
+ if reopenbtn.text() isnt reopentext
+ reopenbtn.text(reopentext)
+
+ if closebtn.text() isnt closetext
+ closebtn.text(closetext)
+
+ if reopenbtn.is(':not(.btn-comment-and-reopen)')
+ reopenbtn.removeClass('btn-comment-and-reopen')
+
+ if closebtn.is(':not(.btn-comment-and-close)')
+ closebtn.removeClass('btn-comment-and-close')
+
+ if discardbtn.is(':visible')
+ discardbtn.hide()
initTaskList: ->
@enableTaskList()
diff --git a/app/assets/javascripts/profile.js.coffee b/app/assets/javascripts/profile.js.coffee
index 9110b732adc..59d44c30bee 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 c98e43ad09f..ff551f151f1 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -12,11 +12,13 @@
.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-5 { margin-right: 5px }
.append-right-10 { margin-right:10px }
+.append-right-default { margin-right: $gl-padding; }
.append-right-20 { margin-right:20px }
+.append-bottom-0 { margin-bottom:0 }
.append-bottom-10 { margin-bottom:10px }
.append-bottom-15 { margin-bottom:15px }
.append-bottom-20 { margin-bottom:20px }
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 6561b3de7c1..835364b2990 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -34,13 +34,15 @@ $error-exclamation-point: #E62958;
$border-radius-default: 3px;
$list-title-color: #333333;
$list-text-color: #555555;
-$profile-settings-link-color: $md-link-color;
$btn-transparent-color: #8F8F8F;
$ssh-key-icon-color: #8F8F8F;
$ssh-key-icon-size: 18px;
+$provider-btn-group-border: #E5E5E5;
+$provider-btn-not-active-color: #4688F1;
+
/*
* Color schema
*/
@@ -70,7 +72,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;
@@ -94,7 +96,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 4826b994e37..248c56e459d 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -1,7 +1,6 @@
-.account-page {
- fieldset {
- margin-bottom: 15px;
- padding-bottom: 15px;
+.profile-avatar-form-option {
+ hr {
+ margin: 10px 0;
}
}
@@ -20,7 +19,7 @@
.account-btn-link,
.profile-settings-sidebar a {
- color: $profile-settings-link-color;
+ color: $md-link-color;
}
.oauth-buttons {
@@ -172,6 +171,47 @@
.profile-settings-content {
a {
- color: $profile-settings-link-color;
+ color: $md-link-color;
+ }
+}
+
+.change-username-title {
+ color: $gl-warning;
+}
+
+.remove-account-title {
+ color: $gl-danger;
+}
+
+.provider-btn-group {
+ display: inline-block;
+ margin-right: 10px;
+ border: 1px solid $provider-btn-group-border;
+ border-radius: 3px;
+
+ &:last-child {
+ margin-right: 0;
+ }
+}
+
+.provider-btn-image {
+ display: inline-block;
+ padding: 5px 10px;
+ border-right: 1px solid $provider-btn-group-border;
+
+ > img {
+ width: 20px;
+ }
+}
+
+.provider-btn {
+ display: inline-block;
+ padding: 5px 10px;
+ margin-left: -3px;
+ line-height: 22px;
+ background-color: $gray-light;
+
+ &.not-active {
+ color: $provider-btn-not-active-color;
}
}
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index 9fa96084f94..6efd119f260 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -5,114 +5,113 @@
.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"
- - else
- = f.submit 'Generate', class: "btn btn-default"
-
- .panel.panel-default
- .panel-heading
+.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, html: {class: "private-token"} 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
- .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',
+ %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'))}.
+ .append-bottom-10
+ = link_to 'Enable two-factor authentication', new_profile_two_factor_auth_path, class: 'btn btn-success'
+ - else
+ = link_to 'Disable Two-factor Authentication', profile_two_factor_auth_path, method: :delete, class: 'btn btn-danger',
data: { confirm: 'Are you sure?' }
- %p.text-success
- %strong
- Two-factor Authentication is enabled
- %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.
-
- - 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
+%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
- .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|
- %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"
+ %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
+ = 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
- - if signup_enabled?
- .panel.panel-danger.remove-account
- .panel-heading
+- if signup_enabled?
+ .row.prepend-top-default
+ .col-lg-3.profile-settings-sidebar
+ %h4.prepend-top-0.remove-account-title
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.
+ .col-lg-9
+ - 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
+ = 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.
+.append-bottom-default
diff --git a/app/views/profiles/two_factor_auths/new.html.haml b/app/views/profiles/two_factor_auths/new.html.haml
index b2830aa0834..5d342ef58e5 100644
--- a/app/views/profiles/two_factor_auths/new.html.haml
+++ b/app/views/profiles/two_factor_auths/new.html.haml
@@ -1,41 +1,41 @@
- page_title 'Two-factor Authentication', 'Account'
-%h2.page-title Two-factor Authentication (2FA)
-%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'))}.
-
-%hr
-
-= form_tag profile_two_factor_auth_path, method: :post, class: 'form-horizontal two-factor-new' do |f|
- - if @error
- .alert.alert-danger
- = @error
- .form-group
- .col-lg-2.col-lg-offset-2
- = raw @qr_code
- .col-lg-7.col-lg-offset-1.manual-instructions
- %h3 Can't scan the code?
-
- %p
- To add the entry manually, provide the following details to the
- application on your phone.
-
- %dl
- %dt Account
- %dd= current_user.email
- %dl
- %dt Key
- %dd= current_user.otp_secret.scan(/.{4}/).join(' ')
- %dl
- %dt Time based
- %dd Yes
- .form-group
- = label_tag :pin_code, nil, class: "control-label"
- .col-lg-10
- = text_field_tag :pin_code, nil, class: "form-control", required: true, autofocus: true
- .form-actions
- = submit_tag 'Submit', class: 'btn btn-success'
- = link_to 'Configure it later', skip_profile_two_factor_auth_path, :method => :patch, class: 'btn btn-cancel' if two_factor_skippable?
+.row.prepend-top-default
+ .col-lg-3
+ %h4.prepend-top-0
+ Two-factor Authentication (2FA)
+ %p
+ Increase your account's security by enabling two-factor authentication (2FA).
+ .col-lg-9
+ %p
+ Status: #{current_user.two_factor_enabled? ? 'enabled' : 'disabled'}
+ %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
+ .account-well
+ %p.prepend-top-0.append-bottom-0
+ Can't scan the code?
+ %p.prepend-top-0.append-bottom-0
+ To add the entry manually, provide the following details to the application on your phone.
+ %p.prepend-top-0.append-bottom-0
+ Account:
+ = current_user.email
+ %p.prepend-top-0.append-bottom-0
+ Key:
+ = current_user.otp_secret.scan(/.{4}/).join(' ')
+ %p.two-factor-new-manual-content
+ Time based: Yes
+ = form_tag profile_two_factor_auth_path, method: :post do |f|
+ - if @error
+ .alert.alert-danger
+ = @error
+ .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'
+ = link_to 'Configure it later', skip_profile_two_factor_auth_path, :method => :patch, class: 'btn btn-cancel' if two_factor_skippable?
diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml
index eb9c225df2f..b151393abab 100644
--- a/app/views/projects/issues/_discussion.html.haml
+++ b/app/views/projects/issues/_discussion.html.haml
@@ -1,7 +1,7 @@
- content_for :note_actions do
- if can?(current_user, :update_issue, @issue)
- = link_to 'Reopen issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-reopen btn-comment js-note-target-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue'
- = link_to 'Close issue', issue_path(@issue, issue: {state_event: :close}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-close btn-comment js-note-target-close #{issue_button_visibility(@issue, true)}", title: 'Close issue'
+ = link_to 'Reopen issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true, format: 'json'), data: {no_turbolink: true, original_text: "Reopen issue", alternative_text: "Comment & reopen issue"}, class: "btn btn-nr btn-grouped btn-reopen btn-comment js-note-target-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue'
+ = link_to 'Close issue', issue_path(@issue, issue: {state_event: :close}, status_only: true, format: 'json'), data: {no_turbolink: true, original_text: "Close issue", alternative_text: "Comment & close issue"}, class: "btn btn-nr btn-grouped btn-close btn-comment js-note-target-close #{issue_button_visibility(@issue, true)}", title: 'Close issue'
#notes
= render 'projects/notes/notes_with_form'
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 617b0437807..f5bb5d998bb 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -18,7 +18,7 @@
%span.hidden-sm.hidden-md.hidden-lg
= icon('circle-o')
- %a.btn.btn-default.pull-right.hidden-sm.hidden-md.hidden-lg.gutter-toggle{ href: "#" }
+ %a.btn.btn-default.pull-right.visible-xs-block.gutter-toggle.js-sidebar-toggle{ href: "#" }
= icon('angle-double-left')
.issue-meta
diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml
index 1c7de94acfd..393998f15b9 100644
--- a/app/views/projects/merge_requests/_discussion.html.haml
+++ b/app/views/projects/merge_requests/_discussion.html.haml
@@ -1,8 +1,8 @@
- content_for :note_actions do
- if can?(current_user, :update_merge_request, @merge_request)
- if @merge_request.open?
- = link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-nr btn-comment btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request"
+ = link_to 'Close merge request', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-nr btn-comment btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request", data: {original_text: "Close merge request", alternative_text: "Comment & close merge request"}
- if @merge_request.closed?
- = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-nr btn-comment btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request"
+ = link_to 'Reopen merge request', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-nr btn-comment btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request", data: {original_text: "Reopen merge request", alternative_text: "Comment & reopen merge request"}
#notes= render "projects/notes/notes_with_form"
diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml
index d24c12251f3..a75c0d96c57 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -4,7 +4,7 @@
= @merge_request.state_human_name
%span.hidden-sm.hidden-md.hidden-lg
= icon(@merge_request.state_icon_name)
- %a.btn.btn-default.pull-right.hidden-sm.hidden-md.hidden-lg.gutter-toggle{ href: "#" }
+ %a.btn.btn-default.pull-right.visible-xs-block.gutter-toggle.js-sidebar-toggle{ href: "#" }
= icon('angle-double-left')
.issue-meta
%strong.identifier
diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml
index 09740d8ea12..f675f092da1 100644
--- a/app/views/projects/notes/_form.html.haml
+++ b/app/views/projects/notes/_form.html.haml
@@ -13,6 +13,7 @@
.error-alert
.note-form-actions.clearfix
- = f.submit 'Add Comment', class: "btn btn-nr btn-create comment-btn btn-grouped js-comment-button"
+ = f.submit 'Comment', class: "btn btn-nr btn-create comment-btn btn-grouped js-comment-button"
= yield(:note_actions)
- %a.btn.btn-nr.btn-cancel.js-close-discussion-note-form Cancel
+ %a.btn.btn-cancel.js-note-discard{role: "button", data: {cancel_text: "Cancel"}}
+ Discard draft
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 36f06377886..9020a1330a3 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -6,7 +6,7 @@
of
= issuables_count(issuable)
%span.pull-right
- %a.gutter-toggle{href: '#'}
+ %a.gutter-toggle.js-sidebar-toggle{href: '#'}
= sidebar_gutter_toggle_icon
.issuable-nav.hide-collapsed.pull-right.btn-group{role: 'group', "aria-label" => '...'}
- if prev_issuable = prev_issuable_for(issuable)
diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb
index 0c60328583a..d9436e9e21a 100644
--- a/features/steps/profile/profile.rb
+++ b/features/steps/profile/profile.rb
@@ -99,9 +99,9 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
end
step 'I reset my token' do
- page.within '.update-token' do
+ page.within '.private-token' do
@old_token = @user.private_token
- click_button "Reset"
+ click_button "Reset private token"
end
end
diff --git a/features/steps/project/issues/award_emoji.rb b/features/steps/project/issues/award_emoji.rb
index 277c63914d1..937fbbd34eb 100644
--- a/features/steps/project/issues/award_emoji.rb
+++ b/features/steps/project/issues/award_emoji.rb
@@ -79,7 +79,7 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps
step 'I leave comment with a single emoji' do
page.within('.js-main-target-form') do
fill_in 'note[note]', with: ':smile:'
- click_button 'Add Comment'
+ click_button 'Comment'
end
end
diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb
index 383ab4e14da..8c31fa890b2 100644
--- a/features/steps/project/issues/issues.rb
+++ b/features/steps/project/issues/issues.rb
@@ -268,7 +268,7 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
step 'I leave a comment with code block' do
page.within(".js-main-target-form") do
fill_in "note[note]", with: "```\nCommand [1]: /usr/local/bin/git , see [text](doc/text)\n```"
- click_button "Add Comment"
+ click_button "Comment"
sleep 0.05
end
end
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index c19b15bc9ed..df4259b9ddf 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -419,7 +419,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
page.within(".js-discussion-note-form") do
fill_in "note_note", with: "Line is correct"
- click_button "Add Comment"
+ click_button "Comment"
end
page.within ".files [id^=diff]:nth-child(2) .note-body > .note-text" do
@@ -432,7 +432,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
page.within(".js-discussion-note-form") do
fill_in "note_note", with: "Line is wrong on here"
- click_button "Add Comment"
+ click_button "Comment"
end
end
@@ -528,7 +528,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
def leave_comment(message)
page.within(".js-discussion-note-form", visible: true) do
fill_in "note_note", with: message
- click_button "Add Comment"
+ click_button "Comment"
end
page.within(".notes_holder", visible: true) do
expect(page).to have_content message
diff --git a/features/steps/project/snippets.rb b/features/steps/project/snippets.rb
index 504654f90dd..786a0cad975 100644
--- a/features/steps/project/snippets.rb
+++ b/features/steps/project/snippets.rb
@@ -77,7 +77,7 @@ class Spinach::Features::ProjectSnippets < Spinach::FeatureSteps
step 'I leave a comment like "Good snippet!"' do
page.within('.js-main-target-form') do
fill_in "note_note", with: "Good snippet!"
- click_button "Add Comment"
+ click_button "Comment"
end
end
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index 51b15791674..243469b8e7d 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -361,7 +361,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end
step 'I can see the new rendered SVG image' do
- expect(find('.file-content')).to have_css('img')
+ expect(page).to have_css('.file-content img')
end
private
diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb
index 06e69441894..906b66a4a63 100644
--- a/features/steps/shared/diff_note.rb
+++ b/features/steps/shared/diff_note.rb
@@ -93,14 +93,14 @@ module SharedDiffNote
page.within("form[id$='#{sample_commit.line_code}']") do
fill_in 'note[note]', with: ':smile:'
- click_button('Add Comment')
+ click_button('Comment')
end
end
end
step 'I submit the diff comment' do
page.within(diff_file_selector) do
- click_button("Add Comment")
+ click_button("Comment")
end
end
diff --git a/features/steps/shared/issuable.rb b/features/steps/shared/issuable.rb
index ae10c6069a9..e59bfbea998 100644
--- a/features/steps/shared/issuable.rb
+++ b/features/steps/shared/issuable.rb
@@ -182,7 +182,7 @@ module SharedIssuable
page.within('.js-main-target-form') do
fill_in 'note[note]', with: "##{issuable.to_reference(project)}"
- click_button 'Add Comment'
+ click_button 'Comment'
end
end
diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb
index 444d6726f99..fb0462d6e04 100644
--- a/features/steps/shared/note.rb
+++ b/features/steps/shared/note.rb
@@ -17,7 +17,7 @@ module SharedNote
step 'I leave a comment like "XML attached"' do
page.within(".js-main-target-form") do
fill_in "note[note]", with: "XML attached"
- click_button "Add Comment"
+ click_button "Comment"
end
end
@@ -30,7 +30,7 @@ module SharedNote
step 'I submit the comment' do
page.within(".js-main-target-form") do
- click_button "Add Comment"
+ click_button "Comment"
end
end
@@ -115,7 +115,7 @@ module SharedNote
step 'I leave a comment with a header containing "Comment with a header"' do
page.within(".js-main-target-form") do
fill_in "note[note]", with: "# Comment with a header"
- click_button "Add Comment"
+ click_button "Comment"
sleep 0.05
end
end
diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb
index 04b58cf1cd3..c89e1b51019 100644
--- a/lib/ci/gitlab_ci_yaml_processor.rb
+++ b/lib/ci/gitlab_ci_yaml_processor.rb
@@ -12,7 +12,7 @@ module Ci
attr_reader :before_script, :image, :services, :variables, :path, :cache
def initialize(config, path = nil)
- @config = YAML.safe_load(config, [Symbol])
+ @config = YAML.safe_load(config, [Symbol], [], true)
@path = path
unless @config.is_a? Hash
diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb
index 1a360cd1ebc..d9a8058efd9 100644
--- a/spec/features/notes_on_merge_requests_spec.rb
+++ b/spec/features/notes_on_merge_requests_spec.rb
@@ -22,7 +22,7 @@ describe 'Comments', feature: true do
it 'should be valid' do
is_expected.to have_css('.js-main-target-form', visible: true, count: 1)
expect(find('.js-main-target-form input[type=submit]').value).
- to eq('Add Comment')
+ to eq('Comment')
page.within('.js-main-target-form') do
expect(page).not_to have_link('Cancel')
end
@@ -49,7 +49,7 @@ describe 'Comments', feature: true do
page.within('.js-main-target-form') do
fill_in 'note[note]', with: 'This is awsome!'
find('.js-md-preview-button').click
- click_button 'Add Comment'
+ click_button 'Comment'
end
end
@@ -202,7 +202,7 @@ describe 'Comments', feature: true do
before do
page.within("tr[id='#{line_code_2}'] + .js-temp-notes-holder") do
fill_in 'note[note]', with: 'Another comment on line 10'
- click_button('Add Comment')
+ click_button('Comment')
end
end
diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
index fe5096989b2..fab6412d29f 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -495,6 +495,45 @@ module Ci
end
end
+ describe "YAML Alias/Anchor" do
+ it "is correctly supported for jobs" do
+ config = <<EOT
+job1: &JOBTMPL
+ script: execute-script-for-job
+
+job2: *JOBTMPL
+EOT
+
+ config_processor = GitlabCiYamlProcessor.new(config)
+
+ expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(2)
+ expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
+ except: nil,
+ stage: "test",
+ stage_idx: 1,
+ name: :job1,
+ only: nil,
+ commands: "\nexecute-script-for-job",
+ tag_list: [],
+ options: {},
+ when: "on_success",
+ allow_failure: false
+ })
+ expect(config_processor.builds_for_stage_and_ref("test", "master").second).to eq({
+ except: nil,
+ stage: "test",
+ stage_idx: 1,
+ name: :job2,
+ only: nil,
+ commands: "\nexecute-script-for-job",
+ tag_list: [],
+ options: {},
+ when: "on_success",
+ allow_failure: false
+ })
+ end
+ end
+
describe "Error handling" do
it "fails to parse YAML" do
expect{GitlabCiYamlProcessor.new("invalid: yaml: test")}.to raise_error(Psych::SyntaxError)