From 568d40858777d567458a07e1c8fbdc5f5e73329a Mon Sep 17 00:00:00 2001 From: Sean O'Connor Date: Thu, 12 Feb 2026 00:53:28 -0500 Subject: [PATCH] feat: Add guided tour functionality for analytics and wizard components, including new tour steps and triggers. --- .../analytics/study-analytics-data-table.tsx | 3 +- .../experiments/designer/DesignerRoot.tsx | 25 +++++--- src/components/onboarding/TourProvider.tsx | 63 ++++++++++++++++++- .../trials/views/TrialAnalysisView.tsx | 17 ++++- .../wizard/panels/WizardControlPanel.tsx | 6 +- 5 files changed, 96 insertions(+), 18 deletions(-) diff --git a/src/components/analytics/study-analytics-data-table.tsx b/src/components/analytics/study-analytics-data-table.tsx index a647ece..e23ef8b 100644 --- a/src/components/analytics/study-analytics-data-table.tsx +++ b/src/components/analytics/study-analytics-data-table.tsx @@ -230,7 +230,7 @@ export function StudyAnalyticsDataTable({ data }: StudyAnalyticsDataTableProps) }); return ( -
+
diff --git a/src/components/experiments/designer/DesignerRoot.tsx b/src/components/experiments/designer/DesignerRoot.tsx index 0c1ed43..395a6ff 100755 --- a/src/components/experiments/designer/DesignerRoot.tsx +++ b/src/components/experiments/designer/DesignerRoot.tsx @@ -1193,15 +1193,22 @@ export function DesignerRoot({ )} Flow Workspace {rightCollapsed && ( - +
+ + {rightCollapsed && ( + + )} +
)}
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" ? ( -
+