Commit 4c938b8c authored by Olena Horal-Koretska's avatar Olena Horal-Koretska

Merge branch 'afontaine/environments-graphql-stop' into 'master'

Make Environment Stop work with GraphQL

See merge request gitlab-org/gitlab!76886
parents 4044ef15 aced918d
...@@ -8,6 +8,8 @@ import { GlTooltipDirective, GlButton, GlModalDirective } from '@gitlab/ui'; ...@@ -8,6 +8,8 @@ import { GlTooltipDirective, GlButton, GlModalDirective } from '@gitlab/ui';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants'; import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import setEnvironmentToStopMutation from '../graphql/mutations/set_environment_to_stop.mutation.graphql';
import isEnvironmentStoppingQuery from '../graphql/queries/is_environment_stopping.query.graphql';
export default { export default {
components: { components: {
...@@ -22,6 +24,19 @@ export default { ...@@ -22,6 +24,19 @@ export default {
type: Object, type: Object,
required: true, required: true,
}, },
graphql: {
type: Boolean,
required: false,
default: false,
},
},
apollo: {
isEnvironmentStopping: {
query: isEnvironmentStoppingQuery,
variables() {
return { environment: this.environment };
},
},
}, },
i18n: { i18n: {
title: s__('Environments|Stop environment'), title: s__('Environments|Stop environment'),
...@@ -30,6 +45,7 @@ export default { ...@@ -30,6 +45,7 @@ export default {
data() { data() {
return { return {
isLoading: false, isLoading: false,
isEnvironmentStopping: false,
}; };
}, },
mounted() { mounted() {
...@@ -41,7 +57,14 @@ export default { ...@@ -41,7 +57,14 @@ export default {
methods: { methods: {
onClick() { onClick() {
this.$root.$emit(BV_HIDE_TOOLTIP, this.$options.stopEnvironmentTooltipId); this.$root.$emit(BV_HIDE_TOOLTIP, this.$options.stopEnvironmentTooltipId);
eventHub.$emit('requestStopEnvironment', this.environment); if (this.graphql) {
this.$apollo.mutate({
mutation: setEnvironmentToStopMutation,
variables: { environment: this.environment },
});
} else {
eventHub.$emit('requestStopEnvironment', this.environment);
}
}, },
onStopEnvironment(environment) { onStopEnvironment(environment) {
if (this.environment.id === environment.id) { if (this.environment.id === environment.id) {
...@@ -56,7 +79,7 @@ export default { ...@@ -56,7 +79,7 @@ export default {
<gl-button <gl-button
v-gl-tooltip="{ id: $options.stopEnvironmentTooltipId }" v-gl-tooltip="{ id: $options.stopEnvironmentTooltipId }"
v-gl-modal-directive="'stop-environment-modal'" v-gl-modal-directive="'stop-environment-modal'"
:loading="isLoading" :loading="isLoading || isEnvironmentStopping"
:title="$options.i18n.title" :title="$options.i18n.title"
:aria-label="$options.i18n.title" :aria-label="$options.i18n.title"
icon="stop" icon="stop"
......
...@@ -5,8 +5,10 @@ import { updateHistory, setUrlParams, queryToObject } from '~/lib/utils/url_util ...@@ -5,8 +5,10 @@ import { updateHistory, setUrlParams, queryToObject } from '~/lib/utils/url_util
import environmentAppQuery from '../graphql/queries/environment_app.query.graphql'; import environmentAppQuery from '../graphql/queries/environment_app.query.graphql';
import pollIntervalQuery from '../graphql/queries/poll_interval.query.graphql'; import pollIntervalQuery from '../graphql/queries/poll_interval.query.graphql';
import pageInfoQuery from '../graphql/queries/page_info.query.graphql'; import pageInfoQuery from '../graphql/queries/page_info.query.graphql';
import environmentToStopQuery from '../graphql/queries/environment_to_stop.query.graphql';
import EnvironmentFolder from './new_environment_folder.vue'; import EnvironmentFolder from './new_environment_folder.vue';
import EnableReviewAppModal from './enable_review_app_modal.vue'; import EnableReviewAppModal from './enable_review_app_modal.vue';
import StopEnvironmentModal from './stop_environment_modal.vue';
export default { export default {
components: { components: {
...@@ -16,6 +18,7 @@ export default { ...@@ -16,6 +18,7 @@ export default {
GlPagination, GlPagination,
GlTab, GlTab,
GlTabs, GlTabs,
StopEnvironmentModal,
}, },
apollo: { apollo: {
environmentApp: { environmentApp: {
...@@ -36,6 +39,9 @@ export default { ...@@ -36,6 +39,9 @@ export default {
pageInfo: { pageInfo: {
query: pageInfoQuery, query: pageInfoQuery,
}, },
environmentToStop: {
query: environmentToStopQuery,
},
}, },
inject: ['newEnvironmentPath', 'canCreateEnvironment'], inject: ['newEnvironmentPath', 'canCreateEnvironment'],
i18n: { i18n: {
...@@ -57,6 +63,7 @@ export default { ...@@ -57,6 +63,7 @@ export default {
isReviewAppModalVisible: false, isReviewAppModalVisible: false,
page: parseInt(page, 10), page: parseInt(page, 10),
scope, scope,
environmentToStop: {},
}; };
}, },
computed: { computed: {
...@@ -157,6 +164,7 @@ export default { ...@@ -157,6 +164,7 @@ export default {
:modal-id="$options.modalId" :modal-id="$options.modalId"
data-testid="enable-review-app-modal" data-testid="enable-review-app-modal"
/> />
<stop-environment-modal :environment="environmentToStop" graphql />
<gl-tabs <gl-tabs
:action-secondary="addEnvironment" :action-secondary="addEnvironment"
:action-primary="openReviewAppModal" :action-primary="openReviewAppModal"
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import { GlSprintf, GlTooltipDirective, GlModal } from '@gitlab/ui'; import { GlSprintf, GlTooltipDirective, GlModal } from '@gitlab/ui';
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import stopEnvironmentMutation from '../graphql/mutations/stop_environment.mutation.graphql';
export default { export default {
id: 'stop-environment-modal', id: 'stop-environment-modal',
...@@ -21,6 +22,11 @@ export default { ...@@ -21,6 +22,11 @@ export default {
type: Object, type: Object,
required: true, required: true,
}, },
graphql: {
type: Boolean,
required: false,
default: false,
},
}, },
computed: { computed: {
...@@ -39,7 +45,14 @@ export default { ...@@ -39,7 +45,14 @@ export default {
methods: { methods: {
onSubmit() { onSubmit() {
eventHub.$emit('stopEnvironment', this.environment); if (this.graphql) {
this.$apollo.mutate({
mutation: stopEnvironmentMutation,
variables: { environment: this.environment },
});
} else {
eventHub.$emit('stopEnvironment', this.environment);
}
}, },
}, },
}; };
......
mutation SetEnvironmentToStop($environment: LocalEnvironmentInput) {
setEnvironmentToStop(environment: $environment) @client
}
query isEnvironmentStopping($environment: LocalEnvironment) {
isEnvironmentStopping(environment: $environment) @client
}
...@@ -8,6 +8,7 @@ import { ...@@ -8,6 +8,7 @@ import {
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 environmentToStopQuery from './queries/environment_to_stop.query.graphql';
import environmentToDeleteQuery from './queries/environment_to_delete.query.graphql'; import environmentToDeleteQuery from './queries/environment_to_delete.query.graphql';
import pageInfoQuery from './queries/page_info.query.graphql'; import pageInfoQuery from './queries/page_info.query.graphql';
...@@ -108,6 +109,12 @@ export const resolvers = (endpoint) => ({ ...@@ -108,6 +109,12 @@ export const resolvers = (endpoint) => ({
]); ]);
}); });
}, },
setEnvironmentToStop(_, { environment }, { client }) {
client.writeQuery({
query: environmentToStopQuery,
data: { environmentToStop: environment },
});
},
setEnvironmentToDelete(_, { environment }, { client }) { setEnvironmentToDelete(_, { environment }, { client }) {
client.writeQuery({ client.writeQuery({
query: environmentToDeleteQuery, query: environmentToDeleteQuery,
......
...@@ -68,6 +68,8 @@ extend type Query { ...@@ -68,6 +68,8 @@ extend type Query {
environmentToDelete: LocalEnvironment environmentToDelete: LocalEnvironment
pageInfo: LocalPageInfo pageInfo: LocalPageInfo
environmentToRollback: LocalEnvironment environmentToRollback: LocalEnvironment
environmentToStop: LocalEnvironment
isEnvironmentStopping(environment: LocalEnvironmentInput): Boolean
isLastDeployment: Boolean isLastDeployment: Boolean
} }
...@@ -78,4 +80,5 @@ extend type Mutation { ...@@ -78,4 +80,5 @@ extend type Mutation {
cancelAutoStop(environment: LocalEnvironmentInput): LocalErrors cancelAutoStop(environment: LocalEnvironmentInput): LocalErrors
setEnvironmentToDelete(environment: LocalEnvironmentInput): LocalErrors setEnvironmentToDelete(environment: LocalEnvironmentInput): LocalErrors
setEnvironmentToRollback(environment: LocalEnvironmentInput): LocalErrors setEnvironmentToRollback(environment: LocalEnvironmentInput): LocalErrors
setEnvironmentToStop(environment: LocalEnvironmentInput): LocalErrors
} }
import { GlButton } from '@gitlab/ui'; import { GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import $ from 'jquery'; import Vue from 'vue';
import VueApollo from 'vue-apollo';
import setEnvironmentToStopMutation from '~/environments/graphql/mutations/set_environment_to_stop.mutation.graphql';
import isEnvironmentStoppingQuery from '~/environments/graphql/queries/is_environment_stopping.query.graphql';
import StopComponent from '~/environments/components/environment_stop.vue'; import StopComponent from '~/environments/components/environment_stop.vue';
import eventHub from '~/environments/event_hub'; import eventHub from '~/environments/event_hub';
import createMockApollo from 'helpers/mock_apollo_helper';
$.fn.tooltip = () => {}; import { resolvedEnvironment } from './graphql/mock_data';
describe('Stop Component', () => { describe('Stop Component', () => {
let wrapper; let wrapper;
const createWrapper = () => { const createWrapper = (props = {}, options = {}) => {
wrapper = shallowMount(StopComponent, { wrapper = shallowMount(StopComponent, {
propsData: { propsData: {
environment: {}, environment: {},
...props,
}, },
...options,
}); });
}; };
const findButton = () => wrapper.find(GlButton); const findButton = () => wrapper.find(GlButton);
beforeEach(() => { describe('eventHub', () => {
jest.spyOn(window, 'confirm'); beforeEach(() => {
createWrapper();
});
createWrapper(); it('should render a button to stop the environment', () => {
}); expect(findButton().exists()).toBe(true);
expect(wrapper.attributes('title')).toEqual('Stop environment');
});
it('should render a button to stop the environment', () => { it('emits requestStopEnvironment in the event hub when button is clicked', () => {
expect(findButton().exists()).toBe(true); jest.spyOn(eventHub, '$emit');
expect(wrapper.attributes('title')).toEqual('Stop environment'); findButton().vm.$emit('click');
expect(eventHub.$emit).toHaveBeenCalledWith('requestStopEnvironment', wrapper.vm.environment);
});
}); });
it('emits requestStopEnvironment in the event hub when button is clicked', () => { describe('graphql', () => {
jest.spyOn(eventHub, '$emit'); Vue.use(VueApollo);
findButton().vm.$emit('click'); let mockApollo;
expect(eventHub.$emit).toHaveBeenCalledWith('requestStopEnvironment', wrapper.vm.environment);
beforeEach(() => {
mockApollo = createMockApollo();
mockApollo.clients.defaultClient.writeQuery({
query: isEnvironmentStoppingQuery,
variables: { environment: resolvedEnvironment },
data: { isEnvironmentStopping: true },
});
createWrapper(
{ graphql: true, environment: resolvedEnvironment },
{ apolloProvider: mockApollo },
);
});
it('should render a button to stop the environment', () => {
expect(findButton().exists()).toBe(true);
expect(wrapper.attributes('title')).toEqual('Stop environment');
});
it('sets the environment to stop on click', () => {
jest.spyOn(mockApollo.defaultClient, 'mutate');
findButton().vm.$emit('click');
expect(mockApollo.defaultClient.mutate).toHaveBeenCalledWith({
mutation: setEnvironmentToStopMutation,
variables: { environment: resolvedEnvironment },
});
});
it('should show a loading icon if the environment is currently stopping', async () => {
expect(findButton().props('loading')).toBe(true);
});
}); });
}); });
...@@ -3,6 +3,7 @@ import axios from '~/lib/utils/axios_utils'; ...@@ -3,6 +3,7 @@ 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 environmentToDelete from '~/environments/graphql/queries/environment_to_delete.query.graphql';
import environmentToStopQuery from '~/environments/graphql/queries/environment_to_stop.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 pageInfoQuery from '~/environments/graphql/queries/page_info.query.graphql'; import pageInfoQuery from '~/environments/graphql/queries/page_info.query.graphql';
...@@ -210,4 +211,19 @@ describe('~/frontend/environments/graphql/resolvers', () => { ...@@ -210,4 +211,19 @@ describe('~/frontend/environments/graphql/resolvers', () => {
}); });
}); });
}); });
describe('setEnvironmentToStop', () => {
it('should write the given environment to the cache', () => {
localState.client.writeQuery = jest.fn();
mockResolvers.Mutation.setEnvironmentToStop(
null,
{ environment: resolvedEnvironment },
localState,
);
expect(localState.client.writeQuery).toHaveBeenCalledWith({
query: environmentToStopQuery,
data: { environmentToStop: resolvedEnvironment },
});
});
});
}); });
...@@ -8,7 +8,8 @@ import setWindowLocation from 'helpers/set_window_location_helper'; ...@@ -8,7 +8,8 @@ import setWindowLocation from 'helpers/set_window_location_helper';
import { sprintf, __, s__ } from '~/locale'; import { sprintf, __, s__ } from '~/locale';
import EnvironmentsApp from '~/environments/components/new_environments_app.vue'; import EnvironmentsApp from '~/environments/components/new_environments_app.vue';
import EnvironmentsFolder from '~/environments/components/new_environment_folder.vue'; import EnvironmentsFolder from '~/environments/components/new_environment_folder.vue';
import { resolvedEnvironmentsApp, resolvedFolder } from './graphql/mock_data'; import StopEnvironmentModal from '~/environments/components/stop_environment_modal.vue';
import { resolvedEnvironmentsApp, resolvedFolder, resolvedEnvironment } from './graphql/mock_data';
Vue.use(VueApollo); Vue.use(VueApollo);
...@@ -17,6 +18,7 @@ describe('~/environments/components/new_environments_app.vue', () => { ...@@ -17,6 +18,7 @@ describe('~/environments/components/new_environments_app.vue', () => {
let environmentAppMock; let environmentAppMock;
let environmentFolderMock; let environmentFolderMock;
let paginationMock; let paginationMock;
let environmentToStopMock;
const createApolloProvider = () => { const createApolloProvider = () => {
const mockResolvers = { const mockResolvers = {
...@@ -24,6 +26,7 @@ describe('~/environments/components/new_environments_app.vue', () => { ...@@ -24,6 +26,7 @@ describe('~/environments/components/new_environments_app.vue', () => {
environmentApp: environmentAppMock, environmentApp: environmentAppMock,
folder: environmentFolderMock, folder: environmentFolderMock,
pageInfo: paginationMock, pageInfo: paginationMock,
environmentToStop: environmentToStopMock,
}, },
}; };
...@@ -45,6 +48,7 @@ describe('~/environments/components/new_environments_app.vue', () => { ...@@ -45,6 +48,7 @@ describe('~/environments/components/new_environments_app.vue', () => {
provide = {}, provide = {},
environmentsApp, environmentsApp,
folder, folder,
environmentToStop = {},
pageInfo = { pageInfo = {
total: 20, total: 20,
perPage: 5, perPage: 5,
...@@ -58,6 +62,7 @@ describe('~/environments/components/new_environments_app.vue', () => { ...@@ -58,6 +62,7 @@ describe('~/environments/components/new_environments_app.vue', () => {
environmentAppMock.mockReturnValue(environmentsApp); environmentAppMock.mockReturnValue(environmentsApp);
environmentFolderMock.mockReturnValue(folder); environmentFolderMock.mockReturnValue(folder);
paginationMock.mockReturnValue(pageInfo); paginationMock.mockReturnValue(pageInfo);
environmentToStopMock.mockReturnValue(environmentToStop);
const apolloProvider = createApolloProvider(); const apolloProvider = createApolloProvider();
wrapper = createWrapper({ apolloProvider, provide }); wrapper = createWrapper({ apolloProvider, provide });
...@@ -68,6 +73,7 @@ describe('~/environments/components/new_environments_app.vue', () => { ...@@ -68,6 +73,7 @@ describe('~/environments/components/new_environments_app.vue', () => {
beforeEach(() => { beforeEach(() => {
environmentAppMock = jest.fn(); environmentAppMock = jest.fn();
environmentFolderMock = jest.fn(); environmentFolderMock = jest.fn();
environmentToStopMock = jest.fn();
paginationMock = jest.fn(); paginationMock = jest.fn();
}); });
...@@ -175,6 +181,20 @@ describe('~/environments/components/new_environments_app.vue', () => { ...@@ -175,6 +181,20 @@ describe('~/environments/components/new_environments_app.vue', () => {
}); });
}); });
describe('modals', () => {
it('should pass the environment to stop to the stop environment modal', async () => {
await createWrapperWithMocked({
environmentsApp: resolvedEnvironmentsApp,
folder: resolvedFolder,
environmentToStop: resolvedEnvironment,
});
const modal = wrapper.findComponent(StopEnvironmentModal);
expect(modal.props('environment')).toMatchObject(resolvedEnvironment);
});
});
describe('pagination', () => { describe('pagination', () => {
it('should sync page from query params on load', async () => { it('should sync page from query params on load', async () => {
await createWrapperWithMocked({ await createWrapperWithMocked({
......
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