summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJose Ivan Vargas <jvargas@gitlab.com>2018-01-30 16:45:10 -0600
committerJose Ivan Vargas <jvargas@gitlab.com>2018-02-05 12:19:25 -0600
commitc60f32d572f924837aa7b1bf9cdd0a1c157c4891 (patch)
tree3e7283da67ce0624e4acbd18fd876f1c5ef30b19
parent2150ed4094ddb67d7b403cd56360700c80e7d928 (diff)
downloadgitlab-ce-c60f32d572f924837aa7b1bf9cdd0a1c157c4891.tar.gz
Refactor the branches modal from haml to vue
-rw-r--r--app/assets/javascripts/pages/projects/branches/components/delete_branch_modal_component.vue151
-rw-r--r--app/assets/javascripts/pages/projects/branches/index/index.js87
-rw-r--r--app/assets/javascripts/pages/projects/branches/shared/event_hub.js3
-rw-r--r--app/assets/javascripts/vue_shared/components/confirmation_input.vue9
-rw-r--r--app/views/projects/branches/_branch.html.haml34
-rw-r--r--app/views/projects/branches/_delete_protected_modal.html.haml41
-rw-r--r--app/views/projects/branches/index.html.haml3
-rw-r--r--changelogs/unreleased/42603-refactor-the-delete-branch-and-delete-protected-branches-from-haml-to-vuejs.yml5
8 files changed, 271 insertions, 62 deletions
diff --git a/app/assets/javascripts/pages/projects/branches/components/delete_branch_modal_component.vue b/app/assets/javascripts/pages/projects/branches/components/delete_branch_modal_component.vue
new file mode 100644
index 00000000000..7a209dbc922
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/branches/components/delete_branch_modal_component.vue
@@ -0,0 +1,151 @@
+<script>
+ import axios from '~/lib/utils/axios_utils';
+ import modal from '~/vue_shared/components/modal.vue';
+ import confirmationInput from '~/vue_shared/components/confirmation_input.vue';
+ import { s__, sprintf } from '~/locale';
+ import { redirectTo } from '~/lib/utils/url_utility';
+ import Flash from '~/flash';
+ import eventHub from '../shared/event_hub';
+
+ export default {
+ components: {
+ modal,
+ confirmationInput,
+ },
+ props: {
+ id: {
+ type: String,
+ required: false,
+ default: 'delete-branch-modal',
+ },
+ branchName: {
+ required: true,
+ type: String,
+ },
+ deletePath: {
+ required: true,
+ type: String,
+ },
+ isMerged: {
+ required: true,
+ type: Boolean,
+ },
+ isProtected: {
+ required: true,
+ type: Boolean,
+ },
+ rootRef: {
+ required: true,
+ type: String,
+ },
+ redirectUrl: {
+ required: true,
+ type: String,
+ },
+ },
+ computed: {
+ title() {
+ const protectedTitle = sprintf(s__(`Branches|
+ Delete protected branch '%{branchName}'`), { branchName: this.branchName });
+ const normalTitle = sprintf(s__(`Branches|
+ Delete branch '%{branchName}'`), { branchName: this.branchName });
+
+ return this.isProtected ? protectedTitle : normalTitle;
+ },
+ text() {
+ const protectedBranch = sprintf(`<p>You’re about to permanently
+ delete the protected branch <strong>%{branchName}.</strong></p>`,
+ {
+ branchName: this.branchName,
+ });
+ const whenNotMerged = sprintf(`<p>This branch hasn’t been merged into <span class='ref-name'>%{rootRef}</span>
+ To avoid data loss, consider merging this branch before deleting it.</p>`,
+ {
+ rootRef: this.rootRef,
+ });
+ const finalWarning = sprintf(`<p>Once you confirm and press
+ <strong>%{buttonText}</strong>, it cannot be undone or recovered.</p>`,
+ {
+ buttonText: this.buttonText,
+ });
+ let text = sprintf(s__(`Branches|
+ Deleting the '%{branchName}' branch cannot be undone. Are you sure?`),
+ {
+ branchName: this.branchName,
+ });
+
+ if (this.isProtected) {
+ text = !this.isMerged ?
+ sprintf(s__(`Branches|
+ %{protectedBranch} %{whenNotMerged} %{finalWarning}`),
+ {
+ protectedBranch,
+ whenNotMerged,
+ finalWarning,
+ },
+ false) :
+ sprintf(s__(`Branches|
+ %{protectedBranch} %{finalWarning}`),
+ {
+ protectedBranch,
+ finalWarning,
+ },
+ false);
+ }
+
+ return text;
+ },
+ buttonText() {
+ return this.isProtected ? s__('Branches|Delete protected branch') : s__('Branches|Delete branch');
+ },
+ canSubmit() {
+ let enableDeleteButton = this.$refs.confirmation &&
+ this.$refs.confirmation.hasCorrectValue();
+
+ enableDeleteButton = this.isProtected ? enableDeleteButton : true;
+ return !enableDeleteButton;
+ },
+ },
+ methods: {
+ onSubmit() {
+ eventHub.$emit('deleteBranchModal.requestStarted', this.deletePath);
+ axios.delete(this.deletePath)
+ .then(() => {
+ eventHub.$emit('deleteBranchModal.requestFinished', { deletePath: this.deletePath, successful: true });
+ redirectTo(this.redirectUrl);
+ })
+ .catch((error) => {
+ eventHub.$emit('deleteBranchModal.requestFinished', { deletePath: this.deletePath, successful: false });
+ Flash(sprintf(s__(`Branches|
+ An error has ocurred when deleting the branch %{branchName}`), { branchName: this.branchName }));
+ throw error;
+ });
+ },
+ },
+ };
+</script>
+<template>
+ <modal
+ id="delete-branch-modal"
+ :title="title"
+ :text="text"
+ kind="danger"
+ :primary-button-label="buttonText"
+ @submit="onSubmit"
+ :submit-disabled="canSubmit">
+
+ <template
+ slot="body"
+ slot-scope="props">
+ <p v-html="props.text"></p>
+
+ <confirmation-input
+ ref="confirmation"
+ :input-id="`${id}-input`"
+ confirmation-key="branch-name"
+ :confirmation-value="branchName"
+ v-show="isProtected"
+ />
+ </template>
+ </modal>
+</template>
diff --git a/app/assets/javascripts/pages/projects/branches/index/index.js b/app/assets/javascripts/pages/projects/branches/index/index.js
index cee0f19bf2a..20d2bb44a96 100644
--- a/app/assets/javascripts/pages/projects/branches/index/index.js
+++ b/app/assets/javascripts/pages/projects/branches/index/index.js
@@ -1,7 +1,86 @@
-import AjaxLoadingSpinner from '~/ajax_loading_spinner';
-import DeleteModal from '~/branches/branches_delete_modal';
+import Vue from 'vue';
+import Translate from '~/vue_shared/translate';
+import { convertPermissionToBoolean } from '~/lib/utils/common_utils';
+import deleteBranchModal from '../components/delete_branch_modal_component.vue';
+import eventHub from '../shared/event_hub';
export default () => {
- AjaxLoadingSpinner.init();
- new DeleteModal(); // eslint-disable-line no-new
+ Vue.use(Translate);
+
+ const onRequestFinished = ({ branchUrl, successful }) => {
+ const button = document.querySelector(`.js-delete-branch[data-delete-path="${branchUrl}"]`);
+
+ if (!successful) {
+ button.removeAttribute('disabled');
+ }
+ };
+
+ const onRequestStarted = (branchUrl) => {
+ const button = document.querySelector(`.js-delete-branch[data-delete-path="${branchUrl}"]`);
+ button.setAttribute('disabled', '');
+ eventHub.$once('deleteBranchModal.requestFinished', onRequestFinished);
+ };
+
+ const onDeleteButtonClick = (event) => {
+ const button = event.currentTarget;
+ const modalProps = {
+ deletePath: button.dataset.deletePath,
+ branchName: button.dataset.branchName,
+ isMerged: convertPermissionToBoolean(button.dataset.isMerged) || false,
+ isProtected: convertPermissionToBoolean(button.dataset.isProtected) || false,
+ rootRef: button.dataset.rootRef,
+ redirectUrl: button.dataset.redirectUrl,
+ };
+ eventHub.$once('deleteBranchModal.requestStarted', onRequestStarted);
+ eventHub.$emit('deleteBranchModal.props', modalProps);
+ };
+
+ const deleteBranchButtons = document.querySelectorAll('.js-delete-branch');
+ for (let i = 0; i < deleteBranchButtons.length; i += 1) {
+ const button = deleteBranchButtons[i];
+ button.addEventListener('click', onDeleteButtonClick);
+ }
+
+ eventHub.$once('deleteBranchModal.mounted', () => {
+ for (let i = 0; i < deleteBranchButtons.length; i += 1) {
+ const button = deleteBranchButtons[i];
+ button.removeAttribute('disabled');
+ }
+ });
+
+ return new Vue({
+ el: '#delete-branch-modal',
+ components: {
+ deleteBranchModal,
+ },
+ data() {
+ return {
+ modalProps: {
+ deletePath: '',
+ branchName: '',
+ isMerged: false,
+ isProtected: false,
+ rootRef: '',
+ redirectUrl: '',
+ },
+ };
+ },
+ mounted() {
+ eventHub.$on('deleteBranchModal.props', this.setModalProps);
+ eventHub.$emit('deleteBranchModal.mounted');
+ },
+ beforeDestroy() {
+ eventHub.$off('deleteBranchModal.props', this.setModalProps);
+ },
+ methods: {
+ setModalProps(modalProps) {
+ this.modalProps = modalProps;
+ },
+ },
+ render(createElement) {
+ return createElement('delete-branch-modal', {
+ props: this.modalProps,
+ });
+ },
+ });
};
diff --git a/app/assets/javascripts/pages/projects/branches/shared/event_hub.js b/app/assets/javascripts/pages/projects/branches/shared/event_hub.js
new file mode 100644
index 00000000000..0948c2e5352
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/branches/shared/event_hub.js
@@ -0,0 +1,3 @@
+import Vue from 'vue';
+
+export default new Vue();
diff --git a/app/assets/javascripts/vue_shared/components/confirmation_input.vue b/app/assets/javascripts/vue_shared/components/confirmation_input.vue
index 1aa03ea6317..df967d0eb3a 100644
--- a/app/assets/javascripts/vue_shared/components/confirmation_input.vue
+++ b/app/assets/javascripts/vue_shared/components/confirmation_input.vue
@@ -22,6 +22,11 @@
default: true,
},
},
+ data() {
+ return {
+ enteredValue: '',
+ };
+ },
computed: {
inputLabel() {
let value = this.confirmationValue;
@@ -38,7 +43,7 @@
},
methods: {
hasCorrectValue() {
- return this.$refs.enteredValue.value === this.confirmationValue;
+ return this.enteredValue === this.confirmationValue;
},
},
};
@@ -55,7 +60,7 @@
:id="inputId"
:name="confirmationKey"
type="text"
- ref="enteredValue"
+ v-model="enteredValue"
class="form-control"
/>
</div>
diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml
index 1da0e865a41..41f003455a8 100644
--- a/app/views/projects/branches/_branch.html.haml
+++ b/app/views/projects/branches/_branch.html.haml
@@ -39,31 +39,39 @@
%button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip disabled",
disabled: true,
title: s_('Branches|The default branch cannot be deleted') }
- = icon("trash-o")
+ = sprite_icon("remove")
- 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",
+ %button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip js-delete-branch",
title: s_('Branches|Delete protected branch'),
data: { toggle: "modal",
- target: "#modal-delete-branch",
+ target: "#delete-branch-modal",
delete_path: project_branch_path(@project, branch.name),
branch_name: branch.name,
+ container: 'body',
+ is_protected: "true",
+ redirect_url: project_branches_path(@project),
+ root_ref: @repository.root_ref,
is_merged: ("true" if merged) } }
- = icon("trash-o")
+ = sprite_icon("remove")
- else
%button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip disabled",
disabled: true,
title: s_('Branches|Only a project master or owner can delete a protected branch') }
- = icon("trash-o")
+ = sprite_icon("remove")
- else
- = link_to project_branch_path(@project, branch.name),
- class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip",
- title: s_('Branches|Delete branch'),
- method: :delete,
- data: { confirm: s_("Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?") % { branch_name: branch.name } },
- remote: true,
- 'aria-label' => s_('Branches|Delete branch') do
- = icon("trash-o")
+ %button.btn.btn-remove.remove-row.js-ajax-loading-spinner.has-tooltip.js-delete-branch{ title: s_('Branches|Delete branch'),
+ data: { target: "#delete-branch-modal",
+ delete_path: project_branch_path(@project, branch.name),
+ branch_name: branch.name,
+ root_ref: @repository.root_ref,
+ redirect_url: project_branches_path(@project),
+ isProtected: "false",
+ is_merged: ("true" if merged),
+ toggle: "modal",
+ container: 'body' },
+ 'aria-label': s_('Branches|Delete branch') }
+ = sprite_icon("remove")
- if branch.name != @repository.root_ref
.divergence-graph{ title: s_('%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead') % { number_commits_behind: diverging_count_label(number_commits_behind),
diff --git a/app/views/projects/branches/_delete_protected_modal.html.haml b/app/views/projects/branches/_delete_protected_modal.html.haml
deleted file mode 100644
index e0008e322a0..00000000000
--- a/app/views/projects/branches/_delete_protected_modal.html.haml
+++ /dev/null
@@ -1,41 +0,0 @@
-#modal-delete-branch.modal{ tabindex: -1 }
- .modal-dialog
- .modal-content
- .modal-header
- %button.close{ data: { dismiss: 'modal' } } ×
- %h3.page-title
- - title_branch_name = capture do
- %span.js-branch-name.ref-name>[branch name]
- = s_("Branches|Delete protected branch '%{branch_name}'?").html_safe % { branch_name: title_branch_name }
-
- .modal-body
- %p
- - branch_name = capture do
- %strong.js-branch-name.ref-name>[branch name]
- = s_('Branches|You’re about to permanently delete the protected branch %{branch_name}.').html_safe % { branch_name: branch_name }
- %p.js-not-merged
- - default_branch = capture do
- %span.ref-name= @repository.root_ref
- = s_('Branches|This branch hasn’t been merged into %{default_branch}.').html_safe % { default_branch: default_branch }
- = s_('Branches|To avoid data loss, consider merging this branch before deleting it.')
- %p
- - delete_protected_branch = capture do
- %strong
- = s_('Branches|Delete protected branch')
- = s_('Branches|Once you confirm and press %{delete_protected_branch}, it cannot be undone or recovered.').html_safe % { delete_protected_branch: delete_protected_branch }
- %p
- - branch_name_confirmation = capture do
- %kbd.js-branch-name [branch name]
- %strong
- = s_('Branches|To confirm, type %{branch_name_confirmation}:').html_safe % { branch_name_confirmation: branch_name_confirmation }
-
- .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 s_('Branches|Delete protected branch'), '',
- class: "btn btn-danger js-delete-branch",
- title: s_('Branches|Delete branch'),
- method: :delete,
- 'aria-label' => s_('Branches|Delete branch')
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index fb770764364..22f4424a31c 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -2,6 +2,7 @@
- page_title _('Branches')
%div{ class: container_class }
+ #delete-branch-modal
.top-area.adjust
- if can?(current_user, :admin_project, @project)
.nav-text
@@ -43,5 +44,3 @@
- else
.nothing-here-block
= s_('Branches|No branches to show')
-
-= render 'projects/branches/delete_protected_modal'
diff --git a/changelogs/unreleased/42603-refactor-the-delete-branch-and-delete-protected-branches-from-haml-to-vuejs.yml b/changelogs/unreleased/42603-refactor-the-delete-branch-and-delete-protected-branches-from-haml-to-vuejs.yml
new file mode 100644
index 00000000000..3ab10d6303c
--- /dev/null
+++ b/changelogs/unreleased/42603-refactor-the-delete-branch-and-delete-protected-branches-from-haml-to-vuejs.yml
@@ -0,0 +1,5 @@
+---
+title: Refactor the delete branch and delete protected branches modal to vue
+merge_request: 16809
+author:
+type: changed