Fix Cora filter, speed up Overview, add inbox path link

Remove status gate from Cora filter — LB Method is the discriminator,
not status. Derive Overview stats and Cora section from /tasks data
directly (no slow /tasks/link-building fetch). Add click-to-copy
Z:\cora-inbox path next to Cora header. Show due dates in This Month.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cora-start
PeninsulaInd 2026-02-20 11:51:29 -06:00
parent f67f1b9124
commit 01ba657b35
2 changed files with 35 additions and 37 deletions

View File

@ -184,11 +184,17 @@ async def get_link_building_tasks():
# -- Build focused groups -- # -- Build focused groups --
# need_cora: status "to do" AND LB Method = "Cora Backlinks" # Split active vs closed
need_cora = [ closed_statuses = {"complete", "closed", "done"}
active_lb = [
t for t in lb_tasks t for t in lb_tasks
if t["status"] == "to do" if not any(kw in t["status"] for kw in closed_statuses)
and t["custom_fields"].get("LB Method") == "Cora Backlinks" ]
# need_cora: open LB tasks where LB Method = "Cora Backlinks"
need_cora = [
t for t in active_lb
if t["custom_fields"].get("LB Method") == "Cora Backlinks"
] ]
# recently_completed: closed/complete tasks with date_done in last 7 days # recently_completed: closed/complete tasks with date_done in last 7 days
@ -215,13 +221,6 @@ async def get_link_building_tasks():
kv = t.get("kv_state") kv = t.get("kv_state")
if kv is None or kv.get("state", "") in early_states: if kv is None or kv.get("state", "") in early_states:
in_progress_not_started.append(t) in_progress_not_started.append(t)
# Group by company (exclude closed from the active list for the grid)
closed_statuses = {"complete", "closed", "done"}
active_lb = [
t for t in lb_tasks
if not any(kw in t["status"] for kw in closed_statuses)
]
by_company: dict[str, list] = {} by_company: dict[str, list] = {}
for task in active_lb: for task in active_lb:
company = task["custom_fields"].get("Customer") or "Unassigned" company = task["custom_fields"].get("Customer") or "Unassigned"

View File

@ -151,6 +151,7 @@
<div class="section section--tight"> <div class="section section--tight">
<div class="section__header"> <div class="section__header">
<h2 class="section__title"><span class="icon">&#128203;</span> Cora Reports Needed</h2> <h2 class="section__title"><span class="icon">&#128203;</span> Cora Reports Needed</h2>
<span onclick="navigator.clipboard.writeText('Z:\\cora-inbox');this.textContent='Copied!';setTimeout(()=>this.textContent='Z:\\cora-inbox',1500)" style="font-size:0.75rem;color:var(--gold-light);cursor:pointer;margin-left:0.5rem;" title="Click to copy path">Z:\cora-inbox</span>
<span class="section__badge"><a href="#" class="section__link" data-tab="linkbuilding">View LB</a></span> <span class="section__badge"><a href="#" class="section__link" data-tab="linkbuilding">View LB</a></span>
</div> </div>
<div class="task-table-wrap task-table-wrap--compact" id="overview-cora"> <div class="task-table-wrap task-table-wrap--compact" id="overview-cora">
@ -350,39 +351,35 @@ function updateGreeting() {
// --- Overview Tab --- // --- Overview Tab ---
async function loadOverview() { async function loadOverview() {
const [tasks, lb, pr, agents, health] = await Promise.all([ const [tasks, agents, health] = await Promise.all([
fetchJSON('/tasks'), fetchJSON('/tasks'),
fetchJSON('/tasks/link-building'),
fetchJSON('/tasks/press-releases'),
fetchJSON('/agents'), fetchJSON('/agents'),
fetchJSON('/system/health'), fetchJSON('/system/health'),
]); ]);
// Cache for other tabs // Cache for other tabs
_cache.tasks = tasks; _cache.tasks = tasks;
_cache.lb = lb;
_cache.pr = pr;
_cache.agents = agents; _cache.agents = agents;
_cache.health = health; _cache.health = health;
// Stats // Stats — derive LB/PR counts from tasks data
if (tasks) { if (tasks && tasks.tasks) {
document.getElementById('stat-total').textContent = tasks.count || 0; document.getElementById('stat-total').textContent = tasks.count || 0;
document.getElementById('stat-total-detail').textContent = `ClickUp tasks`; document.getElementById('stat-total-detail').textContent = `ClickUp tasks`;
}
if (lb) { const lbTasks = tasks.tasks.filter(t => t.task_type === 'Link Building');
document.getElementById('stat-lb').textContent = lb.total || 0; const prTasks = tasks.tasks.filter(t => t.task_type === 'Press Release');
document.getElementById('stat-lb-detail').textContent =
`${lb.companies ? lb.companies.length : 0} companies`; document.getElementById('stat-lb').textContent = lbTasks.length;
document.getElementById('badge-lb').textContent = lb.total || 0; const lbCompanies = new Set(lbTasks.map(t => t.custom_fields?.Customer || 'Unassigned'));
} document.getElementById('stat-lb-detail').textContent = `${lbCompanies.size} companies`;
if (pr) { document.getElementById('badge-lb').textContent = lbTasks.length;
document.getElementById('stat-pr').textContent = pr.total || 0;
document.getElementById('stat-pr-detail').textContent = document.getElementById('stat-pr').textContent = prTasks.length;
`${pr.companies ? pr.companies.length : 0} companies`; const prCompanies = new Set(prTasks.map(t => t.custom_fields?.Customer || 'Unassigned'));
document.getElementById('badge-pr').textContent = pr.total || 0; document.getElementById('stat-pr-detail').textContent = `${prCompanies.size} companies`;
} document.getElementById('badge-pr').textContent = prTasks.length;
if (tasks && tasks.tasks) {
const companies = new Set(tasks.tasks.map(t => t.custom_fields?.Customer || 'Unassigned')); const companies = new Set(tasks.tasks.map(t => t.custom_fields?.Customer || 'Unassigned'));
document.getElementById('stat-companies').textContent = companies.size; document.getElementById('stat-companies').textContent = companies.size;
const names = [...companies].filter(c => c !== 'Unassigned').slice(0, 4).join(', '); const names = [...companies].filter(c => c !== 'Unassigned').slice(0, 4).join(', ');
@ -443,12 +440,14 @@ async function loadOverview() {
} }
} }
document.getElementById('this-month-count').textContent = thisMonth.length; document.getElementById('this-month-count').textContent = thisMonth.length;
renderOverviewTable('overview-this-month', thisMonth, false); renderOverviewTable('overview-this-month', thisMonth, true);
}
// -- Cora Reports Needed -- // -- Cora Reports Needed: LB tasks with LB Method = Cora Backlinks --
if (lb && lb.need_cora) { const needCora = openTasks.filter(t =>
renderOverviewTable('overview-cora', lb.need_cora, false); t.task_type === 'Link Building'
&& t.custom_fields?.['LB Method'] === 'Cora Backlinks'
);
renderOverviewTable('overview-cora', needCora, false);
} }
// Health inline // Health inline