diff --git a/src/components/onboarding/TourProvider.tsx b/src/components/onboarding/TourProvider.tsx
index c5c0242..70b1772 100644
--- a/src/components/onboarding/TourProvider.tsx
+++ b/src/components/onboarding/TourProvider.tsx
@@ -7,7 +7,7 @@ import { useTheme } from "next-themes";
import { usePathname } from "next/navigation";
import Cookies from "js-cookie";
-type TourType = "dashboard" | "study_creation" | "participant_creation" | "designer" | "wizard" | "full_platform";
+type TourType = "dashboard" | "study_creation" | "participant_creation" | "designer" | "wizard" | "analytics" | "full_platform";
interface TourContextType {
startTour: (tour: TourType) => void;
@@ -58,7 +58,20 @@ export function TourProvider({ children }: { children: React.ReactNode }) {
}
}, [pathname]);
- const runTourSegment = (segment: "dashboard" | "study_creation" | "participant_creation" | "designer" | "wizard") => {
+ useEffect(() => {
+ // Listen for custom tour triggers (from components without context access)
+ const handleTourTrigger = (e: Event) => {
+ const detail = (e as CustomEvent).detail as TourType;
+ if (detail) {
+ startTour(detail);
+ }
+ };
+
+ document.addEventListener('hristudio-start-tour', handleTourTrigger);
+ return () => document.removeEventListener('hristudio-start-tour', handleTourTrigger);
+ }, []);
+
+ const runTourSegment = (segment: "dashboard" | "study_creation" | "participant_creation" | "designer" | "wizard" | "analytics") => {
const isDark = theme === "dark";
// We add a specific class to handle dark/light overrides reliably
const themeClass = isDark ? "driverjs-theme-dark" : "driverjs-theme-light";
@@ -234,6 +247,50 @@ export function TourProvider({ children }: { children: React.ReactNode }) {
},
];
}
+ else if (segment === "analytics") {
+ steps = [
+ {
+ element: "#tour-analytics-table",
+ popover: {
+ title: "Study Analytics",
+ description: "View aggregate data across all participant sessions. Sort and filter to identify trends or specific trials.",
+ side: "bottom",
+ },
+ },
+ {
+ element: "#tour-analytics-filter",
+ popover: {
+ title: "Filter Data",
+ description: "Quickly find participants by ID or name using this search bar.",
+ side: "bottom",
+ },
+ },
+ {
+ element: "#tour-trial-metrics",
+ popover: {
+ title: "Trial Metrics",
+ description: "High-level KPIs for the selected trial: Duration, Robot Actions, and Intervention counts.",
+ side: "bottom",
+ },
+ },
+ {
+ element: "#tour-trial-timeline",
+ popover: {
+ title: "Video & Timeline",
+ description: "Watch the trial recording synced with the event timeline. Click any event to jump to that moment in the video.",
+ side: "right",
+ },
+ },
+ {
+ element: "#tour-trial-events",
+ popover: {
+ title: "Event Log",
+ description: "A detailed, searchable log of every system event, robot action, and wizard interaction.",
+ side: "left",
+ },
+ },
+ ];
+ }
driverObj.current = driver({
showProgress: true,
@@ -265,6 +322,7 @@ export function TourProvider({ children }: { children: React.ReactNode }) {
else if (pathname.includes("/participants/new")) runTourSegment("participant_creation");
else if (pathname.includes("/designer")) runTourSegment("designer");
else if (pathname.includes("/wizard")) runTourSegment("wizard");
+ else if (pathname.includes("/analysis")) runTourSegment("analytics");
else runTourSegment("dashboard"); // Fallback
} else {
localStorage.setItem("hristudio_tour_mode", "manual");
@@ -275,6 +333,7 @@ export function TourProvider({ children }: { children: React.ReactNode }) {
if (tour === "participant_creation") runTourSegment("participant_creation");
if (tour === "designer") runTourSegment("designer");
if (tour === "wizard") runTourSegment("wizard");
+ if (tour === "analytics") runTourSegment("analytics");
}
};
diff --git a/src/components/trials/views/TrialAnalysisView.tsx b/src/components/trials/views/TrialAnalysisView.tsx
index 633e0be..378a9ec 100644
--- a/src/components/trials/views/TrialAnalysisView.tsx
+++ b/src/components/trials/views/TrialAnalysisView.tsx
@@ -60,6 +60,17 @@ export function TrialAnalysisView({ trial, backHref }: TrialAnalysisViewProps) {
+
{trial.experiment.name}
@@ -82,7 +93,7 @@ export function TrialAnalysisView({ trial, backHref }: TrialAnalysisViewProps) {
{/* Metrics Header */}
-
+
Duration
@@ -147,7 +158,7 @@ export function TrialAnalysisView({ trial, backHref }: TrialAnalysisViewProps) {
{/* TOP: Video & Timeline */}
-
+
{videoUrl ? (
@@ -175,7 +186,7 @@ export function TrialAnalysisView({ trial, backHref }: TrialAnalysisViewProps) {
{/* BOTTOM: Events Table */}
-
+
diff --git a/src/components/trials/wizard/panels/WizardControlPanel.tsx b/src/components/trials/wizard/panels/WizardControlPanel.tsx
index 3facfa2..10b0e38 100755
--- a/src/components/trials/wizard/panels/WizardControlPanel.tsx
+++ b/src/components/trials/wizard/panels/WizardControlPanel.tsx
@@ -145,7 +145,7 @@ export const WizardControlPanel = React.memo(function WizardControlPanel({
};
return (
-
+
@@ -155,7 +155,7 @@ export const WizardControlPanel = React.memo(function WizardControlPanel({
{/* Decision Point UI removed as per user request (handled in Execution Panel) */}
{trial.status === "in_progress" ? (
-