diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-16 21:25:58 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-16 21:25:58 +0300 |
commit | a5f4bba440d7f9ea47046a0a561d49adf0a1e6d4 (patch) | |
tree | fb69158581673816a8cd895f9d352dcb3c678b1e /app/assets/javascripts/branches | |
parent | d16b2e8639e99961de6ddc93909f3bb5c1445ba1 (diff) |
Add latest changes from gitlab-org/gitlab@14-0-stable-eev14.0.0-rc42
Diffstat (limited to 'app/assets/javascripts/branches')
7 files changed, 345 insertions, 4 deletions
diff --git a/app/assets/javascripts/branches/components/delete_branch_button.vue b/app/assets/javascripts/branches/components/delete_branch_button.vue new file mode 100644 index 00000000000..5a5f49e25e7 --- /dev/null +++ b/app/assets/javascripts/branches/components/delete_branch_button.vue @@ -0,0 +1,91 @@ +<script> +import { GlButton, GlTooltipDirective } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import eventHub from '../event_hub'; + +export default { + name: 'DeleteBranchButton', + components: { GlButton }, + directives: { + GlTooltip: GlTooltipDirective, + }, + props: { + branchName: { + type: String, + required: false, + default: '', + }, + defaultBranchName: { + type: String, + required: false, + default: '', + }, + deletePath: { + type: String, + required: false, + default: '', + }, + tooltip: { + type: String, + required: false, + default: s__('Branches|Delete branch'), + }, + disabled: { + type: Boolean, + required: false, + default: false, + }, + isProtectedBranch: { + type: Boolean, + required: false, + default: false, + }, + merged: { + type: Boolean, + required: false, + default: false, + }, + }, + computed: { + variant() { + if (this.disabled) { + return 'default'; + } + return 'danger'; + }, + title() { + if (this.isProtectedBranch && this.disabled) { + return s__('Branches|Only a project maintainer or owner can delete a protected branch'); + } else if (this.isProtectedBranch) { + return s__('Branches|Delete protected branch'); + } + return this.tooltip; + }, + }, + methods: { + openModal() { + eventHub.$emit('openModal', { + branchName: this.branchName, + defaultBranchName: this.defaultBranchName, + deletePath: this.deletePath, + isProtectedBranch: this.isProtectedBranch, + merged: this.merged, + }); + }, + }, +}; +</script> + +<template> + <gl-button + v-gl-tooltip.hover + icon="remove" + class="js-delete-branch-button" + data-qa-selector="delete_branch_button" + :disabled="disabled" + :variant="variant" + :title="title" + :aria-label="title" + @click="openModal" + /> +</template> diff --git a/app/assets/javascripts/branches/components/delete_branch_modal.vue b/app/assets/javascripts/branches/components/delete_branch_modal.vue new file mode 100644 index 00000000000..14c2badeb3f --- /dev/null +++ b/app/assets/javascripts/branches/components/delete_branch_modal.vue @@ -0,0 +1,193 @@ +<script> +import { GlButton, GlFormInput, GlModal, GlSprintf, GlAlert } from '@gitlab/ui'; +import csrf from '~/lib/utils/csrf'; +import { sprintf, s__ } from '~/locale'; +import eventHub from '../event_hub'; + +export default { + csrf, + components: { + GlModal, + GlButton, + GlFormInput, + GlSprintf, + GlAlert, + }, + data() { + return { + isProtectedBranch: false, + branchName: '', + defaultBranchName: '', + deletePath: '', + merged: false, + enteredBranchName: '', + modalId: 'delete-branch-modal', + }; + }, + computed: { + title() { + const modalTitle = this.isProtectedBranch + ? this.$options.i18n.modalTitleProtectedBranch + : this.$options.i18n.modalTitle; + + return sprintf(modalTitle, { branchName: this.branchName }); + }, + message() { + const modalMessage = this.isProtectedBranch + ? this.$options.i18n.modalMessageProtectedBranch + : this.$options.i18n.modalMessage; + + return sprintf(modalMessage, { branchName: this.branchName }); + }, + unmergedWarning() { + return sprintf(this.$options.i18n.unmergedWarning, { + defaultBranchName: this.defaultBranchName, + }); + }, + undoneWarning() { + return sprintf(this.$options.i18n.undoneWarning, { + buttonText: this.buttonText, + }); + }, + confirmationText() { + return sprintf(this.$options.i18n.confirmationText, { + branchName: this.branchName, + }); + }, + buttonText() { + return this.isProtectedBranch + ? this.$options.i18n.deleteButtonTextProtectedBranch + : this.$options.i18n.deleteButtonText; + }, + branchNameConfirmed() { + return this.enteredBranchName === this.branchName; + }, + deleteButtonDisabled() { + return this.isProtectedBranch && !this.branchNameConfirmed; + }, + }, + mounted() { + eventHub.$on('openModal', this.openModal); + }, + destroyed() { + eventHub.$off('openModal', this.openModal); + }, + methods: { + openModal({ isProtectedBranch, branchName, defaultBranchName, deletePath, merged }) { + this.isProtectedBranch = isProtectedBranch; + this.branchName = branchName; + this.defaultBranchName = defaultBranchName; + this.deletePath = deletePath; + this.merged = merged; + + this.$refs.modal.show(); + }, + submitForm() { + this.$refs.form.submit(); + }, + closeModal() { + this.$refs.modal.hide(); + }, + }, + i18n: { + modalTitle: s__('Branches|Delete branch. Are you ABSOLUTELY SURE?'), + modalTitleProtectedBranch: s__('Branches|Delete protected branch. Are you ABSOLUTELY SURE?'), + modalMessage: s__( + "Branches|You're about to permanently delete the branch %{strongStart}%{branchName}.%{strongEnd}", + ), + modalMessageProtectedBranch: s__( + "Branches|You're about to permanently delete the protected branch %{strongStart}%{branchName}.%{strongEnd}", + ), + unmergedWarning: s__( + 'Branches|This branch hasn’t been merged into %{defaultBranchName}. To avoid data loss, consider merging this branch before deleting it.', + ), + undoneWarning: s__( + 'Branches|Once you confirm and press %{strongStart}%{buttonText},%{strongEnd} it cannot be undone or recovered.', + ), + cancelButtonText: s__('Branches|Cancel, keep branch'), + confirmationText: s__( + 'Branches|Deleting the %{strongStart}%{branchName}%{strongEnd} branch cannot be undone. Are you sure?', + ), + confirmationTextProtectedBranch: s__('Branches|Please type the following to confirm:'), + deleteButtonText: s__('Branches|Yes, delete branch'), + deleteButtonTextProtectedBranch: s__('Branches|Yes, delete protected branch'), + }, +}; +</script> + +<template> + <gl-modal ref="modal" size="sm" :modal-id="modalId" :title="title"> + <gl-alert class="gl-mb-5" variant="danger" :dismissible="false"> + <div data-testid="modal-message"> + <gl-sprintf :message="message"> + <template #strong="{ content }"> + <strong> {{ content }} </strong> + </template> + </gl-sprintf> + <p v-if="!merged" class="gl-mb-0 gl-mt-4"> + {{ unmergedWarning }} + </p> + </div> + </gl-alert> + + <form ref="form" :action="deletePath" method="post"> + <div v-if="isProtectedBranch" class="gl-mt-4"> + <p> + <gl-sprintf :message="undoneWarning"> + <template #strong="{ content }"> + <strong> {{ content }} </strong> + </template> + </gl-sprintf> + </p> + <p> + <gl-sprintf :message="$options.i18n.confirmationTextProtectedBranch"> + <template #strong="{ content }"> + {{ content }} + </template> + </gl-sprintf> + <code class="gl-white-space-pre-wrap"> {{ branchName }} </code> + <gl-form-input + v-model="enteredBranchName" + name="delete_branch_input" + type="text" + class="gl-mt-4" + aria-labelledby="input-label" + autocomplete="off" + /> + </p> + </div> + <div v-else> + <p class="gl-mt-4"> + <gl-sprintf :message="confirmationText"> + <template #strong="{ content }"> + <strong> + {{ content }} + </strong> + </template> + </gl-sprintf> + </p> + </div> + + <input ref="method" type="hidden" name="_method" value="delete" /> + <input :value="$options.csrf.token" type="hidden" name="authenticity_token" /> + </form> + + <template #modal-footer> + <div class="gl-display-flex gl-flex-direction-row gl-justify-content-end gl-flex-wrap gl-m-0"> + <gl-button data-testid="delete-branch-cancel-button" @click="closeModal"> + {{ $options.i18n.cancelButtonText }} + </gl-button> + <div class="gl-mr-3"></div> + <gl-button + ref="deleteBranchButton" + :disabled="deleteButtonDisabled" + variant="danger" + data-qa-selector="delete_branch_confirmation_button" + data-testid="delete-branch-confirmation-button" + @click="submitForm" + >{{ buttonText }}</gl-button + > + </div> + </template> + </gl-modal> +</template> diff --git a/app/assets/javascripts/branches/components/sort_dropdown.vue b/app/assets/javascripts/branches/components/sort_dropdown.vue index ddb4c5c0015..5f782b5e652 100644 --- a/app/assets/javascripts/branches/components/sort_dropdown.vue +++ b/app/assets/javascripts/branches/components/sort_dropdown.vue @@ -62,17 +62,18 @@ export default { }; </script> <template> - <div class="gl-display-flex gl-pr-4"> + <div class="gl-display-flex"> <gl-search-box-by-click v-model="searchTerm" :placeholder="$options.i18n.searchPlaceholder" - class="gl-pr-4" + class="gl-mr-3" data-testid="branch-search" @submit="visitUrlFromOption(selectedKey)" /> <gl-dropdown v-if="shouldShowDropdown" :text="selectedSortMethodName" + class="gl-mr-3" data-testid="branches-dropdown" > <gl-dropdown-item diff --git a/app/assets/javascripts/branches/divergence_graph.js b/app/assets/javascripts/branches/divergence_graph.js index 66e8d982113..b88c056b00f 100644 --- a/app/assets/javascripts/branches/divergence_graph.js +++ b/app/assets/javascripts/branches/divergence_graph.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import { deprecatedCreateFlash as createFlash } from '../flash'; +import createFlash from '../flash'; import axios from '../lib/utils/axios_utils'; import { __ } from '../locale'; import DivergenceGraph from './components/divergence_graph.vue'; @@ -51,6 +51,8 @@ export default (endpoint, defaultBranch) => { }); }) .catch(() => - createFlash(__('Error fetching diverging counts for branches. Please try again.')), + createFlash({ + message: __('Error fetching diverging counts for branches. Please try again.'), + }), ); }; diff --git a/app/assets/javascripts/branches/event_hub.js b/app/assets/javascripts/branches/event_hub.js new file mode 100644 index 00000000000..e31806ad199 --- /dev/null +++ b/app/assets/javascripts/branches/event_hub.js @@ -0,0 +1,3 @@ +import createEventHub from '~/helpers/event_hub_factory'; + +export default createEventHub(); diff --git a/app/assets/javascripts/branches/init_delete_branch_button.js b/app/assets/javascripts/branches/init_delete_branch_button.js new file mode 100644 index 00000000000..43df5d993a4 --- /dev/null +++ b/app/assets/javascripts/branches/init_delete_branch_button.js @@ -0,0 +1,35 @@ +import Vue from 'vue'; +import DeleteBranchButton from '~/branches/components/delete_branch_button.vue'; +import { parseBoolean } from '~/lib/utils/common_utils'; + +export default function initDeleteBranchButton(el) { + if (!el) { + return false; + } + + const { + branchName, + defaultBranchName, + deletePath, + tooltip, + disabled, + isProtectedBranch, + merged, + } = el.dataset; + + return new Vue({ + el, + render: (createElement) => + createElement(DeleteBranchButton, { + props: { + branchName, + defaultBranchName, + deletePath, + tooltip, + disabled: parseBoolean(disabled), + isProtectedBranch: parseBoolean(isProtectedBranch), + merged: parseBoolean(merged), + }, + }), + }); +} diff --git a/app/assets/javascripts/branches/init_delete_branch_modal.js b/app/assets/javascripts/branches/init_delete_branch_modal.js new file mode 100644 index 00000000000..f3a95d03c5a --- /dev/null +++ b/app/assets/javascripts/branches/init_delete_branch_modal.js @@ -0,0 +1,16 @@ +import Vue from 'vue'; +import DeleteBranchModal from '~/branches/components/delete_branch_modal.vue'; + +export default function initDeleteBranchModal() { + const el = document.querySelector('.js-delete-branch-modal'); + if (!el) { + return false; + } + + return new Vue({ + el, + render(createComponent) { + return createComponent(DeleteBranchModal); + }, + }); +} |