196 lines
5.3 KiB
Vue
196 lines
5.3 KiB
Vue
<script>
|
|
import { GlButton, GlModalDirective, GlModal, GlSprintf } from '@gitlab/ui';
|
|
import { createAlert } from '~/flash';
|
|
import { __, s__, n__, sprintf } from '~/locale';
|
|
import checkedRunnerIdsQuery from '../graphql/list/checked_runner_ids.query.graphql';
|
|
import BulkRunnerDelete from '../graphql/list/bulk_runner_delete.mutation.graphql';
|
|
import { RUNNER_TYPENAME } from '../constants';
|
|
|
|
export default {
|
|
components: {
|
|
GlButton,
|
|
GlModal,
|
|
GlSprintf,
|
|
},
|
|
directives: {
|
|
GlModal: GlModalDirective,
|
|
},
|
|
inject: ['localMutations'],
|
|
props: {
|
|
runners: {
|
|
type: Array,
|
|
default: () => [],
|
|
required: false,
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
isDeleting: false,
|
|
checkedRunnerIds: [],
|
|
};
|
|
},
|
|
apollo: {
|
|
checkedRunnerIds: {
|
|
query: checkedRunnerIdsQuery,
|
|
},
|
|
},
|
|
computed: {
|
|
currentCheckedRunnerIds() {
|
|
return this.runners
|
|
.map(({ id }) => id)
|
|
.filter((id) => this.checkedRunnerIds.indexOf(id) >= 0);
|
|
},
|
|
checkedCount() {
|
|
return this.currentCheckedRunnerIds.length || 0;
|
|
},
|
|
bannerMessage() {
|
|
return sprintf(
|
|
n__(
|
|
'Runners|%{strongStart}%{count}%{strongEnd} runner selected',
|
|
'Runners|%{strongStart}%{count}%{strongEnd} runners selected',
|
|
this.checkedCount,
|
|
),
|
|
{
|
|
count: this.checkedCount,
|
|
},
|
|
);
|
|
},
|
|
modalTitle() {
|
|
return n__('Runners|Delete %d runner', 'Runners|Delete %d runners', this.checkedCount);
|
|
},
|
|
modalActionPrimary() {
|
|
return {
|
|
text: n__(
|
|
'Runners|Permanently delete %d runner',
|
|
'Runners|Permanently delete %d runners',
|
|
this.checkedCount,
|
|
),
|
|
attributes: {
|
|
loading: this.isDeleting,
|
|
variant: 'danger',
|
|
},
|
|
};
|
|
},
|
|
modalActionCancel() {
|
|
return {
|
|
text: __('Cancel'),
|
|
attributes: {
|
|
loading: this.isDeleting,
|
|
},
|
|
};
|
|
},
|
|
modalMessage() {
|
|
return sprintf(
|
|
n__(
|
|
'Runners|%{strongStart}%{count}%{strongEnd} runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?',
|
|
'Runners|%{strongStart}%{count}%{strongEnd} runners will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?',
|
|
this.checkedCount,
|
|
),
|
|
{ count: this.checkedCount },
|
|
);
|
|
},
|
|
},
|
|
methods: {
|
|
toastConfirmationMessage(deletedCount) {
|
|
return n__(
|
|
'Runners|%d selected runner deleted',
|
|
'Runners|%d selected runners deleted',
|
|
deletedCount,
|
|
);
|
|
},
|
|
onClearChecked() {
|
|
this.localMutations.clearChecked();
|
|
},
|
|
async onConfirmDelete(e) {
|
|
this.isDeleting = true;
|
|
e.preventDefault(); // don't close modal until deletion is complete
|
|
|
|
try {
|
|
await this.$apollo.mutate({
|
|
mutation: BulkRunnerDelete,
|
|
variables: {
|
|
input: {
|
|
ids: this.currentCheckedRunnerIds,
|
|
},
|
|
},
|
|
update: (cache, { data }) => {
|
|
const { errors, deletedIds } = data.bulkRunnerDelete;
|
|
|
|
if (errors?.length) {
|
|
this.onError(new Error(errors.join(' ')));
|
|
this.$refs.modal.hide();
|
|
return;
|
|
}
|
|
|
|
this.$emit('deleted', {
|
|
message: this.toastConfirmationMessage(deletedIds.length),
|
|
});
|
|
|
|
// Clean up
|
|
|
|
// Remove deleted runners from the cache
|
|
deletedIds.forEach((id) => {
|
|
const cacheId = cache.identify({ __typename: RUNNER_TYPENAME, id });
|
|
cache.evict({ id: cacheId });
|
|
});
|
|
cache.gc();
|
|
|
|
this.$refs.modal.hide();
|
|
},
|
|
});
|
|
} catch (error) {
|
|
this.onError(error);
|
|
} finally {
|
|
this.isDeleting = false;
|
|
}
|
|
},
|
|
onError(error) {
|
|
createAlert({
|
|
message: s__(
|
|
'Runners|Something went wrong while deleting. Please refresh the page to try again.',
|
|
),
|
|
captureError: true,
|
|
error,
|
|
});
|
|
},
|
|
},
|
|
BULK_DELETE_MODAL_ID: 'bulk-delete-modal',
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div v-if="checkedCount" class="gl-my-4 gl-p-4 gl-border-1 gl-border-solid gl-border-gray-100">
|
|
<div class="gl-display-flex gl-align-items-center">
|
|
<div>
|
|
<gl-sprintf :message="bannerMessage">
|
|
<template #strong="{ content }">
|
|
<strong>{{ content }}</strong>
|
|
</template>
|
|
</gl-sprintf>
|
|
</div>
|
|
<div class="gl-ml-auto">
|
|
<gl-button variant="default" @click="onClearChecked">{{
|
|
s__('Runners|Clear selection')
|
|
}}</gl-button>
|
|
<gl-button v-gl-modal="$options.BULK_DELETE_MODAL_ID" variant="danger">{{
|
|
s__('Runners|Delete selected')
|
|
}}</gl-button>
|
|
</div>
|
|
</div>
|
|
<gl-modal
|
|
ref="modal"
|
|
size="sm"
|
|
:modal-id="$options.BULK_DELETE_MODAL_ID"
|
|
:title="modalTitle"
|
|
:action-primary="modalActionPrimary"
|
|
:action-cancel="modalActionCancel"
|
|
@primary="onConfirmDelete"
|
|
>
|
|
<gl-sprintf :message="modalMessage">
|
|
<template #strong="{ content }">
|
|
<strong>{{ content }}</strong>
|
|
</template>
|
|
</gl-sprintf>
|
|
</gl-modal>
|
|
</div>
|
|
</template>
|