Commit ed0c2f66 authored by Tom Quirk's avatar Tom Quirk

Create sign_in_button for Jira Connect App

In preparation for a layout re-organisation, this commit
abstracts the sign in button into its
own Vue component. Relevant tests have been
updated.

There are no user-facing changes in this MR.
parent 19d9aa5f
<script>
import { GlAlert, GlButton, GlLink, GlSprintf } from '@gitlab/ui';
import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui';
import { mapState, mapMutations } from 'vuex';
import { retrieveAlert, getLocation } from '~/jira_connect/subscriptions/utils';
import { retrieveAlert } from '~/jira_connect/subscriptions/utils';
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';
export default {
name: 'JiraConnectApp',
components: {
GlAlert,
GlButton,
GlLink,
GlSprintf,
SubscriptionsList,
AddNamespaceButton,
SignInButton,
},
inject: {
usersPath: {
default: '',
},
},
data() {
return {
location: '',
};
},
computed: {
...mapState(['alert']),
usersPathWithReturnTo() {
if (this.location) {
return `${this.usersPath}?return_to=${this.location}`;
}
return this.usersPath;
},
shouldShowAlert() {
return Boolean(this.alert?.message);
},
userSignedIn() {
return Boolean(!this.usersPath);
},
},
created() {
this.setInitialAlert();
this.setLocation();
},
methods: {
...mapMutations({
setAlert: SET_ALERT,
}),
async setLocation() {
this.location = await getLocation();
},
setInitialAlert() {
const { linkUrl, title, message, variant } = retrieveAlert() || {};
this.setAlert({ linkUrl, title, message, variant });
......@@ -82,15 +70,7 @@ export default {
<div class="jira-connect-app-body gl-my-7 gl-px-5 gl-pb-4">
<div class="gl-display-flex gl-justify-content-end">
<gl-button
v-if="usersPath"
category="primary"
variant="info"
class="gl-align-self-center"
:href="usersPathWithReturnTo"
target="_blank"
>{{ s__('Integrations|Sign in to add namespaces') }}</gl-button
>
<sign-in-button v-if="!userSignedIn" :users-path="usersPath" />
<add-namespace-button v-else />
</div>
......
<script>
import { GlButton } from '@gitlab/ui';
import { getLocation } from '~/jira_connect/subscriptions/utils';
import { objectToQuery } from '~/lib/utils/url_utility';
export default {
components: {
GlButton,
},
props: {
usersPath: {
type: String,
required: true,
},
},
data() {
return {
location: '',
};
},
computed: {
usersPathWithReturnTo() {
if (this.location) {
const queryParams = {
return_to: this.location,
};
return `${this.usersPath}?${objectToQuery(queryParams)}`;
}
return this.usersPath;
},
},
created() {
this.setLocation();
},
methods: {
async setLocation() {
this.location = await getLocation();
},
},
};
</script>
<template>
<gl-button category="primary" variant="info" :href="usersPathWithReturnTo" target="_blank">
<slot>
{{ s__('Integrations|Sign in to add namespaces') }}
</slot>
</gl-button>
</template>
......@@ -11,6 +11,9 @@ import { getLocation, sizeToParent } from './utils';
const store = createStore();
/**
* Add `return_to` query param to all HAML-defined GitLab sign in links.
*/
const updateSignInLinks = async () => {
const location = await getLocation();
Array.from(document.querySelectorAll('.js-jira-connect-sign-in')).forEach((el) => {
......
import { GlAlert, GlButton, GlLink } from '@gitlab/ui';
import { GlAlert, GlLink } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils';
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 createStore from '~/jira_connect/subscriptions/store';
import { SET_ALERT } from '~/jira_connect/subscriptions/store/mutation_types';
import { __ } from '~/locale';
jest.mock('~/jira_connect/subscriptions/utils', () => ({
retrieveAlert: jest.fn().mockReturnValue({ message: 'error message' }),
getLocation: jest.fn(),
}));
describe('JiraConnectApp', () => {
......@@ -18,7 +18,7 @@ describe('JiraConnectApp', () => {
const findAlert = () => wrapper.findComponent(GlAlert);
const findAlertLink = () => findAlert().findComponent(GlLink);
const findGlButton = () => wrapper.findComponent(GlButton);
const findSignInButton = () => wrapper.findComponent(SignInButton);
const findAddNamespaceButton = () => wrapper.findComponent(AddNamespaceButton);
const createComponent = ({ provide, mountFn = shallowMount } = {}) => {
......@@ -35,28 +35,25 @@ describe('JiraConnectApp', () => {
});
describe('template', () => {
describe('when user is not logged in', () => {
describe.each`
scenario | usersPath | expectSignInButton | expectNamespaceButton
${'user is not signed in'} | ${'/users'} | ${true} | ${false}
${'user is signed in'} | ${undefined} | ${false} | ${true}
`('when $scenario', ({ usersPath, expectSignInButton, expectNamespaceButton }) => {
beforeEach(() => {
createComponent({
provide: {
usersPath: '/users',
usersPath,
},
});
});
it('renders "Sign in" button', () => {
expect(findGlButton().text()).toBe('Sign in to add namespaces');
expect(findAddNamespaceButton().exists()).toBe(false);
});
});
describe('when user is logged in', () => {
beforeEach(() => {
createComponent();
it('renders sign in button as expected', () => {
expect(findSignInButton().exists()).toBe(expectSignInButton);
});
it('renders "Add namespace" button ', () => {
expect(findAddNamespaceButton().exists()).toBe(true);
it('renders "Add Namespace" button as expected', () => {
expect(findAddNamespaceButton().exists()).toBe(expectNamespaceButton);
});
});
......
import { GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { getLocation } from '~/jira_connect/subscriptions/utils';
import SignInButton from '~/jira_connect/subscriptions/components/sign_in_button.vue';
import waitForPromises from 'helpers/wait_for_promises';
const MOCK_USERS_PATH = '/user';
jest.mock('~/jira_connect/subscriptions/utils');
describe('SignInButton', () => {
let wrapper;
const createComponent = () => {
wrapper = shallowMount(SignInButton, {
propsData: {
usersPath: MOCK_USERS_PATH,
},
});
};
const findButton = () => wrapper.findComponent(GlButton);
afterEach(() => {
wrapper.destroy();
});
it('displays a button', () => {
createComponent();
expect(findButton().exists()).toBe(true);
});
describe.each`
getLocationValue | expectedHref
${''} | ${MOCK_USERS_PATH}
${undefined} | ${MOCK_USERS_PATH}
${'https://test.jira.com'} | ${`${MOCK_USERS_PATH}?return_to=${encodeURIComponent('https://test.jira.com')}`}
`('when getLocation resolves with `$getLocationValue`', ({ getLocationValue, expectedHref }) => {
it(`sets button href to ${expectedHref}`, async () => {
getLocation.mockResolvedValue(getLocationValue);
createComponent();
expect(getLocation).toHaveBeenCalled();
await waitForPromises();
expect(findButton().attributes('href')).toBe(expectedHref);
});
});
});
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