fa2af5e0f5
Reduced the technical debt around our JS flash function by making it a module that is imported rather than relying on the global function. The global function still exists mainly for technical debt with how some requests are being completed, but new JS should import the module directly. Also reduces some tech debt in the file by removing the need for jQuery. Instead Flash is now 100% vanilla JS.
115 lines
3.3 KiB
JavaScript
115 lines
3.3 KiB
JavaScript
/* eslint-disable no-new */
|
|
import Flash from './flash';
|
|
|
|
/**
|
|
* In each pipelines table we have a mini pipeline graph for each pipeline.
|
|
*
|
|
* When we click in a pipeline stage, we need to make an API call to get the
|
|
* builds list to render in a dropdown.
|
|
*
|
|
* The container should be the table element.
|
|
*
|
|
* The stage icon clicked needs to have the following HTML structure:
|
|
* <div class="dropdown">
|
|
* <button class="dropdown js-builds-dropdown-button" data-toggle="dropdown"></button>
|
|
* <div class="js-builds-dropdown-container dropdown-menu"></div>
|
|
* </div>
|
|
*/
|
|
|
|
export default class MiniPipelineGraph {
|
|
constructor(opts = {}) {
|
|
this.container = opts.container || '';
|
|
this.dropdownListSelector = '.js-builds-dropdown-container';
|
|
this.getBuildsList = this.getBuildsList.bind(this);
|
|
}
|
|
|
|
/**
|
|
* Adds the event listener when the dropdown is opened.
|
|
* All dropdown events are fired at the .dropdown-menu's parent element.
|
|
*/
|
|
bindEvents() {
|
|
$(document)
|
|
.off('shown.bs.dropdown', this.container)
|
|
.on('shown.bs.dropdown', this.container, this.getBuildsList);
|
|
}
|
|
|
|
/**
|
|
* 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() {
|
|
$(document).on(
|
|
'click',
|
|
`${this.container} .js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item`,
|
|
(e) => {
|
|
e.stopPropagation();
|
|
},
|
|
);
|
|
}
|
|
|
|
/**
|
|
* For the clicked stage, renders the given data in the dropdown list.
|
|
*
|
|
* @param {HTMLElement} stageContainer
|
|
* @param {Object} data
|
|
*/
|
|
renderBuildsList(stageContainer, data) {
|
|
const dropdownContainer = stageContainer.parentElement.querySelector(
|
|
`${this.dropdownListSelector} .js-builds-dropdown-list`,
|
|
);
|
|
|
|
dropdownContainer.innerHTML = data;
|
|
}
|
|
|
|
/**
|
|
* For the clicked stage, gets the list of builds.
|
|
*
|
|
* All dropdown events have a relatedTarget property,
|
|
* whose value is the toggling anchor element.
|
|
*
|
|
* @param {Object} e bootstrap dropdown event
|
|
* @return {Promise}
|
|
*/
|
|
getBuildsList(e) {
|
|
const button = e.relatedTarget;
|
|
const endpoint = button.dataset.stageEndpoint;
|
|
|
|
return $.ajax({
|
|
dataType: 'json',
|
|
type: 'GET',
|
|
url: endpoint,
|
|
beforeSend: () => {
|
|
this.renderBuildsList(button, '');
|
|
this.toggleLoading(button);
|
|
},
|
|
success: (data) => {
|
|
this.toggleLoading(button);
|
|
this.renderBuildsList(button, data.html);
|
|
this.stopDropdownClickPropagation();
|
|
},
|
|
error: () => {
|
|
this.toggleLoading(button);
|
|
if ($(button).parent().hasClass('open')) {
|
|
$(button).dropdown('toggle');
|
|
}
|
|
new Flash('An error occurred while fetching the builds.', 'alert');
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Toggles the visibility of the loading icon.
|
|
*
|
|
* @param {HTMLElement} stageContainer
|
|
* @return {type}
|
|
*/
|
|
toggleLoading(stageContainer) {
|
|
stageContainer.parentElement.querySelector(
|
|
`${this.dropdownListSelector} .js-builds-dropdown-loading`,
|
|
).classList.toggle('hidden');
|
|
}
|
|
}
|