add calendar icon next to the tasks to edit dates within the gant
This commit is contained in:
@@ -1249,6 +1249,39 @@ GANTT
|
||||
font-size: 11px;
|
||||
color: var(--fg-muted);
|
||||
padding-left: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.gantt-ticket-id-label {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.gantt-date-edit-btn {
|
||||
flex-shrink: 0;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--border);
|
||||
background: var(--bg-input);
|
||||
color: var(--accent);
|
||||
font-size: 11px;
|
||||
cursor: pointer;
|
||||
margin-right: 8px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.gantt-date-edit-btn:hover {
|
||||
background: var(--accent-glow);
|
||||
border-color: var(--accent);
|
||||
transform: scale(1.08);
|
||||
}
|
||||
|
||||
/* Grille de fond (colonnes verticales sous les barres) */
|
||||
@@ -1353,4 +1386,99 @@ GANTT
|
||||
|
||||
.mr-4 { margin-right: 4px; }
|
||||
|
||||
/* --- Date Edit Modal --- */
|
||||
.modal-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 9998;
|
||||
background: rgba(0, 0, 0, 0.55);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
animation: fadeIn 0.2s ease;
|
||||
}
|
||||
|
||||
.modal-overlay.visible {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.modal-box {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow);
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
margin: 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 18px 20px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
.modal-title i { color: var(--accent); }
|
||||
|
||||
.modal-close {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--fg-muted);
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
line-height: 1;
|
||||
border-radius: 6px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.modal-close:hover {
|
||||
color: var(--danger);
|
||||
background: var(--accent-glow);
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.modal-ticket-key {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.modal-ticket-summary {
|
||||
font-size: 12px;
|
||||
color: var(--fg-muted);
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
.modal-date-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
padding: 16px 20px;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+78
-13
@@ -368,9 +368,8 @@ async function updateTicket(ticketKey, dueDate, goLiveDate) {
|
||||
}
|
||||
|
||||
const btn = document.querySelector(`[data-ticket="${ticketKey}"]`);
|
||||
const orig = btn.innerHTML;
|
||||
btn.innerHTML = '<span class="spinner"></span>';
|
||||
btn.disabled = true;
|
||||
const orig = btn ? btn.innerHTML : null;
|
||||
if (btn) { btn.innerHTML = '<span class="spinner"></span>'; btn.disabled = true; }
|
||||
|
||||
const goLiveField = customFieldsMap.find(cf => cf.label.toLowerCase().includes('go live'));
|
||||
const updates = {};
|
||||
@@ -400,8 +399,7 @@ async function updateTicket(ticketKey, dueDate, goLiveDate) {
|
||||
} catch (err) {
|
||||
showToast(err.message, 'error');
|
||||
} finally {
|
||||
btn.innerHTML = orig;
|
||||
btn.disabled = false;
|
||||
if (btn) { btn.innerHTML = orig; btn.disabled = false; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,6 +420,66 @@ function handleUpdateClick(ticketKey, goLiveColName) {
|
||||
updateTicket(ticketKey, dueDate, goLiveDate);
|
||||
}
|
||||
|
||||
// --- GANTT DATE EDIT MODAL ---
|
||||
let dateEditContext = { ticketKey: null, goLiveColName: null };
|
||||
|
||||
// Detects the real go-live custom field name, ignoring known built-in ticket properties
|
||||
function getGoLiveColumnName() {
|
||||
if (!allTickets.length) return null;
|
||||
return Object.keys(allTickets[0]).find(key =>
|
||||
!['key','url','summary','description','status','statusCategory','assignee','reporter','priority','issueType','created','updated','dueDate','resolution','resolutionDate','labels','components','fixVersions','projectName'].includes(key)
|
||||
) || null;
|
||||
}
|
||||
|
||||
function openDateEditModal(ticketKey) {
|
||||
const ticket = allTickets.find(t => t.key === ticketKey);
|
||||
if (!ticket) return;
|
||||
|
||||
const goLiveColName = getGoLiveColumnName();
|
||||
dateEditContext = { ticketKey, goLiveColName };
|
||||
|
||||
document.getElementById('dateEditTicketKey').textContent = ticket.key;
|
||||
document.getElementById('dateEditTicketSummary').textContent = ticket.summary || '';
|
||||
document.getElementById('modalDueDate').value = ticket.dueDate ? ticket.dueDate.substring(0, 10) : '';
|
||||
|
||||
const goLiveGroup = document.getElementById('modalGoLiveGroup');
|
||||
if (goLiveColName) {
|
||||
goLiveGroup.style.display = '';
|
||||
document.getElementById('modalGoLiveLabel').textContent = goLiveColName;
|
||||
document.getElementById('modalGoLiveDate').value = ticket[goLiveColName] ? ticket[goLiveColName].substring(0, 10) : '';
|
||||
} else {
|
||||
goLiveGroup.style.display = 'none';
|
||||
}
|
||||
|
||||
document.getElementById('dateEditModal').classList.add('visible');
|
||||
}
|
||||
|
||||
function closeDateEditModal() {
|
||||
document.getElementById('dateEditModal').classList.remove('visible');
|
||||
dateEditContext = { ticketKey: null, goLiveColName: null };
|
||||
}
|
||||
|
||||
async function saveDateEditModal() {
|
||||
const { ticketKey, goLiveColName } = dateEditContext;
|
||||
if (!ticketKey) return;
|
||||
|
||||
const dueDate = document.getElementById('modalDueDate').value || null;
|
||||
const goLiveDate = goLiveColName ? (document.getElementById('modalGoLiveDate').value || null) : undefined;
|
||||
|
||||
const btn = document.getElementById('modalSaveBtn');
|
||||
const orig = btn.innerHTML;
|
||||
btn.innerHTML = '<span class="spinner"></span>';
|
||||
btn.disabled = true;
|
||||
|
||||
try {
|
||||
await updateTicket(ticketKey, dueDate, goLiveDate);
|
||||
closeDateEditModal();
|
||||
} finally {
|
||||
btn.innerHTML = orig;
|
||||
btn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// --- RENDERING ---
|
||||
function renderResults() {
|
||||
document.getElementById('results-section').classList.add('visible');
|
||||
@@ -444,12 +502,7 @@ function escHtml(s) { if(!s) return ''; const d=document.createElement('div'); d
|
||||
function fmtDate(d) { if(!d) return '<span class="empty-cell">-</span>'; try { return new Date(d).toLocaleDateString('en-US',{day:'2-digit',month:'short',year:'numeric'}); } catch { return escHtml(d); } }
|
||||
|
||||
function renderTable() {
|
||||
let goLiveColName = null;
|
||||
if (allTickets.length > 0) {
|
||||
goLiveColName = Object.keys(allTickets[0]).find(key =>
|
||||
!['key','url','summary','description','status','statusCategory','assignee','reporter','priority','issueType','created','updated','dueDate','resolution','resolutionDate','labels','components','fixVersions','projectName'].includes(key)
|
||||
);
|
||||
}
|
||||
const goLiveColName = getGoLiveColumnName();
|
||||
|
||||
const colMapping = {
|
||||
'Ticket': 'key',
|
||||
@@ -704,7 +757,10 @@ function renderRoadmap() {
|
||||
|
||||
html += `<div class="gantt-row">
|
||||
<div class="gantt-sticky-col gantt-ticket-id" style="width:${leftWidth}px;" title="${escHtml(t.key)}: ${escHtml(t.summary)}">
|
||||
${escHtml(shortTitle)}
|
||||
<button class="gantt-date-edit-btn" onclick="event.stopPropagation(); openDateEditModal('${t.key}')" title="Edit dates">
|
||||
<i class="fa-solid fa-calendar-days"></i>
|
||||
</button>
|
||||
<span class="gantt-ticket-id-label">${escHtml(shortTitle)}</span>
|
||||
</div>
|
||||
|
||||
<div class="gantt-bar"
|
||||
@@ -906,9 +962,18 @@ function copyJSON() { navigator.clipboard.writeText(JSON.stringify(allTickets, n
|
||||
|
||||
function clearResults() { allTickets=[]; filteredTickets=[]; document.getElementById('results-section').classList.remove('visible'); }
|
||||
|
||||
document.addEventListener('keydown', e => { if((e.ctrlKey||e.metaKey)&&e.key==='Enter'){e.preventDefault();startExtraction()} });
|
||||
document.addEventListener('keydown', e => {
|
||||
if((e.ctrlKey||e.metaKey)&&e.key==='Enter'){e.preventDefault();startExtraction()}
|
||||
if(e.key === 'Escape') closeDateEditModal();
|
||||
});
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initTheme();
|
||||
loadSettings();
|
||||
|
||||
const modalOverlay = document.getElementById('dateEditModal');
|
||||
if (modalOverlay) {
|
||||
modalOverlay.addEventListener('click', e => { if (e.target === modalOverlay) closeDateEditModal(); });
|
||||
}
|
||||
|
||||
console.log("Settings loaded from local storage.");
|
||||
});
|
||||
Reference in New Issue
Block a user