diff --git a/apps/report/src/components/sidebar/index.less b/apps/report/src/components/sidebar/index.less index 85745fbbc1..f76090d419 100644 --- a/apps/report/src/components/sidebar/index.less +++ b/apps/report/src/components/sidebar/index.less @@ -285,6 +285,7 @@ // Allow tags to shrink .cache-tag, + .xpath-tag, .deepthink-tag { flex-shrink: 0; white-space: nowrap; @@ -395,7 +396,7 @@ } // Light mode Tag styles -.cache-tag { +.cache-tag, .xpath-tag { color: #1890ff; background-color: #e0f5ff; } @@ -558,7 +559,7 @@ } // Tag styles for dark mode - .cache-tag { + .cache-tag, .xpath-tag { color: #1890ff !important; background-color: rgba(24, 144, 255, 0.15) !important; } diff --git a/apps/report/src/components/sidebar/index.tsx b/apps/report/src/components/sidebar/index.tsx index ebbca661d4..79d777b4c2 100644 --- a/apps/report/src/components/sidebar/index.tsx +++ b/apps/report/src/components/sidebar/index.tsx @@ -49,6 +49,9 @@ const Sidebar = (props: SidebarProps = {}): JSX.Element => { setReplayAllMode, } = props; const groupedDump = useExecutionDump((store) => store.dump); + const playwrightAttributes = useExecutionDump( + (store) => store.playwrightAttributes, + ); const setActiveTask = useExecutionDump((store) => store.setActiveTask); const activeTask = useExecutionDump((store) => store.activeTask); const setHoverTask = useExecutionDump((store) => store.setHoverTask); @@ -174,6 +177,27 @@ const Sidebar = (props: SidebarProps = {}): JSX.Element => { ) : null; }; + const getXPathTag = (task: ExecutionTaskWithSearchAreaUsage) => { + if (task.hitBy?.from !== 'User expected path') { + return null; + } + + return ( + + XPath + + ); + }; + const getStatusText = (task: ExecutionTaskWithSearchAreaUsage) => { if (typeof task.timing?.cost === 'number') { return timeCostStrElement(task.timing.cost); @@ -405,6 +429,28 @@ const Sidebar = (props: SidebarProps = {}): JSX.Element => { 0, ); + // Calculate total time cost + // Prefer playwright_test_duration if available (from Playwright test framework) + // Otherwise, sum up all task timing costs + const totalTimeCost = useMemo(() => { + // Use Playwright test duration if available + if (playwrightAttributes?.playwright_test_duration) { + return playwrightAttributes.playwright_test_duration; + } + + // Fallback: sum up all task timing costs + if (!groupedDump) return 0; + + return groupedDump.executions.reduce((sum, execution) => { + return ( + sum + + execution.tasks.reduce((taskSum, task) => { + return taskSum + (task.timing?.cost || 0); + }, 0) + ); + }, 0); + }, [groupedDump, playwrightAttributes]); + // Keyboard navigation useEffect(() => { // all tasks @@ -466,6 +512,7 @@ const Sidebar = (props: SidebarProps = {}): JSX.Element => { {taskName} {getTitleIcon(task)} {getCacheTag(task)} + {getXPathTag(task)} {getDeepThinkTag(task)} ); @@ -585,10 +632,58 @@ const Sidebar = (props: SidebarProps = {}): JSX.Element => { {/* Summary */} - {proModeEnabled && ( -
-
- {(() => { +
+
+ {/* Total time row - always visible */} +
+
+
Total Time
+
+
+ + {timeCostStrElement(totalTimeCost)} + +
+ {proModeEnabled && ( + <> +
+
+
+ {hasCachedInput && ( +
+ )} +
+ + )} +
+ + {/* Token usage rows - only in pro mode */} + {proModeEnabled && + (() => { const modelEntries = Array.from(tokensByModel.entries()); const hasMultipleModels = modelEntries.length > 1; @@ -648,7 +743,7 @@ const Sidebar = (props: SidebarProps = {}): JSX.Element => {
)) : [ -
+
{
, ]; })()} -
- )} +
?