summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/pipelines/components/stage.js
blob: 203485f299047fd03b0b09509753fd4800d27e72 (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
/* global Flash */
import StatusIconEntityMap from '../../ci_status_icons';

export default {
  props: {
    stage: {
      type: Object,
      required: true,
    },
  },

  data() {
    return {
      builds: '',
      spinner: '<span class="fa fa-spinner fa-spin"></span>',
    };
  },

  updated() {
    if (this.builds) {
      this.stopDropdownClickPropagation();
    }
  },

  methods: {
    fetchBuilds(e) {
      const ariaExpanded = e.currentTarget.attributes['aria-expanded'];

      if (ariaExpanded && (ariaExpanded.textContent === 'true')) return null;

      return this.$http.get(this.stage.dropdown_path)
        .then((response) => {
          this.builds = JSON.parse(response.body).html;
        })
        .catch(() => {
          // If dropdown is opened we'll close it.
          if (this.$el.classList.contains('open')) {
            $(this.$refs.dropdown).dropdown('toggle');
          }

          const flash = new Flash('Something went wrong on our end.');
          return flash;
        });
    },

    /**
     * When the user right clicks or cmd/ctrl + click in the job name
     * the dropdown should not be closed and the link should open in another tab,
     * so we stop propagation of the click event inside the dropdown.
     *
     * Since this component is rendered multiple times per page we need to guarantee we only
     * target the click event of this component.
     */
    stopDropdownClickPropagation() {
      $(this.$el.querySelectorAll('.js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item'))
        .on('click', (e) => {
          e.stopPropagation();
        });
    },
  },
  computed: {
    buildsOrSpinner() {
      return this.builds ? this.builds : this.spinner;
    },
    dropdownClass() {
      if (this.builds) return 'js-builds-dropdown-container';
      return 'js-builds-dropdown-loading builds-dropdown-loading';
    },
    buildStatus() {
      return `Build: ${this.stage.status.label}`;
    },
    tooltip() {
      return `has-tooltip ci-status-icon ci-status-icon-${this.stage.status.group}`;
    },
    triggerButtonClass() {
      return `mini-pipeline-graph-dropdown-toggle has-tooltip js-builds-dropdown-button ci-status-icon-${this.stage.status.group}`;
    },
    svgHTML() {
      return StatusIconEntityMap[this.stage.status.icon];
    },
  },
  template: `
    <div>
      <button
        @click="fetchBuilds($event)"
        :class="triggerButtonClass"
        :title="stage.title"
        data-placement="top"
        data-toggle="dropdown"
        type="button"
        :aria-label="stage.title"
        ref="dropdown">
        <span
          v-html="svgHTML"
          aria-hidden="true">
        </span>
        <i
          class="fa fa-caret-down"
          aria-hidden="true" />
      </button>
      <ul
        ref="dropdown-content"
        class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container">
        <div
          class="arrow-up"
          aria-hidden="true"></div>
        <div
          :class="dropdownClass"
          class="js-builds-dropdown-list scrollable-menu"
          v-html="buildsOrSpinner">
        </div>
      </ul>
    </div>
  `,
};