diff options
author | Sam Rose <samrose3@gmail.com> | 2017-05-08 07:41:58 +0000 |
---|---|---|
committer | Phil Hughes <me@iamphill.com> | 2017-05-08 07:41:58 +0000 |
commit | 1ebd9dad8e4a3ade4fa829d1d5ac6cbc9825bf48 (patch) | |
tree | ea175b4ef388f79d8550a424ac5b46a535555664 /app | |
parent | 1a5e84febeb3f2d63c019981e80c777195c37dd2 (diff) | |
download | gitlab-ce-1ebd9dad8e4a3ade4fa829d1d5ac6cbc9825bf48.tar.gz |
Add confirm delete protected branch modal
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/branches/branches_delete_modal.js | 36 | ||||
-rw-r--r-- | app/assets/javascripts/dispatcher.js | 2 | ||||
-rw-r--r-- | app/assets/stylesheets/framework/lists.scss | 1 | ||||
-rw-r--r-- | app/controllers/projects/branches_controller.rb | 12 | ||||
-rw-r--r-- | app/controllers/projects/tags_controller.rb | 4 | ||||
-rw-r--r-- | app/helpers/branches_helper.rb | 10 | ||||
-rw-r--r-- | app/policies/project_policy.rb | 6 | ||||
-rw-r--r-- | app/services/delete_branch_service.rb | 16 | ||||
-rw-r--r-- | app/views/projects/branches/_branch.html.haml | 35 | ||||
-rw-r--r-- | app/views/projects/branches/_delete_protected_modal.html.haml | 34 | ||||
-rw-r--r-- | app/views/projects/branches/index.html.haml | 2 |
11 files changed, 120 insertions, 38 deletions
diff --git a/app/assets/javascripts/branches/branches_delete_modal.js b/app/assets/javascripts/branches/branches_delete_modal.js new file mode 100644 index 00000000000..af8bcdc1794 --- /dev/null +++ b/app/assets/javascripts/branches/branches_delete_modal.js @@ -0,0 +1,36 @@ +const MODAL_SELECTOR = '#modal-delete-branch'; + +class DeleteModal { + constructor() { + this.$modal = $(MODAL_SELECTOR); + this.$toggleBtns = $(`[data-target="${MODAL_SELECTOR}"]`); + this.$branchName = $('.js-branch-name', this.$modal); + this.$confirmInput = $('.js-delete-branch-input', this.$modal); + this.$deleteBtn = $('.js-delete-branch', this.$modal); + this.bindEvents(); + } + + bindEvents() { + this.$toggleBtns.on('click', this.setModalData.bind(this)); + this.$confirmInput.on('input', this.setDeleteDisabled.bind(this)); + } + + setModalData(e) { + this.branchName = e.currentTarget.dataset.branchName || ''; + this.deletePath = e.currentTarget.dataset.deletePath || ''; + this.updateModal(); + } + + setDeleteDisabled(e) { + this.$deleteBtn.attr('disabled', e.currentTarget.value !== this.branchName); + } + + updateModal() { + this.$branchName.text(this.branchName); + this.$confirmInput.val(''); + this.$deleteBtn.attr('href', this.deletePath); + this.$deleteBtn.attr('disabled', true); + } +} + +export default DeleteModal; diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index d27d89cf91d..bf802056d36 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -38,6 +38,7 @@ import Issue from './issue'; import BindInOut from './behaviors/bind_in_out'; +import DeleteModal from './branches/branches_delete_modal'; import Group from './group'; import GroupName from './group_name'; import GroupsList from './groups_list'; @@ -180,6 +181,7 @@ const ShortcutsBlob = require('./shortcuts_blob'); break; case 'projects:branches:index': gl.AjaxLoadingSpinner.init(); + new DeleteModal(); break; case 'projects:issues:new': case 'projects:issues:edit': diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index c9a25946ffd..d76053fe72a 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -152,6 +152,7 @@ ul.content-list { margin-top: 3px; margin-bottom: 4px; + &.has-tooltip, &:last-child { margin-right: 0; diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index f0f031303d8..59247280559 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -73,13 +73,17 @@ class Projects::BranchesController < Projects::ApplicationController def destroy @branch_name = Addressable::URI.unescape(params[:id]) - status = DeleteBranchService.new(project, current_user).execute(@branch_name) + result = DeleteBranchService.new(project, current_user).execute(@branch_name) + respond_to do |format| format.html do - redirect_to namespace_project_branches_path(@project.namespace, - @project), status: 303 + flash_type = result[:status] == :error ? :alert : :notice + flash[flash_type] = result[:message] + + redirect_to namespace_project_branches_path(@project.namespace, @project), status: 303 end - format.js { render nothing: true, status: status[:return_code] } + + format.js { render nothing: true, status: result[:return_code] } end end diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index e13f0bde315..750c3ec486a 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -48,7 +48,7 @@ class Projects::TagsController < Projects::ApplicationController respond_to do |format| if result[:status] == :success format.html do - redirect_to namespace_project_tags_path(@project.namespace, @project) + redirect_to namespace_project_tags_path(@project.namespace, @project), status: 303 end format.js @@ -57,7 +57,7 @@ class Projects::TagsController < Projects::ApplicationController format.html do redirect_to namespace_project_tags_path(@project.namespace, @project), - alert: @error + alert: @error, status: 303 end format.js do diff --git a/app/helpers/branches_helper.rb b/app/helpers/branches_helper.rb index b7a28b1b4a7..59519c1335b 100644 --- a/app/helpers/branches_helper.rb +++ b/app/helpers/branches_helper.rb @@ -1,14 +1,4 @@ module BranchesHelper - def can_remove_branch?(project, branch_name) - if ProtectedBranch.protected?(project, branch_name) - false - elsif branch_name == project.repository.root_ref - false - else - can?(current_user, :push_code, project) - end - end - def filter_branches_path(options = {}) exist_opts = { search: params[:search], diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index 8f25ac30a22..3959b895f44 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -98,7 +98,7 @@ class ProjectPolicy < BasePolicy end def master_access! - can! :push_code_to_protected_branches + can! :delete_protected_branch can! :update_project_snippet can! :update_environment can! :update_deployment @@ -173,7 +173,7 @@ class ProjectPolicy < BasePolicy def archived_access! cannot! :create_merge_request cannot! :push_code - cannot! :push_code_to_protected_branches + cannot! :delete_protected_branch cannot! :update_merge_request cannot! :admin_merge_request end @@ -211,7 +211,7 @@ class ProjectPolicy < BasePolicy unless repository_enabled cannot! :push_code - cannot! :push_code_to_protected_branches + cannot! :delete_protected_branch cannot! :download_code cannot! :fork_project cannot! :read_commit_status diff --git a/app/services/delete_branch_service.rb b/app/services/delete_branch_service.rb index 38a113caec7..64b3c0118fb 100644 --- a/app/services/delete_branch_service.rb +++ b/app/services/delete_branch_service.rb @@ -3,22 +3,14 @@ class DeleteBranchService < BaseService repository = project.repository branch = repository.find_branch(branch_name) - unless branch - return error('No such branch', 404) - end - - if branch_name == repository.root_ref - return error('Cannot remove HEAD branch', 405) - end - - if ProtectedBranch.protected?(project, branch_name) - return error('Protected branch cant be removed', 405) - end - unless current_user.can?(:push_code, project) return error('You dont have push access to repo', 405) end + unless branch + return error('No such branch', 404) + end + if repository.rm_branch(current_user, branch_name) success('Branch was removed') else diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml index 0f9ef3eded3..8b35a037c55 100644 --- a/app/views/projects/branches/_branch.html.haml +++ b/app/views/projects/branches/_branch.html.haml @@ -30,13 +30,34 @@ = render 'projects/buttons/download', project: @project, ref: branch.name, pipeline: @refs_pipelines[branch.name] - if can?(current_user, :push_code, @project) - = link_to namespace_project_branch_path(@project.namespace, @project, branch.name), - class: "btn btn-remove remove-row js-ajax-loading-spinner #{can_remove_branch?(@project, branch.name) ? '' : 'disabled'}", - method: :delete, - data: { confirm: "Deleting the '#{branch.name}' branch cannot be undone. Are you sure?" }, - remote: true, - "aria-label" => "Delete branch" do - = icon("trash-o") + - if branch.name == @project.repository.root_ref + %button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip disabled", + disabled: true, + title: "The default branch cannot be deleted" } + = icon("trash-o") + - elsif protected_branch?(@project, branch) + - if can?(current_user, :delete_protected_branch, @project) + %button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip", + title: "Delete protected branch", + data: { toggle: "modal", + target: "#modal-delete-branch", + delete_path: namespace_project_branch_path(@project.namespace, @project, branch.name), + branch_name: branch.name } } + = icon("trash-o") + - else + %button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip disabled", + disabled: true, + title: "Only a project master or owner can delete a protected branch" } + = icon("trash-o") + - else + = link_to namespace_project_branch_path(@project.namespace, @project, branch.name), + class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip", + title: "Delete branch", + method: :delete, + data: { confirm: "Deleting the '#{branch.name}' branch cannot be undone. Are you sure?" }, + remote: true, + "aria-label" => "Delete branch" do + = icon("trash-o") - if branch.name != @repository.root_ref .divergence-graph{ title: "#{number_commits_ahead} commits ahead, #{number_commits_behind} commits behind #{@repository.root_ref}" } diff --git a/app/views/projects/branches/_delete_protected_modal.html.haml b/app/views/projects/branches/_delete_protected_modal.html.haml new file mode 100644 index 00000000000..c5888afa54d --- /dev/null +++ b/app/views/projects/branches/_delete_protected_modal.html.haml @@ -0,0 +1,34 @@ +#modal-delete-branch.modal{ tabindex: -1 } + .modal-dialog + .modal-content + .modal-header + %button.close{ data: { dismiss: 'modal' } } × + %h3.page-title + Delete protected branch + = surround "'", "'?" do + %span.js-branch-name>[branch name] + + .modal-body + %p + You’re about to permanently delete the protected branch + = succeed '.' do + %strong.js-branch-name [branch name] + %p + Once you confirm and press + = succeed ',' do + %strong Delete protected branch + it cannot be undone or recovered. + %p + %strong To confirm, type + %kbd.js-branch-name [branch name] + + .form-group + = text_field_tag 'delete_branch_input', '', class: 'form-control js-delete-branch-input' + + .modal-footer + %button.btn{ data: { dismiss: 'modal' } } Cancel + = link_to 'Delete protected branch', '', + class: "btn btn-danger js-delete-branch", + title: 'Delete branch', + method: :delete, + "aria-label" => "Delete" diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml index 91b86280e4c..4bade77a077 100644 --- a/app/views/projects/branches/index.html.haml +++ b/app/views/projects/branches/index.html.haml @@ -37,3 +37,5 @@ = paginate @branches, theme: 'gitlab' - else .nothing-here-block No branches to show + += render 'projects/branches/delete_protected_modal' |