railwatch 0.9.3 → 1.0.0

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 (454) hide show
  1. checksums.yaml +4 -4
  2. data/AGENTS.md +37 -33
  3. data/CHANGELOG.md +66 -0
  4. data/README.md +51 -60
  5. data/config/routes.rb +0 -59
  6. data/docs/ai-and-mcp.md +9 -8
  7. data/docs/configuration.md +57 -71
  8. data/docs/faq.md +17 -25
  9. data/docs/getting-started.md +105 -117
  10. data/docs/replacing-nightwatch.md +8 -7
  11. data/docs/replacing-sentry.md +12 -16
  12. data/docs/security.md +14 -20
  13. data/docs/self-hosting.md +24 -22
  14. data/docs/testing.md +6 -14
  15. data/docs/troubleshooting.md +12 -46
  16. data/lib/generators/railwatch/install/install_generator.rb +12 -240
  17. data/lib/generators/railwatch/install/templates/initializer.rb.tt +10 -40
  18. data/lib/generators/railwatch/install/templates/post-deploy +0 -7
  19. data/lib/railwatch/authentication.rb +6 -5
  20. data/lib/railwatch/buffer.rb +9 -0
  21. data/lib/railwatch/configuration.rb +21 -151
  22. data/lib/railwatch/engine.rb +9 -118
  23. data/lib/railwatch/patches.rb +0 -11
  24. data/lib/railwatch/reporter.rb +92 -21
  25. data/lib/railwatch/sampler.rb +10 -2
  26. data/lib/railwatch/subscribers/process_info.rb +1 -2
  27. data/lib/railwatch/version.rb +1 -1
  28. data/lib/railwatch.rb +8 -64
  29. data/lib/tasks/railwatch_tasks.rake +3 -325
  30. data/llms.txt +23 -25
  31. metadata +3 -453
  32. data/app/channels/railwatch/environment_channel.rb +0 -62
  33. data/app/controllers/concerns/railwatch/telemetry_identity.rb +0 -25
  34. data/app/controllers/railwatch/alerts_controller.rb +0 -48
  35. data/app/controllers/railwatch/anomaly_rules_controller.rb +0 -31
  36. data/app/controllers/railwatch/attachments_controller.rb +0 -22
  37. data/app/controllers/railwatch/broadcasts_controller.rb +0 -15
  38. data/app/controllers/railwatch/cache_events_controller.rb +0 -30
  39. data/app/controllers/railwatch/commands_controller.rb +0 -16
  40. data/app/controllers/railwatch/comments_controller.rb +0 -11
  41. data/app/controllers/railwatch/dashboard_controller.rb +0 -70
  42. data/app/controllers/railwatch/deploys_controller.rb +0 -34
  43. data/app/controllers/railwatch/deprecations_controller.rb +0 -54
  44. data/app/controllers/railwatch/environment_scoped.rb +0 -81
  45. data/app/controllers/railwatch/exceptions_controller.rb +0 -52
  46. data/app/controllers/railwatch/executions_controller.rb +0 -13
  47. data/app/controllers/railwatch/issues_controller.rb +0 -258
  48. data/app/controllers/railwatch/jobs_controller.rb +0 -63
  49. data/app/controllers/railwatch/llm_calls_controller.rb +0 -124
  50. data/app/controllers/railwatch/logs_controller.rb +0 -40
  51. data/app/controllers/railwatch/mails_controller.rb +0 -19
  52. data/app/controllers/railwatch/notifications_controller.rb +0 -11
  53. data/app/controllers/railwatch/outgoing_requests_controller.rb +0 -19
  54. data/app/controllers/railwatch/overview_controller.rb +0 -38
  55. data/app/controllers/railwatch/people_controller.rb +0 -25
  56. data/app/controllers/railwatch/processes_controller.rb +0 -33
  57. data/app/controllers/railwatch/profiles_controller.rb +0 -65
  58. data/app/controllers/railwatch/queries_controller.rb +0 -59
  59. data/app/controllers/railwatch/releases_controller.rb +0 -75
  60. data/app/controllers/railwatch/requests_controller.rb +0 -37
  61. data/app/controllers/railwatch/saved_views_controller.rb +0 -53
  62. data/app/controllers/railwatch/scheduled_tasks_controller.rb +0 -45
  63. data/app/controllers/railwatch/spans_controller.rb +0 -47
  64. data/app/controllers/railwatch/storage_ops_controller.rb +0 -15
  65. data/app/controllers/railwatch/tenants_controller.rb +0 -44
  66. data/app/controllers/railwatch/thresholds_controller.rb +0 -47
  67. data/app/controllers/railwatch/traces_controller.rb +0 -72
  68. data/app/controllers/railwatch/transactions_controller.rb +0 -21
  69. data/app/controllers/railwatch/view_renders_controller.rb +0 -28
  70. data/app/controllers/railwatch/visits_controller.rb +0 -53
  71. data/app/frontend/components/app-content.tsx +0 -26
  72. data/app/frontend/components/app-logo-icon.tsx +0 -23
  73. data/app/frontend/components/app-logo.tsx +0 -14
  74. data/app/frontend/components/app-shell.tsx +0 -38
  75. data/app/frontend/components/app-sidebar-header.tsx +0 -54
  76. data/app/frontend/components/app-sidebar.tsx +0 -94
  77. data/app/frontend/components/app-wordmark.tsx +0 -29
  78. data/app/frontend/components/breadcrumbs.tsx +0 -46
  79. data/app/frontend/components/icon.tsx +0 -16
  80. data/app/frontend/components/input-error.tsx +0 -18
  81. data/app/frontend/components/nav-footer.tsx +0 -46
  82. data/app/frontend/components/nav-main.tsx +0 -41
  83. data/app/frontend/components/nav-user.tsx +0 -50
  84. data/app/frontend/components/railwatch/chart-hover.tsx +0 -34
  85. data/app/frontend/components/railwatch/chart-panel.tsx +0 -170
  86. data/app/frontend/components/railwatch/code.tsx +0 -28
  87. data/app/frontend/components/railwatch/command-palette.tsx +0 -132
  88. data/app/frontend/components/railwatch/copy-block.tsx +0 -52
  89. data/app/frontend/components/railwatch/copy-id.tsx +0 -49
  90. data/app/frontend/components/railwatch/cursor-load-more.tsx +0 -39
  91. data/app/frontend/components/railwatch/data-table.tsx +0 -195
  92. data/app/frontend/components/railwatch/digit-roll.tsx +0 -312
  93. data/app/frontend/components/railwatch/empty-state.tsx +0 -159
  94. data/app/frontend/components/railwatch/env-nav.tsx +0 -130
  95. data/app/frontend/components/railwatch/env-switcher.tsx +0 -145
  96. data/app/frontend/components/railwatch/filter-bar.tsx +0 -153
  97. data/app/frontend/components/railwatch/flamegraph.tsx +0 -324
  98. data/app/frontend/components/railwatch/frames.tsx +0 -295
  99. data/app/frontend/components/railwatch/json-viewer.tsx +0 -159
  100. data/app/frontend/components/railwatch/live-dot.tsx +0 -78
  101. data/app/frontend/components/railwatch/live-toggle.tsx +0 -76
  102. data/app/frontend/components/railwatch/metric-chart.tsx +0 -112
  103. data/app/frontend/components/railwatch/mobile-page-switcher.tsx +0 -89
  104. data/app/frontend/components/railwatch/onboarding.tsx +0 -91
  105. data/app/frontend/components/railwatch/origin-identity.tsx +0 -84
  106. data/app/frontend/components/railwatch/page-header.tsx +0 -42
  107. data/app/frontend/components/railwatch/percentile-picker.tsx +0 -18
  108. data/app/frontend/components/railwatch/relative-time.tsx +0 -18
  109. data/app/frontend/components/railwatch/saved-views.tsx +0 -232
  110. data/app/frontend/components/railwatch/segmented.tsx +0 -64
  111. data/app/frontend/components/railwatch/series-chart.tsx +0 -400
  112. data/app/frontend/components/railwatch/shortcuts-dialog.tsx +0 -89
  113. data/app/frontend/components/railwatch/signal-toast.tsx +0 -121
  114. data/app/frontend/components/railwatch/sort-header.tsx +0 -37
  115. data/app/frontend/components/railwatch/source-link.tsx +0 -57
  116. data/app/frontend/components/railwatch/sparkline-cell.tsx +0 -14
  117. data/app/frontend/components/railwatch/sql-block.tsx +0 -116
  118. data/app/frontend/components/railwatch/stat.tsx +0 -185
  119. data/app/frontend/components/railwatch/status-badge.tsx +0 -79
  120. data/app/frontend/components/railwatch/step-picker.tsx +0 -57
  121. data/app/frontend/components/railwatch/timeline.tsx +0 -405
  122. data/app/frontend/components/railwatch/utilisation-bar.tsx +0 -44
  123. data/app/frontend/components/railwatch/window-picker.tsx +0 -147
  124. data/app/frontend/components/ui/avatar.tsx +0 -51
  125. data/app/frontend/components/ui/badge.tsx +0 -46
  126. data/app/frontend/components/ui/breadcrumb.tsx +0 -109
  127. data/app/frontend/components/ui/button.tsx +0 -60
  128. data/app/frontend/components/ui/card.tsx +0 -92
  129. data/app/frontend/components/ui/chart.tsx +0 -374
  130. data/app/frontend/components/ui/checkbox.tsx +0 -32
  131. data/app/frontend/components/ui/collapsible.tsx +0 -31
  132. data/app/frontend/components/ui/command.tsx +0 -182
  133. data/app/frontend/components/ui/dialog.tsx +0 -158
  134. data/app/frontend/components/ui/dropdown-menu.tsx +0 -255
  135. data/app/frontend/components/ui/hover-card.tsx +0 -42
  136. data/app/frontend/components/ui/input.tsx +0 -21
  137. data/app/frontend/components/ui/label.tsx +0 -24
  138. data/app/frontend/components/ui/popover.tsx +0 -87
  139. data/app/frontend/components/ui/select.tsx +0 -185
  140. data/app/frontend/components/ui/separator.tsx +0 -28
  141. data/app/frontend/components/ui/sheet.tsx +0 -137
  142. data/app/frontend/components/ui/sidebar.tsx +0 -726
  143. data/app/frontend/components/ui/skeleton.tsx +0 -13
  144. data/app/frontend/components/ui/sonner.tsx +0 -41
  145. data/app/frontend/components/ui/table.tsx +0 -114
  146. data/app/frontend/components/ui/tabs.tsx +0 -91
  147. data/app/frontend/components/ui/textarea.tsx +0 -18
  148. data/app/frontend/components/ui/tooltip.tsx +0 -61
  149. data/app/frontend/components/user-info.tsx +0 -32
  150. data/app/frontend/components/user-menu-content.tsx +0 -94
  151. data/app/frontend/entrypoints/application.css +0 -244
  152. data/app/frontend/entrypoints/inertia.tsx +0 -92
  153. data/app/frontend/fonts/CommitMono-Bold.woff2 +0 -0
  154. data/app/frontend/fonts/CommitMono-Regular.woff2 +0 -0
  155. data/app/frontend/fonts/Roboto-Black.woff2 +0 -0
  156. data/app/frontend/fonts/Roboto-Bold.woff2 +0 -0
  157. data/app/frontend/fonts/Roboto-Medium.woff2 +0 -0
  158. data/app/frontend/fonts/Roboto-Regular.woff2 +0 -0
  159. data/app/frontend/hooks/use-appearance.tsx +0 -67
  160. data/app/frontend/hooks/use-clipboard.ts +0 -32
  161. data/app/frontend/hooks/use-flash.tsx +0 -23
  162. data/app/frontend/hooks/use-hotkeys.ts +0 -63
  163. data/app/frontend/hooks/use-initials.tsx +0 -15
  164. data/app/frontend/hooks/use-live.ts +0 -205
  165. data/app/frontend/hooks/use-mobile-navigation.ts +0 -8
  166. data/app/frontend/hooks/use-mobile.ts +0 -21
  167. data/app/frontend/hooks/use-percentile.ts +0 -24
  168. data/app/frontend/hooks/use-reduced-motion.ts +0 -25
  169. data/app/frontend/hooks/use-row-nav.ts +0 -106
  170. data/app/frontend/hooks/use-step.ts +0 -27
  171. data/app/frontend/hooks/use-ticker.ts +0 -12
  172. data/app/frontend/hooks/use-window.ts +0 -58
  173. data/app/frontend/layouts/app/app-sidebar-layout.tsx +0 -107
  174. data/app/frontend/layouts/app-layout.tsx +0 -21
  175. data/app/frontend/layouts/env-layout.tsx +0 -53
  176. data/app/frontend/layouts/persistent-layout.tsx +0 -18
  177. data/app/frontend/lib/cable.ts +0 -10
  178. data/app/frontend/lib/env-pages.ts +0 -236
  179. data/app/frontend/lib/execution-path.ts +0 -55
  180. data/app/frontend/lib/explain.ts +0 -50
  181. data/app/frontend/lib/filter.ts +0 -25
  182. data/app/frontend/lib/flamegraph.ts +0 -155
  183. data/app/frontend/lib/format.ts +0 -71
  184. data/app/frontend/lib/keyboard.ts +0 -18
  185. data/app/frontend/lib/mount.ts +0 -23
  186. data/app/frontend/lib/source-link.ts +0 -217
  187. data/app/frontend/lib/utils.ts +0 -6
  188. data/app/frontend/pages/alerts/index.tsx +0 -171
  189. data/app/frontend/pages/broadcasts/index.tsx +0 -171
  190. data/app/frontend/pages/cache_events/index.tsx +0 -127
  191. data/app/frontend/pages/commands/index.tsx +0 -143
  192. data/app/frontend/pages/deploys/index.tsx +0 -94
  193. data/app/frontend/pages/deploys/show.tsx +0 -309
  194. data/app/frontend/pages/deprecations/index.tsx +0 -176
  195. data/app/frontend/pages/exceptions/index.tsx +0 -271
  196. data/app/frontend/pages/executions/show.tsx +0 -821
  197. data/app/frontend/pages/issues/index.tsx +0 -399
  198. data/app/frontend/pages/issues/show.tsx +0 -1367
  199. data/app/frontend/pages/jobs/index.tsx +0 -381
  200. data/app/frontend/pages/jobs/klass.tsx +0 -215
  201. data/app/frontend/pages/llm_calls/index.tsx +0 -664
  202. data/app/frontend/pages/logs/index.tsx +0 -303
  203. data/app/frontend/pages/mails/index.tsx +0 -218
  204. data/app/frontend/pages/notifications/index.tsx +0 -161
  205. data/app/frontend/pages/outgoing_requests/index.tsx +0 -309
  206. data/app/frontend/pages/overview/show.tsx +0 -333
  207. data/app/frontend/pages/people/index.tsx +0 -102
  208. data/app/frontend/pages/people/show.tsx +0 -149
  209. data/app/frontend/pages/processes/index.tsx +0 -335
  210. data/app/frontend/pages/profiles/index.tsx +0 -110
  211. data/app/frontend/pages/profiles/show.tsx +0 -105
  212. data/app/frontend/pages/queries/index.tsx +0 -492
  213. data/app/frontend/pages/queries/show.tsx +0 -276
  214. data/app/frontend/pages/releases/index.tsx +0 -190
  215. data/app/frontend/pages/releases/release-health.tsx +0 -68
  216. data/app/frontend/pages/releases/release-path.ts +0 -25
  217. data/app/frontend/pages/releases/show.tsx +0 -262
  218. data/app/frontend/pages/requests/index.tsx +0 -235
  219. data/app/frontend/pages/requests/route.tsx +0 -159
  220. data/app/frontend/pages/scheduled_tasks/index.tsx +0 -220
  221. data/app/frontend/pages/spans/index.tsx +0 -229
  222. data/app/frontend/pages/spans/show.tsx +0 -220
  223. data/app/frontend/pages/storage_ops/index.tsx +0 -150
  224. data/app/frontend/pages/tenants/index.tsx +0 -236
  225. data/app/frontend/pages/tenants/show.tsx +0 -477
  226. data/app/frontend/pages/tenants/tenant-path.ts +0 -26
  227. data/app/frontend/pages/thresholds/index.tsx +0 -414
  228. data/app/frontend/pages/traces/show.tsx +0 -208
  229. data/app/frontend/pages/transactions/index.tsx +0 -220
  230. data/app/frontend/pages/view_renders/index.tsx +0 -241
  231. data/app/frontend/pages/visits/index.tsx +0 -321
  232. data/app/frontend/public/icon.png +0 -0
  233. data/app/frontend/public/icon.svg +0 -5
  234. data/app/frontend/routes/index.d.ts +0 -2136
  235. data/app/frontend/routes/index.js +0 -2112
  236. data/app/frontend/types/globals.d.ts +0 -9
  237. data/app/frontend/types/index.ts +0 -288
  238. data/app/frontend/types/vite-env.d.ts +0 -9
  239. data/app/helpers/railwatch/assets_helper.rb +0 -52
  240. data/app/jobs/railwatch/anomaly_scan_job.rb +0 -11
  241. data/app/jobs/railwatch/application_job.rb +0 -7
  242. data/app/jobs/railwatch/auto_resolve_issues_job.rb +0 -19
  243. data/app/jobs/railwatch/check_scheduled_tasks_job.rb +0 -113
  244. data/app/jobs/railwatch/detect_anomalies_job.rb +0 -171
  245. data/app/jobs/railwatch/detect_performance_issues_job.rb +0 -95
  246. data/app/jobs/railwatch/group_exceptions_job.rb +0 -91
  247. data/app/jobs/railwatch/optimize_telemetry_job.rb +0 -23
  248. data/app/jobs/railwatch/performance_scan_job.rb +0 -11
  249. data/app/jobs/railwatch/prune_telemetry_job.rb +0 -129
  250. data/app/jobs/railwatch/release_health_rollup_job.rb +0 -64
  251. data/app/jobs/railwatch/rollup_catchup_job.rb +0 -21
  252. data/app/jobs/railwatch/rollup_job.rb +0 -132
  253. data/app/jobs/railwatch/scheduled_task_scan_job.rb +0 -11
  254. data/app/models/concerns/railwatch/detection_snapshotting.rb +0 -20
  255. data/app/models/railwatch/alert.rb +0 -229
  256. data/app/models/railwatch/alert_rule.rb +0 -121
  257. data/app/models/railwatch/anomaly_rule.rb +0 -51
  258. data/app/models/railwatch/application.rb +0 -44
  259. data/app/models/railwatch/application_record.rb +0 -33
  260. data/app/models/railwatch/comment.rb +0 -36
  261. data/app/models/railwatch/deploy.rb +0 -67
  262. data/app/models/railwatch/environment.rb +0 -68
  263. data/app/models/railwatch/execution_presenter.rb +0 -185
  264. data/app/models/railwatch/filter_query.rb +0 -184
  265. data/app/models/railwatch/followup_receipt.rb +0 -27
  266. data/app/models/railwatch/ingest/batch.rb +0 -355
  267. data/app/models/railwatch/ingest/mapper.rb +0 -585
  268. data/app/models/railwatch/ingest/payload.rb +0 -96
  269. data/app/models/railwatch/ingest/rollup_absorber.rb +0 -170
  270. data/app/models/railwatch/ingest/writer.rb +0 -137
  271. data/app/models/railwatch/issue.rb +0 -277
  272. data/app/models/railwatch/issue_activity.rb +0 -23
  273. data/app/models/railwatch/issue_detection_presenter.rb +0 -309
  274. data/app/models/railwatch/issue_detection_snapshot.rb +0 -77
  275. data/app/models/railwatch/maintenance_task.rb +0 -53
  276. data/app/models/railwatch/saved_view.rb +0 -63
  277. data/app/models/railwatch/telemetry/aggregations.rb +0 -251
  278. data/app/models/railwatch/telemetry/attachment.rb +0 -31
  279. data/app/models/railwatch/telemetry/bounded_gzip.rb +0 -101
  280. data/app/models/railwatch/telemetry/broadcast.rb +0 -13
  281. data/app/models/railwatch/telemetry/cache_event.rb +0 -16
  282. data/app/models/railwatch/telemetry/child.rb +0 -53
  283. data/app/models/railwatch/telemetry/cursor_page.rb +0 -99
  284. data/app/models/railwatch/telemetry/deprecation.rb +0 -13
  285. data/app/models/railwatch/telemetry/enqueued_job.rb +0 -13
  286. data/app/models/railwatch/telemetry/exception.rb +0 -28
  287. data/app/models/railwatch/telemetry/execution.rb +0 -152
  288. data/app/models/railwatch/telemetry/export_delivery.rb +0 -32
  289. data/app/models/railwatch/telemetry/export_destination.rb +0 -66
  290. data/app/models/railwatch/telemetry/health_sample.rb +0 -72
  291. data/app/models/railwatch/telemetry/ingest_batch.rb +0 -31
  292. data/app/models/railwatch/telemetry/llm_call.rb +0 -37
  293. data/app/models/railwatch/telemetry/log.rb +0 -91
  294. data/app/models/railwatch/telemetry/mail.rb +0 -13
  295. data/app/models/railwatch/telemetry/n_plus_one.rb +0 -92
  296. data/app/models/railwatch/telemetry/notification.rb +0 -13
  297. data/app/models/railwatch/telemetry/outgoing_request.rb +0 -13
  298. data/app/models/railwatch/telemetry/person.rb +0 -50
  299. data/app/models/railwatch/telemetry/process.rb +0 -10
  300. data/app/models/railwatch/telemetry/profile.rb +0 -37
  301. data/app/models/railwatch/telemetry/query.rb +0 -57
  302. data/app/models/railwatch/telemetry/query_shape.rb +0 -45
  303. data/app/models/railwatch/telemetry/release_health.rb +0 -69
  304. data/app/models/railwatch/telemetry/rollup.rb +0 -157
  305. data/app/models/railwatch/telemetry/session.rb +0 -24
  306. data/app/models/railwatch/telemetry/span.rb +0 -19
  307. data/app/models/railwatch/telemetry/storage_op.rb +0 -13
  308. data/app/models/railwatch/telemetry/tenant.rb +0 -240
  309. data/app/models/railwatch/telemetry/transaction.rb +0 -13
  310. data/app/models/railwatch/telemetry/view_render.rb +0 -13
  311. data/app/models/railwatch/telemetry/visit.rb +0 -24
  312. data/app/models/railwatch/telemetry_record.rb +0 -107
  313. data/app/models/railwatch/threshold.rb +0 -66
  314. data/app/models/railwatch/user.rb +0 -47
  315. data/app/models/railwatch/viewer.rb +0 -13
  316. data/app/models/railwatch/window.rb +0 -66
  317. data/app/views/layouts/railwatch/dashboard.html.erb +0 -25
  318. data/db/railwatch_migrate/20260916000000_create_railwatch_tables.rb +0 -151
  319. data/db/railwatch_migrate/20260917000000_create_railwatch_maintenance_tasks.rb +0 -18
  320. data/db/railwatch_migrate/20260917120000_create_railwatch_followup_receipts.rb +0 -20
  321. data/db/railwatch_migrate/20260918120000_widen_host_user_ids.rb +0 -71
  322. data/db/railwatch_telemetry_migrate/20260903000000_enable_incremental_vacuum.rb +0 -62
  323. data/db/railwatch_telemetry_migrate/20260903000001_create_telemetry.rb +0 -481
  324. data/db/railwatch_telemetry_migrate/20260903000002_rename_tenant_to_app_tenant.rb +0 -14
  325. data/db/railwatch_telemetry_migrate/20260903000003_add_statement_count_to_transactions.rb +0 -9
  326. data/db/railwatch_telemetry_migrate/20260903000004_add_role_and_channel.rb +0 -10
  327. data/db/railwatch_telemetry_migrate/20260903000005_add_locals_to_exceptions.rb +0 -9
  328. data/db/railwatch_telemetry_migrate/20260903000006_add_spans_health_vitals_and_fts.rb +0 -82
  329. data/db/railwatch_telemetry_migrate/20260903000007_rename_span_attributes_to_payload.rb +0 -10
  330. data/db/railwatch_telemetry_migrate/20260903000008_add_profiles_and_attachments.rb +0 -60
  331. data/db/railwatch_telemetry_migrate/20260903000009_add_truncated_to_attachments.rb +0 -9
  332. data/db/railwatch_telemetry_migrate/20260903000010_create_sessions_and_release_health.rb +0 -51
  333. data/db/railwatch_telemetry_migrate/20260903000011_add_fingerprint_to_exceptions.rb +0 -11
  334. data/db/railwatch_telemetry_migrate/20260904000012_add_failed_to_broadcasts.rb +0 -10
  335. data/db/railwatch_telemetry_migrate/20260904010000_add_filter_cursor_indexes.rb +0 -37
  336. data/db/railwatch_telemetry_migrate/20260904020000_add_n_plus_ones_execution_id_index.rb +0 -11
  337. data/db/railwatch_telemetry_migrate/20260904120000_create_query_shapes.rb +0 -15
  338. data/db/railwatch_telemetry_migrate/20260906120000_add_backpressure_factor_to_ingest_batches.rb +0 -9
  339. data/db/railwatch_telemetry_migrate/20260907000000_rename_lantern_version_on_processes.rb +0 -10
  340. data/db/railwatch_telemetry_migrate/20260913000000_rename_nightrail_version_on_processes.rb +0 -9
  341. data/db/railwatch_telemetry_migrate/20260914000000_drop_orphan_durable_ingest_tables.rb +0 -18
  342. data/db/railwatch_telemetry_migrate/20260914010000_drop_orphan_durable_ingest_columns.rb +0 -25
  343. data/db/railwatch_telemetry_migrate/20260915000000_create_llm_calls.rb +0 -55
  344. data/db/railwatch_telemetry_migrate/20260915120000_add_detail_to_llm_calls.rb +0 -21
  345. data/db/railwatch_telemetry_migrate/20260915200000_add_explained_index_to_queries.rb +0 -16
  346. data/db/railwatch_telemetry_migrate/20260915210000_add_slowest_index_to_queries.rb +0 -18
  347. data/db/railwatch_telemetry_migrate/20260917010000_add_batch_ledger_to_ingest_batches.rb +0 -16
  348. data/db/railwatch_telemetry_migrate/20260919000100_create_export_queue.rb +0 -146
  349. data/db/railwatch_telemetry_migrate/20260922000000_add_covering_indexes_for_dashboard_aggregates.rb +0 -34
  350. data/db/railwatch_telemetry_migrate/20260923000000_add_people_index.rb +0 -15
  351. data/db/railwatch_telemetry_migrate/20260925000000_add_tenant_summary_index.rb +0 -17
  352. data/db/railwatch_telemetry_migrate/20261008000000_add_in_transaction_to_outgoing_requests.rb +0 -10
  353. data/docs/embedded.md +0 -503
  354. data/lib/puma/plugin/railwatch.rb +0 -215
  355. data/lib/railwatch/dashboard_assets.rb +0 -45
  356. data/lib/railwatch/embedded.rb +0 -50
  357. data/lib/railwatch/export/client.rb +0 -124
  358. data/lib/railwatch/export/lease.rb +0 -56
  359. data/lib/railwatch/export/outbox.rb +0 -361
  360. data/lib/railwatch/export/policy.rb +0 -79
  361. data/lib/railwatch/export/sender.rb +0 -130
  362. data/lib/railwatch/ingest_request_body_limit.rb +0 -10
  363. data/lib/railwatch/maintenance.rb +0 -194
  364. data/lib/railwatch/patches/migration_busy_timeout.rb +0 -73
  365. data/lib/railwatch/transport/local.rb +0 -78
  366. data/lib/railwatch/transport/socket.rb +0 -183
  367. data/lib/railwatch/writer.rb +0 -370
  368. data/public/railwatch/assets/CommitMono-Bold-D6h61ieg.woff2 +0 -0
  369. data/public/railwatch/assets/CommitMono-Regular-zr8w7Obm.woff2 +0 -0
  370. data/public/railwatch/assets/Roboto-Black-auA4GeOK.woff2 +0 -0
  371. data/public/railwatch/assets/Roboto-Bold-CJLnO8j1.woff2 +0 -0
  372. data/public/railwatch/assets/Roboto-Medium-Cm2bwKpj.woff2 +0 -0
  373. data/public/railwatch/assets/Roboto-Regular-Chaq1-PV.woff2 +0 -0
  374. data/public/railwatch/assets/app-layout-by7G3sa1.js +0 -41
  375. data/public/railwatch/assets/application-Cc5v_Vk9.css +0 -1
  376. data/public/railwatch/assets/arrow-up-DCZ7emux.js +0 -1
  377. data/public/railwatch/assets/braces-CykT5_5u.js +0 -1
  378. data/public/railwatch/assets/card-C-PPSA0g.js +0 -1
  379. data/public/railwatch/assets/chart-Cov79YC5.js +0 -39
  380. data/public/railwatch/assets/chart-hover-DdK4E-2h.js +0 -1
  381. data/public/railwatch/assets/chart-panel-BPaYRXJB.js +0 -1
  382. data/public/railwatch/assets/code-BYjC4YZ_.js +0 -1
  383. data/public/railwatch/assets/copy-id-LPfoj9cC.js +0 -1
  384. data/public/railwatch/assets/cursor-load-more-DSdhgpGl.js +0 -1
  385. data/public/railwatch/assets/data-table-CQ_YRWQs.js +0 -1
  386. data/public/railwatch/assets/env-layout-CdMWbUkm.js +0 -1
  387. data/public/railwatch/assets/execution-path-7MYt-Qbn.js +0 -1
  388. data/public/railwatch/assets/filter-bar-CrzpQ_vD.js +0 -1
  389. data/public/railwatch/assets/flamegraph-BIFEdTAg.js +0 -2
  390. data/public/railwatch/assets/format-B9SDkrWj.js +0 -1
  391. data/public/railwatch/assets/frames-C5t-x4f0.js +0 -1
  392. data/public/railwatch/assets/index--NQ7us-L.js +0 -1
  393. data/public/railwatch/assets/index-2kgYe_99.js +0 -1
  394. data/public/railwatch/assets/index-4YEPHxtO.js +0 -1
  395. data/public/railwatch/assets/index-AOCC1GDJ.js +0 -1
  396. data/public/railwatch/assets/index-BEo-u0eO.js +0 -1
  397. data/public/railwatch/assets/index-BJ1V3w2N.js +0 -1
  398. data/public/railwatch/assets/index-BPoHsBKb.js +0 -1
  399. data/public/railwatch/assets/index-BZzyGUM3.js +0 -1
  400. data/public/railwatch/assets/index-BgVq7yKL.js +0 -1
  401. data/public/railwatch/assets/index-BqFGEZvW.js +0 -1
  402. data/public/railwatch/assets/index-ByuHJ1CH.js +0 -1
  403. data/public/railwatch/assets/index-C2j50AL2.js +0 -1
  404. data/public/railwatch/assets/index-CLEdTkvW.js +0 -1
  405. data/public/railwatch/assets/index-CWgq8qBu.js +0 -1
  406. data/public/railwatch/assets/index-CXQ7_oVj.js +0 -2
  407. data/public/railwatch/assets/index-CmyYrjS2.js +0 -1
  408. data/public/railwatch/assets/index-Cn9_HjDo.js +0 -1
  409. data/public/railwatch/assets/index-CsMAm9UK.js +0 -1
  410. data/public/railwatch/assets/index-D0Kk_oGY.js +0 -1
  411. data/public/railwatch/assets/index-DC9ZptJh.js +0 -1
  412. data/public/railwatch/assets/index-DNzg7jmV.js +0 -1
  413. data/public/railwatch/assets/index-DQ8uJO5f.js +0 -1
  414. data/public/railwatch/assets/index-Deq14BxB.js +0 -1
  415. data/public/railwatch/assets/index-IaV3Blzp.js +0 -1
  416. data/public/railwatch/assets/index-TYNWcJQs.js +0 -1
  417. data/public/railwatch/assets/index-WonH2fcZ.js +0 -1
  418. data/public/railwatch/assets/index-WxWUaH_d.js +0 -1
  419. data/public/railwatch/assets/index-mUNrl4ky.js +0 -1
  420. data/public/railwatch/assets/inertia-DfNRARuA.js +0 -97
  421. data/public/railwatch/assets/json-viewer-DMsF5glp.js +0 -1
  422. data/public/railwatch/assets/klass-CmHYk5rz.js +0 -1
  423. data/public/railwatch/assets/origin-identity-1R3bqa3R.js +0 -1
  424. data/public/railwatch/assets/percentile-picker-73z5PAps.js +0 -1
  425. data/public/railwatch/assets/relative-time-Dsc_cCdX.js +0 -1
  426. data/public/railwatch/assets/release-health-BV5OaOWd.js +0 -1
  427. data/public/railwatch/assets/route-CWh58C7K.js +0 -1
  428. data/public/railwatch/assets/segmented-DB4zh-Am.js +0 -1
  429. data/public/railwatch/assets/select-DBKjFlOX.js +0 -1
  430. data/public/railwatch/assets/series-chart-BaiDG795.js +0 -1
  431. data/public/railwatch/assets/show-B4ICCFGh.js +0 -1
  432. data/public/railwatch/assets/show-B5lOU9Gv.js +0 -1
  433. data/public/railwatch/assets/show-BYPB74t4.js +0 -2
  434. data/public/railwatch/assets/show-C7A0m2M8.js +0 -1
  435. data/public/railwatch/assets/show-DT5X1zqE.js +0 -1
  436. data/public/railwatch/assets/show-D_NBdXsn.js +0 -2
  437. data/public/railwatch/assets/show-DgPCnRg8.js +0 -1
  438. data/public/railwatch/assets/show-Yl69HF0x.js +0 -1
  439. data/public/railwatch/assets/show-_QxuUQCm.js +0 -3
  440. data/public/railwatch/assets/show-g__jnN36.js +0 -1
  441. data/public/railwatch/assets/show-l4ztfjl9.js +0 -1
  442. data/public/railwatch/assets/sort-header-BcG8ulEH.js +0 -1
  443. data/public/railwatch/assets/source-link-B2183i2-.js +0 -1
  444. data/public/railwatch/assets/sparkline-cell-B47ipscB.js +0 -1
  445. data/public/railwatch/assets/stat-DT2hhsqS.js +0 -1
  446. data/public/railwatch/assets/status-badge-CmbRKlY7.js +0 -1
  447. data/public/railwatch/assets/tenant-path-C4rNGauE.js +0 -1
  448. data/public/railwatch/assets/use-clipboard-oTNeP4ax.js +0 -1
  449. data/public/railwatch/assets/use-live-CLZZj245.js +0 -1
  450. data/public/railwatch/icon.png +0 -0
  451. data/public/railwatch/icon.svg +0 -5
  452. data/public/railwatch/manifest.json +0 -1245
  453. data/public/railwatch/rails-vite.json +0 -1
  454. /data/{app/frontend/lib → lib/generators/railwatch/install/templates}/railwatch.ts +0 -0
