diff --git a/torchci/components/benchmark_v3/components/benchmarkSideBar/BenchmarkTopBar.tsx b/torchci/components/benchmark_v3/components/benchmarkSideBar/BenchmarkTopBar.tsx
index 2447ab29f4..516edcf555 100644
--- a/torchci/components/benchmark_v3/components/benchmarkSideBar/BenchmarkTopBar.tsx
+++ b/torchci/components/benchmark_v3/components/benchmarkSideBar/BenchmarkTopBar.tsx
@@ -4,13 +4,16 @@ import { BenchmarkUIConfigHandler } from "components/benchmark_v3/configs/benchm
import { BenchmarkReportFeatureNotification } from "../benchmarkRegressionReport/BenchmarkReportFeatureNotification";
import { BenchmarkReportFeatureSidePanel } from "../benchmarkRegressionReport/BenchmarkReportFeatureSidePanel";
import { CommitWorflowSelectSection } from "./components/commits/CommitWorkfowSelectSection";
+import { SingleCommitSelectSelection } from "./components/commits/SingleCommitSelectSelection";
export function BenchmarkTopBar({
config,
title = "",
+ mode = "default",
}: {
config: BenchmarkUIConfigHandler;
title?: string;
+ mode?: string;
}) {
const reportFeature =
config.raw.dataRender?.sideRender?.RegressionReportFeature;
@@ -41,9 +44,12 @@ export function BenchmarkTopBar({
>
)}
-
-
-
+ {reportFeature && }
+ {reportFeature && (
+
+ )}
+ {mode == "default" && }
+ {mode == "single" && }
);
diff --git a/torchci/components/benchmark_v3/components/benchmarkSideBar/components/SideBarMainSection.tsx b/torchci/components/benchmark_v3/components/benchmarkSideBar/components/SideBarMainSection.tsx
index 24358eb956..becfb1d86f 100644
--- a/torchci/components/benchmark_v3/components/benchmarkSideBar/components/SideBarMainSection.tsx
+++ b/torchci/components/benchmark_v3/components/benchmarkSideBar/components/SideBarMainSection.tsx
@@ -107,6 +107,7 @@ export function SideBarMainSection() {
branchOptionType,
enableMultiBranchOption,
enableSamplingSetting,
+ enableSamplingFeature,
commitMainOptions,
revertMainOptions,
} = useDashboardSelector((s) => ({
@@ -115,6 +116,7 @@ export function SideBarMainSection() {
stagedLbranch: s.stagedLbranch,
stagedRbranch: s.stagedRbranch,
stagedMaxSampling: s.stagedMaxSampling,
+ enableSamplingFeature: s.enableSamplingFeature,
enableMultiBranchOption: s.enableMultiBranchOption,
branchOptionType: s.branchOptionType,
@@ -253,15 +255,19 @@ export function SideBarMainSection() {
end={stagedTime.end}
gap={0}
/>
- {/* Fetch Settings */}
-
- Fetch Settings
-
+ {enableSamplingFeature && (
+ <>
+ {/* Fetch Settings */}
+
+ Fetch Settings{" "}
+
+ >
+ )}
{showSamplinginfo && (
{`Data Sampling: subsample from ${sampling_info?.origin ?? 0} to ${
diff --git a/torchci/components/benchmark_v3/components/benchmarkSideBar/components/commits/BranchDropdown.tsx b/torchci/components/benchmark_v3/components/benchmarkSideBar/components/commits/BranchDropdown.tsx
index d68a4a142f..c8da8fe1c8 100644
--- a/torchci/components/benchmark_v3/components/benchmarkSideBar/components/commits/BranchDropdown.tsx
+++ b/torchci/components/benchmark_v3/components/benchmarkSideBar/components/commits/BranchDropdown.tsx
@@ -49,7 +49,6 @@ export function BranchDropdowns({
return (
- {type}
{empty ? (
No branch is found, please select other features.
diff --git a/torchci/components/benchmark_v3/components/benchmarkSideBar/components/commits/SingleCommitSelectSelection.tsx b/torchci/components/benchmark_v3/components/benchmarkSideBar/components/commits/SingleCommitSelectSelection.tsx
new file mode 100644
index 0000000000..1d01d82009
--- /dev/null
+++ b/torchci/components/benchmark_v3/components/benchmarkSideBar/components/commits/SingleCommitSelectSelection.tsx
@@ -0,0 +1,210 @@
+import OpenInNewIcon from "@mui/icons-material/OpenInNew";
+import { Typography } from "@mui/material";
+import { Box, Stack } from "@mui/system";
+import { useBenchmarkBook } from "components/benchmark_v3/configs/benchmark_config_book";
+import { QueryParameterConverterInputs } from "components/benchmark_v3/configs/utils/dataBindingRegistration";
+import { CenteredLoader } from "components/common/LoadingIcon";
+import {
+ UMDenseCommitDropdown,
+ UMDenseSingleButton,
+} from "components/uiModules/UMDenseComponents";
+import { useBenchmarkCommitsData } from "lib/benchmark/api_helper/fe/hooks";
+import { useDashboardSelector } from "lib/benchmark/store/benchmark_dashboard_provider";
+import { BenchmarkCommitMeta } from "lib/benchmark/store/benchmark_regression_store";
+import { stateToQuery } from "lib/helpers/urlQuery";
+import { NextRouter, useRouter } from "next/router";
+import { useEffect, useState } from "react";
+
+export function SingleCommitSelectSelection() {
+ const {
+ repo,
+ type,
+ benchmarkName,
+ benchmarkId,
+ committedTime,
+ committedFilters,
+ lcommit,
+ committedLBranch,
+ committedMaxSampling,
+ enableSamplingSetting,
+ setLcommit,
+ } = useDashboardSelector((s) => ({
+ type: s.type,
+ benchmarkId: s.benchmarkId,
+ committedTime: s.committedTime,
+ committedFilters: s.committedFilters,
+ committedMaxSampling: s.committedMaxSampling,
+ enableSamplingSetting: s.enableSamplingSetting,
+ repo: s.repo,
+ benchmarkName: s.benchmarkName,
+ lcommit: s.lcommit,
+ rcommit: s.rcommit,
+ committedLBranch: s.committedLbranch,
+ setLcommit: s.setLcommit,
+ }));
+
+ const [leftList, setLeftList] = useState([]);
+ const getConfig = useBenchmarkBook((s) => s.getConfig);
+ const config = getConfig(benchmarkId, type);
+ const dataBinding = config.dataBinding;
+ const required_filter_fields = config.raw?.required_filter_fields ?? [];
+
+ const ready =
+ !!committedTime?.start &&
+ !!committedTime?.end &&
+ !!committedLBranch &&
+ committedLBranch.length > 0 &&
+ (enableSamplingSetting ? committedMaxSampling : true) &&
+ required_filter_fields.every((k) => !!committedFilters[k]);
+
+ // Fetch data
+ const branches = [...new Set([committedLBranch].filter((b) => b.length > 0))];
+
+ // Convert to query params
+ const params = dataBinding.toQueryParams({
+ repo: repo,
+ benchmarkName: benchmarkName,
+ branches,
+ timeRange: committedTime,
+ filters: committedFilters,
+ maxSampling: enableSamplingSetting ? committedMaxSampling : undefined,
+ } as QueryParameterConverterInputs);
+ if (!params) {
+ throw new Error(`Failed to convert to query params for ${benchmarkId}`);
+ }
+
+ const queryParams: any | null = ready ? params : null;
+
+ // Fetch data
+ const { data, isLoading, error } = useBenchmarkCommitsData(
+ benchmarkId,
+ queryParams
+ );
+
+ useEffect(() => {
+ if (isLoading || !data) return;
+
+ const groups = data?.data?.branch ?? [];
+ const branchMap = convertToBranchMap(groups);
+
+ const L: BenchmarkCommitMeta[] = branchMap[committedLBranch] ?? [];
+
+ // update list
+ setLeftList(L);
+
+ if (L.length === 0) return;
+
+ // check if user has selected a commit that is not in the list
+ const lSelected = lcommit?.workflow_id ?? null;
+
+ const lHas = !!lSelected && L.some((c) => c.workflow_id === lSelected);
+
+ // rule left and right both pick left option
+ const nextAutoL = lHas ? lSelected : L[0]?.workflow_id ?? null;
+
+ if (!lHas) {
+ setLcommit(
+ nextAutoL ? L.find((c) => c.workflow_id === nextAutoL) ?? null : null
+ );
+ }
+ }, [isLoading, data, committedLBranch, lcommit?.workflow_id, setLcommit]);
+
+ if (error) return Error: {error.message}
;
+ if (isLoading || !data) return ;
+
+ return (
+
+
+ Commit:
+
+
+ {lcommit?.branch}:
+
+ {
+ setLcommit(c);
+ }}
+ />
+
+
+ );
+}
+
+export const convertToBranchMap = (
+ raw: any[]
+): Record => {
+ return raw.reduce((acc, g) => {
+ const branch = g?.group_info?.branch ?? "unknown";
+ acc[branch] = g.rows.map((r: any) => ({
+ commit: r.commit,
+ workflow_id: String(r.workflow_id),
+ date: r.date,
+ branch,
+ }));
+ return acc;
+ }, {} as Record);
+};
+
+export function NavigateToDashboardButton({
+ benchmarkId,
+ commit,
+}: {
+ benchmarkId: string;
+ commit: BenchmarkCommitMeta | null;
+}) {
+ const router = useRouter();
+ if (!commit) {
+ return <>>;
+ }
+ return (
+ }
+ sx={{
+ whiteSpace: "nowrap",
+ }}
+ >
+ View {commit.workflow_id} ({commit.commit.slice(0, 7)}) in Dashboard
+
+ );
+}
+
+export function toDashboardUrl(
+ benchmarkId: string,
+ commit: BenchmarkCommitMeta,
+ router: NextRouter
+) {
+ const pathname = `/benchmark/v3/dashboard/${benchmarkId}`;
+ const lcommit: BenchmarkCommitMeta = commit;
+ const rcommit: BenchmarkCommitMeta = commit;
+ const reformattedPrams = stateToQuery({
+ lcommit,
+ rcommit,
+ });
+
+ const nextDashboardMainQuery = {
+ ...router.query, // keep existing params
+ ...reformattedPrams,
+ renderGroupId: "main",
+ };
+ const params = new URLSearchParams(
+ Object.entries(nextDashboardMainQuery)
+ .filter(([_, v]) => v != null && v !== "")
+ .map(([k, v]) => [k, String(v)])
+ );
+ const url = `${pathname}?${params.toString()}`;
+ return url;
+}
diff --git a/torchci/components/benchmark_v3/components/common/BenchmarkLinkButton.tsx b/torchci/components/benchmark_v3/components/common/BenchmarkLinkButton.tsx
new file mode 100644
index 0000000000..255813d25e
--- /dev/null
+++ b/torchci/components/benchmark_v3/components/common/BenchmarkLinkButton.tsx
@@ -0,0 +1,43 @@
+import type { ButtonProps } from "@mui/material/Button";
+import Button from "@mui/material/Button";
+import { styled } from "@mui/material/styles";
+import * as React from "react";
+
+/** Anchor-style MUI Button with proper typing for href/target/rel. */
+export interface BenchmarkLinkButtonProps
+ extends Omit, "component"> {
+ href: string;
+ /** Default: "_self". Use "_blank" for new tab. */
+ target?: "_self" | "_blank" | "_parent" | "_top";
+ /** Default: added automatically for _blank */
+ rel?: string;
+}
+
+export const LinkButton = React.forwardRef<
+ HTMLAnchorElement,
+ BenchmarkLinkButtonProps
+>(({ href, target = "_self", rel, ...props }, ref) => {
+ // Security for new-tab links
+ const finalRel = target === "_blank" ? rel ?? "noopener noreferrer" : rel;
+ return (
+
+ );
+});
+LinkButton.displayName = "LinkButton";
+
+export const BenchmarkLinkButton = styled(LinkButton)(({ theme }) => ({
+ px: 0.5,
+ py: 0,
+ mx: 1,
+ minWidth: "auto",
+ lineHeight: 2,
+ fontSize: "0.75rem",
+ textTransform: "none",
+}));
diff --git a/torchci/components/benchmark_v3/components/common/RawContentDialog.tsx b/torchci/components/benchmark_v3/components/common/RawContentDialog.tsx
index b30f7b1363..b0a5d62743 100644
--- a/torchci/components/benchmark_v3/components/common/RawContentDialog.tsx
+++ b/torchci/components/benchmark_v3/components/common/RawContentDialog.tsx
@@ -11,6 +11,7 @@ import {
Tooltip,
Typography,
} from "@mui/material";
+import { UMDenseSingleButton } from "components/uiModules/UMDenseComponents";
import React, { useState } from "react";
import { StaticRenderViewOnlyContent } from "./StaticRenderViewOnlyContent";
@@ -66,9 +67,9 @@ export function RawContentDialog({
return (
<>
-
+