Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JENKINS-64581] Middle-click or Ctrl+click a build in a trend chart to open the build in a new tab. #381

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 119 additions & 16 deletions src/main/webapp/js/echarts-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ const echartsJenkinsApi = {
const pointInPixel = [params.offsetX, params.offsetY];
const pointInGrid = chart.convertFromPixel('grid', pointInPixel);
const buildDisplayName = chart.getModel().get('xAxis')[0].data[pointInGrid[0]]
chartClickedEventHandler(buildDisplayName);
handleChartClick(params.event, buildDisplayName, chartDivId);
}
})
}
Expand Down Expand Up @@ -454,22 +454,17 @@ const echartsJenkinsApi = {
const pointInPixel = [params.offsetX, params.offsetY];
const pointInGrid = chart.convertFromPixel('grid', pointInPixel);
const buildDisplayName = chart.getModel().get('xAxis')[0].data[pointInGrid[0]]
const builds = chartPlaceHolder.model.buildNumbers;
const labels = chartPlaceHolder.model.domainAxisLabels;

let selectedBuild = 0;
for (let i = 0; i < builds.length; i++) {
if (buildDisplayName === labels[i]) {
selectedBuild = builds[i];
break;
}
}

if (selectedBuild > 0) {
window.location.assign(selectedBuild + '/' + urlName);
}
handleChartClick(params.event, buildDisplayName, chartDivId);
}
})
});
chart.getZr().on('contextmenu', params => {
if (params.offsetY > 30) { // skip the legend
const pointInPixel = [params.offsetX, params.offsetY];
const pointInGrid = chart.convertFromPixel('grid', pointInPixel);
const buildDisplayName = chart.getModel().get('xAxis')[0].data[pointInGrid[0]];
handleContextMenu(params.event, buildDisplayName, chartDivId);
}
});
}
}
}
Expand Down Expand Up @@ -671,3 +666,111 @@ const echartsJenkinsApi = {
}
}
}

//Add global function
function handleChartClick(event, buildDisplayName, chartDivId) {
let chartPlaceHolder = document.getElementById(chartDivId);
if (!chartPlaceHolder || !chartPlaceHolder.model) {
console.warn('Chart placeholder or model not found for:', chartDivId);
return;
}

let builds = chartPlaceHolder.model.buildNumbers;
let labels = chartPlaceHolder.model.domainAxisLabels;
let urlName = chartPlaceHolder.getAttribute("tool");


let selectedBuild = 0;
for (let i = 0; i < builds.length; i++) {
if (buildDisplayName === labels[i]) {
selectedBuild = builds[i];
break;
}
}

if (selectedBuild > 0) {
let url = selectedBuild + '/' + urlName;

if (event.ctrlKey || event.which === 2) { // Ctrl+Click or Middle-click
window.open(url, '_blank'); // Open in new tab/window
} else if (event.shiftKey) { // Shift+Click
window.open(url, '_blank'); // just open in new window
} else {
window.location.href = url; // Original behavior (same tab)
}

event.preventDefault(); // Prevent default action if needed.
}
}

// Add global function
function handleContextMenu(event, buildDisplayName, chartDivId) {
event.preventDefault(); // Prevent the browser's default context menu

let chartPlaceHolder = document.getElementById(chartDivId);
if (!chartPlaceHolder || !chartPlaceHolder.model) {
console.warn('Chart placeholder or model not found for:', chartDivId);
return;
}

let builds = chartPlaceHolder.model.buildNumbers;
let labels = chartPlaceHolder.model.domainAxisLabels;
let urlName = chartPlaceHolder.getAttribute("tool");

let selectedBuild = 0;
for (let i = 0; i < builds.length; i++) {
if (buildDisplayName === labels[i]) {
selectedBuild = builds[i];
break;
}
}

if (selectedBuild > 0) {
let url = selectedBuild + '/' + urlName;

// Create a custom context menu
const contextMenu = document.createElement('div');
contextMenu.style.position = 'absolute';
contextMenu.style.left = event.clientX + 'px';
contextMenu.style.top = event.clientY + 'px';
contextMenu.style.border = '1px solid #ccc';
contextMenu.style.backgroundColor = '#fff';
contextMenu.style.padding = '5px';
contextMenu.style.zIndex = '1000'; // Ensure it's above other elements
// Option to open in new tab
const openNewTabOption = document.createElement('div');
openNewTabOption.textContent = 'Open in New Tab';
openNewTabOption.style.cursor = 'pointer';
openNewTabOption.addEventListener('click', () => {
window.open(url, '_blank');
contextMenu.remove(); // Remove the context menu after selection
});
contextMenu.appendChild(openNewTabOption);

// Option to copy link address
const copyLinkOption = document.createElement('div');
copyLinkOption.textContent = 'Copy Link Address';
copyLinkOption.style.cursor = 'pointer';
copyLinkOption.addEventListener('click', () => {
navigator.clipboard.writeText(url).then(() => {
// Optional: Provide feedback to the user that the link was copied
console.log('Link copied to clipboard');
}).catch(err => {
console.error('Failed to copy link: ', err);
});
contextMenu.remove(); // Remove the context menu after selection
});
contextMenu.appendChild(copyLinkOption);

// Add the context menu to the document
document.body.appendChild(contextMenu);

// Remove the context menu when clicking outside of it
document.addEventListener('click', function removeContextMenu(e) {
if (!contextMenu.contains(e.target)) {
contextMenu.remove();
document.removeEventListener('click', removeContextMenu);
}
});
}
}
Loading