Skip to content

Commit 8fb1ba7

Browse files
committed
The agent landing page chart now displays correct data per the chosen date/time range
1 parent a80dd96 commit 8fb1ba7

8 files changed

Lines changed: 285 additions & 254 deletions

File tree

apps/webapp/app/components/primitives/charts/Chart.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as React from "react";
22
import * as RechartsPrimitive from "recharts";
33
import { cn } from "~/utils/cn";
44
import { AnimatedNumber } from "../AnimatedNumber";
5+
import TooltipPortal from "../TooltipPortal";
56

67
// Format: { THEME_NAME: CSS_SELECTOR }
78
const THEMES = { light: "", dark: ".dark" } as const;
@@ -162,6 +163,7 @@ const ChartTooltipContent = React.forwardRef<
162163
const nestLabel = payload.length === 1 && indicator !== "dot";
163164

164165
return (
166+
<TooltipPortal active={active}>
165167
<div
166168
ref={ref}
167169
className={cn(
@@ -239,6 +241,7 @@ const ChartTooltipContent = React.forwardRef<
239241
})}
240242
</div>
241243
</div>
244+
</TooltipPortal>
242245
);
243246
}
244247
);

apps/webapp/app/components/primitives/charts/ChartBar.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ export type ChartBarRendererProps = {
4141
tooltipLabelFormatter?: (label: string, payload: any[]) => string;
4242
/** Optional formatter for numeric tooltip values (e.g. bytes, duration) */
4343
tooltipValueFormatter?: (value: number) => string;
44+
/** Corner radius for the outermost bars in each stack (defaults to 2). Pass 0 for square corners. */
45+
barRadius?: number;
4446
/** Width injected by ResponsiveContainer */
4547
width?: number;
4648
/** Height injected by ResponsiveContainer */
@@ -66,6 +68,7 @@ export function ChartBarRenderer({
6668
referenceLine,
6769
tooltipLabelFormatter,
6870
tooltipValueFormatter,
71+
barRadius = 2,
6972
width,
7073
height,
7174
}: ChartBarRendererProps) {
@@ -205,10 +208,10 @@ export function ChartBarRenderer({
205208
fill={config[key]?.color}
206209
radius={
207210
[
208-
index === array.length - 1 ? 2 : 0,
209-
index === array.length - 1 ? 2 : 0,
210-
index === 0 ? 2 : 0,
211-
index === 0 ? 2 : 0,
211+
index === array.length - 1 ? barRadius : 0,
212+
index === array.length - 1 ? barRadius : 0,
213+
index === 0 ? barRadius : 0,
214+
index === 0 ? barRadius : 0,
212215
] as [number, number, number, number]
213216
}
214217
activeBar={false}

apps/webapp/app/components/runs/v3/TaskRunsTable.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ type RunsTableProps = {
7474
variant?: TableVariant;
7575
disableAdjacentRows?: boolean;
7676
additionalTableState?: Record<string, string>;
77+
showTopBorder?: boolean;
7778
};
7879

7980
export function TaskRunsTable({
@@ -87,6 +88,7 @@ export function TaskRunsTable({
8788
allowSelection = false,
8889
variant = "dimmed",
8990
additionalTableState,
91+
showTopBorder = true,
9092
}: RunsTableProps) {
9193
const regions = useRegions();
9294
const regionByMasterQueue = new Map(regions.map((r) => [r.masterQueue, r] as const));
@@ -141,7 +143,7 @@ export function TaskRunsTable({
141143
);
142144

143145
return (
144-
<Table variant={variant} className="max-h-full overflow-y-auto">
146+
<Table variant={variant} className="max-h-full overflow-y-auto" showTopBorder={showTopBorder}>
145147
<TableHeader>
146148
<TableRow>
147149
{allowSelection && (

apps/webapp/app/components/sessions/v1/SessionsTable.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,15 @@ import {
3434
allSessionStatuses,
3535
} from "./SessionStatus";
3636

37-
type SessionsTableProps = Pick<SessionList, "sessions" | "filters" | "hasFilters">;
37+
type SessionsTableProps = Pick<SessionList, "sessions" | "filters" | "hasFilters"> & {
38+
showTopBorder?: boolean;
39+
};
3840

39-
export function SessionsTable({ sessions, hasFilters }: SessionsTableProps) {
41+
export function SessionsTable({
42+
sessions,
43+
hasFilters,
44+
showTopBorder = true,
45+
}: SessionsTableProps) {
4046
const navigation = useNavigation();
4147
const location = useLocation();
4248
const isLoading =
@@ -47,7 +53,7 @@ export function SessionsTable({ sessions, hasFilters }: SessionsTableProps) {
4753
const environment = useEnvironment();
4854

4955
return (
50-
<Table className="max-h-full overflow-y-auto">
56+
<Table className="max-h-full overflow-y-auto" showTopBorder={showTopBorder}>
5157
<TableHeader>
5258
<TableRow>
5359
<TableHeaderCell>ID</TableHeaderCell>

apps/webapp/app/presenters/v3/AgentDetailPresenter.server.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ export class AgentDetailPresenter {
127127
? 6 * 60 * 60 // 6h buckets
128128
: 24 * 60 * 60; // 1d buckets
129129

130+
// NOTE: We intentionally don't filter by `task_kind = 'AGENT'` here:
131+
// ClickHouse stores `task_kind = ""` for pre-migration rows and rows
132+
// whose taskKind annotation was never set, even for AGENT tasks. We've
133+
// already verified this task is an agent via `findAgent` (Postgres), so
134+
// matching on environment_id + task_identifier is sufficient.
130135
const queryFn = this.clickhouse.reader.query({
131136
name: "agentRunStatusActivity",
132137
query: `SELECT
@@ -136,7 +141,6 @@ export class AgentDetailPresenter {
136141
FROM trigger_dev.task_runs_v2
137142
WHERE environment_id = {environmentId: String}
138143
AND task_identifier = {agentSlug: String}
139-
AND task_kind = 'AGENT'
140144
AND created_at >= {fromTime: DateTime64(3, 'UTC')}
141145
AND created_at < {toTime: DateTime64(3, 'UTC')}
142146
GROUP BY bucket, status
@@ -159,8 +163,10 @@ export class AgentDetailPresenter {
159163
environmentId,
160164
agentSlug,
161165
bucketSeconds,
162-
fromTime: from.toISOString(),
163-
toTime: to.toISOString(),
166+
// ClickHouse's DateTime64(3, 'UTC') parser rejects the trailing `Z` from
167+
// JS toISOString() ("only 23 of 24 bytes was parsed"). Strip it.
168+
fromTime: from.toISOString().slice(0, -1),
169+
toTime: to.toISOString().slice(0, -1),
164170
});
165171

166172
if (error) {
@@ -169,22 +175,22 @@ export class AgentDetailPresenter {
169175
}
170176

171177
const bucketMap = new Map<number, Record<string, number>>();
172-
const usedGroups = new Set<GroupLabel>();
173178
for (const row of rows) {
174179
const group = groupForStatus(row.status) ?? "RUNNING";
175-
usedGroups.add(group);
176180
const ts = row.bucket * 1000;
177181
const existing = bucketMap.get(ts) ?? {};
178182
existing[group] = (existing[group] ?? 0) + row.val;
179183
bucketMap.set(ts, existing);
180184
}
181185

182-
// Build zero-filled time series
186+
// Build zero-filled time series. We always emit every status group so
187+
// the chart legend is stable across time ranges (even when a group has
188+
// no runs in the current window).
183189
const bucketMs = bucketSeconds * 1000;
184190
const start = Math.floor(from.getTime() / bucketMs) * bucketMs;
185191
const end = Math.ceil(to.getTime() / bucketMs) * bucketMs;
186192
const points: AgentActivityPoint[] = [];
187-
const orderedStatuses = GROUP_LABEL.filter((g) => usedGroups.has(g));
193+
const orderedStatuses = [...GROUP_LABEL];
188194
for (let ts = start; ts < end; ts += bucketMs) {
189195
const existing = bucketMap.get(ts) ?? {};
190196
const point: AgentActivityPoint = { bucket: ts };

apps/webapp/app/presenters/v3/TaskDetailPresenter.server.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,10 @@ export class TaskDetailPresenter {
159159
environmentId,
160160
taskSlug,
161161
bucketSeconds,
162-
fromTime: from.toISOString(),
163-
toTime: to.toISOString(),
162+
// ClickHouse's DateTime64(3, 'UTC') parser rejects the trailing `Z` from
163+
// JS toISOString() ("only 23 of 24 bytes was parsed"). Strip it.
164+
fromTime: from.toISOString().slice(0, -1),
165+
toTime: to.toISOString().slice(0, -1),
164166
});
165167

166168
if (error) {

0 commit comments

Comments
 (0)