179 lines
4.4 KiB
Vue
179 lines
4.4 KiB
Vue
<script>
|
|
import { GlButton, GlModalDirective, GlTooltipDirective } from '@gitlab/ui';
|
|
import runnerDeleteMutation from '~/runner/graphql/shared/runner_delete.mutation.graphql';
|
|
import { createAlert } from '~/flash';
|
|
import { sprintf } from '~/locale';
|
|
import { captureException } from '~/runner/sentry_utils';
|
|
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
|
import {
|
|
I18N_DELETE_DISABLED_MANY_PROJECTS,
|
|
I18N_DELETE_DISABLED_UNKNOWN_REASON,
|
|
I18N_DELETE_RUNNER,
|
|
I18N_DELETED_TOAST,
|
|
} from '../constants';
|
|
import RunnerDeleteModal from './runner_delete_modal.vue';
|
|
|
|
export default {
|
|
name: 'RunnerDeleteButton',
|
|
components: {
|
|
GlButton,
|
|
RunnerDeleteModal,
|
|
},
|
|
directives: {
|
|
GlTooltip: GlTooltipDirective,
|
|
GlModal: GlModalDirective,
|
|
},
|
|
props: {
|
|
runner: {
|
|
type: Object,
|
|
required: true,
|
|
validator: (runner) => {
|
|
return runner?.id && runner?.shortSha;
|
|
},
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
compact: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
},
|
|
emits: ['deleted'],
|
|
data() {
|
|
return {
|
|
deleting: false,
|
|
};
|
|
},
|
|
computed: {
|
|
runnerId() {
|
|
return getIdFromGraphQLId(this.runner.id);
|
|
},
|
|
runnerName() {
|
|
return `#${this.runnerId} (${this.runner.shortSha})`;
|
|
},
|
|
runnerDeleteModalId() {
|
|
return `delete-runner-modal-${this.runnerId}`;
|
|
},
|
|
icon() {
|
|
if (this.compact) {
|
|
return 'close';
|
|
}
|
|
return '';
|
|
},
|
|
buttonContent() {
|
|
if (this.compact) {
|
|
return null;
|
|
}
|
|
return I18N_DELETE_RUNNER;
|
|
},
|
|
buttonClass() {
|
|
// Ensure a square button is shown when compact: true.
|
|
// Without this class we will have distorted/rectangular button.
|
|
if (this.compact) {
|
|
return 'btn-icon';
|
|
}
|
|
return null;
|
|
},
|
|
ariaLabel() {
|
|
if (this.compact) {
|
|
return I18N_DELETE_RUNNER;
|
|
}
|
|
return null;
|
|
},
|
|
tooltip() {
|
|
if (this.disabled && this.runner.projectCount > 1) {
|
|
return I18N_DELETE_DISABLED_MANY_PROJECTS;
|
|
}
|
|
if (this.disabled) {
|
|
return I18N_DELETE_DISABLED_UNKNOWN_REASON;
|
|
}
|
|
|
|
// Only show basic "delete" tooltip when compact.
|
|
// Also prevent a "sticky" tooltip: If this button is
|
|
// disabled, mouseout listeners don't run leaving the tooltip stuck
|
|
if (this.compact && !this.deleting) {
|
|
return I18N_DELETE_RUNNER;
|
|
}
|
|
return '';
|
|
},
|
|
wrapperTabindex() {
|
|
if (this.disabled) {
|
|
// Trigger tooltip on keyboard-focusable wrapper
|
|
// See https://bootstrap-vue.org/docs/directives/tooltip
|
|
return '0';
|
|
}
|
|
return null;
|
|
},
|
|
},
|
|
methods: {
|
|
async onDelete() {
|
|
// Deleting stays "true" until this row is removed,
|
|
// should only change back if the operation fails.
|
|
this.deleting = true;
|
|
try {
|
|
await this.$apollo.mutate({
|
|
mutation: runnerDeleteMutation,
|
|
variables: {
|
|
input: {
|
|
id: this.runner.id,
|
|
},
|
|
},
|
|
update: (cache, { data }) => {
|
|
const { errors } = data.runnerDelete;
|
|
|
|
if (errors?.length) {
|
|
this.onError(new Error(errors.join(' ')));
|
|
return;
|
|
}
|
|
|
|
this.$emit('deleted', {
|
|
message: sprintf(I18N_DELETED_TOAST, { name: this.runnerName }),
|
|
});
|
|
|
|
// Remove deleted runner from the cache
|
|
const cacheId = cache.identify(this.runner);
|
|
cache.evict({ id: cacheId });
|
|
cache.gc();
|
|
},
|
|
});
|
|
} catch (e) {
|
|
this.onError(e);
|
|
}
|
|
},
|
|
onError(error) {
|
|
this.deleting = false;
|
|
const { message } = error;
|
|
|
|
createAlert({ message });
|
|
captureException({ error, component: this.$options.name });
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div v-gl-tooltip="tooltip" class="btn-group" :tabindex="wrapperTabindex">
|
|
<gl-button
|
|
v-gl-modal="runnerDeleteModalId"
|
|
:aria-label="ariaLabel"
|
|
:icon="icon"
|
|
:class="buttonClass"
|
|
:loading="deleting"
|
|
:disabled="disabled"
|
|
variant="danger"
|
|
category="secondary"
|
|
v-bind="$attrs"
|
|
>
|
|
{{ buttonContent }}
|
|
</gl-button>
|
|
<runner-delete-modal
|
|
:modal-id="runnerDeleteModalId"
|
|
:runner-name="runnerName"
|
|
@primary="onDelete"
|
|
/>
|
|
</div>
|
|
</template>
|