No scenarios match your query and/or filters.
+ ) : (
+ No scenarios were executed.
+ )
+ }
+
+ const selectedItem = items.find((item) => item.id === selectedId)
+
+ return (
+
+
+
+
+ {item.scenario}
+
+ {item.feature &&
{item.feature}
}
+
+
+
+
- Status
+ - {statusName(item.status)}
+
+
+
- Duration
+ - {formatExecutionDuration(new Date(item.start), new Date(item.end))}
+
+
+
- Worker
+ - {item.groupLabel}
+
+
+
+
+ )
+}
diff --git a/src/components/app/index.ts b/src/components/app/index.ts
index 890c590d..b6399b7b 100644
--- a/src/components/app/index.ts
+++ b/src/components/app/index.ts
@@ -11,4 +11,5 @@ export * from './Report.js'
export * from './SearchBar.js'
export * from './StatusesSummary.js'
export * from './TestRunHooks.js'
+export * from './Timeline.js'
export * from './UrlSearchProvider.js'
diff --git a/src/custom.d.ts b/src/custom.d.ts
index e48f665b..14a684e2 100644
--- a/src/custom.d.ts
+++ b/src/custom.d.ts
@@ -2,3 +2,5 @@ declare module '*.module.scss' {
const classes: { [key: string]: string }
export default classes
}
+
+declare module '*.css'
diff --git a/src/hooks/useTimelineData.ts b/src/hooks/useTimelineData.ts
new file mode 100644
index 00000000..16ef807e
--- /dev/null
+++ b/src/hooks/useTimelineData.ts
@@ -0,0 +1,141 @@
+import {
+ type PickleTag,
+ type TestCaseStarted,
+ TestStepResultStatus,
+ TimeConversion,
+} from '@cucumber/messages'
+import { useMemo } from 'react'
+
+import { useQueries } from './useQueries.js'
+import { useSearch } from './useSearch.js'
+
+export interface TimelineItem {
+ readonly id: string
+ readonly groupId: string
+ readonly groupLabel: string
+ readonly feature: string
+ readonly scenario: string
+ readonly tags: readonly PickleTag[]
+ readonly status: TestStepResultStatus
+ readonly start: number
+ readonly end: number
+ readonly testCaseStarted: TestCaseStarted
+}
+
+export interface TimelineGroup {
+ readonly id: string
+ readonly label: string
+}
+
+export interface TimelineData {
+ readonly groups: readonly TimelineGroup[]
+ readonly items: readonly TimelineItem[]
+ readonly fullStart: number | undefined
+ readonly fullEnd: number | undefined
+ readonly filtered: boolean
+}
+
+const UNASSIGNED_GROUP_ID = ''
+
+export function useTimelineData(): TimelineData {
+ const { cucumberQuery } = useQueries()
+ const { hideStatuses, tagExpression, searchTerm, unchanged } = useSearch()
+
+ return useMemo(() => {
+ const items: TimelineItem[] = []
+ const groupIds = new Set