Add Cora Reports to Run queue as first section on Link Building tab
Filters out automation-touched tasks (error, automation underway, complete, closed, done, internal review) and sorts by due date. Renders with 10-at-a-time pagination and responsive mobile layout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>cora-start
parent
3f2798d338
commit
ee7b4cc256
|
|
@ -192,10 +192,17 @@ async def get_link_building_tasks():
|
|||
]
|
||||
|
||||
# need_cora: open LB tasks where LB Method = "Cora Backlinks"
|
||||
# Exclude tasks that automation already touched
|
||||
automation_touched = {
|
||||
"error", "automation underway", "complete",
|
||||
"closed", "done", "internal review",
|
||||
}
|
||||
need_cora = [
|
||||
t for t in active_lb
|
||||
if t["custom_fields"].get("LB Method") == "Cora Backlinks"
|
||||
and t["status"] not in automation_touched
|
||||
]
|
||||
need_cora.sort(key=lambda t: int(t.get("due_date") or "9999999999999"))
|
||||
|
||||
# recently_completed: closed/complete tasks with date_done in last 7 days
|
||||
seven_days_ago_ms = (time.time() - 7 * 86400) * 1000
|
||||
|
|
|
|||
|
|
@ -178,6 +178,17 @@
|
|||
|
||||
<div class="stats-row" id="lb-stats"></div>
|
||||
|
||||
<!-- Cora Reports to Run -->
|
||||
<div class="section">
|
||||
<div class="section__header">
|
||||
<h2 class="section__title"><span class="icon">📋</span> Cora Reports to Run</h2>
|
||||
<span class="section__badge" id="lb-cora-count">-</span>
|
||||
</div>
|
||||
<div class="task-table-wrap" id="lb-cora-table">
|
||||
<p style="padding:1rem;color:var(--text-muted);">Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recently Completed (Past 7 Days) -->
|
||||
<div class="section">
|
||||
<div class="section__header">
|
||||
|
|
@ -523,6 +534,69 @@ function renderRecentTable(containerId, tasks) {
|
|||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
function renderCoraQueue(containerId, tasks) {
|
||||
const container = document.getElementById(containerId);
|
||||
if (!tasks || tasks.length === 0) {
|
||||
container.innerHTML = '<p style="padding:1rem;color:var(--text-muted);">No Cora reports queued.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
const PAGE_SIZE = 10;
|
||||
let showAll = false;
|
||||
|
||||
function render() {
|
||||
const visible = showAll ? tasks : tasks.slice(0, PAGE_SIZE);
|
||||
let html = `<table class="task-table task-table--dense">
|
||||
<thead><tr>
|
||||
<th class="cora-hide-mobile">#</th>
|
||||
<th class="cora-hide-mobile">Task</th>
|
||||
<th>Keyword</th>
|
||||
<th>Company</th>
|
||||
<th class="cora-hide-mobile">Due Date</th>
|
||||
</tr></thead><tbody>`;
|
||||
|
||||
visible.forEach((t, i) => {
|
||||
const company = t.custom_fields?.Customer || 'Unassigned';
|
||||
const keyword = t.custom_fields?.Keyword || '';
|
||||
const link = t.url ? `<a href="${esc(t.url)}" target="_blank" style="color:var(--cream-light);text-decoration:none;">${esc(t.name)}</a>` : esc(t.name);
|
||||
let dueStr = '-';
|
||||
if (t.due_date) {
|
||||
const d = new Date(parseInt(t.due_date, 10));
|
||||
dueStr = d.toLocaleDateString('en-US', {month:'short', day:'numeric'});
|
||||
}
|
||||
html += `<tr>
|
||||
<td class="task-table__num cora-hide-mobile">${i + 1}</td>
|
||||
<td class="task-table__title cora-hide-mobile">${link}</td>
|
||||
<td class="task-table__keyword">${esc(keyword)}</td>
|
||||
<td class="task-table__company">${esc(company)}</td>
|
||||
<td class="cora-hide-mobile" style="white-space:nowrap;">${esc(dueStr)}</td>
|
||||
</tr>`;
|
||||
});
|
||||
|
||||
html += '</tbody></table>';
|
||||
|
||||
if (tasks.length > PAGE_SIZE) {
|
||||
const remaining = tasks.length - PAGE_SIZE;
|
||||
const label = showAll ? 'Show less' : `Show more (${remaining} remaining)`;
|
||||
html += `<div style="text-align:center;padding:0.75rem;">
|
||||
<button id="cora-toggle-btn" style="background:none;border:1px solid var(--border);color:var(--gold-light);padding:0.4rem 1.2rem;border-radius:var(--radius);cursor:pointer;font-size:0.8rem;">${label}</button>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
container.innerHTML = html;
|
||||
|
||||
const btn = document.getElementById('cora-toggle-btn');
|
||||
if (btn) {
|
||||
btn.addEventListener('click', () => {
|
||||
showAll = !showAll;
|
||||
render();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render();
|
||||
}
|
||||
|
||||
function renderOverviewTable(containerId, tasks, showDueDate) {
|
||||
const container = document.getElementById(containerId);
|
||||
if (!tasks || tasks.length === 0) {
|
||||
|
|
@ -644,6 +718,11 @@ async function loadLinkBuilding() {
|
|||
`;
|
||||
document.getElementById('lb-stats').innerHTML = statsHtml;
|
||||
|
||||
// Cora Reports to Run
|
||||
const coraQueue = data.need_cora || [];
|
||||
document.getElementById('lb-cora-count').textContent = coraQueue.length;
|
||||
renderCoraQueue('lb-cora-table', coraQueue);
|
||||
|
||||
// Recently Completed
|
||||
const recent = data.recently_completed || [];
|
||||
document.getElementById('lb-recent-count').textContent = recent.length;
|
||||
|
|
|
|||
|
|
@ -1014,6 +1014,10 @@ body {
|
|||
min-width: 700px;
|
||||
}
|
||||
|
||||
.cora-hide-mobile {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.page-header__greeting {
|
||||
font-size: 1.35rem;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue