update
This commit is contained in:
1 parent
806200b3d1
commit
5547c29491
216 files changed
+5043
-3352
No files matched your search
@@ -48,13 +48,13 @@ export function Inbox({ items, onNavigate }: InboxProps) {
|
||||
};
|
||||
|
||||
const filterButtons: Array<{ key: InboxItemType | "all"; label: string; count: number }> = [
|
||||
{ key: "all", label: "All", count: counts.all },
|
||||
{ key: "pending_approval", label: "Approvals", count: counts.pending_approval },
|
||||
{ key: "review_needed", label: "Reviews", count: counts.review_needed },
|
||||
{ key: "failed_run", label: "Failed", count: counts.failed_run },
|
||||
{ key: "blocked_task", label: "Blocked", count: counts.blocked_task },
|
||||
{ key: "budget_warning", label: "Budget", count: counts.budget_warning },
|
||||
{ key: "agent_message", label: "Messages", count: counts.agent_message },
|
||||
{ key: "all", label: t("inbox.filter.all"), count: counts.all },
|
||||
{ key: "pending_approval", label: t("inbox.filter.approvals"), count: counts.pending_approval },
|
||||
{ key: "review_needed", label: t("inbox.filter.reviews"), count: counts.review_needed },
|
||||
{ key: "failed_run", label: t("inbox.filter.failed"), count: counts.failed_run },
|
||||
{ key: "blocked_task", label: t("inbox.filter.blocked"), count: counts.blocked_task },
|
||||
{ key: "budget_warning", label: t("inbox.filter.budget"), count: counts.budget_warning },
|
||||
{ key: "agent_message", label: t("inbox.filter.messages"), count: counts.agent_message },
|
||||
];
|
||||
|
||||
return (
|
||||
@@ -67,7 +67,7 @@ export function Inbox({ items, onNavigate }: InboxProps) {
|
||||
<div>
|
||||
<h2 className="text-[18px] font-bold tracking-[-0.02em] text-foreground">{t("inbox.title")}</h2>
|
||||
<p className="text-[12px] text-muted-foreground">
|
||||
{counts.all} item{counts.all !== 1 ? "s" : ""} need{counts.all === 1 ? "s" : ""} your attention
|
||||
{counts.all} {t("inbox.needsAttention")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { CompanyMetrics, SectionId } from "@shared/types";
|
||||
import { formatDuration, formatMoney, getAgentInitials } from "../../lib/formatters";
|
||||
import { useT } from "../../i18n";
|
||||
import { CompactMetric, RunProgressBar } from "./inbox-helpers";
|
||||
import { Card, Eyebrow } from "../ui";
|
||||
|
||||
interface PerformanceProps {
|
||||
metrics: CompanyMetrics | null;
|
||||
@@ -48,8 +49,8 @@ export function PerformanceView({ metrics, onNavigate }: PerformanceProps) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="rounded-lg border border-border bg-card p-5">
|
||||
<div className="mb-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">Run Activity (30d)</div>
|
||||
<Card padding="lg">
|
||||
<Eyebrow className="mb-3">{t("perf.runActivity30d")}</Eyebrow>
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="flex-1">
|
||||
<RunProgressBar
|
||||
@@ -61,28 +62,28 @@ export function PerformanceView({ metrics, onNavigate }: PerformanceProps) {
|
||||
<div className="flex gap-4 text-[12px]">
|
||||
<span className="flex items-center gap-1.5">
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-success" />
|
||||
<span className="text-muted-foreground">{metrics.successfulRuns} succeeded</span>
|
||||
<span className="text-muted-foreground">{t("perf.runsSucceeded").replace("{n}", String(metrics.successfulRuns))}</span>
|
||||
</span>
|
||||
<span className="flex items-center gap-1.5">
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-destructive" />
|
||||
<span className="text-muted-foreground">{metrics.failedRuns} failed</span>
|
||||
<span className="text-muted-foreground">{t("perf.runsFailed").replace("{n}", String(metrics.failedRuns))}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<section>
|
||||
<div className="mb-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">Agent Performance</div>
|
||||
<Eyebrow className="mb-3">{t("perf.agentPerformance")}</Eyebrow>
|
||||
<div className="overflow-x-auto rounded-lg border border-border">
|
||||
<table className="w-full text-left">
|
||||
<thead>
|
||||
<tr className="border-b border-border bg-muted">
|
||||
<th className="px-4 py-2.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-muted-foreground">Agent</th>
|
||||
<th className="px-3 py-2.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-muted-foreground text-right">Tasks Done</th>
|
||||
<th className="px-3 py-2.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-muted-foreground text-right">Success %</th>
|
||||
<th className="px-3 py-2.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-muted-foreground text-right">Runs</th>
|
||||
<th className="px-3 py-2.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-muted-foreground text-right">Avg Duration</th>
|
||||
<th className="px-3 py-2.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-muted-foreground text-right">Cost</th>
|
||||
<th className="px-4 py-2.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-muted-foreground">{t("perf.agent")}</th>
|
||||
<th className="px-3 py-2.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-muted-foreground text-right">{t("perf.tasksDoneCol")}</th>
|
||||
<th className="px-3 py-2.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-muted-foreground text-right">{t("perf.successPct")}</th>
|
||||
<th className="px-3 py-2.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-muted-foreground text-right">{t("perf.runsCol")}</th>
|
||||
<th className="px-3 py-2.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-muted-foreground text-right">{t("perf.avgDuration")}</th>
|
||||
<th className="px-3 py-2.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-muted-foreground text-right">{t("perf.costCol")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import type { SectionId, StandupReport } from "@shared/types";
|
||||
import { getAgentInitials } from "../../lib/formatters";
|
||||
import { useT } from "../../i18n";
|
||||
import { Card, Eyebrow } from "../ui";
|
||||
|
||||
interface StandupProps {
|
||||
report: StandupReport | null;
|
||||
@@ -28,7 +29,7 @@ export function StandupView({ report, onNavigate }: StandupProps) {
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="rounded-lg border border-border bg-card p-5">
|
||||
<Card padding="lg">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-accent">
|
||||
<Heartbeat size={20} weight="fill" className="text-primary" />
|
||||
@@ -36,7 +37,7 @@ export function StandupView({ report, onNavigate }: StandupProps) {
|
||||
<div>
|
||||
<h2 className="text-[16px] font-bold text-foreground">{t("standup.dailyStandup")}</h2>
|
||||
<p className="text-[12px] text-muted-foreground">
|
||||
Generated {new Date(report.generatedAt).toLocaleString()}
|
||||
{t("standup.generatedAt").replace("{time}", new Date(report.generatedAt).toLocaleString())}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -64,11 +65,11 @@ export function StandupView({ report, onNavigate }: StandupProps) {
|
||||
<div className="text-[10px] text-muted-foreground">{t("standup.budgetUsed")}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{report.companyHighlights.length > 0 ? (
|
||||
<section>
|
||||
<div className="mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">{t("standup.highlights")}</div>
|
||||
<Eyebrow className="mb-2">{t("standup.highlights")}</Eyebrow>
|
||||
<div className="space-y-1.5">
|
||||
{report.companyHighlights.map((h, i) => (
|
||||
<div key={i} className="flex items-center gap-2 rounded-lg bg-success-muted px-3 py-2 text-[12px] text-success">
|
||||
@@ -82,7 +83,7 @@ export function StandupView({ report, onNavigate }: StandupProps) {
|
||||
|
||||
{report.blockers.length > 0 ? (
|
||||
<section>
|
||||
<div className="mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-destructive">Blockers</div>
|
||||
<Eyebrow tone="destructive" className="mb-2">{t("standup.blockers")}</Eyebrow>
|
||||
<div className="space-y-1.5">
|
||||
{report.blockers.map((b, i) => (
|
||||
<div key={i} className="flex items-center gap-2 rounded-lg bg-destructive-muted px-3 py-2 text-[12px] text-destructive">
|
||||
@@ -95,7 +96,7 @@ export function StandupView({ report, onNavigate }: StandupProps) {
|
||||
) : null}
|
||||
|
||||
<section>
|
||||
<div className="mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">{t("standup.agentStatus")}</div>
|
||||
<Eyebrow className="mb-2">{t("standup.agentStatus")}</Eyebrow>
|
||||
<div className="space-y-2">
|
||||
{report.agentReports.map((ar) => (
|
||||
<button
|
||||
@@ -125,9 +126,9 @@ export function StandupView({ report, onNavigate }: StandupProps) {
|
||||
<span className="text-[10px] text-muted-foreground">{ar.role}</span>
|
||||
</div>
|
||||
<div className="mt-1 flex flex-wrap gap-3 text-[11px] text-muted-foreground">
|
||||
{ar.tasksInProgress > 0 ? <span className="text-primary">{ar.tasksInProgress} in progress</span> : null}
|
||||
{ar.tasksCompleted24h > 0 ? <span className="text-success">{ar.tasksCompleted24h} done</span> : null}
|
||||
{ar.tasksBlocked > 0 ? <span className="text-destructive">{ar.tasksBlocked} blocked</span> : null}
|
||||
{ar.tasksInProgress > 0 ? <span className="text-primary">{t("standup.runHighlight.tasksInProgress").replace("{n}", String(ar.tasksInProgress))}</span> : null}
|
||||
{ar.tasksCompleted24h > 0 ? <span className="text-success">{t("standup.runHighlight.tasksDone").replace("{n}", String(ar.tasksCompleted24h))}</span> : null}
|
||||
{ar.tasksBlocked > 0 ? <span className="text-destructive">{t("standup.runHighlight.tasksBlocked").replace("{n}", String(ar.tasksBlocked))}</span> : null}
|
||||
{ar.costLast24h > 0 ? <span className="tabular-nums">${ar.costLast24h.toFixed(2)}</span> : null}
|
||||
</div>
|
||||
{ar.highlights.length > 0 ? (
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
ChatCircle,
|
||||
} from "../ui/icons";
|
||||
import type { InboxItemType } from "@shared/types";
|
||||
import { Card } from "../ui";
|
||||
|
||||
export const typeConfig: Record<InboxItemType, { icon: React.ElementType; color: string; bg: string; label: string }> = {
|
||||
pending_approval: { icon: ShieldCheck, color: "var(--destructive)", bg: "var(--muted-foreground)", label: "Approval" },
|
||||
@@ -45,11 +46,11 @@ export function CompactMetric({ label, value, tone = "default", subtitle }: {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-border bg-card px-4 py-3">
|
||||
<Card padding="sm">
|
||||
<div className="text-[10px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">{label}</div>
|
||||
<div className={`text-[22px] font-bold ${toneMap[tone]}`}>{value}</div>
|
||||
{subtitle ? <div className="text-[10px] text-muted-foreground">{subtitle}</div> : null}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user