Fix all renderer lint errors
Remove dead imports and unused values across pages; replace the MentionTextarea index-reset effect with an event-time reset; compute budget chart segment offsets in a pure helper instead of mutating a render-scope variable; drop the manual memoization the compiler could not preserve in BillingPanel.
This commit is contained in:
1 parent
a65347b91f
commit
f964d052e2
10 files changed
+37
-35
No files matched your search
@@ -2,7 +2,6 @@ import { useMemo, useState, type FormEvent } from "react";
|
||||
import { Avatar, Button, Field, Icon, IconButton, Pill } from "../shared/ui";
|
||||
import { TopbarActions } from "../shared/TopbarActions";
|
||||
import { Dialog } from "../shared/Dialog";
|
||||
import type { DocumentRecord } from "../../../shared/domain";
|
||||
import type { PageProps } from "./types";
|
||||
import { activeOrgId, formatRelative } from "./types";
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import { Avatar, Button, Icon, Pill, Segmented } from "../shared/ui";
|
||||
import { Avatar, Pill, Segmented } from "../shared/ui";
|
||||
import { TopbarActions } from "../shared/TopbarActions";
|
||||
import type { AgentRecord, ApprovalRecord, ChatMessageRecord, TaskRecord, TaskRunRecord } from "../../../shared/domain";
|
||||
import { TASK_STATUS } from "../../../shared/domain";
|
||||
import type { PageProps } from "./types";
|
||||
import { activeOrgId, formatRelative, requireActiveEmployee } from "./types";
|
||||
import { activeOrgId, formatRelative } from "./types";
|
||||
|
||||
type InboxFilter = "all" | "approvals" | "failures" | "blocked" | "messages";
|
||||
const FILTERS: Array<{ id: InboxFilter; label: string }> = [
|
||||
@@ -32,9 +32,8 @@ interface InboxItem {
|
||||
tone: "amber" | "red" | "violet" | undefined;
|
||||
}
|
||||
|
||||
export function InboxPage({ snapshot, actions, navigate }: PageProps) {
|
||||
export function InboxPage({ snapshot }: PageProps) {
|
||||
const orgId = activeOrgId(snapshot);
|
||||
const employee = requireActiveEmployee(snapshot);
|
||||
const agents = useMemo(() => snapshot.agents.filter((a) => a.orgId === orgId), [snapshot.agents, orgId]);
|
||||
const tasks = useMemo(() => snapshot.tasks.filter((t) => t.orgId === orgId), [snapshot.tasks, orgId]);
|
||||
const taskRuns = useMemo(() => snapshot.taskRuns.filter((r) => r.orgId === orgId), [snapshot.taskRuns, orgId]);
|
||||
@@ -116,7 +115,6 @@ function PerformanceView({ agents, tasks, taskRuns }: { agents: AgentRecord[]; t
|
||||
const completedRuns = taskRuns.filter((r) => r.state === "completed").length;
|
||||
const failedRuns = taskRuns.filter((r) => r.state === "failed").length;
|
||||
const successRate = completedRuns + failedRuns > 0 ? Math.round((completedRuns / (completedRuns + failedRuns)) * 100) : 0;
|
||||
const throughput = doneTasks;
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Button, Field, Icon, IconButton, Pill } from "../shared/ui";
|
||||
import { TopbarActions } from "../shared/TopbarActions";
|
||||
import { Dialog } from "../shared/Dialog";
|
||||
import type { PageProps } from "./types";
|
||||
import { activeOrgId, formatRelative } from "./types";
|
||||
import { activeOrgId } from "./types";
|
||||
|
||||
const MEETING_TYPES = ["standup", "all_hands", "sprint_review", "retrospective", "planning", "one_on_one", "ad_hoc"] as const;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import { Avatar, Button, Icon, IconButton, Pill, Segmented } from "../shared/ui";
|
||||
import { TopbarActions } from "../shared/TopbarActions";
|
||||
import { Avatar, Pill, Segmented } from "../shared/ui";
|
||||
import type { AgentRecord, ProviderRecord, TaskRecord, TaskRunRecord } from "../../../shared/domain";
|
||||
import type { PageProps } from "./types";
|
||||
import { activeOrgId, formatRelative } from "./types";
|
||||
@@ -14,7 +13,7 @@ const FILTERS: Array<{ id: StatusFilter; label: string }> = [
|
||||
{ id: "failed", label: "Failed" },
|
||||
];
|
||||
|
||||
export function RunsPage({ snapshot, actions }: PageProps) {
|
||||
export function RunsPage({ snapshot }: PageProps) {
|
||||
const orgId = activeOrgId(snapshot);
|
||||
const taskRuns = useMemo(() => snapshot.taskRuns.filter((r) => r.orgId === orgId), [snapshot.taskRuns, orgId]);
|
||||
const tasks = useMemo(() => snapshot.tasks.filter((t) => t.orgId === orgId), [snapshot.tasks, orgId]);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState, type MutableRefObject } from "react";
|
||||
import { useRef, useState, type MutableRefObject } from "react";
|
||||
import { Avatar } from "../../shared/ui";
|
||||
import type { AgentRecord, EmployeeRecord } from "../../../../shared/domain";
|
||||
|
||||
@@ -44,8 +44,6 @@ export function MentionTextarea({
|
||||
? candidates.filter((c) => c.handle.toLowerCase().includes(query.toLowerCase()))
|
||||
: [];
|
||||
|
||||
useEffect(() => { setIndex(0); }, [query]);
|
||||
|
||||
const close = () => setQuery(null);
|
||||
|
||||
const insertMention = (handle: string) => {
|
||||
@@ -69,6 +67,7 @@ export function MentionTextarea({
|
||||
if (atMatch) {
|
||||
anchor.current = pos - atMatch[2].length - 1;
|
||||
setQuery(atMatch[2]);
|
||||
setIndex(0);
|
||||
} else {
|
||||
close();
|
||||
}
|
||||
|
||||
@@ -39,30 +39,38 @@ export function BudgetUtilizationChart({ agents, providers }: { agents: AgentRec
|
||||
});
|
||||
const total = Math.max(1, data.reduce((s, d) => s + d.cents, 0));
|
||||
|
||||
const segments = stackSegments(data, total);
|
||||
const colors = ["var(--accent)", "var(--green)", "var(--amber)", "var(--violet)", "var(--red)", "var(--text-3)"];
|
||||
|
||||
return (
|
||||
<ChartCard title="Budget utilization">
|
||||
<svg viewBox={`0 0 ${CHART_W} ${CHART_H}`} style={{ width: "100%", height: CHART_H }}>
|
||||
{(() => {
|
||||
let cumX = 0;
|
||||
return data.map((d, i) => {
|
||||
const w = (d.cents / total) * CHART_W;
|
||||
const x = cumX;
|
||||
cumX += w;
|
||||
const colors = ["var(--accent)", "var(--green)", "var(--amber)", "var(--violet)", "var(--red)", "var(--text-3)"];
|
||||
return (
|
||||
<g key={d.label}>
|
||||
<rect x={x} y={20} width={Math.max(1, w - 2)} height={CHART_H - 40} rx={4} fill={colors[i % colors.length]} opacity={0.8} />
|
||||
<text x={x + w / 2} y={CHART_H - 4} textAnchor="middle" fontSize="9" fill="var(--text-3)">{d.label}</text>
|
||||
<text x={x + w / 2} y={14} textAnchor="middle" fontSize="9" fill="var(--text-2)">${Math.round(d.cents / 100)}</text>
|
||||
</g>
|
||||
);
|
||||
});
|
||||
})()}
|
||||
{segments.map((segment, i) => (
|
||||
<g key={segment.label}>
|
||||
<rect x={segment.x} y={20} width={Math.max(1, segment.w - 2)} height={CHART_H - 40} rx={4} fill={colors[i % colors.length]} opacity={0.8} />
|
||||
<text x={segment.x + segment.w / 2} y={CHART_H - 4} textAnchor="middle" fontSize="9" fill="var(--text-3)">{segment.label}</text>
|
||||
<text x={segment.x + segment.w / 2} y={14} textAnchor="middle" fontSize="9" fill="var(--text-2)">${Math.round(segment.cents / 100)}</text>
|
||||
</g>
|
||||
))}
|
||||
</svg>
|
||||
</ChartCard>
|
||||
);
|
||||
}
|
||||
|
||||
function stackSegments(
|
||||
data: Array<{ label: string; cents: number }>,
|
||||
total: number,
|
||||
): Array<{ label: string; cents: number; x: number; w: number }> {
|
||||
const segments: Array<{ label: string; cents: number; x: number; w: number }> = [];
|
||||
let cumX = 0;
|
||||
for (const d of data) {
|
||||
const w = (d.cents / total) * CHART_W;
|
||||
segments.push({ label: d.label, cents: d.cents, x: cumX, w });
|
||||
cumX += w;
|
||||
}
|
||||
return segments;
|
||||
}
|
||||
|
||||
export function RunActivityChart({ taskRuns }: { taskRuns: TaskRunRecord[] }) {
|
||||
const buckets = last7DayBuckets(taskRuns.map((r) => r.createdAt));
|
||||
const max = Math.max(1, ...buckets.map((b) => b.count));
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useMemo } from "react";
|
||||
import { Avatar, Pill } from "../../shared/ui";
|
||||
import type { AgentRecord, HiringPolicyRecord, ProviderRecord, ProviderRequestRecord } from "../../../../shared/domain";
|
||||
import { money, formatRelative } from "../types";
|
||||
import { money } from "../types";
|
||||
|
||||
export function BillingPanel({
|
||||
agents,
|
||||
@@ -20,7 +19,7 @@ export function BillingPanel({
|
||||
const totalInputChars = monthRequests.reduce((s, r) => s + r.inputCharCount, 0);
|
||||
const totalOutputChars = monthRequests.reduce((s, r) => s + r.outputCharCount, 0);
|
||||
const failedRequests = monthRequests.filter((r) => r.state === "failed");
|
||||
const agentSpend = useMemo(() => buildAgentSpend(agents, providers, monthRequests), [agents, providers, monthRequests]);
|
||||
const agentSpend = buildAgentSpend(agents, providers, monthRequests);
|
||||
|
||||
return (
|
||||
<div className="page">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Avatar, Pill } from "../../shared/ui";
|
||||
import { Avatar } from "../../shared/ui";
|
||||
import type { AgentRecord, ApprovalRecord } from "../../../../shared/domain";
|
||||
import { formatRelative } from "../types";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { type FormEvent } from "react";
|
||||
import { Field } from "../../shared/ui";
|
||||
import { Dialog } from "../../shared/Dialog";
|
||||
import type { AgentRecord, AppSnapshot } from "../../../../shared/domain";
|
||||
import type { AgentRecord } from "../../../../shared/domain";
|
||||
import type { SnapshotActions } from "../../app/useSnapshot";
|
||||
|
||||
function text(form: FormData, key: string): string {
|
||||
|
||||
@@ -11,7 +11,7 @@ import type {
|
||||
TaskRunRecord,
|
||||
WorkspaceRecord,
|
||||
} from "../../../../shared/domain";
|
||||
import { TASK_PRIORITY, TASK_STATUS } from "../../../../shared/domain";
|
||||
import { TASK_STATUS } from "../../../../shared/domain";
|
||||
import { auditEventLabel, formatRelative } from "../types";
|
||||
import { canRun, nextStatus, prettyRunState, prettyStatus, providerFor, runsForTask, runTone } from "./task-helpers";
|
||||
import type { SnapshotActions } from "../../app/useSnapshot";
|
||||
|
||||
Reference in new issue
Block a user