Commit 4829062d authored by Martin Wortschack's avatar Martin Wortschack

Merge branch...

Merge branch '344566-migrate-app-views-shared-_confirm_fork_modal-html-haml-modal-implementation-to-glmodal' into 'master'

Migrate confirm fork modal implementation to `GlModal`

See merge request gitlab-org/gitlab!77549
parents 5a713f73 9188bf0e
<script>
import { GlModal } from '@gitlab/ui';
import { __ } from '~/locale';
export const i18n = {
btnText: __('Fork project'),
title: __('Fork project?'),
message: __(
'You can’t edit files directly in this project. Fork this project and submit a merge request with your changes.',
),
};
export default {
name: 'ConfirmForkModal',
components: {
GlModal,
},
model: {
prop: 'visible',
event: 'change',
},
props: {
visible: {
type: Boolean,
required: false,
default: false,
},
modalId: {
type: String,
required: true,
},
forkPath: {
type: String,
required: true,
},
},
computed: {
btnActions() {
return {
cancel: { text: __('Cancel') },
primary: {
text: this.$options.i18n.btnText,
attributes: {
href: this.forkPath,
variant: 'confirm',
'data-qa-selector': 'fork_project_button',
'data-method': 'post',
},
},
};
},
},
i18n,
};
</script>
<template>
<gl-modal
:visible="visible"
data-qa-selector="confirm_fork_modal"
:modal-id="modalId"
:title="$options.i18n.title"
:action-primary="btnActions.primary"
:action-cancel="btnActions.cancel"
@change="$emit('change', $event)"
>
<p>{{ $options.i18n.message }}</p>
</gl-modal>
</template>
<script>
import $ from 'jquery';
import { GlModal, GlSprintf, GlLink } from '@gitlab/ui';
import { s__, __ } from '~/locale';
import ActionsButton from '~/vue_shared/components/actions_button.vue';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import ConfirmForkModal from '~/vue_shared/components/confirm_fork_modal.vue';
const KEY_EDIT = 'edit';
const KEY_WEB_IDE = 'webide';
......@@ -16,6 +16,7 @@ export default {
GlModal,
GlSprintf,
GlLink,
ConfirmForkModal,
},
i18n: {
modal: {
......@@ -103,11 +104,22 @@ export default {
required: false,
default: false,
},
forkPath: {
type: String,
required: false,
default: '',
},
forkModalId: {
type: String,
required: false,
default: '',
},
},
data() {
return {
selection: KEY_WEB_IDE,
showEnableGitpodModal: false,
showForkModal: false,
};
},
computed: {
......@@ -128,7 +140,7 @@ export default {
return;
}
this.showJQueryModal('#modal-confirm-fork-edit');
this.showModal('showForkModal');
},
}
: { href: this.editUrl };
......@@ -171,7 +183,7 @@ export default {
return;
}
this.showJQueryModal('#modal-confirm-fork-webide');
this.showModal('showForkModal');
},
}
: { href: this.webIdeUrl };
......@@ -247,9 +259,6 @@ export default {
select(key) {
this.selection = key;
},
showJQueryModal(id) {
$(id).modal('show');
},
showModal(dataKey) {
this[dataKey] = true;
},
......@@ -282,5 +291,11 @@ export default {
</template>
</gl-sprintf>
</gl-modal>
<confirm-fork-modal
v-if="showWebIdeButton || showEditButton"
v-model="showForkModal"
:modal-id="forkModalId"
:fork-path="forkPath"
/>
</div>
</template>
......@@ -175,6 +175,21 @@ module TreeHelper
}
end
def fork_modal_options(project, ref, path, blob)
if show_edit_button?({ blob: blob })
fork_path = fork_and_edit_path(project, ref, path)
fork_modal_id = "modal-confirm-fork-edit"
elsif show_web_ide_button?
fork_path = ide_fork_and_edit_path(project, ref, path)
fork_modal_id = "modal-confirm-fork-webide"
end
{
fork_path: fork_path,
fork_modal_id: fork_modal_id
}
end
def web_ide_button_data(options = {})
{
project_path: project_to_use.full_path,
......
.modal{ data: { qa_selector: 'confirm_fork_modal'}, id: "modal-confirm-fork-#{type}" }
.modal-dialog
.modal-content
.modal-header
%h3.page-title= _('Fork project?')
%button.close{ type: "button", "data-dismiss": "modal", "aria-label" => _('Close') }
%span{ "aria-hidden": "true" } &times;
.modal-body.p-3
%p= _("You can’t %{tag_start}edit%{tag_end} files directly in this project. Fork this project and submit a merge request with your changes.") % { tag_start: '', tag_end: ''}
.modal-footer
= link_to _('Cancel'), '#', class: "btn gl-button btn-default", "data-dismiss" => "modal"
= link_to _('Fork project'), fork_path, class: 'btn gl-button btn-confirm', data: { qa_selector: 'fork_project_button' }, method: :post
- type = blob ? 'blob' : 'tree'
- button_data = web_ide_button_data({ blob: blob })
- fork_options = fork_modal_options(@project, @ref, @path, blob)
.d-inline-block{ data: { options: web_ide_button_data({ blob: blob }).to_json }, id: "js-#{type}-web-ide-link" }
- if show_edit_button?({ blob: blob })
= render 'shared/confirm_fork_modal', fork_path: fork_and_edit_path(@project, @ref, @path), type: 'edit'
- if show_web_ide_button?
= render 'shared/confirm_fork_modal', fork_path: ide_fork_and_edit_path(@project, @ref, @path), type: 'webide'
.gl-display-inline-block{ data: { options: button_data.merge(fork_options).to_json }, id: "js-#{type}-web-ide-link" }
......@@ -41456,9 +41456,6 @@ msgstr ""
msgid "You cannot write to this read-only GitLab instance."
msgstr ""
msgid "You can’t %{tag_start}edit%{tag_end} files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
msgid "You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
......
......@@ -68,7 +68,7 @@ module QA
element :delete_button
end
view 'app/views/shared/_confirm_fork_modal.html.haml' do
view 'app/assets/javascripts/vue_shared/components/confirm_fork_modal.vue' do
element :fork_project_button
element :confirm_fork_modal
end
......
import { GlModal } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ConfirmForkModal, { i18n } from '~/vue_shared/components/confirm_fork_modal.vue';
describe('vue_shared/components/confirm_fork_modal', () => {
let wrapper = null;
const forkPath = '/fake/fork/path';
const modalId = 'confirm-fork-modal';
const defaultProps = { modalId, forkPath };
const findModal = () => wrapper.findComponent(GlModal);
const findModalProp = (prop) => findModal().props(prop);
const findModalActionProps = () => findModalProp('actionPrimary');
const createComponent = (props = {}) =>
shallowMountExtended(ConfirmForkModal, {
propsData: {
...defaultProps,
...props,
},
});
afterEach(() => {
wrapper.destroy();
});
describe('visible = false', () => {
beforeEach(() => {
wrapper = createComponent();
});
it('sets the visible prop to `false`', () => {
expect(findModalProp('visible')).toBe(false);
});
it('sets the modal title', () => {
const title = findModalProp('title');
expect(title).toBe(i18n.title);
});
it('sets the modal id', () => {
const fakeModalId = findModalProp('modalId');
expect(fakeModalId).toBe(modalId);
});
it('has the fork path button', () => {
const modalProps = findModalActionProps();
expect(modalProps.text).toBe(i18n.btnText);
expect(modalProps.attributes.variant).toBe('confirm');
});
it('sets the correct fork path', () => {
const modalProps = findModalActionProps();
expect(modalProps.attributes.href).toBe(forkPath);
});
it('has the fork message', () => {
expect(findModal().text()).toContain(i18n.message);
});
});
describe('visible = true', () => {
beforeEach(() => {
wrapper = createComponent({ visible: true });
});
it('sets the visible prop to `true`', () => {
expect(findModalProp('visible')).toBe(true);
});
it('emits the `change` event if the modal is hidden', () => {
expect(wrapper.emitted('change')).toBeUndefined();
findModal().vm.$emit('change', false);
expect(wrapper.emitted('change')).toEqual([[false]]);
});
});
});
......@@ -4,6 +4,7 @@ import { nextTick } from 'vue';
import ActionsButton from '~/vue_shared/components/actions_button.vue';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import WebIdeLink from '~/vue_shared/components/web_ide_link.vue';
import ConfirmForkModal from '~/vue_shared/components/confirm_fork_modal.vue';
import { stubComponent } from 'helpers/stub_component';
import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
......@@ -13,6 +14,7 @@ const TEST_WEB_IDE_URL = '/-/ide/project/gitlab-test/test/edit/main/-/';
const TEST_GITPOD_URL = 'https://gitpod.test/';
const TEST_USER_PREFERENCES_GITPOD_PATH = '/-/profile/preferences#user_gitpod_enabled';
const TEST_USER_PROFILE_ENABLE_GITPOD_PATH = '/-/profile?user%5Bgitpod_enabled%5D=true';
const forkPath = '/some/fork/path';
const ACTION_EDIT = {
href: TEST_EDIT_URL,
......@@ -74,6 +76,7 @@ describe('Web IDE link component', () => {
editUrl: TEST_EDIT_URL,
webIdeUrl: TEST_WEB_IDE_URL,
gitpodUrl: TEST_GITPOD_URL,
forkPath,
...props,
},
stubs: {
......@@ -96,6 +99,7 @@ describe('Web IDE link component', () => {
const findActionsButton = () => wrapper.find(ActionsButton);
const findLocalStorageSync = () => wrapper.find(LocalStorageSync);
const findModal = () => wrapper.findComponent(GlModal);
const findForkConfirmModal = () => wrapper.findComponent(ConfirmForkModal);
it.each([
{
......@@ -231,16 +235,28 @@ describe('Web IDE link component', () => {
});
describe('edit actions', () => {
it.each([
const testActions = [
{
props: { showWebIdeButton: true, showEditButton: false },
props: {
showWebIdeButton: true,
showEditButton: false,
forkPath,
forkModalId: 'edit-modal',
},
expectedEventPayload: 'ide',
},
{
props: { showWebIdeButton: false, showEditButton: true },
props: {
showWebIdeButton: false,
showEditButton: true,
forkPath,
forkModalId: 'webide-modal',
},
expectedEventPayload: 'simple',
},
])(
];
it.each(testActions)(
'emits the correct event when an action handler is called',
async ({ props, expectedEventPayload }) => {
createComponent({ ...props, needsToFork: true, disableForkModal: true });
......@@ -250,6 +266,29 @@ describe('Web IDE link component', () => {
expect(wrapper.emitted('edit')).toEqual([[expectedEventPayload]]);
},
);
it.each(testActions)('renders the fork confirmation modal', async ({ props }) => {
createComponent({ ...props, needsToFork: true });
expect(findForkConfirmModal().exists()).toBe(true);
expect(findForkConfirmModal().props()).toEqual({
visible: false,
forkPath,
modalId: props.forkModalId,
});
});
it.each(testActions)('opens the modal when the button is clicked', async ({ props }) => {
createComponent({ ...props, needsToFork: true }, mountExtended);
await findActionsButton().trigger('click');
expect(findForkConfirmModal().props()).toEqual({
visible: true,
forkPath,
modalId: props.forkModalId,
});
});
});
describe('when Gitpod is not enabled', () => {
......
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