Commit 4f163766 authored by Simon Knox's avatar Simon Knox

Merge branch 'afontaine/add-buttons-back-to-environments' into 'master'

Add new environment and review app buttons back

See merge request gitlab-org/gitlab!75947
parents 44609bdc 6071b0e9
......@@ -12,11 +12,20 @@ export default {
ModalCopyButton,
},
inject: ['defaultBranchName'],
model: {
prop: 'visible',
event: 'change',
},
props: {
modalId: {
type: String,
required: true,
},
visible: {
type: Boolean,
required: false,
default: false,
},
},
instructionText: {
step1: s__(
......@@ -57,12 +66,15 @@ export default {
</script>
<template>
<gl-modal
:visible="visible"
:modal-id="modalId"
:title="$options.modalInfo.title"
static
size="lg"
ok-only
ok-variant="light"
:ok-title="$options.modalInfo.closeText"
@change="$emit('change', $event)"
>
<p>
<gl-sprintf :message="$options.instructionText.step1">
......
<script>
import { GlBadge, GlTab, GlTabs } from '@gitlab/ui';
import { s__ } from '~/locale';
import environmentAppQuery from '../graphql/queries/environment_app.query.graphql';
import pollIntervalQuery from '../graphql/queries/poll_interval.query.graphql';
import EnvironmentFolder from './new_environment_folder.vue';
import EnableReviewAppModal from './enable_review_app_modal.vue';
export default {
components: {
EnvironmentFolder,
EnableReviewAppModal,
GlBadge,
GlTab,
GlTabs,
......@@ -22,22 +25,73 @@ export default {
query: pollIntervalQuery,
},
},
inject: ['newEnvironmentPath', 'canCreateEnvironment'],
i18n: {
newEnvironmentButtonLabel: s__('Environments|New environment'),
reviewAppButtonLabel: s__('Environments|Enable review app'),
},
modalId: 'enable-review-app-info',
data() {
return { interval: undefined };
return { interval: undefined, isReviewAppModalVisible: false };
},
computed: {
canSetupReviewApp() {
return this.environmentApp?.reviewApp?.canSetupReviewApp;
},
folders() {
return this.environmentApp?.environments.filter((e) => e.size > 1) ?? [];
},
availableCount() {
return this.environmentApp?.availableCount;
},
addEnvironment() {
if (!this.canCreateEnvironment) {
return null;
}
return {
text: this.$options.i18n.newEnvironmentButtonLabel,
attributes: {
href: this.newEnvironmentPath,
category: 'primary',
variant: 'confirm',
},
};
},
openReviewAppModal() {
if (!this.canSetupReviewApp) {
return null;
}
return {
text: this.$options.i18n.reviewAppButtonLabel,
attributes: {
category: 'secondary',
variant: 'confirm',
},
};
},
},
methods: {
showReviewAppModal() {
this.isReviewAppModalVisible = true;
},
},
};
</script>
<template>
<div>
<gl-tabs>
<enable-review-app-modal
v-if="canSetupReviewApp"
v-model="isReviewAppModalVisible"
:modal-id="$options.modalId"
data-testid="enable-review-app-modal"
/>
<gl-tabs
:action-secondary="addEnvironment"
:action-primary="openReviewAppModal"
@primary="showReviewAppModal"
>
<gl-tab>
<template #title>
<span>{{ __('Available') }}</span>
......
import { shallowMount } from '@vue/test-utils';
import { GlModal } from '@gitlab/ui';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import EnableReviewAppButton from '~/environments/components/enable_review_app_modal.vue';
import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
describe('Enable Review App Button', () => {
let wrapper;
let modal;
afterEach(() => {
wrapper.destroy();
......@@ -16,12 +18,15 @@ describe('Enable Review App Button', () => {
shallowMount(EnableReviewAppButton, {
propsData: {
modalId: 'fake-id',
visible: true,
},
provide: {
defaultBranchName: 'main',
},
}),
);
modal = wrapper.findComponent(GlModal);
});
it('renders the defaultBranchName copy', () => {
......@@ -32,5 +37,15 @@ describe('Enable Review App Button', () => {
it('renders the copyToClipboard button', () => {
expect(wrapper.findComponent(ModalCopyButton).exists()).toBe(true);
});
it('emits change events from the modal up', () => {
modal.vm.$emit('change', false);
expect(wrapper.emitted('change')).toEqual([[false]]);
});
it('passes visible to the modal', () => {
expect(modal.props('visible')).toBe(true);
});
});
});
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { mount } from '@vue/test-utils';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { s__ } from '~/locale';
import EnvironmentsApp from '~/environments/components/new_environments_app.vue';
import EnvironmentsFolder from '~/environments/components/new_environment_folder.vue';
import { resolvedEnvironmentsApp, resolvedFolder } from './graphql/mock_data';
......@@ -22,7 +23,16 @@ describe('~/environments/components/new_environments_app.vue', () => {
return createMockApollo([], mockResolvers);
};
const createWrapper = (apolloProvider) => mount(EnvironmentsApp, { apolloProvider });
const createWrapper = ({ provide = {}, apolloProvider } = {}) =>
mountExtended(EnvironmentsApp, {
provide: {
newEnvironmentPath: '/environments/new',
canCreateEnvironment: true,
defaultBranchName: 'main',
...provide,
},
apolloProvider,
});
beforeEach(() => {
environmentAppMock = jest.fn();
......@@ -37,7 +47,7 @@ describe('~/environments/components/new_environments_app.vue', () => {
environmentAppMock.mockReturnValue(resolvedEnvironmentsApp);
environmentFolderMock.mockReturnValue(resolvedFolder);
const apolloProvider = createApolloProvider();
wrapper = createWrapper(apolloProvider);
wrapper = createWrapper({ apolloProvider });
await waitForPromises();
await Vue.nextTick();
......@@ -47,4 +57,66 @@ describe('~/environments/components/new_environments_app.vue', () => {
expect(text).toContainEqual(expect.stringMatching('review'));
expect(text).not.toContainEqual(expect.stringMatching('production'));
});
it('should show a button to create a new environment', async () => {
environmentAppMock.mockReturnValue(resolvedEnvironmentsApp);
environmentFolderMock.mockReturnValue(resolvedFolder);
const apolloProvider = createApolloProvider();
wrapper = createWrapper({ apolloProvider });
await waitForPromises();
await Vue.nextTick();
const button = wrapper.findByRole('link', { name: s__('Environments|New environment') });
expect(button.attributes('href')).toBe('/environments/new');
});
it('should not show a button to create a new environment if the user has no permissions', async () => {
environmentAppMock.mockReturnValue(resolvedEnvironmentsApp);
environmentFolderMock.mockReturnValue(resolvedFolder);
const apolloProvider = createApolloProvider();
wrapper = createWrapper({
apolloProvider,
provide: { canCreateEnvironment: false, newEnvironmentPath: '' },
});
await waitForPromises();
await Vue.nextTick();
const button = wrapper.findByRole('link', { name: s__('Environments|New environment') });
expect(button.exists()).toBe(false);
});
it('should show a button to open the review app modal', async () => {
environmentAppMock.mockReturnValue(resolvedEnvironmentsApp);
environmentFolderMock.mockReturnValue(resolvedFolder);
const apolloProvider = createApolloProvider();
wrapper = createWrapper({ apolloProvider });
await waitForPromises();
await Vue.nextTick();
const button = wrapper.findByRole('button', { name: s__('Environments|Enable review app') });
button.trigger('click');
await Vue.nextTick();
expect(wrapper.findByText(s__('ReviewApp|Enable Review App')).exists()).toBe(true);
});
it('should not show a button to open the review app modal if review apps are configured', async () => {
environmentAppMock.mockReturnValue({
...resolvedEnvironmentsApp,
reviewApp: { canSetupReviewApp: false },
});
environmentFolderMock.mockReturnValue(resolvedFolder);
const apolloProvider = createApolloProvider();
wrapper = createWrapper({ apolloProvider });
await waitForPromises();
await Vue.nextTick();
const button = wrapper.findByRole('button', { name: s__('Environments|Enable review app') });
expect(button.exists()).toBe(false);
});
});
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