Skip to content

Commit f24ded7

Browse files
authored
[CRCR] Add PR/Nightly tabs to metrics page (#8538)
## Summary - Add Pull Requests / Nightly tabs to the CRCR metrics page (`/crcr/metrics`), matching the tab pattern on the CRCR summary page - Consolidate `crcr_success_rate` query with an `{event_type: String}` parameter instead of duplicating it — PR tab uses `event_type = 'pull_request'`, Nightly tab uses `event_type = 'nightly'` - Both datasets are fetched in parallel via `useSWR`; only the active tab's charts render - Chart components (`PassRateChart`, `FailuresChart`, `TotalRunsChart`) are shared via a `MetricsCharts` wrapper - Repo chips in "Repos in view" link to the correct event view per tab (`?event=nightly` on the Nightly tab) ## Mockup https://subinz1.github.io/CRCR/mockups/crcr-metrics-tabs-mockup.html ## Test plan - [ ] Verify the PR tab shows the same data as before (no regression) - [ ] Verify the Nightly tab shows nightly success rate, failures, and total runs - [ ] Verify switching tabs does not cause re-fetching (both are prefetched) - [ ] Verify the time range dropdown applies to both tabs - [ ] Verify the "Repos in view" list updates per tab and links to correct event view - [ ] Verify the "Back to CRCR Summary" link works from both tabs
1 parent 7bf48a5 commit f24ded7

3 files changed

Lines changed: 125 additions & 60 deletions

File tree

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
{
22
"params": {
3-
"days": "UInt64"
3+
"days": "UInt64",
4+
"event_type": "String"
45
},
56
"tests": [
67
{
7-
"days": "30"
8+
"days": "30",
9+
"event_type": "pull_request"
10+
},
11+
{
12+
"days": "7",
13+
"event_type": "nightly"
814
}
915
]
1016
}

torchci/clickhouse_queries/crcr_success_rate/query.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ FROM
3535
WHERE
3636
started_at > now() - INTERVAL {days: UInt64} DAY
3737
AND status = 'completed'
38-
AND pr_number > 0
38+
AND event_type = {event_type: String}
3939
GROUP BY
4040
day, repo
4141
ORDER BY

torchci/pages/crcr/metrics.tsx

Lines changed: 116 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
SelectChangeEvent,
99
Skeleton,
1010
Stack,
11+
Tab,
12+
Tabs,
1113
Typography,
1214
} from "@mui/material";
1315
import {
@@ -23,6 +25,8 @@ import { useMemo, useState } from "react";
2325
import useSWR from "swr";
2426
dayjs.extend(utc);
2527

28+
type MetricsTab = "pr" | "nightly";
29+
2630
interface SuccessRateRow {
2731
day: string;
2832
repo: string;
@@ -153,23 +157,103 @@ function TotalRunsChart({
153157
);
154158
}
155159

156-
export default function CrcrMetricsPage() {
157-
const [days, setDays] = useState(30);
158-
159-
const url = `/api/clickhouse/crcr_success_rate?parameters=${encodeURIComponent(
160-
JSON.stringify({ days: String(days) })
161-
)}`;
162-
const { data, error } = useSWR<SuccessRateRow[]>(url, fetcherHandleError, {
163-
refreshInterval: 5 * 60_000,
164-
});
165-
160+
function MetricsCharts({
161+
data,
162+
days,
163+
error,
164+
eventSuffix,
165+
}: {
166+
data: SuccessRateRow[] | undefined;
167+
days: number;
168+
error: Error | undefined;
169+
eventSuffix: string;
170+
}) {
166171
const repos = useMemo(() => {
167172
if (!data) return [];
168173
return [...new Set(data.map((r) => r.repo))].sort();
169174
}, [data]);
170175

171176
const isLoading = !data && !error;
172177

178+
return (
179+
<>
180+
{error && (
181+
<Typography color="error">
182+
{error.message || "Failed to load metrics data"}
183+
</Typography>
184+
)}
185+
186+
{isLoading && (
187+
<Stack spacing={2}>
188+
<Skeleton variant="rectangular" height={420} />
189+
<Skeleton variant="rectangular" height={420} />
190+
</Stack>
191+
)}
192+
193+
{data && (
194+
<Stack spacing={3}>
195+
<PassRateChart data={data} days={days} />
196+
<FailuresChart data={data} days={days} />
197+
<TotalRunsChart data={data} days={days} />
198+
</Stack>
199+
)}
200+
201+
{data && repos.length > 0 && (
202+
<Box>
203+
<Typography variant="subtitle2" color="text.secondary" gutterBottom>
204+
Repos in view ({repos.length}):
205+
</Typography>
206+
<Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
207+
{repos.map((repo) => (
208+
<NextLink
209+
key={repo}
210+
href={`/crcr/${repo}${eventSuffix}`}
211+
passHref
212+
legacyBehavior
213+
>
214+
<Link
215+
underline="hover"
216+
sx={{
217+
fontSize: "0.85rem",
218+
px: 1,
219+
py: 0.25,
220+
bgcolor: "action.hover",
221+
borderRadius: 1,
222+
}}
223+
>
224+
{repo}
225+
</Link>
226+
</NextLink>
227+
))}
228+
</Box>
229+
</Box>
230+
)}
231+
</>
232+
);
233+
}
234+
235+
export default function CrcrMetricsPage() {
236+
const [days, setDays] = useState(30);
237+
const [activeTab, setActiveTab] = useState<MetricsTab>("pr");
238+
239+
const prUrl = `/api/clickhouse/crcr_success_rate?parameters=${encodeURIComponent(
240+
JSON.stringify({ days: String(days), event_type: "pull_request" })
241+
)}`;
242+
const { data: prData, error: prError } = useSWR<SuccessRateRow[]>(
243+
prUrl,
244+
fetcherHandleError,
245+
{ refreshInterval: 5 * 60_000 }
246+
);
247+
248+
const nightlyUrl = `/api/clickhouse/crcr_success_rate?parameters=${encodeURIComponent(
249+
JSON.stringify({ days: String(days), event_type: "nightly" })
250+
)}`;
251+
const { data: nightlyData, error: nightlyError } = useSWR<SuccessRateRow[]>(
252+
nightlyUrl,
253+
fetcherHandleError,
254+
{ refreshInterval: 5 * 60_000 }
255+
);
256+
173257
return (
174258
<>
175259
<Head>
@@ -203,56 +287,31 @@ export default function CrcrMetricsPage() {
203287
</NextLink>
204288
</Typography>
205289

206-
{error && (
207-
<Typography color="error">
208-
{error.message || "Failed to load metrics data"}
209-
</Typography>
210-
)}
211-
212-
{isLoading && (
213-
<Stack spacing={2}>
214-
<Skeleton variant="rectangular" height={420} />
215-
<Skeleton variant="rectangular" height={420} />
216-
</Stack>
217-
)}
290+
<Tabs
291+
value={activeTab}
292+
onChange={(_, v: MetricsTab) => setActiveTab(v)}
293+
sx={{ borderBottom: 1, borderColor: "divider" }}
294+
>
295+
<Tab label="Pull Requests" value="pr" />
296+
<Tab label="Nightly" value="nightly" />
297+
</Tabs>
218298

219-
{data && (
220-
<Stack spacing={3}>
221-
<PassRateChart data={data} days={days} />
222-
<FailuresChart data={data} days={days} />
223-
<TotalRunsChart data={data} days={days} />
224-
</Stack>
299+
{activeTab === "pr" && (
300+
<MetricsCharts
301+
data={prData}
302+
days={days}
303+
error={prError}
304+
eventSuffix=""
305+
/>
225306
)}
226307

227-
{data && repos.length > 0 && (
228-
<Box>
229-
<Typography variant="subtitle2" color="text.secondary" gutterBottom>
230-
Repos in view ({repos.length}):
231-
</Typography>
232-
<Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
233-
{repos.map((repo) => (
234-
<NextLink
235-
key={repo}
236-
href={`/crcr/${repo}`}
237-
passHref
238-
legacyBehavior
239-
>
240-
<Link
241-
underline="hover"
242-
sx={{
243-
fontSize: "0.85rem",
244-
px: 1,
245-
py: 0.25,
246-
bgcolor: "action.hover",
247-
borderRadius: 1,
248-
}}
249-
>
250-
{repo}
251-
</Link>
252-
</NextLink>
253-
))}
254-
</Box>
255-
</Box>
308+
{activeTab === "nightly" && (
309+
<MetricsCharts
310+
data={nightlyData}
311+
days={days}
312+
error={nightlyError}
313+
eventSuffix="?event=nightly"
314+
/>
256315
)}
257316
</Stack>
258317
</>

0 commit comments

Comments
 (0)