diff --git a/app/assets/javascripts/jira_connect/branches/index.js b/app/assets/javascripts/jira_connect/branches/index.js index 04510fcff4bfc8a611da8087c0e26942591aaa8e..a9a56a6362e682c87b58f5f771e874ea58025cd9 100644 --- a/app/assets/javascripts/jira_connect/branches/index.js +++ b/app/assets/javascripts/jira_connect/branches/index.js @@ -5,7 +5,7 @@ import createDefaultClient from '~/lib/graphql'; Vue.use(VueApollo); -export default async function initJiraConnectBranches() { +export default function initJiraConnectBranches() { const el = document.querySelector('.js-jira-connect-create-branch'); if (!el) { return null; diff --git a/app/assets/javascripts/jira_connect/subscriptions/components/app.vue b/app/assets/javascripts/jira_connect/subscriptions/components/app.vue index c0504cbb6453fcfe1a515da7bfead189a2e75204..7fd4cc38f1146cf15bc615b2595f794c5f863519 100644 --- a/app/assets/javascripts/jira_connect/subscriptions/components/app.vue +++ b/app/assets/javascripts/jira_connect/subscriptions/components/app.vue @@ -7,6 +7,7 @@ import { SET_ALERT } from '../store/mutation_types'; import SubscriptionsList from './subscriptions_list.vue'; import AddNamespaceButton from './add_namespace_button.vue'; import SignInButton from './sign_in_button.vue'; +import UserLink from './user_link.vue'; export default { name: 'JiraConnectApp', @@ -18,6 +19,7 @@ export default { SubscriptionsList, AddNamespaceButton, SignInButton, + UserLink, }, inject: { usersPath: { @@ -74,6 +76,8 @@ export default { </template> </gl-alert> + <user-link :user-signed-in="userSignedIn" :has-subscriptions="hasSubscriptions" /> + <h2 class="gl-text-center gl-mb-7">{{ s__('JiraService|GitLab for Jira Configuration') }}</h2> <div class="jira-connect-app-body gl-mx-auto gl-px-5 gl-mb-7"> <template v-if="hasSubscriptions"> diff --git a/app/assets/javascripts/jira_connect/subscriptions/components/user_link.vue b/app/assets/javascripts/jira_connect/subscriptions/components/user_link.vue new file mode 100644 index 0000000000000000000000000000000000000000..fad3d2616d80175997c57448069562f033873038 --- /dev/null +++ b/app/assets/javascripts/jira_connect/subscriptions/components/user_link.vue @@ -0,0 +1,67 @@ +<script> +import { GlLink, GlSprintf } from '@gitlab/ui'; +import { __ } from '~/locale'; +import { getGitlabSignInURL } from '~/jira_connect/subscriptions/utils'; + +export default { + components: { + GlLink, + GlSprintf, + }, + inject: { + usersPath: { + default: '', + }, + gitlabUserPath: { + default: '', + }, + }, + props: { + userSignedIn: { + type: Boolean, + required: true, + }, + hasSubscriptions: { + type: Boolean, + required: true, + }, + }, + data() { + return { + signInURL: '', + }; + }, + computed: { + gitlabUserHandle() { + return `@${gon.current_username}`; + }, + }, + async created() { + this.signInURL = await getGitlabSignInURL(this.usersPath); + }, + i18n: { + signInText: __('Sign in to GitLab'), + signedInAsUserText: __('Signed in to GitLab as %{user_link}'), + }, +}; +</script> +<template> + <div class="jira-connect-user gl-font-base"> + <gl-sprintf v-if="userSignedIn" :message="$options.i18n.signedInAsUserText"> + <template #user_link> + <gl-link data-testid="gitlab-user-link" :href="gitlabUserPath" target="_blank"> + {{ gitlabUserHandle }} + </gl-link> + </template> + </gl-sprintf> + + <gl-link + v-else-if="hasSubscriptions" + data-testid="sign-in-link" + :href="signInURL" + target="_blank" + > + {{ $options.i18n.signInText }} + </gl-link> + </div> +</template> diff --git a/app/assets/javascripts/jira_connect/subscriptions/index.js b/app/assets/javascripts/jira_connect/subscriptions/index.js index 8a7a80d885d85fe9b628da248fd6da09fe1b8c3f..cd1fc1d4455d861008b7694e0230f7accabbde18 100644 --- a/app/assets/javascripts/jira_connect/subscriptions/index.js +++ b/app/assets/javascripts/jira_connect/subscriptions/index.js @@ -7,25 +7,11 @@ import Translate from '~/vue_shared/translate'; import JiraConnectApp from './components/app.vue'; import createStore from './store'; -import { getGitlabSignInURL, sizeToParent } from './utils'; +import { sizeToParent } from './utils'; const store = createStore(); -/** - * Add `return_to` query param to all HAML-defined GitLab sign in links. - */ -const updateSignInLinks = async () => { - await Promise.all( - Array.from(document.querySelectorAll('.js-jira-connect-sign-in')).map(async (el) => { - const updatedLink = await getGitlabSignInURL(el.getAttribute('href')); - el.setAttribute('href', updatedLink); - }), - ); -}; - -export async function initJiraConnect() { - await updateSignInLinks(); - +export function initJiraConnect() { const el = document.querySelector('.js-jira-connect-app'); if (!el) { return null; @@ -35,7 +21,7 @@ export async function initJiraConnect() { Vue.use(Translate); Vue.use(GlFeatureFlagsPlugin); - const { groupsPath, subscriptions, subscriptionsPath, usersPath } = el.dataset; + const { groupsPath, subscriptions, subscriptionsPath, usersPath, gitlabUserPath } = el.dataset; sizeToParent(); return new Vue({ @@ -46,6 +32,7 @@ export async function initJiraConnect() { subscriptions: JSON.parse(subscriptions), subscriptionsPath, usersPath, + gitlabUserPath, }, render(createElement) { return createElement(JiraConnectApp); diff --git a/app/helpers/jira_connect_helper.rb b/app/helpers/jira_connect_helper.rb index 475469a6df9d73842b7d693a004829f880bc23b4..9a0f0944fd16d90c5da0e6e1cd02af5e5f2e4431 100644 --- a/app/helpers/jira_connect_helper.rb +++ b/app/helpers/jira_connect_helper.rb @@ -8,7 +8,8 @@ def jira_connect_app_data(subscriptions) groups_path: api_v4_groups_path(params: { min_access_level: Gitlab::Access::MAINTAINER, skip_groups: skip_groups }), subscriptions: subscriptions.map { |s| serialize_subscription(s) }.to_json, subscriptions_path: jira_connect_subscriptions_path, - users_path: current_user ? nil : jira_connect_users_path + users_path: current_user ? nil : jira_connect_users_path, # users_path is used to determine if user is signed in + gitlab_user_path: current_user ? user_path(current_user) : nil } end diff --git a/app/views/jira_connect/subscriptions/index.html.haml b/app/views/jira_connect/subscriptions/index.html.haml index be2be7288f8b9fb87a082aa12d164cde2f0fb3fd..d92c30c88405c5882098d091f84e1aae2f8af7bb 100644 --- a/app/views/jira_connect/subscriptions/index.html.haml +++ b/app/views/jira_connect/subscriptions/index.html.haml @@ -1,13 +1,6 @@ %header.jira-connect-header.gl-display-flex.gl-align-items-center.gl-justify-content-center.gl-px-5.gl-border-b-solid.gl-border-b-gray-100.gl-border-b-1.gl-bg-white = link_to brand_header_logo, Gitlab.config.gitlab.url, target: '_blank', rel: 'noopener noreferrer' -.jira-connect-user.gl-font-base - - if current_user - - user_link = link_to(current_user.to_reference, jira_connect_users_path, target: '_blank', rel: 'noopener noreferrer', class: 'js-jira-connect-sign-in') - = _('Signed in to GitLab as %{user_link}').html_safe % { user_link: user_link } - - elsif @subscriptions.present? - = link_to _('Sign in to GitLab'), jira_connect_users_path, target: '_blank', rel: 'noopener noreferrer', class: 'js-jira-connect-sign-in' - %main.jira-connect-app.gl-px-5.gl-pt-7.gl-mx-auto .js-jira-connect-app{ data: jira_connect_app_data(@subscriptions) } diff --git a/spec/frontend/jira_connect/subscriptions/components/app_spec.js b/spec/frontend/jira_connect/subscriptions/components/app_spec.js index 8e46496845362b89e42e301482854501cecd7301..47fe96262eec299f5b089d1ea66f1d836ffd9761 100644 --- a/spec/frontend/jira_connect/subscriptions/components/app_spec.js +++ b/spec/frontend/jira_connect/subscriptions/components/app_spec.js @@ -5,6 +5,7 @@ import JiraConnectApp from '~/jira_connect/subscriptions/components/app.vue'; import AddNamespaceButton from '~/jira_connect/subscriptions/components/add_namespace_button.vue'; import SignInButton from '~/jira_connect/subscriptions/components/sign_in_button.vue'; import SubscriptionsList from '~/jira_connect/subscriptions/components/subscriptions_list.vue'; +import UserLink from '~/jira_connect/subscriptions/components/user_link.vue'; import createStore from '~/jira_connect/subscriptions/store'; import { SET_ALERT } from '~/jira_connect/subscriptions/store/mutation_types'; import { __ } from '~/locale'; @@ -12,6 +13,7 @@ import { mockSubscription } from '../mock_data'; jest.mock('~/jira_connect/subscriptions/utils', () => ({ retrieveAlert: jest.fn().mockReturnValue({ message: 'error message' }), + getGitlabSignInURL: jest.fn(), })); describe('JiraConnectApp', () => { @@ -83,6 +85,22 @@ describe('JiraConnectApp', () => { }); }, ); + + it('renders UserLink component', () => { + createComponent({ + provide: { + usersPath: '/user', + subscriptions: [], + }, + }); + + const userLink = wrapper.findComponent(UserLink); + expect(userLink.exists()).toBe(true); + expect(userLink.props()).toEqual({ + hasSubscriptions: false, + userSignedIn: false, + }); + }); }); describe('alert', () => { diff --git a/spec/frontend/jira_connect/subscriptions/components/user_link_spec.js b/spec/frontend/jira_connect/subscriptions/components/user_link_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..b98a36269a322e328e57bf5ea3f3c84868d455d1 --- /dev/null +++ b/spec/frontend/jira_connect/subscriptions/components/user_link_spec.js @@ -0,0 +1,91 @@ +import { GlSprintf } from '@gitlab/ui'; +import UserLink from '~/jira_connect/subscriptions/components/user_link.vue'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import waitForPromises from 'helpers/wait_for_promises'; + +jest.mock('~/jira_connect/subscriptions/utils', () => ({ + getGitlabSignInURL: jest.fn().mockImplementation((path) => Promise.resolve(path)), +})); + +describe('SubscriptionsList', () => { + let wrapper; + + const createComponent = (propsData = {}, { provide } = {}) => { + wrapper = shallowMountExtended(UserLink, { + propsData, + provide, + stubs: { + GlSprintf, + }, + }); + }; + + const findSignInLink = () => wrapper.findByTestId('sign-in-link'); + const findGitlabUserLink = () => wrapper.findByTestId('gitlab-user-link'); + const findSprintf = () => wrapper.findComponent(GlSprintf); + + afterEach(() => { + wrapper.destroy(); + }); + + describe.each` + userSignedIn | hasSubscriptions | expectGlSprintf | expectGlLink + ${true} | ${false} | ${true} | ${false} + ${false} | ${true} | ${false} | ${true} + ${true} | ${true} | ${true} | ${false} + ${false} | ${false} | ${false} | ${false} + `( + 'when `userSignedIn` is $userSignedIn and `hasSubscriptions` is $hasSubscriptions', + ({ userSignedIn, hasSubscriptions, expectGlSprintf, expectGlLink }) => { + it('renders template correctly', () => { + createComponent({ + userSignedIn, + hasSubscriptions, + }); + + expect(findSprintf().exists()).toBe(expectGlSprintf); + expect(findSignInLink().exists()).toBe(expectGlLink); + }); + }, + ); + + describe('sign in link', () => { + it('renders with correct href', async () => { + const mockUsersPath = '/user'; + createComponent( + { + userSignedIn: false, + hasSubscriptions: true, + }, + { provide: { usersPath: mockUsersPath } }, + ); + + await waitForPromises(); + + expect(findSignInLink().exists()).toBe(true); + expect(findSignInLink().attributes('href')).toBe(mockUsersPath); + }); + }); + + describe('gitlab user link', () => { + window.gon = { current_username: 'root' }; + + beforeEach(() => { + createComponent( + { + userSignedIn: true, + hasSubscriptions: true, + }, + { provide: { gitlabUserPath: '/root' } }, + ); + }); + + it('renders with correct href', () => { + expect(findGitlabUserLink().attributes('href')).toBe('/root'); + }); + + it('contains GitLab user handle', () => { + expect(findGitlabUserLink().text()).toBe('@root'); + }); + }); +}); diff --git a/spec/frontend/jira_connect/subscriptions/index_spec.js b/spec/frontend/jira_connect/subscriptions/index_spec.js deleted file mode 100644 index b97918a198e6df57fe542c3526e2a8a179cc0bea..0000000000000000000000000000000000000000 --- a/spec/frontend/jira_connect/subscriptions/index_spec.js +++ /dev/null @@ -1,36 +0,0 @@ -import { initJiraConnect } from '~/jira_connect/subscriptions'; -import { getGitlabSignInURL } from '~/jira_connect/subscriptions/utils'; - -jest.mock('~/jira_connect/subscriptions/utils'); - -describe('initJiraConnect', () => { - const mockInitialHref = 'https://gitlab.com'; - - beforeEach(() => { - setFixtures(` - <a class="js-jira-connect-sign-in" href="${mockInitialHref}">Sign In</a> - <a class="js-jira-connect-sign-in" href="${mockInitialHref}">Another Sign In</a> - `); - }); - - const assertSignInLinks = (expectedLink) => { - Array.from(document.querySelectorAll('.js-jira-connect-sign-in')).forEach((el) => { - expect(el.getAttribute('href')).toBe(expectedLink); - }); - }; - - describe('Sign in links', () => { - it('are updated on initialization', async () => { - const mockSignInLink = `https://gitlab.com?return_to=${encodeURIComponent('/test/location')}`; - getGitlabSignInURL.mockResolvedValue(mockSignInLink); - - // assert the initial state - assertSignInLinks(mockInitialHref); - - await initJiraConnect(); - - // assert the update has occurred - assertSignInLinks(mockSignInLink); - }); - }); -}); diff --git a/spec/helpers/jira_connect_helper_spec.rb b/spec/helpers/jira_connect_helper_spec.rb index 55a5c724665df7ce507c08a565ae14a418f87fe5..0f78185dc7d69623b77470a92042b8c276647209 100644 --- a/spec/helpers/jira_connect_helper_spec.rb +++ b/spec/helpers/jira_connect_helper_spec.rb @@ -19,7 +19,9 @@ is_expected.to include( :groups_path, :subscriptions_path, - :users_path + :users_path, + :subscriptions, + :gitlab_user_path ) end @@ -32,6 +34,10 @@ expect(subject[:groups_path]).to include("#{skip_groups_param}=#{subscription.namespace.id}") end + + it 'assigns gitlab_user_path to nil' do + expect(subject[:gitlab_user_path]).to be_nil + end end context 'user is logged in' do @@ -42,6 +48,10 @@ it 'assigns users_path to nil' do expect(subject[:users_path]).to be_nil end + + it 'assigns gitlab_user_path correctly' do + expect(subject[:gitlab_user_path]).to eq(user_path(user)) + end end end end diff --git a/spec/views/jira_connect/subscriptions/index.html.haml_spec.rb b/spec/views/jira_connect/subscriptions/index.html.haml_spec.rb deleted file mode 100644 index 0a4d283a983a0f7533b4bb004bcbb52b64b05916..0000000000000000000000000000000000000000 --- a/spec/views/jira_connect/subscriptions/index.html.haml_spec.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'jira_connect/subscriptions/index.html.haml' do - let(:user) { build_stubbed(:user) } - - before do - allow(view).to receive(:current_user).and_return(user) - assign(:subscriptions, create_list(:jira_connect_subscription, 1)) - end - - context 'when the user is signed in' do - it 'shows link to user profile' do - render - - expect(rendered).to have_link(user.to_reference) - end - end - - context 'when the user is not signed in' do - let(:user) { nil } - - it 'shows "Sign in" link' do - render - - expect(rendered).to have_link('Sign in to GitLab') - end - end -end