@sudobility/testomniac_ui 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. package/README.md +83 -0
  2. package/dist/components/bundles/AddToBundleButton.d.ts +8 -0
  3. package/dist/components/bundles/AddToBundleButton.d.ts.map +1 -0
  4. package/dist/components/bundles/AddToBundleButton.js +64 -0
  5. package/dist/components/bundles/AddToBundleButton.js.map +1 -0
  6. package/dist/components/cells/BundleCell.d.ts +10 -0
  7. package/dist/components/cells/BundleCell.d.ts.map +1 -0
  8. package/dist/components/cells/BundleCell.js +8 -0
  9. package/dist/components/cells/BundleCell.js.map +1 -0
  10. package/dist/components/cells/InteractionCell.d.ts +17 -0
  11. package/dist/components/cells/InteractionCell.d.ts.map +1 -0
  12. package/dist/components/cells/InteractionCell.js +13 -0
  13. package/dist/components/cells/InteractionCell.js.map +1 -0
  14. package/dist/components/cells/ListCell.d.ts +29 -0
  15. package/dist/components/cells/ListCell.d.ts.map +1 -0
  16. package/dist/components/cells/ListCell.js +19 -0
  17. package/dist/components/cells/ListCell.js.map +1 -0
  18. package/dist/components/cells/PersonaCell.d.ts +10 -0
  19. package/dist/components/cells/PersonaCell.d.ts.map +1 -0
  20. package/dist/components/cells/PersonaCell.js +7 -0
  21. package/dist/components/cells/PersonaCell.js.map +1 -0
  22. package/dist/components/cells/ScaffoldCell.d.ts +12 -0
  23. package/dist/components/cells/ScaffoldCell.d.ts.map +1 -0
  24. package/dist/components/cells/ScaffoldCell.js +10 -0
  25. package/dist/components/cells/ScaffoldCell.js.map +1 -0
  26. package/dist/components/cells/ScenarioCell.d.ts +12 -0
  27. package/dist/components/cells/ScenarioCell.d.ts.map +1 -0
  28. package/dist/components/cells/ScenarioCell.js +8 -0
  29. package/dist/components/cells/ScenarioCell.js.map +1 -0
  30. package/dist/components/cells/SurfaceCell.d.ts +14 -0
  31. package/dist/components/cells/SurfaceCell.d.ts.map +1 -0
  32. package/dist/components/cells/SurfaceCell.js +23 -0
  33. package/dist/components/cells/SurfaceCell.js.map +1 -0
  34. package/dist/components/cells/index.d.ts +9 -0
  35. package/dist/components/cells/index.d.ts.map +1 -0
  36. package/dist/components/cells/index.js +9 -0
  37. package/dist/components/cells/index.js.map +1 -0
  38. package/dist/components/cells/scaffoldMeta.d.ts +6 -0
  39. package/dist/components/cells/scaffoldMeta.d.ts.map +1 -0
  40. package/dist/components/cells/scaffoldMeta.js +47 -0
  41. package/dist/components/cells/scaffoldMeta.js.map +1 -0
  42. package/dist/components/dashboard/DashboardSidebar.d.ts +6 -0
  43. package/dist/components/dashboard/DashboardSidebar.d.ts.map +1 -0
  44. package/dist/components/dashboard/DashboardSidebar.js +163 -0
  45. package/dist/components/dashboard/DashboardSidebar.js.map +1 -0
  46. package/dist/components/data/DataTable.d.ts +16 -0
  47. package/dist/components/data/DataTable.d.ts.map +1 -0
  48. package/dist/components/data/DataTable.js +54 -0
  49. package/dist/components/data/DataTable.js.map +1 -0
  50. package/dist/components/data/JsonViewer.d.ts +6 -0
  51. package/dist/components/data/JsonViewer.d.ts.map +1 -0
  52. package/dist/components/data/JsonViewer.js +5 -0
  53. package/dist/components/data/JsonViewer.js.map +1 -0
  54. package/dist/components/data/index.d.ts +3 -0
  55. package/dist/components/data/index.d.ts.map +1 -0
  56. package/dist/components/data/index.js +3 -0
  57. package/dist/components/data/index.js.map +1 -0
  58. package/dist/components/forms/SelectField.d.ts +22 -0
  59. package/dist/components/forms/SelectField.d.ts.map +1 -0
  60. package/dist/components/forms/SelectField.js +14 -0
  61. package/dist/components/forms/SelectField.js.map +1 -0
  62. package/dist/components/navigation/BackLink.d.ts +7 -0
  63. package/dist/components/navigation/BackLink.d.ts.map +1 -0
  64. package/dist/components/navigation/BackLink.js +6 -0
  65. package/dist/components/navigation/BackLink.js.map +1 -0
  66. package/dist/components/pages/PagesListView.d.ts +12 -0
  67. package/dist/components/pages/PagesListView.d.ts.map +1 -0
  68. package/dist/components/pages/PagesListView.js +19 -0
  69. package/dist/components/pages/PagesListView.js.map +1 -0
  70. package/dist/components/pages/PagesMapView.d.ts +15 -0
  71. package/dist/components/pages/PagesMapView.d.ts.map +1 -0
  72. package/dist/components/pages/PagesMapView.js +232 -0
  73. package/dist/components/pages/PagesMapView.js.map +1 -0
  74. package/dist/components/scanner/EventLog.d.ts +8 -0
  75. package/dist/components/scanner/EventLog.d.ts.map +1 -0
  76. package/dist/components/scanner/EventLog.js +18 -0
  77. package/dist/components/scanner/EventLog.js.map +1 -0
  78. package/dist/components/scanner/LiveCounters.d.ts +9 -0
  79. package/dist/components/scanner/LiveCounters.d.ts.map +1 -0
  80. package/dist/components/scanner/LiveCounters.js +33 -0
  81. package/dist/components/scanner/LiveCounters.js.map +1 -0
  82. package/dist/components/scanner/PhaseIndicator.d.ts +6 -0
  83. package/dist/components/scanner/PhaseIndicator.d.ts.map +1 -0
  84. package/dist/components/scanner/PhaseIndicator.js +31 -0
  85. package/dist/components/scanner/PhaseIndicator.js.map +1 -0
  86. package/dist/components/scanner/RunSummaryCard.d.ts +12 -0
  87. package/dist/components/scanner/RunSummaryCard.d.ts.map +1 -0
  88. package/dist/components/scanner/RunSummaryCard.js +7 -0
  89. package/dist/components/scanner/RunSummaryCard.js.map +1 -0
  90. package/dist/components/scanner/ScanForm.d.ts +9 -0
  91. package/dist/components/scanner/ScanForm.d.ts.map +1 -0
  92. package/dist/components/scanner/ScanForm.js +31 -0
  93. package/dist/components/scanner/ScanForm.js.map +1 -0
  94. package/dist/components/scanner/ScanProgressPanel.d.ts +16 -0
  95. package/dist/components/scanner/ScanProgressPanel.d.ts.map +1 -0
  96. package/dist/components/scanner/ScanProgressPanel.js +8 -0
  97. package/dist/components/scanner/ScanProgressPanel.js.map +1 -0
  98. package/dist/components/scanner/StatusBadge.d.ts +7 -0
  99. package/dist/components/scanner/StatusBadge.d.ts.map +1 -0
  100. package/dist/components/scanner/StatusBadge.js +65 -0
  101. package/dist/components/scanner/StatusBadge.js.map +1 -0
  102. package/dist/components/scanner/index.d.ts +8 -0
  103. package/dist/components/scanner/index.d.ts.map +1 -0
  104. package/dist/components/scanner/index.js +8 -0
  105. package/dist/components/scanner/index.js.map +1 -0
  106. package/dist/components/scenarios/AddScenarioForm.d.ts +14 -0
  107. package/dist/components/scenarios/AddScenarioForm.d.ts.map +1 -0
  108. package/dist/components/scenarios/AddScenarioForm.js +43 -0
  109. package/dist/components/scenarios/AddScenarioForm.js.map +1 -0
  110. package/dist/components/scripts/ScriptPanel.d.ts +17 -0
  111. package/dist/components/scripts/ScriptPanel.d.ts.map +1 -0
  112. package/dist/components/scripts/ScriptPanel.js +32 -0
  113. package/dist/components/scripts/ScriptPanel.js.map +1 -0
  114. package/dist/components/states/index.d.ts +19 -0
  115. package/dist/components/states/index.d.ts.map +1 -0
  116. package/dist/components/states/index.js +16 -0
  117. package/dist/components/states/index.js.map +1 -0
  118. package/dist/config/priorityConfig.d.ts +12 -0
  119. package/dist/config/priorityConfig.d.ts.map +1 -0
  120. package/dist/config/priorityConfig.js +39 -0
  121. package/dist/config/priorityConfig.js.map +1 -0
  122. package/dist/context/config.d.ts +53 -0
  123. package/dist/context/config.d.ts.map +1 -0
  124. package/dist/context/config.js +32 -0
  125. package/dist/context/config.js.map +1 -0
  126. package/dist/context/routing.d.ts +42 -0
  127. package/dist/context/routing.d.ts.map +1 -0
  128. package/dist/context/routing.js +33 -0
  129. package/dist/context/routing.js.map +1 -0
  130. package/dist/hooks/useDashboardEnvironmentContext.d.ts +15 -0
  131. package/dist/hooks/useDashboardEnvironmentContext.d.ts.map +1 -0
  132. package/dist/hooks/useDashboardEnvironmentContext.js +89 -0
  133. package/dist/hooks/useDashboardEnvironmentContext.js.map +1 -0
  134. package/dist/hooks/useEnvBasePath.d.ts +8 -0
  135. package/dist/hooks/useEnvBasePath.d.ts.map +1 -0
  136. package/dist/hooks/useEnvBasePath.js +12 -0
  137. package/dist/hooks/useEnvBasePath.js.map +1 -0
  138. package/dist/hooks/useLocalizedNavigate.d.ts +12 -0
  139. package/dist/hooks/useLocalizedNavigate.d.ts.map +1 -0
  140. package/dist/hooks/useLocalizedNavigate.js +14 -0
  141. package/dist/hooks/useLocalizedNavigate.js.map +1 -0
  142. package/dist/index.d.ts +49 -0
  143. package/dist/index.d.ts.map +1 -0
  144. package/dist/index.js +66 -0
  145. package/dist/index.js.map +1 -0
  146. package/dist/pages/BundleDetailPage.d.ts +2 -0
  147. package/dist/pages/BundleDetailPage.d.ts.map +1 -0
  148. package/dist/pages/BundleDetailPage.js +155 -0
  149. package/dist/pages/BundleDetailPage.js.map +1 -0
  150. package/dist/pages/BundlesPage.d.ts +2 -0
  151. package/dist/pages/BundlesPage.d.ts.map +1 -0
  152. package/dist/pages/BundlesPage.js +61 -0
  153. package/dist/pages/BundlesPage.js.map +1 -0
  154. package/dist/pages/DashboardOverview.d.ts +2 -0
  155. package/dist/pages/DashboardOverview.d.ts.map +1 -0
  156. package/dist/pages/DashboardOverview.js +179 -0
  157. package/dist/pages/DashboardOverview.js.map +1 -0
  158. package/dist/pages/FindingsListPage.d.ts +2 -0
  159. package/dist/pages/FindingsListPage.d.ts.map +1 -0
  160. package/dist/pages/FindingsListPage.js +160 -0
  161. package/dist/pages/FindingsListPage.js.map +1 -0
  162. package/dist/pages/PageDetailPage.d.ts +2 -0
  163. package/dist/pages/PageDetailPage.d.ts.map +1 -0
  164. package/dist/pages/PageDetailPage.js +120 -0
  165. package/dist/pages/PageDetailPage.js.map +1 -0
  166. package/dist/pages/PageGraphPage.d.ts +3 -0
  167. package/dist/pages/PageGraphPage.d.ts.map +1 -0
  168. package/dist/pages/PageGraphPage.js +72 -0
  169. package/dist/pages/PageGraphPage.js.map +1 -0
  170. package/dist/pages/PageStateDetailPage.d.ts +2 -0
  171. package/dist/pages/PageStateDetailPage.d.ts.map +1 -0
  172. package/dist/pages/PageStateDetailPage.js +69 -0
  173. package/dist/pages/PageStateDetailPage.js.map +1 -0
  174. package/dist/pages/PagesPage.d.ts +2 -0
  175. package/dist/pages/PagesPage.d.ts.map +1 -0
  176. package/dist/pages/PagesPage.js +83 -0
  177. package/dist/pages/PagesPage.js.map +1 -0
  178. package/dist/pages/PatternsPage.d.ts +2 -0
  179. package/dist/pages/PatternsPage.d.ts.map +1 -0
  180. package/dist/pages/PatternsPage.js +102 -0
  181. package/dist/pages/PatternsPage.js.map +1 -0
  182. package/dist/pages/PersonasPage.d.ts +2 -0
  183. package/dist/pages/PersonasPage.d.ts.map +1 -0
  184. package/dist/pages/PersonasPage.js +151 -0
  185. package/dist/pages/PersonasPage.js.map +1 -0
  186. package/dist/pages/RunRedirect.d.ts +2 -0
  187. package/dist/pages/RunRedirect.d.ts.map +1 -0
  188. package/dist/pages/RunRedirect.js +25 -0
  189. package/dist/pages/RunRedirect.js.map +1 -0
  190. package/dist/pages/RunSurfaceRunDetailPage.d.ts +2 -0
  191. package/dist/pages/RunSurfaceRunDetailPage.d.ts.map +1 -0
  192. package/dist/pages/RunSurfaceRunDetailPage.js +38 -0
  193. package/dist/pages/RunSurfaceRunDetailPage.js.map +1 -0
  194. package/dist/pages/RunSurfaceRunsPage.d.ts +2 -0
  195. package/dist/pages/RunSurfaceRunsPage.d.ts.map +1 -0
  196. package/dist/pages/RunSurfaceRunsPage.js +35 -0
  197. package/dist/pages/RunSurfaceRunsPage.js.map +1 -0
  198. package/dist/pages/RunTestInteractionRunDetailPage.d.ts +2 -0
  199. package/dist/pages/RunTestInteractionRunDetailPage.d.ts.map +1 -0
  200. package/dist/pages/RunTestInteractionRunDetailPage.js +55 -0
  201. package/dist/pages/RunTestInteractionRunDetailPage.js.map +1 -0
  202. package/dist/pages/RunTestInteractionRunsPage.d.ts +2 -0
  203. package/dist/pages/RunTestInteractionRunsPage.d.ts.map +1 -0
  204. package/dist/pages/RunTestInteractionRunsPage.js +38 -0
  205. package/dist/pages/RunTestInteractionRunsPage.js.map +1 -0
  206. package/dist/pages/RunnerGraphPage.d.ts +3 -0
  207. package/dist/pages/RunnerGraphPage.d.ts.map +1 -0
  208. package/dist/pages/RunnerGraphPage.js +86 -0
  209. package/dist/pages/RunnerGraphPage.js.map +1 -0
  210. package/dist/pages/ScaffoldDetailPage.d.ts +2 -0
  211. package/dist/pages/ScaffoldDetailPage.d.ts.map +1 -0
  212. package/dist/pages/ScaffoldDetailPage.js +56 -0
  213. package/dist/pages/ScaffoldDetailPage.js.map +1 -0
  214. package/dist/pages/ScaffoldsPage.d.ts +2 -0
  215. package/dist/pages/ScaffoldsPage.d.ts.map +1 -0
  216. package/dist/pages/ScaffoldsPage.js +35 -0
  217. package/dist/pages/ScaffoldsPage.js.map +1 -0
  218. package/dist/pages/ScanProgressPage.d.ts +2 -0
  219. package/dist/pages/ScanProgressPage.d.ts.map +1 -0
  220. package/dist/pages/ScanProgressPage.js +30 -0
  221. package/dist/pages/ScanProgressPage.js.map +1 -0
  222. package/dist/pages/SchedulesPage.d.ts +2 -0
  223. package/dist/pages/SchedulesPage.d.ts.map +1 -0
  224. package/dist/pages/SchedulesPage.js +165 -0
  225. package/dist/pages/SchedulesPage.js.map +1 -0
  226. package/dist/pages/StartScanPage.d.ts +2 -0
  227. package/dist/pages/StartScanPage.d.ts.map +1 -0
  228. package/dist/pages/StartScanPage.js +97 -0
  229. package/dist/pages/StartScanPage.js.map +1 -0
  230. package/dist/pages/TestInteractionDetailPage.d.ts +2 -0
  231. package/dist/pages/TestInteractionDetailPage.d.ts.map +1 -0
  232. package/dist/pages/TestInteractionDetailPage.js +60 -0
  233. package/dist/pages/TestInteractionDetailPage.js.map +1 -0
  234. package/dist/pages/TestInteractionsPage.d.ts +2 -0
  235. package/dist/pages/TestInteractionsPage.d.ts.map +1 -0
  236. package/dist/pages/TestInteractionsPage.js +96 -0
  237. package/dist/pages/TestInteractionsPage.js.map +1 -0
  238. package/dist/pages/TestRunDetailPage.d.ts +2 -0
  239. package/dist/pages/TestRunDetailPage.d.ts.map +1 -0
  240. package/dist/pages/TestRunDetailPage.js +81 -0
  241. package/dist/pages/TestRunDetailPage.js.map +1 -0
  242. package/dist/pages/TestRunsListPage.d.ts +2 -0
  243. package/dist/pages/TestRunsListPage.d.ts.map +1 -0
  244. package/dist/pages/TestRunsListPage.js +18 -0
  245. package/dist/pages/TestRunsListPage.js.map +1 -0
  246. package/dist/pages/TestScenarioDetailPage.d.ts +2 -0
  247. package/dist/pages/TestScenarioDetailPage.d.ts.map +1 -0
  248. package/dist/pages/TestScenarioDetailPage.js +101 -0
  249. package/dist/pages/TestScenarioDetailPage.js.map +1 -0
  250. package/dist/pages/TestScenariosPage.d.ts +2 -0
  251. package/dist/pages/TestScenariosPage.d.ts.map +1 -0
  252. package/dist/pages/TestScenariosPage.js +73 -0
  253. package/dist/pages/TestScenariosPage.js.map +1 -0
  254. package/dist/pages/TestSurfaceDetailPage.d.ts +2 -0
  255. package/dist/pages/TestSurfaceDetailPage.d.ts.map +1 -0
  256. package/dist/pages/TestSurfaceDetailPage.js +33 -0
  257. package/dist/pages/TestSurfaceDetailPage.js.map +1 -0
  258. package/dist/pages/TestSurfacesListPage.d.ts +2 -0
  259. package/dist/pages/TestSurfacesListPage.d.ts.map +1 -0
  260. package/dist/pages/TestSurfacesListPage.js +73 -0
  261. package/dist/pages/TestSurfacesListPage.js.map +1 -0
  262. package/dist/utils/formatDateTime.d.ts +13 -0
  263. package/dist/utils/formatDateTime.d.ts.map +1 -0
  264. package/dist/utils/formatDateTime.js +27 -0
  265. package/dist/utils/formatDateTime.js.map +1 -0
  266. package/package.json +72 -0
