diff --git a/corvid/templates/tickets_base.html b/corvid/templates/tickets_base.html
index d65374b..7f1b5b6 100644
--- a/corvid/templates/tickets_base.html
+++ b/corvid/templates/tickets_base.html
@@ -527,6 +527,7 @@ let currentTicket = null;
let expandedParents = new Set();
let currentAttach = null;
let tickets = [];
+let extraTickets = {};
let attachments = [];
let environments = [];
let currentEnvironmentId = null;
@@ -699,17 +700,20 @@ async function loadTickets() {
}
}
+function getTicketById(id) {
+ return tickets.find(t => t.id === id) || extraTickets[id] || null;
+}
+
function renderTicketRow(t) {
- const visibleChildIds = (t.child_ids || []).filter(cid => tickets.some(c => c.id === cid));
const totalChildCount = (t.child_ids || []).length;
- const visibleCount = visibleChildIds.length;
+ const knownChildIds = (t.child_ids || []).filter(cid => getTicketById(cid));
const expanded = expandedParents.has(t.id);
return `
${t.human_id}
${escHtml(t.title)}
- ${totalChildCount ? `${visibleCount ? `` : ''}${totalChildCount}` : ''}
+ ${totalChildCount ? `${totalChildCount}` : ''}
${typeBadge(t.type)}
@@ -722,7 +726,7 @@ function renderTicketRow(t) {
${t.attachment_count ? `·${t.attachment_count} file${t.attachment_count !== 1 ? 's' : ''}` : ''}
- ${visibleCount && expanded ? `${visibleChildIds.map(cid => renderTicketRow(tickets.find(c => c.id === cid))).join('')}
` : ''}
+ ${knownChildIds.length && expanded ? `${knownChildIds.map(cid => renderTicketRow(getTicketById(cid))).join('')}
` : ''}
`;
}
@@ -753,9 +757,14 @@ function renderList() {
list.innerHTML = roots.map(renderTicketRow).join('');
}
-function showDetail(id) {
- currentTicket = tickets.find(t => t.id === id);
- if (!currentTicket) return;
+async function showDetail(id) {
+ currentTicket = getTicketById(id);
+ if (!currentTicket) {
+ try {
+ currentTicket = await api(`/api/tickets/${id}`);
+ extraTickets[id] = currentTicket;
+ } catch(e) { return; }
+ }
const t = currentTicket;
document.getElementById('d-human-id').textContent = t.human_id;
document.getElementById('d-title').textContent = t.title;
@@ -782,16 +791,17 @@ function showDetail(id) {
if (t.child_ids && t.child_ids.length) {
const childList = document.getElementById('d-children-list');
childList.innerHTML = t.child_ids.map(cid => {
- const child = tickets.find(c => c.id === cid);
+ const child = getTicketById(cid);
const label = child ? `${child.human_id} ${escHtml(child.title)}` : `#${cid}`;
return `${label}`;
}).join('');
childWrap.style.display = '';
- // Fetch any children that aren't in the current filtered ticket list
+ // Fetch any children not in the local ticket list and cache them
t.child_ids.forEach(async cid => {
- if (!tickets.find(c => c.id === cid)) {
+ if (!getTicketById(cid)) {
try {
const child = await api(`/api/tickets/${cid}`);
+ extraTickets[child.id] = child;
const el = document.getElementById(`child-ref-${cid}`);
if (el) el.textContent = `${child.human_id} ${child.title}`;
} catch(e) { /* keep fallback label */ }