2017-08-17 22:00:37 +05:30
|
|
|
<script>
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
/**
|
|
|
|
* Renders each stage of the pipeline mini graph.
|
|
|
|
*
|
|
|
|
* Given the provided endpoint will make a request to
|
|
|
|
* fetch the dropdown data when the stage is clicked.
|
|
|
|
*
|
|
|
|
* Request is made inside this component to make it reusable between:
|
|
|
|
* 1. Pipelines main table
|
|
|
|
* 2. Pipelines table in commit and Merge request views
|
|
|
|
* 3. Merge request widget
|
|
|
|
* 4. Commit widget
|
|
|
|
*/
|
|
|
|
|
|
|
|
import Flash from '../../flash';
|
|
|
|
import icon from '../../vue_shared/components/icon.vue';
|
|
|
|
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
|
|
|
|
import tooltip from '../../vue_shared/directives/tooltip';
|
|
|
|
|
|
|
|
export default {
|
|
|
|
components: {
|
|
|
|
loadingIcon,
|
|
|
|
icon,
|
2017-08-17 22:00:37 +05:30
|
|
|
},
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
directives: {
|
|
|
|
tooltip,
|
2017-08-17 22:00:37 +05:30
|
|
|
},
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
props: {
|
|
|
|
stage: {
|
|
|
|
type: Object,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
|
|
|
|
updateDropdown: {
|
|
|
|
type: Boolean,
|
|
|
|
required: false,
|
|
|
|
default: false,
|
|
|
|
},
|
2017-08-17 22:00:37 +05:30
|
|
|
},
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
isLoading: false,
|
|
|
|
dropdownContent: '',
|
|
|
|
};
|
2017-08-17 22:00:37 +05:30
|
|
|
},
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
computed: {
|
|
|
|
dropdownClass() {
|
2018-03-27 19:54:05 +05:30
|
|
|
return this.dropdownContent.length > 0 ? 'js-builds-dropdown-container' : 'js-builds-dropdown-loading';
|
2018-03-17 18:26:18 +05:30
|
|
|
},
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
triggerButtonClass() {
|
|
|
|
return `ci-status-icon-${this.stage.status.group}`;
|
|
|
|
},
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
borderlessIcon() {
|
|
|
|
return `${this.stage.status.icon}_borderless`;
|
|
|
|
},
|
2017-08-17 22:00:37 +05:30
|
|
|
},
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
watch: {
|
|
|
|
updateDropdown() {
|
|
|
|
if (this.updateDropdown &&
|
|
|
|
this.isDropdownOpen() &&
|
|
|
|
!this.isLoading) {
|
|
|
|
this.fetchJobs();
|
|
|
|
}
|
|
|
|
},
|
2017-08-17 22:00:37 +05:30
|
|
|
},
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
updated() {
|
|
|
|
if (this.dropdownContent.length > 0) {
|
|
|
|
this.stopDropdownClickPropagation();
|
|
|
|
}
|
2017-08-17 22:00:37 +05:30
|
|
|
},
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
methods: {
|
|
|
|
onClickStage() {
|
|
|
|
if (!this.isDropdownOpen()) {
|
|
|
|
this.isLoading = true;
|
|
|
|
this.fetchJobs();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
fetchJobs() {
|
|
|
|
this.$http.get(this.stage.dropdown_path)
|
|
|
|
.then(response => response.json())
|
|
|
|
.then((data) => {
|
|
|
|
this.dropdownContent = data.html;
|
|
|
|
this.isLoading = false;
|
|
|
|
})
|
|
|
|
.catch(() => {
|
|
|
|
this.closeDropdown();
|
|
|
|
this.isLoading = false;
|
|
|
|
|
|
|
|
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();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
closeDropdown() {
|
|
|
|
if (this.isDropdownOpen()) {
|
|
|
|
$(this.$refs.dropdown).dropdown('toggle');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
isDropdownOpen() {
|
|
|
|
return this.$el.classList.contains('open');
|
|
|
|
},
|
2017-08-17 22:00:37 +05:30
|
|
|
},
|
2018-03-17 18:26:18 +05:30
|
|
|
};
|
2017-08-17 22:00:37 +05:30
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
|
|
<div class="dropdown">
|
|
|
|
<button
|
2017-09-10 17:25:29 +05:30
|
|
|
v-tooltip
|
2017-08-17 22:00:37 +05:30
|
|
|
:class="triggerButtonClass"
|
|
|
|
@click="onClickStage"
|
2017-09-10 17:25:29 +05:30
|
|
|
class="mini-pipeline-graph-dropdown-toggle js-builds-dropdown-button"
|
2017-08-17 22:00:37 +05:30
|
|
|
:title="stage.title"
|
|
|
|
data-placement="top"
|
|
|
|
data-toggle="dropdown"
|
|
|
|
type="button"
|
|
|
|
id="stageDropdown"
|
|
|
|
aria-haspopup="true"
|
2018-03-17 18:26:18 +05:30
|
|
|
aria-expanded="false"
|
|
|
|
>
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
<span
|
|
|
|
aria-hidden="true"
|
2018-03-17 18:26:18 +05:30
|
|
|
:aria-label="stage.title"
|
|
|
|
>
|
|
|
|
<icon :name="borderlessIcon" />
|
2017-08-17 22:00:37 +05:30
|
|
|
</span>
|
|
|
|
|
|
|
|
<i
|
|
|
|
class="fa fa-caret-down"
|
2018-03-17 18:26:18 +05:30
|
|
|
aria-hidden="true"
|
|
|
|
>
|
2017-08-17 22:00:37 +05:30
|
|
|
</i>
|
|
|
|
</button>
|
|
|
|
|
|
|
|
<ul
|
|
|
|
class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container"
|
2018-03-17 18:26:18 +05:30
|
|
|
aria-labelledby="stageDropdown"
|
|
|
|
>
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
<li
|
|
|
|
:class="dropdownClass"
|
2018-03-17 18:26:18 +05:30
|
|
|
class="js-builds-dropdown-list scrollable-menu"
|
|
|
|
>
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2017-09-10 17:25:29 +05:30
|
|
|
<loading-icon v-if="isLoading"/>
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
<ul
|
|
|
|
v-else
|
2018-03-17 18:26:18 +05:30
|
|
|
v-html="dropdownContent"
|
|
|
|
>
|
2017-08-17 22:00:37 +05:30
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</div>
|
2018-03-17 18:26:18 +05:30
|
|
|
</template>
|