@@ -1,57 +0,0 @@
1
- import { usePage } from "@inertiajs/react"
2
- import { ExternalLink } from "lucide-react"
3
-
4
- import { sourceUrl } from "@/lib/source-link"
5
- import { cn } from "@/lib/utils"
6
- import type { SharedProps } from "@/types"
7
-
8
- // A "file:line" location, linked to the line on the code host (pinned to the
9
- // deploy that produced it) or opened in the viewer's editor, depending on
10
- // their profile. Renders plain text when we can't build a URL.
11
- export function SourceLink({
12
- location,
13
- deploy,
14
- className,
15
- }: {
16
- location: string
17
- // The deploy the location came from, used as the git ref so the link points
18
- // at the code that was actually running. (Named `deploy`, not `ref`: React
19
- // treats a `ref` prop as an element ref.)
20
- deploy?: string | null
21
- className?: string
22
- }) {
23
- const { auth, environment } = usePage<SharedProps>().props
24
- const match = /^(.*):(\d+)$/.exec(location)
25
- const url = match
26
- ? sourceUrl({
27
- file: match[1],
28
- line: Number(match[2]),
29
- repositoryUrl: environment?.repository_url,
30
- ref: deploy,
31
- defaultBranch: environment?.default_branch,
32
- editor: auth.user.editor,
33
- editorRoot: auth.user.editor_root,
34
- })
35
- : null
36
-
37
- if (!url)
38
- return (
39
- <span className={cn("truncate font-mono text-xs", className)}>
40
- {location}
41
- </span>
42
- )
43
- const external = url.startsWith("http")
44
- return (
45
- <a
46
- href={url}
47
- {...(external ? { target: "_blank", rel: "noreferrer" } : {})}
48
- className={cn(
49
- "inline-flex min-w-0 items-center gap-1 font-mono text-xs hover:underline",
50
- className,
51
- )}
52
- >
53
- <span className="truncate">{location}</span>
54
- <ExternalLink className="size-3 shrink-0 opacity-60" />
55
- </a>
56
- )
57
- }
@@ -1,14 +0,0 @@
1
- import { Sparkline } from "@/components/railwatch/series-chart"
2
-
3
- // Compact trend cell for a DataTable row: a 32x10 area chart, no axes.
4
- // `hoverKey` (typically the row's group_hash) wires it into
5
- // ChartHoverProvider so hovering the row emphasizes its own sparkline.
6
- export function SparklineCell({
7
- data,
8
- hoverKey,
9
- }: {
10
- data: number[]
11
- hoverKey?: string
12
- }) {
13
- return <Sparkline data={data} className="h-[10px] w-8" hoverKey={hoverKey} />
14
- }
@@ -1,116 +0,0 @@
1
- import { cn } from "@/lib/utils"
2
-
3
- const KEYWORDS = new Set([
4
- "SELECT",
5
- "FROM",
6
- "WHERE",
7
- "JOIN",
8
- "LEFT",
9
- "INNER",
10
- "ON",
11
- "AND",
12
- "OR",
13
- "ORDER",
14
- "BY",
15
- "GROUP",
16
- "LIMIT",
17
- "OFFSET",
18
- "INSERT",
19
- "INTO",
20
- "VALUES",
21
- "UPDATE",
22
- "SET",
23
- "DELETE",
24
- "RETURNING",
25
- "AS",
26
- "IN",
27
- "IS",
28
- "NULL",
29
- "NOT",
30
- "DISTINCT",
31
- "COUNT",
32
- "SUM",
33
- "AVG",
34
- "MAX",
35
- "MIN",
36
- "CASE",
37
- "WHEN",
38
- "THEN",
39
- "ELSE",
40
- "END",
41
- ])
42
-
43
- type TokenKind =
44
- "identifier" | "string" | "placeholder" | "number" | "keyword" | "text"
45
-
46
- interface Token {
47
- text: string
48
- kind: TokenKind
49
- }
50
-
51
- // Quoted identifier | string literal | `?` bind placeholder | number | bare word.
52
- // Anything not matched (whitespace, punctuation) falls through as plain text.
53
- const TOKEN_RE =
54
- /("(?:[^"]|"")*"|`(?:[^`]|``)*`)|('(?:[^']|'')*')|(\?)|(\b\d+(?:\.\d+)?\b)|(\b[A-Za-z_][A-Za-z_0-9]*\b)/g
55
-
56
- function tokenize(sql: string): Token[] {
57
- const tokens: Token[] = []
58
- let last = 0
59
- TOKEN_RE.lastIndex = 0
60
- let m: RegExpExecArray | null
61
- while ((m = TOKEN_RE.exec(sql))) {
62
- if (m.index > last)
63
- tokens.push({ text: sql.slice(last, m.index), kind: "text" })
64
- const [full, ident, str, placeholder, number] = m
65
- if (ident) tokens.push({ text: full, kind: "identifier" })
66
- else if (str) tokens.push({ text: full, kind: "string" })
67
- else if (placeholder) tokens.push({ text: full, kind: "placeholder" })
68
- else if (number) tokens.push({ text: full, kind: "number" })
69
- else if (KEYWORDS.has(full.toUpperCase()))
70
- tokens.push({ text: full, kind: "keyword" })
71
- else tokens.push({ text: full, kind: "text" })
72
- last = TOKEN_RE.lastIndex
73
- }
74
- if (last < sql.length) tokens.push({ text: sql.slice(last), kind: "text" })
75
- return tokens
76
- }
77
-
78
- const toneClass: Record<TokenKind, string> = {
79
- keyword: "text-primary font-semibold",
80
- string: "text-emerald-600 dark:text-emerald-400",
81
- number: "text-amber-600 dark:text-amber-400",
82
- placeholder: "text-primary font-semibold",
83
- identifier: "text-muted-foreground",
84
- text: "",
85
- }
86
-
87
- export function SqlBlock({
88
- sql,
89
- wrap = false,
90
- inline = false,
91
- className,
92
- }: {
93
- sql: string
94
- wrap?: boolean
95
- inline?: boolean
96
- className?: string
97
- }) {
98
- const tokens = tokenize(sql)
99
- const Tag = inline ? "span" : "code"
100
- return (
101
- <Tag
102
- className={cn(
103
- "font-mono text-xs",
104
- wrap ? "break-words whitespace-pre-wrap" : "block max-w-full truncate",
105
- className,
106
- )}
107
- title={wrap ? undefined : sql}
108
- >
109
- {tokens.map((t, i) => (
110
- <span key={i} className={toneClass[t.kind] || undefined}>
111
- {t.text}
112
- </span>
113
- ))}
114
- </Tag>
115
- )
116
- }
@@ -1,185 +0,0 @@
1
- import { usePage } from "@inertiajs/react"
2
- import { ArrowDown, ArrowUp } from "lucide-react"
3
- import type { ReactNode } from "react"
4
-
5
- import {
6
- DIGIT_ROLL_ENABLED,
7
- DigitRoll,
8
- } from "@/components/railwatch/digit-roll"
9
- import { useIsLive } from "@/hooks/use-live"
10
- import { useReducedMotion } from "@/hooks/use-reduced-motion"
11
- import { cn } from "@/lib/utils"
12
-
13
- function Delta({
14
- current,
15
- previous,
16
- goodDirection,
17
- caption,
18
- }: {
19
- current: number
20
- previous: number
21
- goodDirection: "up" | "down"
22
- caption?: ReactNode
23
- }) {
24
- if (!previous) return null
25
- const change = ((current - previous) / previous) * 100
26
- if (change === 0) return null
27
- const direction = change > 0 ? "up" : "down"
28
- const good = direction === goodDirection
29
- const Icon = direction === "up" ? ArrowUp : ArrowDown
30
- return (
31
- <>
32
- <span
33
- className={cn(
34
- "inline-flex items-center gap-0.5 font-mono text-xs tabular-nums",
35
- good ? "text-live" : "text-destructive",
36
- )}
37
- >
38
- <Icon className="size-3" />
39
- {Math.abs(change).toFixed(1)}%
40
- </span>
41
- {caption && (
42
- <span className="text-muted-foreground text-[11px]">{caption}</span>
43
- )}
44
- </>
45
- )
46
- }
47
-
48
- // A metric a page is happy to see move: the raw number, and the formatter
49
- // that turns it into what the cell reads. Passing this instead of `value` is
50
- // how a page opts into the digit roll, which is deliberately the wrong way
51
- // round from a prop that opts out -- a page that says nothing gets no
52
- // motion, so a new incident page (issues, executions, traces) cannot inherit
53
- // it by accident.
54
- export interface RollingValue {
55
- value: number
56
- format: (value: number) => string
57
- }
58
-
59
- // The rolling digits are decoration, so they are hidden from assistive tech
60
- // and the number itself sits beside them in one plain text node. Not an
61
- // aria-live region: a value that changes every few seconds read aloud all
62
- // day is not an improvement, and fast live regions misbehave across screen
63
- // readers anyway. A metric that genuinely needs announcing wants its own
64
- // debounced role="status" saying what happened, not the number.
65
- //
66
- // Four gates stand between a rolling number and motion on the screen, and
67
- // all of them have to be open: the global switch, the page having opted in
68
- // at all (this component only renders for `roll`), live updates actually
69
- // flowing, and the user not having asked for less motion. Live off, paused,
70
- // disconnected, or reduced motion each mean an instant swap -- which is
71
- // also WCAG 2.2.2's pause/stop mechanism: the live toggle in the page
72
- // header stops the motion, not just the data.
73
- //
74
- // Only the live reload rolls. It keeps the page's URL, and anything that
75
- // changes the URL -- a new window, range, step or filter -- is a different
76
- // number rather than the same one moving, so the roll is keyed by the URL:
77
- // the new number is a fresh first paint, static and immediate, not a roll
78
- // held back behind the last one's coalescing window.
79
- function RollingStatValue({ value, format }: RollingValue) {
80
- const { url } = usePage()
81
- const live = useIsLive()
82
- const reducedMotion = useReducedMotion()
83
- const formatted = format(value)
84
- const animate = DIGIT_ROLL_ENABLED && live && !reducedMotion
85
- return (
86
- <>
87
- <span aria-hidden="true">
88
- {animate ? (
89
- <DigitRoll key={url} value={value} format={format} />
90
- ) : (
91
- formatted
92
- )}
93
- </span>
94
- <span className="sr-only">{formatted}</span>
95
- </>
96
- )
97
- }
98
-
99
- // One metric. Nightwatch-style: a small uppercase mono label, a large
100
- // tabular number, and an optional sub-line. Renders as a cell, not a card,
101
- // so a row of them reads as one strip (see StatStrip); pass `card` to get
102
- // the standalone bordered version.
103
- export function Stat({
104
- label,
105
- value,
106
- roll,
107
- hint,
108
- tone,
109
- delta,
110
- deltaCaption,
111
- card = false,
112
- className,
113
- }: {
114
- label: string
115
- hint?: ReactNode
116
- tone?: "default" | "destructive" | "warning" | "success"
117
- delta?: {
118
- current: number
119
- previous: number
120
- goodDirection: "up" | "down"
121
- }
122
- // e.g. "vs previous 24 hours" — shown next to the delta so it's clear what
123
- // period the percentage compares against.
124
- deltaCaption?: ReactNode
125
- card?: boolean
126
- className?: string
127
- // A pre-formatted value, or a `roll` the digits of which may animate --
128
- // one or the other, never both.
129
- } & (
130
- { value: ReactNode; roll?: never } | { value?: never; roll: RollingValue }
131
- )) {
132
- return (
133
- <div
134
- className={cn(
135
- "flex min-w-0 flex-col gap-1 px-4 py-3",
136
- card && "bg-card rounded-lg border",
137
- className,
138
- )}
139
- >
140
- <div className="label-caps truncate">{label}</div>
141
- <div className="flex flex-wrap items-baseline gap-x-2 gap-y-0.5">
142
- <div
143
- className={cn(
144
- "text-xl font-semibold tracking-tight tabular-nums sm:text-2xl",
145
- tone === "destructive" && "text-destructive",
146
- tone === "warning" && "text-warning",
147
- tone === "success" && "text-live",
148
- )}
149
- >
150
- {roll ? <RollingStatValue {...roll} /> : value}
151
- </div>
152
- {delta && <Delta {...delta} caption={deltaCaption} />}
153
- </div>
154
- {hint && (
155
- <div className="text-muted-foreground truncate font-mono text-[11px]">
156
- {hint}
157
- </div>
158
- )}
159
- </div>
160
- )
161
- }
162
-
163
- // A row of Stats sharing one border, divided by hairlines, that wraps to
164
- // two columns on phones. The header strip on every Nightwatch page.
165
- export function StatStrip({
166
- children,
167
- className,
168
- }: {
169
- children: ReactNode
170
- className?: string
171
- }) {
172
- return (
173
- <div
174
- className={cn(
175
- "bg-card divide-border grid grid-cols-2 divide-y overflow-hidden rounded-lg border sm:divide-x sm:divide-y-0",
176
- "[&>*:nth-child(odd)]:border-r sm:[&>*:nth-child(odd)]:border-r-0",
177
- "[&>*:nth-child(odd):last-child]:col-span-2 [&>*:nth-child(odd):last-child]:border-r-0 sm:[&>*:nth-child(odd):last-child]:col-span-1",
178
- "sm:auto-cols-fr sm:grid-flow-col",
179
- className,
180
- )}
181
- >
182
- {children}
183
- </div>
184
- )
185
- }
@@ -1,79 +0,0 @@
1
- import { Badge } from "@/components/ui/badge"
2
- import { statusTone } from "@/lib/format"
3
- import { cn } from "@/lib/utils"
4
-
5
- // The one status vocabulary: grey is fine, amber is a warning (4xx, elevated),
6
- // red is broken (5xx, failed, unhandled, open). Small mono caps like
7
- // Nightwatch's [ALERT] / HANDLED / UNHANDLED chips.
8
- const tones: Record<string, string> = {
9
- success: "border-live/30 bg-live/10 text-live",
10
- warning: "border-warning/40 bg-warning/10 text-warning",
11
- destructive: "border-danger/40 bg-danger/10 text-danger",
12
- muted: "border-border bg-muted text-muted-foreground",
13
- }
14
-
15
- const base = "rounded-sm px-1.5 font-mono text-[10px] tracking-wider uppercase"
16
-
17
- export function StatusBadge({
18
- status,
19
- outcome,
20
- label,
21
- }: {
22
- status?: number | null
23
- outcome?: string | null
24
- label?: string
25
- }) {
26
- const tone = statusTone(status, outcome)
27
- return (
28
- <Badge variant="outline" className={cn(base, "tabular-nums", tones[tone])}>
29
- {label ?? outcome ?? status ?? "–"}
30
- </Badge>
31
- )
32
- }
33
-
34
- export function LevelBadge({ level }: { level: string }) {
35
- const tone =
36
- level === "error" || level === "fatal"
37
- ? "destructive"
38
- : level === "warn"
39
- ? "warning"
40
- : level === "event"
41
- ? "success"
42
- : "muted"
43
- return (
44
- <Badge variant="outline" className={cn(base, tones[tone])}>
45
- {level}
46
- </Badge>
47
- )
48
- }
49
-
50
- export function IssueStatusBadge({ status }: { status: string }) {
51
- const tone =
52
- status === "open"
53
- ? "destructive"
54
- : status === "resolved"
55
- ? "success"
56
- : "muted"
57
- return (
58
- <Badge variant="outline" className={cn(base, tones[tone])}>
59
- {status}
60
- </Badge>
61
- )
62
- }
63
-
64
- // Generic tinted chip for kinds and categories (EXCEPTION, REQUEST, JOB…).
65
- export function KindBadge({
66
- children,
67
- tone = "muted",
68
- className,
69
- }: {
70
- children: React.ReactNode
71
- tone?: keyof typeof tones
72
- className?: string
73
- }) {
74
- return (
75
- <Badge variant="outline" className={cn(base, tones[tone], className)}>
76
- {children}
77
- </Badge>
78
- )
79
- }
@@ -1,57 +0,0 @@
1
- import { ChevronDown } from "lucide-react"
2
-
3
- import { Button } from "@/components/ui/button"
4
- import {
5
- DropdownMenu,
6
- DropdownMenuContent,
7
- DropdownMenuLabel,
8
- DropdownMenuRadioGroup,
9
- DropdownMenuRadioItem,
10
- DropdownMenuSeparator,
11
- DropdownMenuTrigger,
12
- } from "@/components/ui/dropdown-menu"
13
- import { STEP_LABELS, useStep } from "@/hooks/use-step"
14
- import type { Step } from "@/types"
15
-
16
- // Bucket width for every chart on the page, next to the window picker:
17
- // "1m", "5m", ... as a mono chip opening a menu of the widths the window
18
- // offers. Hidden when the window offers only one.
19
- export function StepPicker() {
20
- const { step, steps, set } = useStep()
21
- if (steps.length < 2) return null
22
- return (
23
- <DropdownMenu>
24
- <DropdownMenuTrigger asChild>
25
- <Button
26
- variant="outline"
27
- size="sm"
28
- className="h-8 gap-1 px-2 font-mono text-xs uppercase"
29
- aria-label={`Chart buckets: ${STEP_LABELS[step]}`}
30
- >
31
- <span className="text-muted-foreground normal-case">per</span>
32
- {step}
33
- <ChevronDown className="text-muted-foreground size-3" />
34
- </Button>
35
- </DropdownMenuTrigger>
36
- <DropdownMenuContent align="end" className="w-44">
37
- <DropdownMenuLabel className="label-caps">
38
- Chart buckets
39
- </DropdownMenuLabel>
40
- <DropdownMenuSeparator />
41
- <DropdownMenuRadioGroup
42
- value={step}
43
- onValueChange={(value) => set(value as Step)}
44
- >
45
- {steps.map((s) => (
46
- <DropdownMenuRadioItem key={s} value={s} className="text-xs">
47
- <span className="font-mono uppercase">{s}</span>
48
- <span className="text-muted-foreground ml-auto">
49
- {STEP_LABELS[s]}
50
- </span>
51
- </DropdownMenuRadioItem>
52
- ))}
53
- </DropdownMenuRadioGroup>
54
- </DropdownMenuContent>
55
- </DropdownMenu>
56
- )
57
- }