Commit 324efaa3 authored by Jacques Erasmus's avatar Jacques Erasmus Committed by Peter Hegman

Show fork suggestion when replacing or deleting a blob

Shows a fork suggestion when a user tries to delete or replace a blob
parent 951313ad
<script> <script>
import { GlButtonGroup, GlButton, GlModalDirective } from '@gitlab/ui'; import { GlButtonGroup, GlButton } from '@gitlab/ui';
import { uniqueId } from 'lodash'; import { uniqueId } from 'lodash';
import { sprintf, __ } from '~/locale'; import { sprintf, __ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
...@@ -20,9 +20,6 @@ export default { ...@@ -20,9 +20,6 @@ export default {
DeleteBlobModal, DeleteBlobModal,
LockButton: () => import('ee_component/repository/components/lock_button.vue'), LockButton: () => import('ee_component/repository/components/lock_button.vue'),
}, },
directives: {
GlModal: GlModalDirective,
},
mixins: [getRefMixin, glFeatureFlagMixin()], mixins: [getRefMixin, glFeatureFlagMixin()],
inject: { inject: {
targetBranch: { targetBranch: {
...@@ -73,6 +70,10 @@ export default { ...@@ -73,6 +70,10 @@ export default {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
showForkSuggestion: {
type: Boolean,
required: true,
},
}, },
computed: { computed: {
replaceModalId() { replaceModalId() {
...@@ -91,6 +92,16 @@ export default { ...@@ -91,6 +92,16 @@ export default {
return this.canLock ? 'lock_button' : 'disabled_lock_button'; return this.canLock ? 'lock_button' : 'disabled_lock_button';
}, },
}, },
methods: {
showModal(modalId) {
if (this.showForkSuggestion) {
this.$emit('fork');
return;
}
this.$refs[modalId].show();
},
},
}; };
</script> </script>
...@@ -107,14 +118,15 @@ export default { ...@@ -107,14 +118,15 @@ export default {
data-testid="lock" data-testid="lock"
:data-qa-selector="lockBtnQASelector" :data-qa-selector="lockBtnQASelector"
/> />
<gl-button v-gl-modal="replaceModalId" data-testid="replace"> <gl-button data-testid="replace" @click="showModal(replaceModalId)">
{{ $options.i18n.replace }} {{ $options.i18n.replace }}
</gl-button> </gl-button>
<gl-button v-gl-modal="deleteModalId" data-testid="delete"> <gl-button data-testid="delete" @click="showModal(deleteModalId)">
{{ $options.i18n.delete }} {{ $options.i18n.delete }}
</gl-button> </gl-button>
</gl-button-group> </gl-button-group>
<upload-blob-modal <upload-blob-modal
:ref="replaceModalId"
:modal-id="replaceModalId" :modal-id="replaceModalId"
:modal-title="replaceModalTitle" :modal-title="replaceModalTitle"
:commit-message="replaceModalTitle" :commit-message="replaceModalTitle"
...@@ -126,6 +138,7 @@ export default { ...@@ -126,6 +138,7 @@ export default {
:primary-btn-text="$options.i18n.replacePrimaryBtnText" :primary-btn-text="$options.i18n.replacePrimaryBtnText"
/> />
<delete-blob-modal <delete-blob-modal
:ref="deleteModalId"
:modal-id="deleteModalId" :modal-id="deleteModalId"
:modal-title="deleteModalTitle" :modal-title="deleteModalTitle"
:delete-path="deletePath" :delete-path="deletePath"
......
...@@ -280,6 +280,8 @@ export default { ...@@ -280,6 +280,8 @@ export default {
:project-path="projectPath" :project-path="projectPath"
:is-locked="Boolean(pathLockedByUser)" :is-locked="Boolean(pathLockedByUser)"
:can-lock="canLock" :can-lock="canLock"
:show-fork-suggestion="showForkSuggestion"
@fork="setForkTarget('ide')"
/> />
</template> </template>
</blob-header> </blob-header>
......
...@@ -146,6 +146,9 @@ export default { ...@@ -146,6 +146,9 @@ export default {
/* eslint-enable dot-notation */ /* eslint-enable dot-notation */
}, },
methods: { methods: {
show() {
this.$refs[this.modalId].show();
},
submitForm(e) { submitForm(e) {
e.preventDefault(); // Prevent modal from closing e.preventDefault(); // Prevent modal from closing
this.form.showValidation = true; this.form.showValidation = true;
...@@ -164,6 +167,7 @@ export default { ...@@ -164,6 +167,7 @@ export default {
<template> <template>
<gl-modal <gl-modal
:ref="modalId"
v-bind="$attrs" v-bind="$attrs"
data-testid="modal-delete" data-testid="modal-delete"
:modal-id="modalId" :modal-id="modalId"
......
...@@ -32,6 +32,7 @@ export default { ...@@ -32,6 +32,7 @@ export default {
class="gl-mr-3" class="gl-mr-3"
category="secondary" category="secondary"
variant="confirm" variant="confirm"
data-method="post"
:href="forkPath" :href="forkPath"
data-testid="fork" data-testid="fork"
> >
......
...@@ -136,6 +136,9 @@ export default { ...@@ -136,6 +136,9 @@ export default {
}, },
}, },
methods: { methods: {
show() {
this.$refs[this.modalId].show();
},
setFile(file) { setFile(file) {
this.file = file; this.file = file;
...@@ -206,6 +209,7 @@ export default { ...@@ -206,6 +209,7 @@ export default {
<template> <template>
<gl-form> <gl-form>
<gl-modal <gl-modal
:ref="modalId"
:modal-id="modalId" :modal-id="modalId"
:title="modalTitle" :title="modalTitle"
:action-primary="primaryOptions" :action-primary="primaryOptions"
......
...@@ -13,6 +13,7 @@ const DEFAULT_PROPS = { ...@@ -13,6 +13,7 @@ const DEFAULT_PROPS = {
projectPath: 'some/project/path', projectPath: 'some/project/path',
isLocked: false, isLocked: false,
canLock: true, canLock: true,
showForkSuggestion: false,
}; };
const DEFAULT_INJECT = { const DEFAULT_INJECT = {
......
import { GlButton } from '@gitlab/ui'; import { GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { mountExtended } from 'helpers/vue_test_utils_helper';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import BlobButtonGroup from '~/repository/components/blob_button_group.vue'; import BlobButtonGroup from '~/repository/components/blob_button_group.vue';
import DeleteBlobModal from '~/repository/components/delete_blob_modal.vue'; import DeleteBlobModal from '~/repository/components/delete_blob_modal.vue';
import UploadBlobModal from '~/repository/components/upload_blob_modal.vue'; import UploadBlobModal from '~/repository/components/upload_blob_modal.vue';
...@@ -16,6 +15,7 @@ const DEFAULT_PROPS = { ...@@ -16,6 +15,7 @@ const DEFAULT_PROPS = {
projectPath: 'some/project/path', projectPath: 'some/project/path',
isLocked: false, isLocked: false,
canLock: true, canLock: true,
showForkSuggestion: false,
}; };
const DEFAULT_INJECT = { const DEFAULT_INJECT = {
...@@ -27,7 +27,7 @@ describe('BlobButtonGroup component', () => { ...@@ -27,7 +27,7 @@ describe('BlobButtonGroup component', () => {
let wrapper; let wrapper;
const createComponent = (props = {}) => { const createComponent = (props = {}) => {
wrapper = shallowMount(BlobButtonGroup, { wrapper = mountExtended(BlobButtonGroup, {
propsData: { propsData: {
...DEFAULT_PROPS, ...DEFAULT_PROPS,
...props, ...props,
...@@ -35,9 +35,6 @@ describe('BlobButtonGroup component', () => { ...@@ -35,9 +35,6 @@ describe('BlobButtonGroup component', () => {
provide: { provide: {
...DEFAULT_INJECT, ...DEFAULT_INJECT,
}, },
directives: {
GlModal: createMockDirective(),
},
}); });
}; };
...@@ -47,7 +44,8 @@ describe('BlobButtonGroup component', () => { ...@@ -47,7 +44,8 @@ describe('BlobButtonGroup component', () => {
const findDeleteBlobModal = () => wrapper.findComponent(DeleteBlobModal); const findDeleteBlobModal = () => wrapper.findComponent(DeleteBlobModal);
const findUploadBlobModal = () => wrapper.findComponent(UploadBlobModal); const findUploadBlobModal = () => wrapper.findComponent(UploadBlobModal);
const findReplaceButton = () => wrapper.find('[data-testid="replace"]'); const findDeleteButton = () => wrapper.findByTestId('delete');
const findReplaceButton = () => wrapper.findByTestId('replace');
it('renders component', () => { it('renders component', () => {
createComponent(); createComponent();
...@@ -63,6 +61,8 @@ describe('BlobButtonGroup component', () => { ...@@ -63,6 +61,8 @@ describe('BlobButtonGroup component', () => {
describe('buttons', () => { describe('buttons', () => {
beforeEach(() => { beforeEach(() => {
createComponent(); createComponent();
jest.spyOn(findUploadBlobModal().vm, 'show');
jest.spyOn(findDeleteBlobModal().vm, 'show');
}); });
it('renders both the replace and delete button', () => { it('renders both the replace and delete button', () => {
...@@ -75,10 +75,37 @@ describe('BlobButtonGroup component', () => { ...@@ -75,10 +75,37 @@ describe('BlobButtonGroup component', () => {
}); });
it('triggers the UploadBlobModal from the replace button', () => { it('triggers the UploadBlobModal from the replace button', () => {
const { value } = getBinding(findReplaceButton().element, 'gl-modal'); findReplaceButton().trigger('click');
const modalId = findUploadBlobModal().props('modalId');
expect(findUploadBlobModal().vm.show).toHaveBeenCalled();
});
it('triggers the DeleteBlobModal from the delete button', () => {
findDeleteButton().trigger('click');
expect(findDeleteBlobModal().vm.show).toHaveBeenCalled();
});
describe('showForkSuggestion set to true', () => {
beforeEach(() => {
createComponent({ showForkSuggestion: true });
jest.spyOn(findUploadBlobModal().vm, 'show');
jest.spyOn(findDeleteBlobModal().vm, 'show');
});
expect(modalId).toEqual(value); it('does not trigger the UploadBlobModal from the replace button', () => {
findReplaceButton().trigger('click');
expect(findUploadBlobModal().vm.show).not.toHaveBeenCalled();
expect(wrapper.emitted().fork).toBeTruthy();
});
it('does not trigger the DeleteBlobModal from the delete button', () => {
findDeleteButton().trigger('click');
expect(findDeleteBlobModal().vm.show).not.toHaveBeenCalled();
expect(wrapper.emitted().fork).toBeTruthy();
});
}); });
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment