summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/pipelines/components/jobs_shared/action_component.vue
blob: 7020bfc1e658b72ce82c3493dda4d0c1ede6b9bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<script>
import { GlTooltipDirective, GlButton, GlLoadingIcon, GlIcon } from '@gitlab/ui';
import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { dasherize } from '~/lib/utils/text_utility';
import { __ } from '~/locale';
import { reportToSentry } from '../../utils';

/**
 * Renders either a cancel, retry or play icon button and handles the post request
 *
 * Used in:
 * - mr widget mini pipeline graph: `mr_widget_pipeline.vue`
 * - pipelines table
 * - pipelines table in merge request page
 * - pipelines table in commit page
 * - pipelines detail page in big graph
 */
export default {
  components: {
    GlIcon,
    GlButton,
    GlLoadingIcon,
  },
  directives: {
    GlTooltip: GlTooltipDirective,
  },
  props: {
    tooltipText: {
      type: String,
      required: true,
    },
    link: {
      type: String,
      required: true,
    },
    actionIcon: {
      type: String,
      required: true,
    },
    withConfirmationModal: {
      type: Boolean,
      required: false,
      default: false,
    },
    shouldTriggerClick: {
      type: Boolean,
      required: false,
      default: false,
    },
  },
  data() {
    return {
      isDisabled: false,
      isLoading: false,
    };
  },
  computed: {
    cssClass() {
      const actionIconDash = dasherize(this.actionIcon);
      return `${actionIconDash} js-icon-${actionIconDash}`;
    },
  },
  watch: {
    shouldTriggerClick(flag) {
      if (flag && this.withConfirmationModal) {
        this.executeAction();
        this.$emit('actionButtonClicked');
      }
    },
  },
  errorCaptured(err, _vm, info) {
    reportToSentry('action_component', `error: ${err}, info: ${info}`);
  },
  methods: {
    /**
     * The request should not be handled here.
     * However due to this component being used in several
     * different apps it avoids repetition & complexity.
     *
     */
    onClickAction() {
      if (this.withConfirmationModal) {
        this.$emit('showActionConfirmationModal');
      } else {
        this.executeAction();
      }
    },
    executeAction() {
      this.$root.$emit(BV_HIDE_TOOLTIP, `js-ci-action-${this.link}`);
      this.isDisabled = true;
      this.isLoading = true;

      axios
        .post(`${this.link}.json`)
        .then(() => {
          this.isLoading = false;

          this.$emit('pipelineActionRequestComplete');
        })
        .catch((err) => {
          this.isDisabled = false;
          this.isLoading = false;

          reportToSentry('action_component', err);

          createAlert({
            message: __('An error occurred while making the request.'),
          });
        });
    },
  },
};
</script>
<template>
  <gl-button
    :id="`js-ci-action-${link}`"
    ref="button"
    :class="cssClass"
    :disabled="isDisabled"
    class="js-ci-action gl-ci-action-icon-container ci-action-icon-container ci-action-icon-wrapper gl-display-flex gl-align-items-center gl-justify-content-center"
    data-testid="ci-action-component"
    @click.stop="onClickAction"
  >
    <div
      v-gl-tooltip.viewport
      :title="tooltipText"
      class="gl-display-flex gl-align-items-center gl-justify-content-center gl-h-full"
      data-testid="ci-action-icon-tooltip-wrapper"
    >
      <gl-loading-icon v-if="isLoading" size="sm" class="js-action-icon-loading" />
      <gl-icon v-else :name="actionIcon" class="gl-mr-0!" :aria-label="actionIcon" />
    </div>
  </gl-button>
</template>