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> <script>
import { GlTooltipDirective, GlModal } from '@gitlab/ui'; import { GlTooltipDirective, GlModal } from '@gitlab/ui';
import createFlash from '~/flash';
import { __, s__, sprintf } from '~/locale'; import { __, s__, sprintf } from '~/locale';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import deleteEnvironmentMutation from '../graphql/mutations/delete_environment.mutation.graphql';
export default { export default {
id: 'delete-environment-modal', id: 'delete-environment-modal',
...@@ -17,6 +19,11 @@ export default { ...@@ -17,6 +19,11 @@ export default {
type: Object, type: Object,
required: true, required: true,
}, },
graphql: {
type: Boolean,
required: false,
default: false,
},
}, },
computed: { computed: {
primaryProps() { primaryProps() {
...@@ -49,7 +56,29 @@ export default { ...@@ -49,7 +56,29 @@ export default {
}, },
methods: { methods: {
onSubmit() { 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 @@ ...@@ -7,6 +7,7 @@
import { GlDropdownItem, GlModalDirective } from '@gitlab/ui'; import { GlDropdownItem, GlModalDirective } from '@gitlab/ui';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import setEnvironmentToDelete from '../graphql/mutations/set_environment_to_delete.mutation.graphql';
export default { export default {
components: { components: {
...@@ -20,6 +21,11 @@ export default { ...@@ -20,6 +21,11 @@ export default {
type: Object, type: Object,
required: true, required: true,
}, },
graphql: {
type: Boolean,
required: false,
default: false,
},
}, },
data() { data() {
return { return {
...@@ -30,14 +36,25 @@ export default { ...@@ -30,14 +36,25 @@ export default {
title: s__('Environments|Delete environment'), title: s__('Environments|Delete environment'),
}, },
mounted() { mounted() {
eventHub.$on('deleteEnvironment', this.onDeleteEnvironment); if (!this.graphql) {
eventHub.$on('deleteEnvironment', this.onDeleteEnvironment);
}
}, },
beforeDestroy() { beforeDestroy() {
eventHub.$off('deleteEnvironment', this.onDeleteEnvironment); if (!this.graphql) {
eventHub.$off('deleteEnvironment', this.onDeleteEnvironment);
}
}, },
methods: { methods: {
onClick() { 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) { onDeleteEnvironment(environment) {
if (this.environment.id === environment.id) { 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'; ...@@ -3,6 +3,7 @@ import { s__ } from '~/locale';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import pollIntervalQuery from './queries/poll_interval.query.graphql'; import pollIntervalQuery from './queries/poll_interval.query.graphql';
import environmentToRollbackQuery from './queries/environment_to_rollback.query.graphql'; import environmentToRollbackQuery from './queries/environment_to_rollback.query.graphql';
import environmentToDeleteQuery from './queries/environment_to_delete.query.graphql';
const buildErrors = (errors = []) => ({ const buildErrors = (errors = []) => ({
errors, errors,
...@@ -67,7 +68,16 @@ export const resolvers = (endpoint) => ({ ...@@ -67,7 +68,16 @@ export const resolvers = (endpoint) => ({
}); });
}, },
deleteEnvironment(_, { environment: { deletePath } }) { 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 }) { rollbackEnvironment(_, { environment, isLastDeployment }) {
return axios return axios
...@@ -85,6 +95,12 @@ export const resolvers = (endpoint) => ({ ...@@ -85,6 +95,12 @@ export const resolvers = (endpoint) => ({
]); ]);
}); });
}, },
setEnvironmentToDelete(_, { environment }, { client }) {
client.writeQuery({
query: environmentToDeleteQuery,
data: { environmentToDelete: environment },
});
},
setEnvironmentToRollback(_, { environment }, { client }) { setEnvironmentToRollback(_, { environment }, { client }) {
client.writeQuery({ client.writeQuery({
query: environmentToRollbackQuery, query: environmentToRollbackQuery,
......
...@@ -58,6 +58,7 @@ type LocalErrors { ...@@ -58,6 +58,7 @@ type LocalErrors {
extend type Query { extend type Query {
environmentApp: LocalEnvironmentApp environmentApp: LocalEnvironmentApp
folder(environment: NestedLocalEnvironmentInput): LocalEnvironmentFolder folder(environment: NestedLocalEnvironmentInput): LocalEnvironmentFolder
environmentToDelete: LocalEnvironment
environmentToRollback: LocalEnvironment environmentToRollback: LocalEnvironment
isLastDeployment: Boolean isLastDeployment: Boolean
} }
...@@ -67,5 +68,6 @@ extend type Mutation { ...@@ -67,5 +68,6 @@ extend type Mutation {
deleteEnvironment(environment: LocalEnvironmentInput): LocalErrors deleteEnvironment(environment: LocalEnvironmentInput): LocalErrors
rollbackEnvironment(environment: LocalEnvironmentInput): LocalErrors rollbackEnvironment(environment: LocalEnvironmentInput): LocalErrors
cancelAutoStop(environment: LocalEnvironmentInput): LocalErrors cancelAutoStop(environment: LocalEnvironmentInput): LocalErrors
setEnvironmentToDelete(environment: LocalEnvironmentInput): LocalErrors
setEnvironmentToRollback(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 { GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; 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 DeleteComponent from '~/environments/components/environment_delete.vue';
import eventHub from '~/environments/event_hub'; import eventHub from '~/environments/event_hub';
import createMockApollo from 'helpers/mock_apollo_helper';
import { resolvedEnvironment } from './graphql/mock_data';
describe('External URL Component', () => { describe('External URL Component', () => {
let wrapper; let wrapper;
const createWrapper = () => { const createWrapper = (props = {}, options = {}) => {
wrapper = shallowMount(DeleteComponent, { wrapper = shallowMount(DeleteComponent, {
...options,
propsData: { propsData: {
environment: {}, environment: resolvedEnvironment,
...props,
}, },
}); });
}; };
const findDropdownItem = () => wrapper.find(GlDropdownItem); const findDropdownItem = () => wrapper.find(GlDropdownItem);
beforeEach(() => { describe('event hub', () => {
jest.spyOn(window, 'confirm'); 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', () => { it('emits requestDeleteEnvironment in the event hub when button is clicked', () => {
expect(findDropdownItem().exists()).toBe(true); jest.spyOn(eventHub, '$emit');
expect(wrapper.text()).toEqual('Delete environment'); findDropdownItem().vm.$emit('click');
expect(findDropdownItem().attributes('variant')).toBe('danger'); expect(eventHub.$emit).toHaveBeenCalledWith('requestDeleteEnvironment', resolvedEnvironment);
});
}); });
it('emits requestDeleteEnvironment in the event hub when button is clicked', () => { describe('graphql', () => {
jest.spyOn(eventHub, '$emit'); Vue.use(VueApollo);
findDropdownItem().vm.$emit('click'); let mockApollo;
expect(eventHub.$emit).toHaveBeenCalledWith('requestDeleteEnvironment', wrapper.vm.environment);
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'; ...@@ -2,6 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { resolvers } from '~/environments/graphql/resolvers'; import { resolvers } from '~/environments/graphql/resolvers';
import environmentToRollback from '~/environments/graphql/queries/environment_to_rollback.query.graphql'; 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 createMockApollo from 'helpers/mock_apollo_helper';
import pollIntervalQuery from '~/environments/graphql/queries/poll_interval.query.graphql'; import pollIntervalQuery from '~/environments/graphql/queries/poll_interval.query.graphql';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
...@@ -135,4 +136,19 @@ describe('~/frontend/environments/graphql/resolvers', () => { ...@@ -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