summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_pipelines_index/stage.js.es6
blob: ddfd00df42eac4ec81f1779b6df49ee73e58aad2 (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
/* global Vue, Flash, gl */
/* eslint-disable no-param-reassign, no-bitwise */

((gl) => {
  gl.VueStage = Vue.extend({
    data() {
      return {
        request: false,
        builds: '',
        spinner: '<span class="fa fa-spinner fa-spin"></span>',
      };
    },
    props: ['stage', 'svgs', 'match'],
    methods: {
      fetchBuilds(e) {
        /**
          This is a very interesting UI problem
          Essentially we have to clear builds on blur no matter what
          This was preventing turbolinks to make the request to the link clicked
          Vue will always look at the VDOM element which is the button

          It has a special attribute 'aria-expanded':
            - which will let us know if it is expanded
            - once the build link is clicked
            - when someone clicks outside of the dropdown

          In order for this to work:
            - here we setTimeout to give enough time to initialize the request
            - but short enough that a subsequent click will reset that state
        */

        const areaExpanded = e.currentTarget.attributes['aria-expanded'];

        if (areaExpanded && (areaExpanded.textContent === 'true')) {
          const related = e.relatedTarget;
          if (!related) {
            return this.clearBuilds();
          } else if (!related.parentElement) {
            return this.clearBuilds();
          } else if (~related.parentElement.parentElement.className.indexOf('js-builds-dropdown-container')) {
            return null;
          }
        }

        if (this.request) return this.clearBuilds();

        return this.$http.get(this.stage.dropdown_path)
          .then((response) => {
            this.request = true;
            this.builds = JSON.parse(response.body).html;
          }, () => {
            const flash = new Flash('Something went wrong on our end.');
            this.request = false;
            return flash;
          });
      },
      clearBuilds() {
        this.builds = '';
        this.request = false;
      },
    },
    computed: {
      buildsOrSpinner() {
        return this.request ? this.builds : this.spinner;
      },
      dropdownClass() {
        if (this.request) 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}`;
      },
      svg() {
        const icon = this.stage.status.icon;
        const stageIcon = icon.replace(/icon/i, 'stage_icon');
        return this.svgs[this.match(stageIcon)];
      },
      triggerButtonClass() {
        return `mini-pipeline-graph-dropdown-toggle has-tooltip js-builds-dropdown-button ci-status-icon-${this.stage.status.group}`;
      },
    },
    template: `
      <div>
        <button
          @click='fetchBuilds($event)'
          @blur='fetchBuilds($event)'
          :class="triggerButtonClass"
          :title='stage.title'
          data-placement="top"
          data-toggle="dropdown"
          type="button">
          <span v-html="svg"></span>
          <i class="fa fa-caret-down "></i>
        </button>
        <ul class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container">
          <div class="arrow-up"></div>
          <div :class="dropdownClass" class="js-builds-dropdown-list scrollable-menu" v-html="buildsOrSpinner"></div>
        </ul>
      </div>
    `,
  });
})(window.gl || (window.gl = {}));