@@ -0,0 +1,81 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useRun, useRunSummary, useRunStructure, useTestInteractionRun, useTestRunFindings, } from '@sudobility/testomniac_client';
3
+ import { formatDate, formatMultilineLog } from '@sudobility/testomniac_lib';
4
+ import { useTestomniacApi } from '../context/config';
5
+ import { useRouteParams } from '../context/routing';
6
+ import BackLink from '../components/navigation/BackLink';
7
+ import { useEnvBasePath } from '../hooks/useEnvBasePath';
8
+ import { useLocalizedNavigate } from '../hooks/useLocalizedNavigate';
9
+ import { Card } from '@sudobility/components';
10
+ import { StatusBadge } from '../components/scanner/StatusBadge';
11
+ import { EmptyState } from '../components/states';
12
+ function FindingTypeBadge({ type }) {
13
+ const colors = type === 'error'
14
+ ? 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300'
15
+ : type === 'warning'
16
+ ? 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-300'
17
+ : 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300';
18
+ return (_jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${colors}`, children: type }));
19
+ }
20
+ export function TestRunDetailPage() {
21
+ const { runId } = useRouteParams();
22
+ const { networkClient, token, baseUrl } = useTestomniacApi();
23
+ const { navigate } = useLocalizedNavigate();
24
+ const basePath = useEnvBasePath();
25
+ const testRunId = Number(runId);
26
+ const { run, isLoading: isRunLoading, error: runError, } = useRun({
27
+ networkClient,
28
+ baseUrl,
29
+ runId: testRunId,
30
+ token: token ?? '',
31
+ enabled: !!runId && !!token,
32
+ });
33
+ const { summary } = useRunSummary({
34
+ networkClient,
35
+ baseUrl,
36
+ runId: testRunId,
37
+ token: token ?? '',
38
+ enabled: !!runId && !!token,
39
+ });
40
+ const { structure } = useRunStructure({
41
+ networkClient,
42
+ baseUrl,
43
+ runId: testRunId,
44
+ token: token ?? '',
45
+ enabled: !!runId && !!token,
46
+ });
47
+ const { findings, isLoading, error } = useTestRunFindings({
48
+ networkClient,
49
+ baseUrl,
50
+ testInteractionRunId: run?.testInteractionRunId ?? 0,
51
+ token: token ?? '',
52
+ enabled: !!run?.testInteractionRunId && !!token,
53
+ });
54
+ const { testInteractionRun, isLoading: isCaseRunLoading, error: elementRunError, } = useTestInteractionRun({
55
+ networkClient,
56
+ baseUrl,
57
+ testInteractionRunId: run?.testInteractionRunId ?? 0,
58
+ token: token ?? '',
59
+ enabled: !!run?.testInteractionRunId && !!token,
60
+ });
61
+ if (runError || error || elementRunError) {
62
+ return (_jsx("div", { className: "p-6", children: _jsxs("div", { className: "text-center text-red-600 dark:text-red-400 py-8", children: ["Error: ", runError || error || elementRunError] }) }));
63
+ }
64
+ if (isRunLoading || !run) {
65
+ return (_jsx("div", { className: "p-6", children: _jsx("div", { className: "text-center text-gray-500 dark:text-gray-400 py-8", children: "Loading run..." }) }));
66
+ }
67
+ const isRootLikeRun = run.testInteractionRunId === null;
68
+ const expertiseEntries = Object.entries(summary?.expertiseSummary ?? {}).sort(([left], [right]) => left.localeCompare(right));
69
+ const surfaceCoverage = structure?.surfaces.map(surface => ({
70
+ id: surface.id,
71
+ title: surface.title,
72
+ surfaceRunId: surface.surfaceRuns[0]?.id ?? null,
73
+ status: surface.surfaceRuns[0]?.status ?? 'pending',
74
+ interactionCount: surface.testInteractions.length,
75
+ })) ?? [];
76
+ const consoleLog = formatMultilineLog(testInteractionRun?.consoleLog);
77
+ const networkLog = formatMultilineLog(testInteractionRun?.networkLog);
78
+ return (_jsxs("div", { className: "p-6", children: [_jsx(BackLink, { label: "Back to Runs", onClick: () => navigate(`${basePath}/runs`) }), _jsxs("nav", { className: "flex items-center gap-1 text-sm text-gray-500 dark:text-gray-400 mb-4", children: [_jsx("button", { onClick: () => navigate(`${basePath}/runs`), className: "hover:text-blue-600 dark:hover:text-blue-400 transition-colors", children: "Runs" }), _jsx("span", { children: "/" }), _jsxs("span", { className: "text-gray-900 dark:text-gray-100 font-medium", children: ["Run #", runId] })] }), _jsxs("h1", { className: "text-2xl font-bold text-gray-900 dark:text-gray-100 mb-2", children: ["Test Run #", runId] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2 mb-6", children: [_jsx(StatusBadge, { status: run.status }), _jsx(StatusBadge, { status: run.sizeClass }), _jsxs("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: ["ID: ", runId] }), run.createdAt && (_jsxs("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: ["Created ", formatDate(run.createdAt)] })), run.startedAt && (_jsxs("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: ["Started ", formatDate(run.startedAt)] })), run.completedAt && (_jsxs("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: ["Completed ", formatDate(run.completedAt)] }))] }), isRootLikeRun && summary && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-8 grid grid-cols-2 gap-4 md:grid-cols-4", children: [_jsxs(Card, { variant: "bordered", padding: "md", children: [_jsx("div", { className: "text-2xl font-bold text-gray-900 dark:text-gray-100", children: summary.pagesFound ?? 0 }), _jsx("div", { className: "text-xs text-gray-500", children: "Pages Found" })] }), _jsxs(Card, { variant: "bordered", padding: "md", children: [_jsx("div", { className: "text-2xl font-bold text-gray-900 dark:text-gray-100", children: summary.pageStatesFound ?? 0 }), _jsx("div", { className: "text-xs text-gray-500", children: "Page States" })] }), _jsxs(Card, { variant: "bordered", padding: "md", children: [_jsx("div", { className: "text-2xl font-bold text-gray-900 dark:text-gray-100", children: summary.testRunsCompleted ?? 0 }), _jsx("div", { className: "text-xs text-gray-500", children: "Completed Runs" })] }), _jsxs(Card, { variant: "bordered", padding: "md", children: [_jsx("div", { className: "text-2xl font-bold text-red-600 dark:text-red-400", children: summary.totalFindings }), _jsx("div", { className: "text-xs text-gray-500", children: "Findings" })] })] }), summary.aiSummary && (_jsxs(Card, { variant: "bordered", padding: "md", className: "mb-8", children: [_jsx("h2", { className: "mb-2 text-sm font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400", children: "Summary" }), _jsx("p", { className: "text-sm leading-6 text-gray-700 dark:text-gray-300", children: summary.aiSummary })] })), _jsxs("div", { className: "mb-8 grid grid-cols-1 gap-3 sm:grid-cols-3", children: [_jsxs("button", { onClick: () => navigate(`${basePath}/runs/${runId}/surface-runs`), className: "rounded-lg border border-gray-200 bg-white p-4 text-left transition-colors hover:border-blue-300 dark:border-gray-700 dark:bg-gray-800 dark:hover:border-blue-600", children: [_jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: "Surface Runs" }), _jsx("div", { className: "mt-1 text-xs text-gray-500 dark:text-gray-400", children: "Navigate the run hierarchy by surface run, then interaction runs and run details." })] }), _jsxs("button", { onClick: () => navigate(`${basePath}/runs/${runId}/pages`), className: "rounded-lg border border-gray-200 bg-white p-4 text-left transition-colors hover:border-blue-300 dark:border-gray-700 dark:bg-gray-800 dark:hover:border-blue-600", children: [_jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: "Pages" }), _jsx("div", { className: "mt-1 text-xs text-gray-500 dark:text-gray-400", children: "Browse discovered pages and drill into captured page states." })] }), _jsxs("button", { onClick: () => navigate(`${basePath}/runs/${runId}/issues`), className: "rounded-lg border border-gray-200 bg-white p-4 text-left transition-colors hover:border-blue-300 dark:border-gray-700 dark:bg-gray-800 dark:hover:border-blue-600", children: [_jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: "Findings" }), _jsx("div", { className: "mt-1 text-xs text-gray-500 dark:text-gray-400", children: "Review grouped warnings and errors for this scan run." })] })] }), surfaceCoverage.length > 0 && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "mb-4 text-lg font-semibold text-gray-900 dark:text-gray-100", children: "Coverage Tree" }), _jsx("div", { className: "space-y-3", children: surfaceCoverage.map(surface => (_jsx("button", { onClick: () => surface.surfaceRunId != null &&
79
+ navigate(`${basePath}/runs/${runId}/surface-runs/${surface.surfaceRunId}`), disabled: surface.surfaceRunId == null, className: "w-full rounded-lg border border-gray-200 bg-white p-4 text-left transition-colors hover:border-blue-300 disabled:cursor-default disabled:hover:border-gray-200 dark:border-gray-700 dark:bg-gray-800 dark:hover:border-blue-600 dark:disabled:hover:border-gray-700", children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: surface.title }), _jsxs("div", { className: "mt-1 text-xs text-gray-500 dark:text-gray-400", children: [surface.interactionCount, " test interaction", surface.interactionCount === 1 ? '' : 's'] })] }), _jsx("div", { className: "shrink-0", children: _jsx(StatusBadge, { status: surface.status }) })] }) }, surface.id))) })] })), expertiseEntries.length > 0 && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "mb-4 text-lg font-semibold text-gray-900 dark:text-gray-100", children: "Findings by Expertise" }), _jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3", children: expertiseEntries.map(([name, counts]) => (_jsxs(Card, { variant: "bordered", padding: "md", children: [_jsx("div", { className: "text-sm font-medium capitalize text-gray-900 dark:text-gray-100", children: name }), _jsxs("div", { className: "mt-3 flex gap-4 text-xs", children: [_jsxs("span", { className: "text-red-600 dark:text-red-400", children: [counts.errors, " error", counts.errors === 1 ? '' : 's'] }), _jsxs("span", { className: "text-amber-600 dark:text-amber-400", children: [counts.warnings, " warning", counts.warnings === 1 ? '' : 's'] }), _jsxs("span", { className: "text-gray-500 dark:text-gray-400", children: [counts.findings, " total"] })] })] }, name))) })] }))] })), _jsx("h2", { className: "text-sm font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-3", children: "Findings" }), run.testInteractionRunId === null && (_jsx(EmptyState, { description: "This test run tracks a surface or discovery workflow and does not map directly to a single test interaction run." })), run.testInteractionRunId !== null && isLoading && (_jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400 py-8 text-center", children: "Loading findings..." })), run.testInteractionRunId !== null && !isLoading && findings.length === 0 && (_jsx(EmptyState, { description: "No findings for this test run." })), run.testInteractionRunId !== null && !isLoading && findings.length > 0 && (_jsx("div", { className: "space-y-3", children: findings.map(finding => (_jsx(Card, { variant: "bordered", padding: "md", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx(FindingTypeBadge, { type: finding.type }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: finding.title }), _jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: finding.description }), finding.createdAt && (_jsx("p", { className: "text-xs text-gray-400 dark:text-gray-500 mt-2", children: formatDate(finding.createdAt) }))] })] }) }, finding.id))) })), run.testInteractionRunId !== null && !isCaseRunLoading && (consoleLog || networkLog) && (_jsxs("div", { className: "mt-8 space-y-6", children: [_jsx("h2", { className: "text-sm font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Runtime Signals" }), consoleLog && (_jsxs("div", { children: [_jsx("h3", { className: "mb-2 text-sm font-medium text-gray-900 dark:text-gray-100", children: "Console Log" }), _jsx("pre", { className: "max-h-80 overflow-auto rounded-lg border border-gray-200 bg-gray-50 p-4 text-xs leading-5 text-gray-700 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300", children: consoleLog })] })), networkLog && (_jsxs("div", { children: [_jsx("h3", { className: "mb-2 text-sm font-medium text-gray-900 dark:text-gray-100", children: "Network Log" }), _jsx("pre", { className: "max-h-80 overflow-auto rounded-lg border border-gray-200 bg-gray-50 p-4 text-xs leading-5 text-gray-700 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300", children: networkLog })] }))] }))] }));
80
+ }
81
+ //# sourceMappingURL=TestRunDetailPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestRunDetailPage.js","sourceRoot":"","sources":["../../src/pages/TestRunDetailPage.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function TestRunsListPage(): import("react").JSX.Element;
2
+ //# sourceMappingURL=TestRunsListPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestRunsListPage.d.ts","sourceRoot":"","sources":["../../src/pages/TestRunsListPage.tsx"],"names":[],"mappings":"AASA,wBAAgB,gBAAgB,gCA4E/B"}
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { formatDuration, formatDate } from '@sudobility/testomniac_lib';
3
+ import { SEOHead } from '../context/config';
4
+ import { useLocalizedNavigate } from '../hooks/useLocalizedNavigate';
5
+ import { useEnvBasePath } from '../hooks/useEnvBasePath';
6
+ import { useDashboardEnvironmentContext } from '../hooks/useDashboardEnvironmentContext';
7
+ import { StatusBadge } from '../components/scanner/StatusBadge';
8
+ import { ErrorState, LoadingState, EmptyState } from '../components/states';
9
+ export function TestRunsListPage() {
10
+ const { navigate } = useLocalizedNavigate();
11
+ const { environmentRuns: testRuns, isLoading, error } = useDashboardEnvironmentContext();
12
+ const basePath = useEnvBasePath();
13
+ if (error) {
14
+ return _jsx(ErrorState, { message: error });
15
+ }
16
+ return (_jsxs("div", { className: "p-6", children: [_jsx(SEOHead, { title: "Test Runs", description: "", noIndex: true }), _jsx("h1", { className: "text-2xl font-bold text-gray-900 dark:text-gray-100 mb-6", children: "Test Runs" }), isLoading && _jsx(LoadingState, { message: "Loading test runs..." }), !isLoading && testRuns.length === 0 && (_jsx(EmptyState, { title: "No test runs yet", description: "Test runs will appear here after tests are executed." })), !isLoading && testRuns.length > 0 && (_jsx("div", { className: "overflow-x-auto rounded-lg border border-gray-200 dark:border-gray-700", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700", children: [_jsx("th", { className: "text-left px-4 py-3 font-medium text-gray-500 dark:text-gray-400", children: "ID" }), _jsx("th", { className: "text-left px-4 py-3 font-medium text-gray-500 dark:text-gray-400", children: "Device" }), _jsx("th", { className: "text-left px-4 py-3 font-medium text-gray-500 dark:text-gray-400", children: "Status" }), _jsx("th", { className: "text-left px-4 py-3 font-medium text-gray-500 dark:text-gray-400", children: "Duration" }), _jsx("th", { className: "text-left px-4 py-3 font-medium text-gray-500 dark:text-gray-400", children: "Created" })] }) }), _jsx("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-700", children: testRuns.map((run) => (_jsxs("tr", { onClick: () => navigate(`${basePath}/runs/${run.id}`), className: "bg-white dark:bg-gray-900 hover:bg-gray-50 dark:hover:bg-gray-800 cursor-pointer transition-colors", children: [_jsxs("td", { className: "px-4 py-3 font-mono text-gray-900 dark:text-gray-100", children: ["#", run.id] }), _jsx("td", { className: "px-4 py-3", children: _jsx(StatusBadge, { status: run.sizeClass }) }), _jsx("td", { className: "px-4 py-3", children: _jsx(StatusBadge, { status: run.status }) }), _jsx("td", { className: "px-4 py-3 text-gray-600 dark:text-gray-400", children: formatDuration(run.totalDurationMs) }), _jsx("td", { className: "px-4 py-3 text-gray-600 dark:text-gray-400", children: formatDate(run.createdAt) })] }, run.id))) })] }) }))] }));
17
+ }
18
+ //# sourceMappingURL=TestRunsListPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestRunsListPage.js","sourceRoot":"","sources":["../../src/pages/TestRunsListPage.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,8BAA8B,EAAE,MAAM,yCAAyC,CAAC;AACzF,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAE5E,MAAM,UAAU,gBAAgB;IAC9B,MAAM,EAAE,QAAQ,EAAE,GAAG,oBAAoB,EAAE,CAAC;IAC5C,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,8BAA8B,EAAE,CAAC;IAEzF,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;IAElC,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,KAAC,UAAU,IAAC,OAAO,EAAE,KAAK,GAAI,CAAC;IACxC,CAAC;IAED,OAAO,CACL,eAAK,SAAS,EAAC,KAAK,aAClB,KAAC,OAAO,IAAC,KAAK,EAAC,WAAW,EAAC,WAAW,EAAC,EAAE,EAAC,OAAO,SAAG,EACpD,aAAI,SAAS,EAAC,0DAA0D,0BAAe,EAEtF,SAAS,IAAI,KAAC,YAAY,IAAC,OAAO,EAAC,sBAAsB,GAAG,EAE5D,CAAC,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,CACtC,KAAC,UAAU,IACT,KAAK,EAAC,kBAAkB,EACxB,WAAW,EAAC,sDAAsD,GAClE,CACH,EAEA,CAAC,SAAS,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,CACpC,cAAK,SAAS,EAAC,wEAAwE,YACrF,iBAAO,SAAS,EAAC,gBAAgB,aAC/B,0BACE,cAAI,SAAS,EAAC,2EAA2E,aACvF,aAAI,SAAS,EAAC,kEAAkE,mBAE3E,EACL,aAAI,SAAS,EAAC,kEAAkE,uBAE3E,EACL,aAAI,SAAS,EAAC,kEAAkE,uBAE3E,EACL,aAAI,SAAS,EAAC,kEAAkE,yBAE3E,EACL,aAAI,SAAS,EAAC,kEAAkE,wBAE3E,IACF,GACC,EACR,gBAAO,SAAS,EAAC,+CAA+C,YAC7D,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAoB,EAAE,EAAE,CAAC,CACtC,cAEE,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,QAAQ,SAAS,GAAG,CAAC,EAAE,EAAE,CAAC,EACrD,SAAS,EAAC,oGAAoG,aAE9G,cAAI,SAAS,EAAC,sDAAsD,kBAChE,GAAG,CAAC,EAAE,IACL,EACL,aAAI,SAAS,EAAC,WAAW,YACvB,KAAC,WAAW,IAAC,MAAM,EAAE,GAAG,CAAC,SAAS,GAAI,GACnC,EACL,aAAI,SAAS,EAAC,WAAW,YACvB,KAAC,WAAW,IAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAI,GAChC,EACL,aAAI,SAAS,EAAC,4CAA4C,YACvD,cAAc,CAAC,GAAG,CAAC,eAAe,CAAC,GACjC,EACL,aAAI,SAAS,EAAC,4CAA4C,YACvD,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,GACvB,KAlBA,GAAG,CAAC,EAAE,CAmBR,CACN,CAAC,GACI,IACF,GACJ,CACP,IACG,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function TestScenarioDetailPage(): import("react").JSX.Element;
2
+ //# sourceMappingURL=TestScenarioDetailPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestScenarioDetailPage.d.ts","sourceRoot":"","sources":["../../src/pages/TestScenarioDetailPage.tsx"],"names":[],"mappings":"AAiIA,wBAAgB,sBAAsB,gCAoMrC"}
@@ -0,0 +1,101 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { useRunnerTestScenarios, useEnvironmentTestInteractions, useTestScenarioSequences, useTestScenarioSequenceTestInteractions, useProductPersonas, } from '@sudobility/testomniac_client';
4
+ import { useSequenceGenerator } from '@sudobility/testomniac_lib';
5
+ import { Alert, ActionButton, Card } from '@sudobility/components';
6
+ import { SEOHead, useTestomniacApi } from '../context/config';
7
+ import { useRouteParams } from '../context/routing';
8
+ import { InteractionCell, ListCell } from '../components/cells';
9
+ import { ScriptPanel } from '../components/scripts/ScriptPanel';
10
+ import BackLink from '../components/navigation/BackLink';
11
+ import { useEnvBasePath } from '../hooks/useEnvBasePath';
12
+ import { useLocalizedNavigate } from '../hooks/useLocalizedNavigate';
13
+ import { useDashboardEnvironmentContext } from '../hooks/useDashboardEnvironmentContext';
14
+ import { AddToBundleButton } from '../components/bundles/AddToBundleButton';
15
+ import { EmptyState } from '../components/states';
16
+ function SequenceCard({ sequence, isExpanded, onToggle, networkClient, token, basePath, navigate, interactions, }) {
17
+ const { baseUrl } = useTestomniacApi();
18
+ const { testInteractionLinks, isLoading } = useTestScenarioSequenceTestInteractions({
19
+ networkClient,
20
+ baseUrl,
21
+ testScenarioSequenceId: sequence.id,
22
+ token,
23
+ enabled: isExpanded,
24
+ });
25
+ const sorted = [...testInteractionLinks].sort((a, b) => (a.stepOrder ?? 0) - (b.stepOrder ?? 0));
26
+ const interactionById = new Map(interactions.map(i => [i.id, i]));
27
+ return (_jsxs(Card, { variant: "bordered", padding: "none", className: "overflow-hidden", children: [_jsxs("button", { onClick: onToggle, className: "flex items-center gap-3 w-full px-4 py-3 text-left hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors", children: [_jsx("span", { className: "text-xs text-gray-400", children: isExpanded ? '▼' : '▶' }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: ["Sequence #", sequence.id] }), _jsxs("div", { className: "text-xs text-gray-500 dark:text-gray-400 mt-0.5", children: ["Environment ID: ", sequence.testEnvironmentId, sequence.createdAt &&
28
+ ` — Created: ${new Date(sequence.createdAt).toLocaleDateString()}`] })] })] }), isExpanded && (_jsxs("div", { className: "border-t border-gray-100 dark:border-gray-700 px-4 py-3", children: [isLoading && _jsx("div", { className: "text-xs text-gray-400 py-2", children: "Loading interactions..." }), !isLoading && sorted.length === 0 && (_jsx("div", { className: "text-xs text-gray-400 py-2", children: "No interactions in this sequence." })), !isLoading && sorted.length > 0 && (_jsx("div", { className: "space-y-2", children: sorted.map(link => {
29
+ const interaction = interactionById.get(link.testInteractionId);
30
+ const onOpen = () => navigate(`${basePath}/test-interactions/${link.testInteractionId}`);
31
+ const stepLabel = (_jsxs("span", { className: "w-6 text-right font-mono text-xs text-gray-400", children: [link.stepOrder, "."] }));
32
+ return interaction ? (_jsx(InteractionCell, { interaction: interaction, onClick: onOpen, leading: stepLabel }, link.id)) : (_jsx(ListCell, { leading: stepLabel, title: `Interaction #${link.testInteractionId}`, onClick: onOpen }, link.id));
33
+ }) })), !isLoading && sorted.length > 0 && (_jsx("div", { className: "mt-4 border-t border-gray-100 pt-3 dark:border-gray-700", children: _jsx(ScriptPanel, { kind: "sequence", id: sequence.id, filename: `sequence-${sequence.id}.spec.ts`, enabled: isExpanded }) }))] }))] }));
34
+ }
35
+ export function TestScenarioDetailPage() {
36
+ const { envId, scenarioId } = useRouteParams();
37
+ const { navigate } = useLocalizedNavigate();
38
+ const { baseUrl } = useTestomniacApi();
39
+ const { networkClient, token, productId, primaryRunner, envId: numericEnvId, error: contextError, } = useDashboardEnvironmentContext();
40
+ const basePath = useEnvBasePath();
41
+ // Fetch the scenario from the list (no single-get endpoint needed)
42
+ const { testScenarios } = useRunnerTestScenarios({
43
+ networkClient,
44
+ baseUrl,
45
+ runnerId: primaryRunner?.id ?? 0,
46
+ token,
47
+ enabled: !!envId && !!token && !!primaryRunner,
48
+ });
49
+ const scenario = testScenarios.find(s => s.id === Number(scenarioId));
50
+ const { personas } = useProductPersonas({
51
+ networkClient,
52
+ baseUrl,
53
+ productId,
54
+ token,
55
+ enabled: !!productId && !!token,
56
+ });
57
+ // Use the same source as the Test Interactions screen so every sequence step
58
+ // resolves to a full InteractionCell (title + path + type badge).
59
+ const { testInteractions, refetch: refetchInteractions } = useEnvironmentTestInteractions({
60
+ networkClient,
61
+ baseUrl,
62
+ envId: numericEnvId,
63
+ token,
64
+ enabled: !!envId && !!token,
65
+ });
66
+ const personaName = scenario?.personaId
67
+ ? personas.find(p => p.id === scenario.personaId)?.title
68
+ : null;
69
+ const { sequences, isLoading: sequencesLoading, error: sequencesError, refetch: refetchSequences, } = useTestScenarioSequences({
70
+ networkClient,
71
+ baseUrl,
72
+ testScenarioId: Number(scenarioId),
73
+ token: token ?? '',
74
+ enabled: !!scenarioId && !!token,
75
+ });
76
+ const { generate, isGenerating, error: generateError, } = useSequenceGenerator({
77
+ networkClient,
78
+ baseUrl,
79
+ token,
80
+ });
81
+ const [generateErrorMsg, setGenerateErrorMsg] = useState(null);
82
+ const [expandedSequenceId, setExpandedSequenceId] = useState(null);
83
+ const handleGenerateSequence = async () => {
84
+ setGenerateErrorMsg(null);
85
+ const result = await generate(Number(scenarioId), numericEnvId);
86
+ if (result) {
87
+ refetchSequences();
88
+ // The generated interactions are new rows; refresh the interaction list
89
+ // so each sequence step resolves to a full cell without a page reload.
90
+ refetchInteractions();
91
+ }
92
+ else if (generateError) {
93
+ setGenerateErrorMsg(generateError);
94
+ }
95
+ };
96
+ if (contextError || sequencesError) {
97
+ return (_jsx("div", { className: "p-6", children: _jsxs("div", { className: "text-center text-red-600 dark:text-red-400 py-8", children: ["Error: ", contextError || sequencesError] }) }));
98
+ }
99
+ return (_jsxs("div", { className: "p-6", children: [_jsx(SEOHead, { title: scenario?.title ?? `Scenario #${scenarioId}`, description: "", noIndex: true }), _jsx(BackLink, { label: "Test Scenarios", onClick: () => navigate(`${basePath}/test-scenarios`) }), _jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("h1", { className: "text-2xl font-bold text-gray-900 dark:text-gray-100", children: scenario?.title ?? `Test Scenario #${scenarioId}` }), _jsx(AddToBundleButton, { itemType: "scenario", itemId: Number(scenarioId) })] }), scenario && (_jsxs("div", { className: "mb-6 space-y-3", children: [_jsxs("div", { className: "flex items-center gap-4 text-sm text-gray-500 dark:text-gray-400", children: [_jsxs("span", { children: ["Starting path:", ' ', _jsx("code", { className: "text-gray-900 dark:text-gray-100", children: scenario.startingPath })] }), _jsxs("span", { children: ["Device: ", _jsx("code", { className: "text-gray-900 dark:text-gray-100", children: scenario.sizeClass })] }), scenario.personaId && (_jsxs("span", { children: ["Persona:", ' ', _jsx("code", { className: "text-gray-900 dark:text-gray-100", children: personaName ?? `#${scenario.personaId}` })] }))] }), _jsxs(Card, { variant: "bordered", padding: "sm", children: [_jsx("div", { className: "text-xs font-medium text-gray-500 dark:text-gray-400 mb-1", children: "Prompt" }), _jsx("p", { className: "text-sm text-gray-900 dark:text-gray-100 whitespace-pre-wrap", children: scenario.prompt })] })] })), _jsxs("div", { className: "flex items-center justify-between mb-3", children: [_jsx("h2", { className: "text-sm font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Sequences" }), _jsx(ActionButton, { variant: "primary", className: "bg-purple-600 hover:bg-purple-700", onClick: handleGenerateSequence, disabled: !scenarioId, isLoading: isGenerating, loadingText: "Generating...", children: "Generate Sequence" })] }), (generateErrorMsg || generateError) && (_jsx(Alert, { variant: "error", description: generateErrorMsg || generateError || undefined, className: "mb-3" })), sequencesLoading && (_jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400 py-8 text-center", children: "Loading..." })), !sequencesLoading && sequences.length === 0 && (_jsx(EmptyState, { title: "No sequences yet", description: "Sequences are created when a scenario is run against an environment." })), sequences.length > 0 && (_jsx("div", { className: "space-y-2", children: sequences.map((seq) => (_jsx(SequenceCard, { sequence: seq, isExpanded: expandedSequenceId === seq.id, onToggle: () => setExpandedSequenceId(expandedSequenceId === seq.id ? null : seq.id), networkClient: networkClient, token: token ?? '', basePath: basePath, navigate: navigate, interactions: testInteractions }, seq.id))) }))] }));
100
+ }
101
+ //# sourceMappingURL=TestScenarioDetailPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestScenarioDetailPage.js","sourceRoot":"","sources":["../../src/pages/TestScenarioDetailPage.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function TestScenariosPage(): import("react").JSX.Element;
2
+ //# sourceMappingURL=TestScenariosPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestScenariosPage.d.ts","sourceRoot":"","sources":["../../src/pages/TestScenariosPage.tsx"],"names":[],"mappings":"AAmBA,wBAAgB,iBAAiB,gCAsJhC"}
@@ -0,0 +1,73 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { useRunnerTestScenarios, useDeleteTestScenario, useProductPersonas, useDetectTestScenarios, } from '@sudobility/testomniac_client';
4
+ import { Alert, Button, ActionButton } from '@sudobility/components';
5
+ import { SEOHead, useTestomniacApi } from '../context/config';
6
+ import { useRouteParams } from '../context/routing';
7
+ import { ScenarioCell } from '../components/cells';
8
+ import { useEnvBasePath } from '../hooks/useEnvBasePath';
9
+ import { useLocalizedNavigate } from '../hooks/useLocalizedNavigate';
10
+ import { StatusBadge } from '../components/scanner/StatusBadge';
11
+ import { AddScenarioForm } from '../components/scenarios/AddScenarioForm';
12
+ import { useDashboardEnvironmentContext } from '../hooks/useDashboardEnvironmentContext';
13
+ import { ErrorState, LoadingState, EmptyState } from '../components/states';
14
+ export function TestScenariosPage() {
15
+ const { envId } = useRouteParams();
16
+ const { navigate } = useLocalizedNavigate();
17
+ const { baseUrl } = useTestomniacApi();
18
+ const { networkClient, token, productId, primaryRunner, isLoading: contextLoading, error: contextError, } = useDashboardEnvironmentContext();
19
+ const [showForm, setShowForm] = useState(false);
20
+ const { testScenarios, isLoading, error, refetch } = useRunnerTestScenarios({
21
+ networkClient,
22
+ baseUrl,
23
+ runnerId: primaryRunner?.id ?? 0,
24
+ token,
25
+ enabled: !!envId && !!token && !!primaryRunner,
26
+ });
27
+ const { personas } = useProductPersonas({
28
+ networkClient,
29
+ baseUrl,
30
+ productId,
31
+ token,
32
+ enabled: !!productId && !!token,
33
+ });
34
+ const { deleteTestScenario } = useDeleteTestScenario({
35
+ networkClient,
36
+ baseUrl,
37
+ runnerId: primaryRunner?.id ?? 0,
38
+ token,
39
+ });
40
+ const { detectTestScenarios, isDetecting } = useDetectTestScenarios({
41
+ networkClient,
42
+ baseUrl,
43
+ token,
44
+ });
45
+ // Detect state
46
+ const [detectError, setDetectError] = useState(null);
47
+ const basePath = useEnvBasePath();
48
+ const handleDelete = async (scenarioId) => {
49
+ await deleteTestScenario(scenarioId);
50
+ refetch();
51
+ };
52
+ const handleDetect = async () => {
53
+ setDetectError(null);
54
+ try {
55
+ await detectTestScenarios({ productId: productId });
56
+ refetch();
57
+ }
58
+ catch (err) {
59
+ // The API returns an actionable message (e.g. naming the missing
60
+ // SHAPESHYFT_* env var) when scenario detection isn't configured.
61
+ setDetectError(err instanceof Error ? err.message : 'Detection failed');
62
+ }
63
+ };
64
+ if (contextError || error) {
65
+ return _jsx(ErrorState, { message: contextError || error || '' });
66
+ }
67
+ return (_jsxs("div", { className: "p-6", children: [_jsx(SEOHead, { title: "Test Scenarios", description: "", noIndex: true }), _jsxs("div", { className: "flex items-center justify-between mb-6", children: [_jsx("h1", { className: "text-2xl font-bold text-gray-900 dark:text-gray-100", children: "Test Scenarios" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(ActionButton, { variant: "primary", className: "bg-purple-600 hover:bg-purple-700", onClick: handleDetect, disabled: !productId, isLoading: isDetecting, loadingText: "Detecting...", children: "Detect Scenarios" }), _jsx(Button, { variant: "primary", onClick: () => setShowForm(!showForm), children: showForm ? 'Cancel' : 'New Scenario' })] })] }), detectError && _jsx(Alert, { variant: "error", description: detectError, className: "mb-4" }), showForm && primaryRunner && (_jsx("div", { className: "mb-6", children: _jsx(AddScenarioForm, { networkClient: networkClient, token: token, runnerId: primaryRunner.id, personas: personas, onCreated: () => {
68
+ setShowForm(false);
69
+ refetch();
70
+ }, onCancel: () => setShowForm(false) }) })), (contextLoading || isLoading) && _jsx(LoadingState, { message: "Loading test scenarios..." }), !isLoading && testScenarios.length === 0 && !showForm && (_jsx(EmptyState, { title: "No test scenarios yet", description: "Create a test scenario to define a user flow you want to test." })), !isLoading && testScenarios.length > 0 && (_jsx("div", { className: "space-y-2", children: testScenarios.map((scenario) => (_jsx(ScenarioCell, { scenario: scenario, onClick: () => navigate(`${basePath}/test-scenarios/${scenario.id}`), trailing: _jsxs(_Fragment, { children: [scenario.personaId && (_jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: personas.find(p => p.id === scenario.personaId)?.title ??
71
+ `Persona #${scenario.personaId}` })), _jsx(StatusBadge, { status: scenario.sizeClass })] }), actions: _jsx("button", { onClick: () => handleDelete(scenario.id), className: "text-xs text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300", children: "Delete" }) }, scenario.id))) }))] }));
72
+ }
73
+ //# sourceMappingURL=TestScenariosPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestScenariosPage.js","sourceRoot":"","sources":["../../src/pages/TestScenariosPage.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function TestSurfaceDetailPage(): import("react").JSX.Element;
2
+ //# sourceMappingURL=TestSurfaceDetailPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestSurfaceDetailPage.d.ts","sourceRoot":"","sources":["../../src/pages/TestSurfaceDetailPage.tsx"],"names":[],"mappings":"AA6BA,wBAAgB,qBAAqB,gCA8EpC"}
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useTestSurfaceTestInteractions } from '@sudobility/testomniac_client';
3
+ import { useTestomniacApi } from '../context/config';
4
+ import { useRouteParams } from '../context/routing';
5
+ import BackLink from '../components/navigation/BackLink';
6
+ import { useEnvBasePath } from '../hooks/useEnvBasePath';
7
+ import { useLocalizedNavigate } from '../hooks/useLocalizedNavigate';
8
+ import { StatusBadge } from '../components/scanner/StatusBadge';
9
+ import { AddToBundleButton } from '../components/bundles/AddToBundleButton';
10
+ import { ErrorState, LoadingState, EmptyState } from '../components/states';
11
+ function FileIcon() {
12
+ return (_jsx("svg", { className: "w-5 h-5 flex-shrink-0 text-blue-500 dark:text-blue-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" }) }));
13
+ }
14
+ export function TestSurfaceDetailPage() {
15
+ const { surfaceId } = useRouteParams();
16
+ const { networkClient, token, baseUrl } = useTestomniacApi();
17
+ const { navigate } = useLocalizedNavigate();
18
+ const basePath = useEnvBasePath();
19
+ const { testInteractions, isLoading: casesLoading, error: casesError, } = useTestSurfaceTestInteractions({
20
+ networkClient,
21
+ baseUrl,
22
+ testSurfaceId: Number(surfaceId),
23
+ token: token ?? '',
24
+ enabled: !!surfaceId && !!token,
25
+ });
26
+ const isLoading = casesLoading;
27
+ const error = casesError;
28
+ if (error) {
29
+ return _jsx(ErrorState, { message: error });
30
+ }
31
+ return (_jsxs("div", { className: "p-6", children: [_jsx(BackLink, { label: "Test Surfaces", onClick: () => navigate(`${basePath}/test-surfaces`) }), _jsxs("div", { className: "flex items-center justify-between mb-6", children: [_jsxs("h1", { className: "text-2xl font-bold text-gray-900 dark:text-gray-100", children: ["Test Surface #", surfaceId] }), _jsx(AddToBundleButton, { itemType: "surface", itemId: Number(surfaceId) })] }), isLoading && _jsx(LoadingState, { message: "Loading..." }), !isLoading && testInteractions.length === 0 && (_jsx(EmptyState, { title: "Empty surface", description: "This test surface has no test interactions." })), testInteractions.length > 0 && (_jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-3", children: "Test Interactions" }), _jsx("div", { className: "space-y-2", children: testInteractions.map((tc) => (_jsxs("button", { onClick: () => navigate(`${basePath}/test-interactions/${tc.id}`), className: "w-full text-left flex items-center gap-3 px-4 py-3 rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors", children: [_jsx(FileIcon, {}), _jsx("div", { className: "flex-1 min-w-0", children: _jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100 truncate", children: tc.title }) }), _jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [_jsx(StatusBadge, { status: tc.testType }), _jsx(StatusBadge, { status: tc.sizeClass })] })] }, tc.id))) })] }))] }));
32
+ }
33
+ //# sourceMappingURL=TestSurfaceDetailPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestSurfaceDetailPage.js","sourceRoot":"","sources":["../../src/pages/TestSurfaceDetailPage.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function TestSurfacesListPage(): import("react").JSX.Element;
2
+ //# sourceMappingURL=TestSurfacesListPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestSurfacesListPage.d.ts","sourceRoot":"","sources":["../../src/pages/TestSurfacesListPage.tsx"],"names":[],"mappings":"AAeA,wBAAgB,oBAAoB,gCAiKnC"}
@@ -0,0 +1,73 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useMemo } from 'react';
3
+ import { useEnvironmentTestSurfaces } from '@sudobility/testomniac_client';
4
+ import { getSurfacePriorityBand } from '@sudobility/testomniac_lib';
5
+ import { SEOHead, useTestomniacApi } from '../context/config';
6
+ import { useRouteParams } from '../context/routing';
7
+ import { SurfaceCell } from '../components/cells';
8
+ import { useEnvBasePath } from '../hooks/useEnvBasePath';
9
+ import { useLocalizedNavigate } from '../hooks/useLocalizedNavigate';
10
+ import { SelectField } from '../components/forms/SelectField';
11
+ import { ErrorState, LoadingState, EmptyState } from '../components/states';
12
+ export function TestSurfacesListPage() {
13
+ const { envId } = useRouteParams();
14
+ const { networkClient, token, baseUrl } = useTestomniacApi();
15
+ const { navigate } = useLocalizedNavigate();
16
+ const [deviceFilter, setDeviceFilter] = useState('all');
17
+ const [priorityFilter, setPriorityFilter] = useState('all');
18
+ const [typeFilter, setTypeFilter] = useState('all');
19
+ const { testSurfaces, isLoading, error } = useEnvironmentTestSurfaces({
20
+ networkClient,
21
+ baseUrl,
22
+ envId: Number(envId),
23
+ token: token ?? '',
24
+ enabled: !!envId && !!token,
25
+ });
26
+ const typeOptions = useMemo(() => {
27
+ const types = new Set();
28
+ for (const surface of testSurfaces) {
29
+ if (surface.scaffoldType)
30
+ types.add(surface.scaffoldType);
31
+ if (surface.patternType)
32
+ types.add(surface.patternType);
33
+ }
34
+ return Array.from(types).sort();
35
+ }, [testSurfaces]);
36
+ const filteredSurfaces = useMemo(() => {
37
+ return testSurfaces.filter((surface) => {
38
+ // Device filter
39
+ if (deviceFilter !== 'all' && surface.sizeClass !== deviceFilter) {
40
+ return false;
41
+ }
42
+ // Priority filter (band thresholds defined in testomniac_lib)
43
+ if (priorityFilter !== 'all' && getSurfacePriorityBand(surface.priority) !== priorityFilter) {
44
+ return false;
45
+ }
46
+ // Type filter
47
+ if (typeFilter !== 'all' &&
48
+ surface.scaffoldType !== typeFilter &&
49
+ surface.patternType !== typeFilter) {
50
+ return false;
51
+ }
52
+ return true;
53
+ });
54
+ }, [testSurfaces, deviceFilter, priorityFilter, typeFilter]);
55
+ const basePath = useEnvBasePath();
56
+ const deviceButtonClass = (value) => `px-3 py-1.5 text-sm font-medium transition-colors ${deviceFilter === value
57
+ ? 'bg-blue-600 text-white'
58
+ : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700'}`;
59
+ if (error) {
60
+ return _jsx(ErrorState, { message: error });
61
+ }
62
+ return (_jsxs("div", { className: "p-6", children: [_jsx(SEOHead, { title: "Test Surfaces", description: "", noIndex: true }), _jsx("h1", { className: "text-2xl font-bold text-gray-900 dark:text-gray-100 mb-6", children: "Test Surfaces" }), !isLoading && testSurfaces.length > 0 && (_jsxs("div", { className: "flex flex-wrap items-center gap-4 mb-6", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Device:" }), _jsxs("div", { className: "flex items-center rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden", children: [_jsx("button", { onClick: () => setDeviceFilter('all'), className: deviceButtonClass('all'), children: "All" }), _jsx("button", { onClick: () => setDeviceFilter('desktop'), className: deviceButtonClass('desktop'), children: "Desktop" }), _jsx("button", { onClick: () => setDeviceFilter('mobile'), className: deviceButtonClass('mobile'), children: "Mobile" })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Priority:" }), _jsx(SelectField, { value: priorityFilter, onChange: v => setPriorityFilter(v), options: [
63
+ { value: 'all', label: 'All priorities' },
64
+ { value: 'critical', label: 'Critical (8+)' },
65
+ { value: 'high', label: 'High (5-7)' },
66
+ { value: 'medium', label: 'Medium (3-4)' },
67
+ { value: 'low', label: 'Low (<3)' },
68
+ ] })] }), typeOptions.length > 0 && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Type:" }), _jsx(SelectField, { value: typeFilter, onChange: setTypeFilter, options: [
69
+ { value: 'all', label: 'All types' },
70
+ ...typeOptions.map(type => ({ value: type, label: type })),
71
+ ] })] })), _jsxs("span", { className: "text-sm text-gray-400 dark:text-gray-500", children: [filteredSurfaces.length, " of ", testSurfaces.length] })] })), isLoading && _jsx(LoadingState, { message: "Loading test surfaces..." }), !isLoading && filteredSurfaces.length === 0 && testSurfaces.length > 0 && (_jsx(EmptyState, { title: "No matching test surfaces", description: "Try adjusting the filters to see more results." })), !isLoading && testSurfaces.length === 0 && (_jsx(EmptyState, { title: "No test surfaces yet", description: "Test surfaces will appear here after a scan generates them." })), !isLoading && filteredSurfaces.length > 0 && (_jsx("div", { className: "space-y-2", children: filteredSurfaces.map((surface) => (_jsx(SurfaceCell, { surface: surface, onClick: () => navigate(`${basePath}/test-surfaces/${surface.id}`) }, surface.id))) }))] }));
72
+ }
73
+ //# sourceMappingURL=TestSurfacesListPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestSurfacesListPage.js","sourceRoot":"","sources":["../../src/pages/TestSurfacesListPage.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Format a date string or ISO timestamp into a locale-aware date/time string.
3
+ *
4
+ * Uses `Intl.DateTimeFormat` so the output respects the user's language
5
+ * and regional conventions (e.g. 24-hour vs. 12-hour clock).
6
+ *
7
+ * @param datetime - An ISO 8601 date string or any value accepted by `new Date()`.
8
+ * @param locale - A BCP 47 language tag (e.g. `"en"`, `"ja"`, `"ar"`).
9
+ * Defaults to the browser's current locale.
10
+ * @returns A human-readable date/time string, or the raw input if parsing fails.
11
+ */
12
+ export declare function formatDateTime(datetime: string | number | Date, locale?: string): string;
13
+ //# sourceMappingURL=formatDateTime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatDateTime.d.ts","sourceRoot":"","sources":["../../src/utils/formatDateTime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAaxF"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Format a date string or ISO timestamp into a locale-aware date/time string.
3
+ *
4
+ * Uses `Intl.DateTimeFormat` so the output respects the user's language
5
+ * and regional conventions (e.g. 24-hour vs. 12-hour clock).
6
+ *
7
+ * @param datetime - An ISO 8601 date string or any value accepted by `new Date()`.
8
+ * @param locale - A BCP 47 language tag (e.g. `"en"`, `"ja"`, `"ar"`).
9
+ * Defaults to the browser's current locale.
10
+ * @returns A human-readable date/time string, or the raw input if parsing fails.
11
+ */
12
+ export function formatDateTime(datetime, locale) {
13
+ try {
14
+ const date = datetime instanceof Date ? datetime : new Date(datetime);
15
+ if (Number.isNaN(date.getTime())) {
16
+ return String(datetime);
17
+ }
18
+ return new Intl.DateTimeFormat(locale, {
19
+ dateStyle: 'medium',
20
+ timeStyle: 'short',
21
+ }).format(date);
22
+ }
23
+ catch {
24
+ return String(datetime);
25
+ }
26
+ }
27
+ //# sourceMappingURL=formatDateTime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatDateTime.js","sourceRoot":"","sources":["../../src/utils/formatDateTime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgC,EAAE,MAAe;IAC9E,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,QAAQ,YAAY,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtE,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;YACjC,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE;YACrC,SAAS,EAAE,QAAQ;YACnB,SAAS,EAAE,OAAO;SACnB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC"}