Fix inbox badge logic and landing view

This commit is contained in:
Dotta
2026-03-10 22:55:45 -05:00
parent 92aef9bae8
commit 21d2b075e7
14 changed files with 453 additions and 230 deletions

View File

@@ -3,7 +3,6 @@ import type { Db } from "@paperclipai/db";
import { and, eq, sql } from "drizzle-orm";
import { joinRequests } from "@paperclipai/db";
import { sidebarBadgeService } from "../services/sidebar-badges.js";
import { issueService } from "../services/issues.js";
import { accessService } from "../services/access.js";
import { dashboardService } from "../services/dashboard.js";
import { assertCompanyAccess } from "./authz.js";
@@ -11,7 +10,6 @@ import { assertCompanyAccess } from "./authz.js";
export function sidebarBadgeRoutes(db: Db) {
const router = Router();
const svc = sidebarBadgeService(db);
const issueSvc = issueService(db);
const access = accessService(db);
const dashboard = dashboardService(db);
@@ -40,12 +38,11 @@ export function sidebarBadgeRoutes(db: Db) {
joinRequests: joinRequestCount,
});
const summary = await dashboard.summary(companyId);
const staleIssueCount = await issueSvc.staleCount(companyId, 24 * 60);
const hasFailedRuns = badges.failedRuns > 0;
const alertsCount =
(summary.agents.error > 0 && !hasFailedRuns ? 1 : 0) +
(summary.costs.monthBudgetCents > 0 && summary.costs.monthUtilizationPercent >= 80 ? 1 : 0);
badges.inbox = badges.failedRuns + alertsCount + staleIssueCount + joinRequestCount + badges.approvals;
badges.inbox = badges.failedRuns + alertsCount + joinRequestCount + badges.approvals;
res.json(badges);
});

View File

@@ -32,19 +32,6 @@ export function dashboardService(db: Db) {
.where(and(eq(approvals.companyId, companyId), eq(approvals.status, "pending")))
.then((rows) => Number(rows[0]?.count ?? 0));
const staleCutoff = new Date(Date.now() - 60 * 60 * 1000);
const staleTasks = await db
.select({ count: sql<number>`count(*)` })
.from(issues)
.where(
and(
eq(issues.companyId, companyId),
eq(issues.status, "in_progress"),
sql`${issues.startedAt} < ${staleCutoff.toISOString()}`,
),
)
.then((rows) => Number(rows[0]?.count ?? 0));
const agentCounts: Record<string, number> = {
active: 0,
running: 0,
@@ -107,7 +94,6 @@ export function dashboardService(db: Db) {
monthUtilizationPercent: Number(utilization.toFixed(2)),
},
pendingApprovals,
staleTasks,
};
},
};

View File

@@ -1411,23 +1411,5 @@ export function issueService(db: Db) {
goal: a.goalId ? goalMap.get(a.goalId) ?? null : null,
}));
},
staleCount: async (companyId: string, minutes = 60) => {
const cutoff = new Date(Date.now() - minutes * 60 * 1000);
const result = await db
.select({ count: sql<number>`count(*)` })
.from(issues)
.where(
and(
eq(issues.companyId, companyId),
eq(issues.status, "in_progress"),
isNull(issues.hiddenAt),
sql`${issues.startedAt} < ${cutoff.toISOString()}`,
),
)
.then((rows) => rows[0]);
return Number(result?.count ?? 0);
},
};
}