Commit e2dbb67b authored by Mike Greiling's avatar Mike Greiling Committed by Martin Wortschack

Add remove cluster confirm modal with multiple options

Adds a new modal which requires a user to explicitly confirm the
deletion of a cluster and allows them to delete all of its resources
as well.
parent 63cbf553
......@@ -12,6 +12,7 @@ import { APPLICATION_STATUS, INGRESS, INGRESS_DOMAIN_SUFFIX, CROSSPLANE } from '
import ClustersService from './services/clusters_service';
import ClustersStore from './stores/clusters_store';
import Applications from './components/applications.vue';
import RemoveClusterConfirmation from './components/remove_cluster_confirmation.vue';
import setupToggleButtons from '../toggle_buttons';
import initProjectSelectDropdown from '~/project_select';
......@@ -144,6 +145,8 @@ export default class Clusters {
() => this.handlePollError(),
);
}
this.initRemoveClusterActions();
}
initApplications(type) {
......@@ -205,6 +208,25 @@ export default class Clusters {
});
}
initRemoveClusterActions() {
const el = document.querySelector('#js-cluster-remove-actions');
if (el && el.dataset) {
const { clusterName, clusterPath } = el.dataset;
this.removeClusterAction = new Vue({
el,
render(createElement) {
return createElement(RemoveClusterConfirmation, {
props: {
clusterName,
clusterPath,
},
});
},
});
}
}
handleClusterEnvironmentsSuccess(data) {
this.store.toggleFetchEnvironments(false);
this.store.updateEnvironments(data.data);
......
<script>
import _ from 'underscore';
import SplitButton from '~/vue_shared/components/split_button.vue';
import { GlModal, GlButton, GlFormInput } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
import csrf from '~/lib/utils/csrf';
const splitButtonActionItems = [
{
title: s__('ClusterIntegration|Remove integration and resources'),
description: s__(
'ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal',
),
eventName: 'remove-cluster-and-cleanup',
},
{
title: s__('ClusterIntegration|Remove integration'),
description: s__(
'ClusterIntegration|Removes cluster from project but keeps associated resources',
),
eventName: 'remove-cluster',
},
];
export default {
splitButtonActionItems,
components: {
SplitButton,
GlModal,
GlButton,
GlFormInput,
},
props: {
clusterPath: {
type: String,
required: true,
},
clusterName: {
type: String,
required: true,
},
},
data() {
return {
enteredClusterName: '',
confirmCleanup: false,
};
},
computed: {
csrfToken() {
return csrf.token;
},
modalTitle() {
return this.confirmCleanup
? s__('ClusterIntegration|Remove integration and resources?')
: s__('ClusterIntegration|Remove integration?');
},
warningMessage() {
return this.confirmCleanup
? s__(
'ClusterIntegration|You are about to remove your cluster integration and all GitLab-created resources associated with this cluster.',
)
: s__('ClusterIntegration|You are about to remove your cluster integration.');
},
warningToBeRemoved() {
return s__(`ClusterIntegration|
This will permanently delete the following resources:
<ul>
<li>All installed applications and related resources</li>
<li>The <code>gitlab-managed-apps</code> namespace</li>
<li>Any project namespaces</li>
<li><code>clusterroles</code></li>
<li><code>clusterrolebindings</code></li>
</ul>
`);
},
confirmationTextLabel() {
return sprintf(
this.confirmCleanup
? s__(
'ClusterIntegration|To remove your integration and resources, type %{clusterName} to confirm:',
)
: s__('ClusterIntegration|To remove your integration, type %{clusterName} to confirm:'),
{
clusterName: `<code>${_.escape(this.clusterName)}</code>`,
},
false,
);
},
canSubmit() {
return this.enteredClusterName === this.clusterName;
},
},
methods: {
handleClickRemoveCluster(cleanup = false) {
this.confirmCleanup = cleanup;
this.$refs.modal.show();
},
handleCancel() {
this.$refs.modal.hide();
this.enteredClusterName = '';
},
handleSubmit(cleanup = false) {
this.$refs.cleanup.name = cleanup === true ? 'cleanup' : 'no_cleanup';
this.$refs.form.submit();
this.enteredClusterName = '';
},
},
};
</script>
<template>
<div>
<split-button
:action-items="$options.splitButtonActionItems"
menu-class="dropdown-menu-large"
variant="danger"
@remove-cluster="handleClickRemoveCluster(false)"
@remove-cluster-and-cleanup="handleClickRemoveCluster(true)"
/>
<gl-modal
ref="modal"
size="lg"
modal-id="delete-cluster-modal"
:title="modalTitle"
kind="danger"
>
<template>
<p>{{ warningMessage }}</p>
<div v-if="confirmCleanup" v-html="warningToBeRemoved"></div>
<strong v-html="confirmationTextLabel"></strong>
<form ref="form" :action="clusterPath" method="post" class="append-bottom-20">
<input ref="method" type="hidden" name="_method" value="delete" />
<input :value="csrfToken" type="hidden" name="authenticity_token" />
<input ref="cleanup" type="hidden" name="cleanup" value="true" />
<gl-form-input
v-model="enteredClusterName"
autofocus
type="text"
name="confirm_cluster_name_input"
autocomplete="off"
/>
</form>
<span v-if="confirmCleanup">{{
s__(
'ClusterIntegration|If you do not wish to delete all associated GitLab resources, you can simply remove the integration.',
)
}}</span>
</template>
<template slot="modal-footer">
<gl-button variant="secondary" @click="handleCancel">{{ s__('Cancel') }}</gl-button>
<template v-if="confirmCleanup">
<gl-button :disabled="!canSubmit" variant="warning" @click="handleSubmit">{{
s__('ClusterIntegration|Remove integration')
}}</gl-button>
<gl-button :disabled="!canSubmit" variant="danger" @click="handleSubmit(true)">{{
s__('ClusterIntegration|Remove integration and resources')
}}</gl-button>
</template>
<template v-else>
<gl-button :disabled="!canSubmit" variant="danger" @click="handleSubmit">{{
s__('ClusterIntegration|Remove integration')
}}</gl-button>
</template>
</template>
</gl-modal>
</div>
</template>
......@@ -26,6 +26,11 @@ export default {
required: false,
default: '',
},
variant: {
type: String,
required: false,
default: 'secondary',
},
},
data() {
......@@ -53,6 +58,7 @@ export default {
:menu-class="`dropdown-menu-selectable ${menuClass}`"
split
:text="dropdownToggleText"
:variant="variant"
v-bind="$attrs"
@click="triggerEvent"
>
......
......@@ -41,4 +41,5 @@
= s_('ClusterIntegration|Remove Kubernetes cluster integration')
%p
= s_("ClusterIntegration|Remove this Kubernetes cluster's configuration from this project. This will not delete your actual Kubernetes cluster.")
= link_to(s_('ClusterIntegration|Remove integration'), clusterable.cluster_path(@cluster), method: :delete, class: 'btn btn-danger', data: { confirm: s_("ClusterIntegration|Are you sure you want to remove this Kubernetes cluster's integration? This will not delete your actual Kubernetes cluster.")})
#js-cluster-remove-actions{ data: { cluster_path: clusterable.cluster_path(@cluster), cluster_name: @cluster.name } }
......@@ -3580,6 +3580,9 @@ msgstr ""
msgid "ClusterIntegration| %{custom_domain_start}More information%{custom_domain_end}."
msgstr ""
msgid "ClusterIntegration| This will permanently delete the following resources: <ul> <li>All installed applications and related resources</li> <li>The <code>gitlab-managed-apps</code> namespace</li> <li>Any project namespaces</li> <li><code>clusterroles</code></li> <li><code>clusterrolebindings</code></li> </ul>"
msgstr ""
msgid "ClusterIntegration| can be used instead of a custom domain."
msgstr ""
......@@ -3667,9 +3670,6 @@ msgstr ""
msgid "ClusterIntegration|Apply for credit"
msgstr ""
msgid "ClusterIntegration|Are you sure you want to remove this Kubernetes cluster's integration? This will not delete your actual Kubernetes cluster."
msgstr ""
msgid "ClusterIntegration|Authenticate with AWS"
msgstr ""
......@@ -3799,6 +3799,9 @@ msgstr ""
msgid "ClusterIntegration|Crossplane enables declarative provisioning of managed services from your cloud of choice using %{kubectl} or %{gitlabIntegrationLink}. Crossplane runs inside your Kubernetes cluster and supports secure connectivity and secrets management between app containers and the cloud services they depend on."
msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
msgid "ClusterIntegration|Did you know?"
msgstr ""
......@@ -3898,6 +3901,9 @@ msgstr ""
msgid "ClusterIntegration|If you are setting up multiple clusters and are using Auto DevOps, %{help_link_start}read this first%{help_link_end}."
msgstr ""
msgid "ClusterIntegration|If you do not wish to delete all associated GitLab resources, you can simply remove the integration."
msgstr ""
msgid "ClusterIntegration|In order to view the health of your cluster, you must first install Prometheus below."
msgstr ""
......@@ -4120,9 +4126,21 @@ msgstr ""
msgid "ClusterIntegration|Remove integration"
msgstr ""
msgid "ClusterIntegration|Remove integration and resources"
msgstr ""
msgid "ClusterIntegration|Remove integration and resources?"
msgstr ""
msgid "ClusterIntegration|Remove integration?"
msgstr ""
msgid "ClusterIntegration|Remove this Kubernetes cluster's configuration from this project. This will not delete your actual Kubernetes cluster."
msgstr ""
msgid "ClusterIntegration|Removes cluster from project but keeps associated resources"
msgstr ""
msgid "ClusterIntegration|Replace this with your own hostname if you want. If you do so, point hostname to Ingress IP Address from above."
msgstr ""
......@@ -4291,6 +4309,12 @@ msgstr ""
msgid "ClusterIntegration|To access your application after deployment, point a wildcard DNS to the Knative Endpoint."
msgstr ""
msgid "ClusterIntegration|To remove your integration and resources, type %{clusterName} to confirm:"
msgstr ""
msgid "ClusterIntegration|To remove your integration, type %{clusterName} to confirm:"
msgstr ""
msgid "ClusterIntegration|Toggle Kubernetes cluster"
msgstr ""
......@@ -4315,6 +4339,12 @@ msgstr ""
msgid "ClusterIntegration|With a Kubernetes cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
msgid "ClusterIntegration|You are about to remove your cluster integration and all GitLab-created resources associated with this cluster."
msgstr ""
msgid "ClusterIntegration|You are about to remove your cluster integration."
msgstr ""
msgid "ClusterIntegration|You are about to uninstall %{appTitle} from your cluster."
msgstr ""
......
......@@ -115,11 +115,11 @@ describe 'User Cluster', :js do
end
end
context 'when user destroy the cluster' do
context 'when user destroys the cluster' do
before do
page.accept_confirm do
click_link 'Remove integration'
end
click_button 'Remove integration and resources'
fill_in 'confirm_cluster_name_input', with: cluster.name
click_button 'Remove integration'
end
it 'user sees creation form with the successful message' do
......
......@@ -131,11 +131,11 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
end
end
context 'when user destroy the cluster' do
context 'when user destroys the cluster' do
before do
page.accept_confirm do
click_link 'Remove integration'
end
click_button 'Remove integration and resources'
fill_in 'confirm_cluster_name_input', with: cluster.name
click_button 'Remove integration'
end
it 'user sees creation form with the successful message' do
......
......@@ -101,11 +101,11 @@ describe 'User Cluster', :js do
end
end
context 'when user destroy the cluster' do
context 'when user destroys the cluster' do
before do
page.accept_confirm do
click_link 'Remove integration'
end
click_button 'Remove integration and resources'
fill_in 'confirm_cluster_name_input', with: cluster.name
click_button 'Remove integration'
end
it 'user sees creation form with the successful message' do
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Remove cluster confirmation modal renders splitbutton with modal included 1`] = `
<div>
<div
class="dropdown btn-group b-dropdown gl-dropdown"
>
<button
class="btn btn-danger"
type="button"
>
Remove integration and resources
<!---->
</button>
<button
aria-expanded="false"
aria-haspopup="true"
class="btn dropdown-toggle btn-danger dropdown-toggle-split"
type="button"
>
<span
class="sr-only"
>
Toggle Dropdown
</span>
</button>
<ul
class="dropdown-menu dropdown-menu-selectable dropdown-menu-large"
role="menu"
tabindex="-1"
>
<li>
<button
class="dropdown-item is-active"
role="menuitem"
type="button"
>
<strong>
Remove integration and resources
</strong>
<div>
Deletes all GitLab resources attached to this cluster during removal
</div>
</button>
</li>
<li>
<hr
aria-orientation="horizontal"
class="dropdown-divider"
role="separator"
/>
</li>
<li>
<button
class="dropdown-item"
role="menuitem"
type="button"
>
<strong>
Remove integration
</strong>
<div>
Removes cluster from project but keeps associated resources
</div>
</button>
</li>
<!---->
</ul>
</div>
<!---->
</div>
`;
import { mount } from '@vue/test-utils';
import { GlModal } from '@gitlab/ui';
import SplitButton from '~/vue_shared/components/split_button.vue';
import RemoveClusterConfirmation from '~/clusters/components/remove_cluster_confirmation.vue';
describe('Remove cluster confirmation modal', () => {
let wrapper;
const createComponent = (props = {}) => {
wrapper = mount(RemoveClusterConfirmation, {
propsData: {
clusterPath: 'clusterPath',
clusterName: 'clusterName',
...props,
},
sync: false,
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('renders splitbutton with modal included', () => {
createComponent();
expect(wrapper.element).toMatchSnapshot();
});
describe('split button dropdown', () => {
const findModal = () => wrapper.find(GlModal).vm;
const findSplitButton = () => wrapper.find(SplitButton).vm;
beforeEach(() => {
createComponent({ clusterName: 'my-test-cluster' });
jest.spyOn(findModal(), 'show').mockReturnValue();
});
it('opens modal with "cleanup" option', () => {
findSplitButton().$emit('remove-cluster-and-cleanup');
return wrapper.vm.$nextTick().then(() => {
expect(findModal().show).toHaveBeenCalled();
expect(wrapper.vm.confirmCleanup).toEqual(true);
});
});
it('opens modal without "cleanup" option', () => {
findSplitButton().$emit('remove-cluster');
return wrapper.vm.$nextTick().then(() => {
expect(findModal().show).toHaveBeenCalled();
expect(wrapper.vm.confirmCleanup).toEqual(false);
});
});
});
});
......@@ -5,6 +5,7 @@ exports[`SplitButton renders actionItems 1`] = `
menu-class="dropdown-menu-selectable "
split="true"
text="professor"
variant="secondary"
>
<gldropdownitem-stub
active="true"
......
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