From aa4d71dcb8b3edf68902dda2e664474ffc466cd9 Mon Sep 17 00:00:00 2001 From: Paul Slaughter Date: Fri, 17 Feb 2023 11:09:27 -0600 Subject: [PATCH 1/4] Show writable forks in WebIDE modal Changelog: changed --- .../projects/shared/web_ide_link/index.js | 12 ++ .../components/confirm_fork_modal.vue | 68 ---------- .../components/web_ide/confirm_fork_modal.vue | 117 ++++++++++++++++++ .../web_ide/get_writable_forks.query.graphql | 12 ++ .../vue_shared/components/web_ide_link.vue | 16 +-- app/helpers/tree_helper.rb | 6 +- app/views/shared/_web_ide_button.html.haml | 2 +- locale/gitlab.pot | 12 ++ qa/qa/page/project/web_ide/edit.rb | 2 +- spec/frontend/fixtures/project.rb | 55 ++++++++ .../components/confirm_fork_modal_spec.js | 52 +++++++- .../components/web_ide_link_spec.js | 14 ++- spec/helpers/tree_helper_spec.rb | 38 ++++++ 13 files changed, 318 insertions(+), 88 deletions(-) delete mode 100644 app/assets/javascripts/vue_shared/components/confirm_fork_modal.vue create mode 100644 app/assets/javascripts/vue_shared/components/web_ide/confirm_fork_modal.vue create mode 100644 app/assets/javascripts/vue_shared/components/web_ide/get_writable_forks.query.graphql create mode 100644 spec/frontend/fixtures/project.rb diff --git a/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js b/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js index 43ff617dabe2f5..ce36ff6a2305dc 100644 --- a/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js +++ b/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js @@ -1,7 +1,15 @@ import Vue from 'vue'; +import VueApollo from 'vue-apollo'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { joinPaths, webIDEUrl } from '~/lib/utils/url_utility'; import WebIdeButton from '~/vue_shared/components/web_ide_link.vue'; +import createDefaultClient from '~/lib/graphql'; + +Vue.use(VueApollo); + +const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), +}); export default ({ el, router }) => { if (!el) return; @@ -15,6 +23,10 @@ export default ({ el, router }) => { new Vue({ el, router, + apolloProvider, + provide: { + projectPath, + }, render(h) { return h(WebIdeButton, { props: { diff --git a/app/assets/javascripts/vue_shared/components/confirm_fork_modal.vue b/app/assets/javascripts/vue_shared/components/confirm_fork_modal.vue deleted file mode 100644 index 64e3b5d0baea7b..00000000000000 --- a/app/assets/javascripts/vue_shared/components/confirm_fork_modal.vue +++ /dev/null @@ -1,68 +0,0 @@ - - diff --git a/app/assets/javascripts/vue_shared/components/web_ide/confirm_fork_modal.vue b/app/assets/javascripts/vue_shared/components/web_ide/confirm_fork_modal.vue new file mode 100644 index 00000000000000..8056e0c0e93d85 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/web_ide/confirm_fork_modal.vue @@ -0,0 +1,117 @@ + + diff --git a/app/assets/javascripts/vue_shared/components/web_ide/get_writable_forks.query.graphql b/app/assets/javascripts/vue_shared/components/web_ide/get_writable_forks.query.graphql new file mode 100644 index 00000000000000..044b79e64f3657 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/web_ide/get_writable_forks.query.graphql @@ -0,0 +1,12 @@ +query getWritableForks($projectPath: ID!) { + project(fullPath: $projectPath) { + id + visibleForks(minimumAccessLevel: DEVELOPER) { + nodes { + id + fullPath + webUrl + } + } + } +} diff --git a/app/assets/javascripts/vue_shared/components/web_ide_link.vue b/app/assets/javascripts/vue_shared/components/web_ide_link.vue index 96944877f61824..5acc3791ddb6e0 100644 --- a/app/assets/javascripts/vue_shared/components/web_ide_link.vue +++ b/app/assets/javascripts/vue_shared/components/web_ide_link.vue @@ -3,7 +3,7 @@ import { GlModal, GlSprintf, GlLink } from '@gitlab/ui'; import { s__, __ } from '~/locale'; import { visitUrl } from '~/lib/utils/url_utility'; import ActionsButton from '~/vue_shared/components/actions_button.vue'; -import ConfirmForkModal from '~/vue_shared/components/confirm_fork_modal.vue'; +import ConfirmForkModal from '~/vue_shared/components/web_ide/confirm_fork_modal.vue'; import { KEY_EDIT, KEY_WEB_IDE, KEY_GITPOD, KEY_PIPELINE_EDITOR } from './constants'; export const i18n = { @@ -152,9 +152,7 @@ export default { return this.actions.length > 0; }, editAction() { - if (!this.showEditButton) { - return null; - } + if (!this.showEditButton) return null; const handleOptions = this.needsToFork ? { @@ -194,9 +192,7 @@ export default { return __('Web IDE'); }, webIdeAction() { - if (!this.showWebIdeButton) { - return null; - } + if (!this.showWebIdeButton) return null; const handleOptions = this.needsToFork ? { @@ -298,6 +294,10 @@ export default { }, }; }, + mountForkModal() { + const { disableForkModal, showWebIdeButton, showEditButton } = this; + return !disableForkModal && (showWebIdeButton || showEditButton); + }, }, methods: { showModal(dataKey) { @@ -330,7 +330,7 @@ export default { { + Vue.use(VueApollo); + let wrapper = null; const forkPath = '/fake/fork/path'; @@ -13,13 +22,18 @@ describe('vue_shared/components/confirm_fork_modal', () => { const findModalProp = (prop) => findModal().props(prop); const findModalActionProps = () => findModalProp('actionPrimary'); - const createComponent = (props = {}) => - shallowMountExtended(ConfirmForkModal, { + const createComponent = (props = {}, getWritableForksResponse = getNoWritableForksResponse) => { + const fakeApollo = createMockApollo([ + [getWritableForksQuery, jest.fn().mockResolvedValue(getWritableForksResponse)], + ]); + return shallowMountExtended(ConfirmForkModal, { propsData: { ...defaultProps, ...props, }, + apolloProvider: fakeApollo, }); + }; describe('visible = false', () => { beforeEach(() => { @@ -73,4 +87,34 @@ describe('vue_shared/components/confirm_fork_modal', () => { expect(wrapper.emitted('change')).toEqual([[false]]); }); }); + + describe('writable forks', () => { + describe('when loading', () => { + it('shows loading spinner', () => { + wrapper = createComponent(); + + expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true); + }); + }); + + describe('with no writable forks', () => { + it('contains `newForkMessage`', async () => { + wrapper = createComponent(); + + await waitForPromises(); + + expect(wrapper.element.textContent).toContain(i18n.newForkMessage); + }); + }); + + describe('with writable forks', () => { + it('contains `existingForksMessage`', async () => { + wrapper = createComponent(null, getSomeWritableForksResponse); + + await waitForPromises(); + + expect(wrapper.element.textContent).toContain(i18n.existingForksMessage); + }); + }); + }); }); diff --git a/spec/frontend/vue_shared/components/web_ide_link_spec.js b/spec/frontend/vue_shared/components/web_ide_link_spec.js index 26557c63a77ecd..e54de25dc0d91c 100644 --- a/spec/frontend/vue_shared/components/web_ide_link_spec.js +++ b/spec/frontend/vue_shared/components/web_ide_link_spec.js @@ -1,14 +1,18 @@ import { GlModal } from '@gitlab/ui'; -import { nextTick } from 'vue'; +import Vue, { nextTick } from 'vue'; +import VueApollo from 'vue-apollo'; +import getWritableForksResponse from 'test_fixtures/graphql/vue_shared/components/web_ide/get_writable_forks.query.graphql_none.json'; import ActionsButton from '~/vue_shared/components/actions_button.vue'; import WebIdeLink, { i18n } from '~/vue_shared/components/web_ide_link.vue'; -import ConfirmForkModal from '~/vue_shared/components/confirm_fork_modal.vue'; +import ConfirmForkModal from '~/vue_shared/components/web_ide/confirm_fork_modal.vue'; import { stubComponent } from 'helpers/stub_component'; import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper'; +import createMockApollo from 'helpers/mock_apollo_helper'; import { visitUrl } from '~/lib/utils/url_utility'; +import getWritableForksQuery from '~/vue_shared/components/web_ide/get_writable_forks.query.graphql'; jest.mock('~/lib/utils/url_utility'); @@ -77,9 +81,14 @@ const ACTION_PIPELINE_EDITOR = { }; describe('vue_shared/components/web_ide_link', () => { + Vue.use(VueApollo); + let wrapper; function createComponent(props, { mountFn = shallowMountExtended, glFeatures = {} } = {}) { + const fakeApollo = createMockApollo([ + [getWritableForksQuery, jest.fn().mockResolvedValue(getWritableForksResponse)], + ]); wrapper = mountFn(WebIdeLink, { propsData: { editUrl: TEST_EDIT_URL, @@ -102,6 +111,7 @@ describe('vue_shared/components/web_ide_link', () => { `, }), }, + apolloProvider: fakeApollo, }); } diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb index 01dacf5fcadcb8..e13b83feefd1f1 100644 --- a/spec/helpers/tree_helper_spec.rb +++ b/spec/helpers/tree_helper_spec.rb @@ -271,4 +271,42 @@ end end end + + describe '.fork_modal_options' do + let_it_be(:blob) { project.repository.blob_at('refs/heads/master', @path) } + + before do + allow(helper).to receive(:current_user).and_return(user) + end + + subject { helper.fork_modal_options(project, blob) } + + it 'returns correct fork path' do + expect(subject).to match a_hash_including(fork_path: '/namespace1/project-1/-/forks/new', fork_modal_id: nil) + end + + context 'when show_edit_button true' do + before do + allow(helper).to receive(:show_edit_button?).and_return(true) + end + + it 'returns correct fork path and modal id' do + expect(subject).to match a_hash_including( + fork_path: '/namespace1/project-1/-/forks/new', + fork_modal_id: 'modal-confirm-fork-edit') + end + end + + context 'when show_web_ide_button true' do + before do + allow(helper).to receive(:show_web_ide_button?).and_return(true) + end + + it 'returns correct fork path and modal id' do + expect(subject).to match a_hash_including( + fork_path: '/namespace1/project-1/-/forks/new', + fork_modal_id: 'modal-confirm-fork-webide') + end + end + end end -- GitLab From 3baee29eb9dcdb04ecb709c8684542bee96e5ac4 Mon Sep 17 00:00:00 2001 From: Lee Tickett Date: Fri, 9 Jun 2023 08:44:06 +0100 Subject: [PATCH 2/4] Apply reviewer suggestions --- spec/frontend/fixtures/project.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/frontend/fixtures/project.rb b/spec/frontend/fixtures/project.rb index 2343f0c23cdeca..8d8c1a69856f43 100644 --- a/spec/frontend/fixtures/project.rb +++ b/spec/frontend/fixtures/project.rb @@ -2,8 +2,6 @@ require 'spec_helper' -WRITEABLE_FORKS_QUERY_PATH = 'vue_shared/components/web_ide/get_writable_forks.query.graphql' - RSpec.describe 'Project (GraphQL fixtures)', feature_category: :groups_and_projects do describe GraphQL::Query, type: :request do include ApiHelpers @@ -14,7 +12,9 @@ let_it_be(:current_user) { create(:user) } describe 'writable forks' do - let(:query) { get_graphql_query_as_string(WRITEABLE_FORKS_QUERY_PATH) } + writeable_forks_query_path = 'vue_shared/components/web_ide/get_writable_forks.query.graphql' + + let(:query) { get_graphql_query_as_string(writeable_forks_query_path) } subject { post_graphql(query, current_user: current_user, variables: { projectPath: project.full_path }) } @@ -23,7 +23,7 @@ end context 'with none' do - it "graphql/#{WRITEABLE_FORKS_QUERY_PATH}_none.json" do + it "graphql/#{writeable_forks_query_path}_none.json" do subject expect_graphql_errors_to_be_empty @@ -44,7 +44,7 @@ # rubocop:enable RSpec/AnyInstanceOf end - it "graphql/#{WRITEABLE_FORKS_QUERY_PATH}_some.json" do + it "graphql/#{writeable_forks_query_path}_some.json" do subject expect_graphql_errors_to_be_empty -- GitLab From d38732ee377f4dba5a47ddbb6ed32024edb498f2 Mon Sep 17 00:00:00 2001 From: Lee Tickett Date: Mon, 12 Jun 2023 12:42:05 +0100 Subject: [PATCH 3/4] Apply reviewer suggestions --- .../components/web_ide/confirm_fork_modal.vue | 17 +++++++---------- .../vue_shared/components/web_ide_link.vue | 4 +++- spec/frontend/fixtures/project.rb | 12 ++++-------- .../components/confirm_fork_modal_spec.js | 15 +++++++++++++-- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/app/assets/javascripts/vue_shared/components/web_ide/confirm_fork_modal.vue b/app/assets/javascripts/vue_shared/components/web_ide/confirm_fork_modal.vue index 8056e0c0e93d85..fbff54e0fc528b 100644 --- a/app/assets/javascripts/vue_shared/components/web_ide/confirm_fork_modal.vue +++ b/app/assets/javascripts/vue_shared/components/web_ide/confirm_fork_modal.vue @@ -1,5 +1,5 @@