Commit 49c4f444 authored by David O'Regan's avatar David O'Regan

Merge branch 'afontaine/new-environment-delete' into 'master'

Make Environment Delete work with GraphQL

See merge request gitlab-org/gitlab!75758
parents 20700e72 2b07f98e
<script>
import { GlTooltipDirective, GlModal } from '@gitlab/ui';
import createFlash from '~/flash';
import { __, s__, sprintf } from '~/locale';
import eventHub from '../event_hub';
import deleteEnvironmentMutation from '../graphql/mutations/delete_environment.mutation.graphql';
export default {
id: 'delete-environment-modal',
......@@ -17,6 +19,11 @@ export default {
type: Object,
required: true,
},
graphql: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
primaryProps() {
......@@ -49,7 +56,29 @@ export default {
},
methods: {
onSubmit() {
eventHub.$emit('deleteEnvironment', this.environment);
if (this.graphql) {
this.$apollo
.mutate({
mutation: deleteEnvironmentMutation,
variables: { environment: this.environment },
})
.then(([message]) => {
if (message) {
createFlash({ message });
}
})
.catch((error) =>
createFlash({
message: s__(
'Environments|An error occurred while deleting the environment. Check if the environment stopped; if not, stop it and try again.',
),
error,
captureError: true,
}),
);
} else {
eventHub.$emit('deleteEnvironment', this.environment);
}
},
},
};
......
......@@ -7,6 +7,7 @@
import { GlDropdownItem, GlModalDirective } from '@gitlab/ui';
import { s__ } from '~/locale';
import eventHub from '../event_hub';
import setEnvironmentToDelete from '../graphql/mutations/set_environment_to_delete.mutation.graphql';
export default {
components: {
......@@ -20,6 +21,11 @@ export default {
type: Object,
required: true,
},
graphql: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
......@@ -30,14 +36,25 @@ export default {
title: s__('Environments|Delete environment'),
},
mounted() {
eventHub.$on('deleteEnvironment', this.onDeleteEnvironment);
if (!this.graphql) {
eventHub.$on('deleteEnvironment', this.onDeleteEnvironment);
}
},
beforeDestroy() {
eventHub.$off('deleteEnvironment', this.onDeleteEnvironment);
if (!this.graphql) {
eventHub.$off('deleteEnvironment', this.onDeleteEnvironment);
}
},
methods: {
onClick() {
eventHub.$emit('requestDeleteEnvironment', this.environment);
if (this.graphql) {
this.$apollo.mutate({
mutation: setEnvironmentToDelete,
variables: { environment: this.environment },
});
} else {
eventHub.$emit('requestDeleteEnvironment', this.environment);
}
},
onDeleteEnvironment(environment) {
if (this.environment.id === environment.id) {
......
mutation SetEnvironmentToDelete($environment: Environment) {
setEnvironmentToDelete(environment: $environment) @client
}
query environmentToDelete {
environmentToDelete @client {
id
name
deletePath
}
}
......@@ -3,6 +3,7 @@ import { s__ } from '~/locale';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import pollIntervalQuery from './queries/poll_interval.query.graphql';
import environmentToRollbackQuery from './queries/environment_to_rollback.query.graphql';
import environmentToDeleteQuery from './queries/environment_to_delete.query.graphql';
const buildErrors = (errors = []) => ({
errors,
......@@ -67,7 +68,16 @@ export const resolvers = (endpoint) => ({
});
},
deleteEnvironment(_, { environment: { deletePath } }) {
return axios.delete(deletePath);
return axios
.delete(deletePath)
.then(() => buildErrors())
.catch(() =>
buildErrors([
s__(
'Environments|An error occurred while deleting the environment. Check if the environment stopped; if not, stop it and try again.',
),
]),
);
},
rollbackEnvironment(_, { environment, isLastDeployment }) {
return axios
......@@ -85,6 +95,12 @@ export const resolvers = (endpoint) => ({
]);
});
},
setEnvironmentToDelete(_, { environment }, { client }) {
client.writeQuery({
query: environmentToDeleteQuery,
data: { environmentToDelete: environment },
});
},
setEnvironmentToRollback(_, { environment }, { client }) {
client.writeQuery({
query: environmentToRollbackQuery,
......
......@@ -58,6 +58,7 @@ type LocalErrors {
extend type Query {
environmentApp: LocalEnvironmentApp
folder(environment: NestedLocalEnvironmentInput): LocalEnvironmentFolder
environmentToDelete: LocalEnvironment
environmentToRollback: LocalEnvironment
isLastDeployment: Boolean
}
......@@ -67,5 +68,6 @@ extend type Mutation {
deleteEnvironment(environment: LocalEnvironmentInput): LocalErrors
rollbackEnvironment(environment: LocalEnvironmentInput): LocalErrors
cancelAutoStop(environment: LocalEnvironmentInput): LocalErrors
setEnvironmentToDelete(environment: LocalEnvironmentInput): LocalErrors
setEnvironmentToRollback(environment: LocalEnvironmentInput): LocalErrors
}
import { GlModal } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import { s__, sprintf } from '~/locale';
import DeleteEnvironmentModal from '~/environments/components/delete_environment_modal.vue';
import createMockApollo from 'helpers/mock_apollo_helper';
import { resolvedEnvironment } from './graphql/mock_data';
Vue.use(VueApollo);
describe('~/environments/components/delete_environment_modal.vue', () => {
let mockApollo;
let deleteResolver;
let wrapper;
const createComponent = ({ props = {}, apolloProvider } = {}) => {
wrapper = shallowMount(DeleteEnvironmentModal, {
propsData: {
graphql: true,
environment: resolvedEnvironment,
...props,
},
apolloProvider,
});
};
beforeEach(() => {
deleteResolver = jest.fn();
mockApollo = createMockApollo([], {
Mutation: { deleteEnvironment: deleteResolver },
});
});
it('should confirm the environment to delete', () => {
createComponent({ apolloProvider: mockApollo });
expect(wrapper.text()).toBe(
sprintf(
s__(
`Environments|Deleting the '%{environmentName}' environment cannot be undone. Do you want to delete it anyway?`,
),
{
environmentName: resolvedEnvironment.name,
},
),
);
});
it('should send the delete mutation on primary', async () => {
createComponent({ apolloProvider: mockApollo });
wrapper.findComponent(GlModal).vm.$emit('primary');
await nextTick();
expect(deleteResolver).toHaveBeenCalledWith(
expect.anything(),
{ environment: resolvedEnvironment },
expect.anything(),
expect.anything(),
);
});
});
import { GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import setEnvironmentToDelete from '~/environments/graphql/mutations/set_environment_to_delete.mutation.graphql';
import DeleteComponent from '~/environments/components/environment_delete.vue';
import eventHub from '~/environments/event_hub';
import createMockApollo from 'helpers/mock_apollo_helper';
import { resolvedEnvironment } from './graphql/mock_data';
describe('External URL Component', () => {
let wrapper;
const createWrapper = () => {
const createWrapper = (props = {}, options = {}) => {
wrapper = shallowMount(DeleteComponent, {
...options,
propsData: {
environment: {},
environment: resolvedEnvironment,
...props,
},
});
};
const findDropdownItem = () => wrapper.find(GlDropdownItem);
beforeEach(() => {
jest.spyOn(window, 'confirm');
describe('event hub', () => {
beforeEach(() => {
createWrapper();
});
createWrapper();
});
it('should render a dropdown item to delete the environment', () => {
expect(findDropdownItem().exists()).toBe(true);
expect(wrapper.text()).toEqual('Delete environment');
expect(findDropdownItem().attributes('variant')).toBe('danger');
});
it('should render a dropdown item to delete the environment', () => {
expect(findDropdownItem().exists()).toBe(true);
expect(wrapper.text()).toEqual('Delete environment');
expect(findDropdownItem().attributes('variant')).toBe('danger');
it('emits requestDeleteEnvironment in the event hub when button is clicked', () => {
jest.spyOn(eventHub, '$emit');
findDropdownItem().vm.$emit('click');
expect(eventHub.$emit).toHaveBeenCalledWith('requestDeleteEnvironment', resolvedEnvironment);
});
});
it('emits requestDeleteEnvironment in the event hub when button is clicked', () => {
jest.spyOn(eventHub, '$emit');
findDropdownItem().vm.$emit('click');
expect(eventHub.$emit).toHaveBeenCalledWith('requestDeleteEnvironment', wrapper.vm.environment);
describe('graphql', () => {
Vue.use(VueApollo);
let mockApollo;
beforeEach(() => {
mockApollo = createMockApollo();
createWrapper(
{ graphql: true, environment: resolvedEnvironment },
{ apolloProvider: mockApollo },
);
});
it('should render a dropdown item to delete the environment', () => {
expect(findDropdownItem().exists()).toBe(true);
expect(wrapper.text()).toEqual('Delete environment');
expect(findDropdownItem().attributes('variant')).toBe('danger');
});
it('emits requestDeleteEnvironment in the event hub when button is clicked', () => {
jest.spyOn(mockApollo.defaultClient, 'mutate');
findDropdownItem().vm.$emit('click');
expect(mockApollo.defaultClient.mutate).toHaveBeenCalledWith({
mutation: setEnvironmentToDelete,
variables: { environment: resolvedEnvironment },
});
});
});
});
......@@ -2,6 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import { resolvers } from '~/environments/graphql/resolvers';
import environmentToRollback from '~/environments/graphql/queries/environment_to_rollback.query.graphql';
import environmentToDelete from '~/environments/graphql/queries/environment_to_delete.query.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
import pollIntervalQuery from '~/environments/graphql/queries/poll_interval.query.graphql';
import { TEST_HOST } from 'helpers/test_constants';
......@@ -135,4 +136,19 @@ describe('~/frontend/environments/graphql/resolvers', () => {
});
});
});
describe('setEnvironmentToDelete', () => {
it('should write the given environment to the cache', () => {
localState.client.writeQuery = jest.fn();
mockResolvers.Mutation.setEnvironmentToDelete(
null,
{ environment: resolvedEnvironment },
localState,
);
expect(localState.client.writeQuery).toHaveBeenCalledWith({
query: environmentToDelete,
data: { environmentToDelete: resolvedEnvironment },
});
});
});
});
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