diff options
Diffstat (limited to 'app/assets/javascripts/runner/components/cells')
3 files changed, 257 insertions, 0 deletions
diff --git a/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue b/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue new file mode 100644 index 00000000000..7f9f796bdee --- /dev/null +++ b/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue @@ -0,0 +1,171 @@ +<script> +import { GlButton, GlButtonGroup, GlTooltipDirective } from '@gitlab/ui'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; +import { __, s__ } from '~/locale'; +import deleteRunnerMutation from '~/runner/graphql/delete_runner.mutation.graphql'; +import runnerUpdateMutation from '~/runner/graphql/runner_update.mutation.graphql'; + +const i18n = { + I18N_EDIT: __('Edit'), + I18N_PAUSE: __('Pause'), + I18N_RESUME: __('Resume'), + I18N_REMOVE: __('Remove'), + I18N_REMOVE_CONFIRMATION: s__('Runners|Are you sure you want to delete this runner?'), +}; + +export default { + components: { + GlButton, + GlButtonGroup, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + props: { + runner: { + type: Object, + required: true, + }, + }, + data() { + return { + updating: false, + deleting: false, + }; + }, + computed: { + runnerNumericalId() { + return getIdFromGraphQLId(this.runner.id); + }, + runnerUrl() { + // TODO implement using webUrl from the API + return `${gon.gitlab_url || ''}/admin/runners/${this.runnerNumericalId}`; + }, + isActive() { + return this.runner.active; + }, + toggleActiveIcon() { + return this.isActive ? 'pause' : 'play'; + }, + toggleActiveTitle() { + if (this.updating) { + // Prevent a "sticky" tooltip: If this button is disabled, + // mouseout listeners don't run leaving the tooltip stuck + return ''; + } + return this.isActive ? i18n.I18N_PAUSE : i18n.I18N_RESUME; + }, + deleteTitle() { + // Prevent a "sticky" tooltip: If element gets removed, + // mouseout listeners don't run and leaving the tooltip stuck + return this.deleting ? '' : i18n.I18N_REMOVE; + }, + }, + methods: { + async onToggleActive() { + this.updating = true; + // TODO In HAML iteration we had a confirmation modal via: + // data-confirm="_('Are you sure?')" + // this may not have to ported, this is an easily reversible operation + + try { + const toggledActive = !this.runner.active; + + const { + data: { + runnerUpdate: { errors }, + }, + } = await this.$apollo.mutate({ + mutation: runnerUpdateMutation, + variables: { + input: { + id: this.runner.id, + active: toggledActive, + }, + }, + }); + + if (errors && errors.length) { + this.onError(new Error(errors[0])); + } + } catch (e) { + this.onError(e); + } finally { + this.updating = false; + } + }, + + async onDelete() { + // TODO Replace confirmation with gl-modal + // eslint-disable-next-line no-alert + if (!window.confirm(i18n.I18N_REMOVE_CONFIRMATION)) { + return; + } + + this.deleting = true; + try { + const { + data: { + runnerDelete: { errors }, + }, + } = await this.$apollo.mutate({ + mutation: deleteRunnerMutation, + variables: { + input: { + id: this.runner.id, + }, + }, + awaitRefetchQueries: true, + refetchQueries: ['getRunners'], + }); + if (errors && errors.length) { + this.onError(new Error(errors[0])); + } + } catch (e) { + this.onError(e); + } finally { + this.deleting = false; + } + }, + + onError(error) { + // TODO Render errors when "delete" action is done + // `active` toggle would not fail due to user input. + throw error; + }, + }, + i18n, +}; +</script> + +<template> + <gl-button-group> + <gl-button + v-gl-tooltip.hover.viewport + :title="$options.i18n.I18N_EDIT" + :aria-label="$options.i18n.I18N_EDIT" + icon="pencil" + :href="runnerUrl" + data-testid="edit-runner" + /> + <gl-button + v-gl-tooltip.hover.viewport + :title="toggleActiveTitle" + :aria-label="toggleActiveTitle" + :icon="toggleActiveIcon" + :loading="updating" + data-testid="toggle-active-runner" + @click="onToggleActive" + /> + <gl-button + v-gl-tooltip.hover.viewport + :title="deleteTitle" + :aria-label="deleteTitle" + icon="close" + :loading="deleting" + variant="danger" + data-testid="delete-runner" + @click="onDelete" + /> + </gl-button-group> +</template> diff --git a/app/assets/javascripts/runner/components/cells/runner_name_cell.vue b/app/assets/javascripts/runner/components/cells/runner_name_cell.vue new file mode 100644 index 00000000000..797a3359147 --- /dev/null +++ b/app/assets/javascripts/runner/components/cells/runner_name_cell.vue @@ -0,0 +1,44 @@ +<script> +import { GlLink } from '@gitlab/ui'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; +import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue'; + +export default { + components: { + GlLink, + TooltipOnTruncate, + }, + props: { + runner: { + type: Object, + required: true, + }, + }, + computed: { + runnerNumericalId() { + return getIdFromGraphQLId(this.runner.id); + }, + runnerUrl() { + // TODO implement using webUrl from the API + return `${gon.gitlab_url || ''}/admin/runners/${this.runnerNumericalId}`; + }, + description() { + return this.runner.description; + }, + shortSha() { + return this.runner.shortSha; + }, + }, +}; +</script> + +<template> + <div> + <gl-link :href="runnerUrl"> #{{ runnerNumericalId }} ({{ shortSha }})</gl-link> + <tooltip-on-truncate class="gl-display-block" :title="description" truncate-target="child"> + <div class="gl-text-truncate"> + {{ description }} + </div> + </tooltip-on-truncate> + </div> +</template> diff --git a/app/assets/javascripts/runner/components/cells/runner_type_cell.vue b/app/assets/javascripts/runner/components/cells/runner_type_cell.vue new file mode 100644 index 00000000000..b3ebdfd82e3 --- /dev/null +++ b/app/assets/javascripts/runner/components/cells/runner_type_cell.vue @@ -0,0 +1,42 @@ +<script> +import { GlBadge } from '@gitlab/ui'; +import RunnerTypeBadge from '../runner_type_badge.vue'; + +export default { + components: { + GlBadge, + RunnerTypeBadge, + }, + props: { + runner: { + type: Object, + required: true, + }, + }, + computed: { + runnerType() { + return this.runner.runnerType; + }, + locked() { + return this.runner.locked; + }, + paused() { + return !this.runner.active; + }, + }, +}; +</script> + +<template> + <div> + <runner-type-badge :type="runnerType" size="sm" /> + + <gl-badge v-if="locked" variant="warning" size="sm"> + {{ __('locked') }} + </gl-badge> + + <gl-badge v-if="paused" variant="danger" size="sm"> + {{ __('paused') }} + </gl-badge> + </div> +</template> |