railwatch 0.9.4 → 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 (452) hide show
  1. checksums.yaml +4 -4
  2. data/AGENTS.md +37 -33
  3. data/CHANGELOG.md +50 -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 +35 -66
  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/configuration.rb +21 -151
  21. data/lib/railwatch/engine.rb +9 -118
  22. data/lib/railwatch/patches.rb +0 -11
  23. data/lib/railwatch/reporter.rb +3 -19
  24. data/lib/railwatch/subscribers/process_info.rb +1 -2
  25. data/lib/railwatch/version.rb +1 -1
  26. data/lib/railwatch.rb +4 -62
  27. data/lib/tasks/railwatch_tasks.rake +3 -325
  28. data/llms.txt +23 -25
  29. metadata +3 -453
  30. data/app/channels/railwatch/environment_channel.rb +0 -62
  31. data/app/controllers/concerns/railwatch/telemetry_identity.rb +0 -25
  32. data/app/controllers/railwatch/alerts_controller.rb +0 -48
  33. data/app/controllers/railwatch/anomaly_rules_controller.rb +0 -31
  34. data/app/controllers/railwatch/attachments_controller.rb +0 -22
  35. data/app/controllers/railwatch/broadcasts_controller.rb +0 -15
  36. data/app/controllers/railwatch/cache_events_controller.rb +0 -30
  37. data/app/controllers/railwatch/commands_controller.rb +0 -16
  38. data/app/controllers/railwatch/comments_controller.rb +0 -11
  39. data/app/controllers/railwatch/dashboard_controller.rb +0 -70
  40. data/app/controllers/railwatch/deploys_controller.rb +0 -34
  41. data/app/controllers/railwatch/deprecations_controller.rb +0 -54
  42. data/app/controllers/railwatch/environment_scoped.rb +0 -81
  43. data/app/controllers/railwatch/exceptions_controller.rb +0 -52
  44. data/app/controllers/railwatch/executions_controller.rb +0 -13
  45. data/app/controllers/railwatch/issues_controller.rb +0 -258
  46. data/app/controllers/railwatch/jobs_controller.rb +0 -63
  47. data/app/controllers/railwatch/llm_calls_controller.rb +0 -124
  48. data/app/controllers/railwatch/logs_controller.rb +0 -40
  49. data/app/controllers/railwatch/mails_controller.rb +0 -19
  50. data/app/controllers/railwatch/notifications_controller.rb +0 -11
  51. data/app/controllers/railwatch/outgoing_requests_controller.rb +0 -19
  52. data/app/controllers/railwatch/overview_controller.rb +0 -38
  53. data/app/controllers/railwatch/people_controller.rb +0 -25
  54. data/app/controllers/railwatch/processes_controller.rb +0 -33
  55. data/app/controllers/railwatch/profiles_controller.rb +0 -65
  56. data/app/controllers/railwatch/queries_controller.rb +0 -59
  57. data/app/controllers/railwatch/releases_controller.rb +0 -75
  58. data/app/controllers/railwatch/requests_controller.rb +0 -37
  59. data/app/controllers/railwatch/saved_views_controller.rb +0 -53
  60. data/app/controllers/railwatch/scheduled_tasks_controller.rb +0 -45
  61. data/app/controllers/railwatch/spans_controller.rb +0 -47
  62. data/app/controllers/railwatch/storage_ops_controller.rb +0 -15
  63. data/app/controllers/railwatch/tenants_controller.rb +0 -44
  64. data/app/controllers/railwatch/thresholds_controller.rb +0 -47
  65. data/app/controllers/railwatch/traces_controller.rb +0 -72
  66. data/app/controllers/railwatch/transactions_controller.rb +0 -21
  67. data/app/controllers/railwatch/view_renders_controller.rb +0 -28
  68. data/app/controllers/railwatch/visits_controller.rb +0 -53
  69. data/app/frontend/components/app-content.tsx +0 -26
  70. data/app/frontend/components/app-logo-icon.tsx +0 -23
  71. data/app/frontend/components/app-logo.tsx +0 -14
  72. data/app/frontend/components/app-shell.tsx +0 -38
  73. data/app/frontend/components/app-sidebar-header.tsx +0 -54
  74. data/app/frontend/components/app-sidebar.tsx +0 -94
  75. data/app/frontend/components/app-wordmark.tsx +0 -29
  76. data/app/frontend/components/breadcrumbs.tsx +0 -46
  77. data/app/frontend/components/icon.tsx +0 -16
  78. data/app/frontend/components/input-error.tsx +0 -18
  79. data/app/frontend/components/nav-footer.tsx +0 -46
  80. data/app/frontend/components/nav-main.tsx +0 -41
  81. data/app/frontend/components/nav-user.tsx +0 -50
  82. data/app/frontend/components/railwatch/chart-hover.tsx +0 -34
  83. data/app/frontend/components/railwatch/chart-panel.tsx +0 -170
  84. data/app/frontend/components/railwatch/code.tsx +0 -28
  85. data/app/frontend/components/railwatch/command-palette.tsx +0 -132
  86. data/app/frontend/components/railwatch/copy-block.tsx +0 -52
  87. data/app/frontend/components/railwatch/copy-id.tsx +0 -49
  88. data/app/frontend/components/railwatch/cursor-load-more.tsx +0 -39
  89. data/app/frontend/components/railwatch/data-table.tsx +0 -195
  90. data/app/frontend/components/railwatch/digit-roll.tsx +0 -312
  91. data/app/frontend/components/railwatch/empty-state.tsx +0 -159
  92. data/app/frontend/components/railwatch/env-nav.tsx +0 -130
  93. data/app/frontend/components/railwatch/env-switcher.tsx +0 -145
  94. data/app/frontend/components/railwatch/filter-bar.tsx +0 -153
  95. data/app/frontend/components/railwatch/flamegraph.tsx +0 -324
  96. data/app/frontend/components/railwatch/frames.tsx +0 -295
  97. data/app/frontend/components/railwatch/json-viewer.tsx +0 -159
  98. data/app/frontend/components/railwatch/live-dot.tsx +0 -78
  99. data/app/frontend/components/railwatch/live-toggle.tsx +0 -76
  100. data/app/frontend/components/railwatch/metric-chart.tsx +0 -112
  101. data/app/frontend/components/railwatch/mobile-page-switcher.tsx +0 -89
  102. data/app/frontend/components/railwatch/onboarding.tsx +0 -91
  103. data/app/frontend/components/railwatch/origin-identity.tsx +0 -84
  104. data/app/frontend/components/railwatch/page-header.tsx +0 -42
  105. data/app/frontend/components/railwatch/percentile-picker.tsx +0 -18
  106. data/app/frontend/components/railwatch/relative-time.tsx +0 -18
  107. data/app/frontend/components/railwatch/saved-views.tsx +0 -232
  108. data/app/frontend/components/railwatch/segmented.tsx +0 -64
  109. data/app/frontend/components/railwatch/series-chart.tsx +0 -400
  110. data/app/frontend/components/railwatch/shortcuts-dialog.tsx +0 -89
  111. data/app/frontend/components/railwatch/signal-toast.tsx +0 -121
  112. data/app/frontend/components/railwatch/sort-header.tsx +0 -37
  113. data/app/frontend/components/railwatch/source-link.tsx +0 -57
  114. data/app/frontend/components/railwatch/sparkline-cell.tsx +0 -14
  115. data/app/frontend/components/railwatch/sql-block.tsx +0 -116
  116. data/app/frontend/components/railwatch/stat.tsx +0 -185
  117. data/app/frontend/components/railwatch/status-badge.tsx +0 -79
  118. data/app/frontend/components/railwatch/step-picker.tsx +0 -57
  119. data/app/frontend/components/railwatch/timeline.tsx +0 -405
  120. data/app/frontend/components/railwatch/utilisation-bar.tsx +0 -44
  121. data/app/frontend/components/railwatch/window-picker.tsx +0 -147
  122. data/app/frontend/components/ui/avatar.tsx +0 -51
  123. data/app/frontend/components/ui/badge.tsx +0 -46
  124. data/app/frontend/components/ui/breadcrumb.tsx +0 -109
  125. data/app/frontend/components/ui/button.tsx +0 -60
  126. data/app/frontend/components/ui/card.tsx +0 -92
  127. data/app/frontend/components/ui/chart.tsx +0 -374
  128. data/app/frontend/components/ui/checkbox.tsx +0 -32
  129. data/app/frontend/components/ui/collapsible.tsx +0 -31
  130. data/app/frontend/components/ui/command.tsx +0 -182
  131. data/app/frontend/components/ui/dialog.tsx +0 -158
  132. data/app/frontend/components/ui/dropdown-menu.tsx +0 -255
  133. data/app/frontend/components/ui/hover-card.tsx +0 -42
  134. data/app/frontend/components/ui/input.tsx +0 -21
  135. data/app/frontend/components/ui/label.tsx +0 -24
  136. data/app/frontend/components/ui/popover.tsx +0 -87
  137. data/app/frontend/components/ui/select.tsx +0 -185
  138. data/app/frontend/components/ui/separator.tsx +0 -28
  139. data/app/frontend/components/ui/sheet.tsx +0 -137
  140. data/app/frontend/components/ui/sidebar.tsx +0 -726
  141. data/app/frontend/components/ui/skeleton.tsx +0 -13
  142. data/app/frontend/components/ui/sonner.tsx +0 -41
  143. data/app/frontend/components/ui/table.tsx +0 -114
  144. data/app/frontend/components/ui/tabs.tsx +0 -91
  145. data/app/frontend/components/ui/textarea.tsx +0 -18
  146. data/app/frontend/components/ui/tooltip.tsx +0 -61
  147. data/app/frontend/components/user-info.tsx +0 -32
  148. data/app/frontend/components/user-menu-content.tsx +0 -94
  149. data/app/frontend/entrypoints/application.css +0 -244
  150. data/app/frontend/entrypoints/inertia.tsx +0 -92
  151. data/app/frontend/fonts/CommitMono-Bold.woff2 +0 -0
  152. data/app/frontend/fonts/CommitMono-Regular.woff2 +0 -0
  153. data/app/frontend/fonts/Roboto-Black.woff2 +0 -0
  154. data/app/frontend/fonts/Roboto-Bold.woff2 +0 -0
  155. data/app/frontend/fonts/Roboto-Medium.woff2 +0 -0
  156. data/app/frontend/fonts/Roboto-Regular.woff2 +0 -0
  157. data/app/frontend/hooks/use-appearance.tsx +0 -67
  158. data/app/frontend/hooks/use-clipboard.ts +0 -32
  159. data/app/frontend/hooks/use-flash.tsx +0 -23
  160. data/app/frontend/hooks/use-hotkeys.ts +0 -63
  161. data/app/frontend/hooks/use-initials.tsx +0 -15
  162. data/app/frontend/hooks/use-live.ts +0 -205
  163. data/app/frontend/hooks/use-mobile-navigation.ts +0 -8
  164. data/app/frontend/hooks/use-mobile.ts +0 -21
  165. data/app/frontend/hooks/use-percentile.ts +0 -24
  166. data/app/frontend/hooks/use-reduced-motion.ts +0 -25
  167. data/app/frontend/hooks/use-row-nav.ts +0 -106
  168. data/app/frontend/hooks/use-step.ts +0 -27
  169. data/app/frontend/hooks/use-ticker.ts +0 -12
  170. data/app/frontend/hooks/use-window.ts +0 -58
  171. data/app/frontend/layouts/app/app-sidebar-layout.tsx +0 -107
  172. data/app/frontend/layouts/app-layout.tsx +0 -21
  173. data/app/frontend/layouts/env-layout.tsx +0 -53
  174. data/app/frontend/layouts/persistent-layout.tsx +0 -18
  175. data/app/frontend/lib/cable.ts +0 -10
  176. data/app/frontend/lib/env-pages.ts +0 -236
  177. data/app/frontend/lib/execution-path.ts +0 -55
  178. data/app/frontend/lib/explain.ts +0 -50
  179. data/app/frontend/lib/filter.ts +0 -25
  180. data/app/frontend/lib/flamegraph.ts +0 -155
  181. data/app/frontend/lib/format.ts +0 -71
  182. data/app/frontend/lib/keyboard.ts +0 -18
  183. data/app/frontend/lib/mount.ts +0 -23
  184. data/app/frontend/lib/source-link.ts +0 -217
  185. data/app/frontend/lib/utils.ts +0 -6
  186. data/app/frontend/pages/alerts/index.tsx +0 -171
  187. data/app/frontend/pages/broadcasts/index.tsx +0 -171
  188. data/app/frontend/pages/cache_events/index.tsx +0 -127
  189. data/app/frontend/pages/commands/index.tsx +0 -143
  190. data/app/frontend/pages/deploys/index.tsx +0 -94
  191. data/app/frontend/pages/deploys/show.tsx +0 -309
  192. data/app/frontend/pages/deprecations/index.tsx +0 -176
  193. data/app/frontend/pages/exceptions/index.tsx +0 -271
  194. data/app/frontend/pages/executions/show.tsx +0 -821
  195. data/app/frontend/pages/issues/index.tsx +0 -399
  196. data/app/frontend/pages/issues/show.tsx +0 -1367
  197. data/app/frontend/pages/jobs/index.tsx +0 -381
  198. data/app/frontend/pages/jobs/klass.tsx +0 -215
  199. data/app/frontend/pages/llm_calls/index.tsx +0 -664
  200. data/app/frontend/pages/logs/index.tsx +0 -303
  201. data/app/frontend/pages/mails/index.tsx +0 -218
  202. data/app/frontend/pages/notifications/index.tsx +0 -161
  203. data/app/frontend/pages/outgoing_requests/index.tsx +0 -309
  204. data/app/frontend/pages/overview/show.tsx +0 -333
  205. data/app/frontend/pages/people/index.tsx +0 -102
  206. data/app/frontend/pages/people/show.tsx +0 -149
  207. data/app/frontend/pages/processes/index.tsx +0 -335
  208. data/app/frontend/pages/profiles/index.tsx +0 -110
  209. data/app/frontend/pages/profiles/show.tsx +0 -105
  210. data/app/frontend/pages/queries/index.tsx +0 -492
  211. data/app/frontend/pages/queries/show.tsx +0 -276
  212. data/app/frontend/pages/releases/index.tsx +0 -190
  213. data/app/frontend/pages/releases/release-health.tsx +0 -68
  214. data/app/frontend/pages/releases/release-path.ts +0 -25
  215. data/app/frontend/pages/releases/show.tsx +0 -262
  216. data/app/frontend/pages/requests/index.tsx +0 -235
  217. data/app/frontend/pages/requests/route.tsx +0 -159
  218. data/app/frontend/pages/scheduled_tasks/index.tsx +0 -220
  219. data/app/frontend/pages/spans/index.tsx +0 -229
  220. data/app/frontend/pages/spans/show.tsx +0 -220
  221. data/app/frontend/pages/storage_ops/index.tsx +0 -150
  222. data/app/frontend/pages/tenants/index.tsx +0 -236
  223. data/app/frontend/pages/tenants/show.tsx +0 -477
  224. data/app/frontend/pages/tenants/tenant-path.ts +0 -26
  225. data/app/frontend/pages/thresholds/index.tsx +0 -414
  226. data/app/frontend/pages/traces/show.tsx +0 -208
  227. data/app/frontend/pages/transactions/index.tsx +0 -220
  228. data/app/frontend/pages/view_renders/index.tsx +0 -241
  229. data/app/frontend/pages/visits/index.tsx +0 -321
  230. data/app/frontend/public/icon.png +0 -0
  231. data/app/frontend/public/icon.svg +0 -5
  232. data/app/frontend/routes/index.d.ts +0 -2136
  233. data/app/frontend/routes/index.js +0 -2112
  234. data/app/frontend/types/globals.d.ts +0 -9
  235. data/app/frontend/types/index.ts +0 -288
  236. data/app/frontend/types/vite-env.d.ts +0 -9
  237. data/app/helpers/railwatch/assets_helper.rb +0 -52
  238. data/app/jobs/railwatch/anomaly_scan_job.rb +0 -11
  239. data/app/jobs/railwatch/application_job.rb +0 -7
  240. data/app/jobs/railwatch/auto_resolve_issues_job.rb +0 -19
  241. data/app/jobs/railwatch/check_scheduled_tasks_job.rb +0 -113
  242. data/app/jobs/railwatch/detect_anomalies_job.rb +0 -171
  243. data/app/jobs/railwatch/detect_performance_issues_job.rb +0 -95
  244. data/app/jobs/railwatch/group_exceptions_job.rb +0 -91
  245. data/app/jobs/railwatch/optimize_telemetry_job.rb +0 -23
  246. data/app/jobs/railwatch/performance_scan_job.rb +0 -11
  247. data/app/jobs/railwatch/prune_telemetry_job.rb +0 -129
  248. data/app/jobs/railwatch/release_health_rollup_job.rb +0 -64
  249. data/app/jobs/railwatch/rollup_catchup_job.rb +0 -21
  250. data/app/jobs/railwatch/rollup_job.rb +0 -132
  251. data/app/jobs/railwatch/scheduled_task_scan_job.rb +0 -11
  252. data/app/models/concerns/railwatch/detection_snapshotting.rb +0 -20
  253. data/app/models/railwatch/alert.rb +0 -229
  254. data/app/models/railwatch/alert_rule.rb +0 -121
  255. data/app/models/railwatch/anomaly_rule.rb +0 -51
  256. data/app/models/railwatch/application.rb +0 -44
  257. data/app/models/railwatch/application_record.rb +0 -33
  258. data/app/models/railwatch/comment.rb +0 -36
  259. data/app/models/railwatch/deploy.rb +0 -67
  260. data/app/models/railwatch/environment.rb +0 -68
  261. data/app/models/railwatch/execution_presenter.rb +0 -185
  262. data/app/models/railwatch/filter_query.rb +0 -184
  263. data/app/models/railwatch/followup_receipt.rb +0 -27
  264. data/app/models/railwatch/ingest/batch.rb +0 -355
  265. data/app/models/railwatch/ingest/mapper.rb +0 -585
  266. data/app/models/railwatch/ingest/payload.rb +0 -96
  267. data/app/models/railwatch/ingest/rollup_absorber.rb +0 -170
  268. data/app/models/railwatch/ingest/writer.rb +0 -137
  269. data/app/models/railwatch/issue.rb +0 -277
  270. data/app/models/railwatch/issue_activity.rb +0 -23
  271. data/app/models/railwatch/issue_detection_presenter.rb +0 -309
  272. data/app/models/railwatch/issue_detection_snapshot.rb +0 -77
  273. data/app/models/railwatch/maintenance_task.rb +0 -53
  274. data/app/models/railwatch/saved_view.rb +0 -63
  275. data/app/models/railwatch/telemetry/aggregations.rb +0 -251
  276. data/app/models/railwatch/telemetry/attachment.rb +0 -31
  277. data/app/models/railwatch/telemetry/bounded_gzip.rb +0 -101
  278. data/app/models/railwatch/telemetry/broadcast.rb +0 -13
  279. data/app/models/railwatch/telemetry/cache_event.rb +0 -16
  280. data/app/models/railwatch/telemetry/child.rb +0 -53
  281. data/app/models/railwatch/telemetry/cursor_page.rb +0 -99
  282. data/app/models/railwatch/telemetry/deprecation.rb +0 -13
  283. data/app/models/railwatch/telemetry/enqueued_job.rb +0 -13
  284. data/app/models/railwatch/telemetry/exception.rb +0 -28
  285. data/app/models/railwatch/telemetry/execution.rb +0 -152
  286. data/app/models/railwatch/telemetry/export_delivery.rb +0 -32
  287. data/app/models/railwatch/telemetry/export_destination.rb +0 -66
  288. data/app/models/railwatch/telemetry/health_sample.rb +0 -72
  289. data/app/models/railwatch/telemetry/ingest_batch.rb +0 -31
  290. data/app/models/railwatch/telemetry/llm_call.rb +0 -37
  291. data/app/models/railwatch/telemetry/log.rb +0 -91
  292. data/app/models/railwatch/telemetry/mail.rb +0 -13
  293. data/app/models/railwatch/telemetry/n_plus_one.rb +0 -92
  294. data/app/models/railwatch/telemetry/notification.rb +0 -13
  295. data/app/models/railwatch/telemetry/outgoing_request.rb +0 -13
  296. data/app/models/railwatch/telemetry/person.rb +0 -50
  297. data/app/models/railwatch/telemetry/process.rb +0 -10
  298. data/app/models/railwatch/telemetry/profile.rb +0 -37
  299. data/app/models/railwatch/telemetry/query.rb +0 -57
  300. data/app/models/railwatch/telemetry/query_shape.rb +0 -45
  301. data/app/models/railwatch/telemetry/release_health.rb +0 -69
  302. data/app/models/railwatch/telemetry/rollup.rb +0 -157
  303. data/app/models/railwatch/telemetry/session.rb +0 -24
  304. data/app/models/railwatch/telemetry/span.rb +0 -19
  305. data/app/models/railwatch/telemetry/storage_op.rb +0 -13
  306. data/app/models/railwatch/telemetry/tenant.rb +0 -240
  307. data/app/models/railwatch/telemetry/transaction.rb +0 -13
  308. data/app/models/railwatch/telemetry/view_render.rb +0 -13
  309. data/app/models/railwatch/telemetry/visit.rb +0 -24
  310. data/app/models/railwatch/telemetry_record.rb +0 -107
  311. data/app/models/railwatch/threshold.rb +0 -66
  312. data/app/models/railwatch/user.rb +0 -47
  313. data/app/models/railwatch/viewer.rb +0 -13
  314. data/app/models/railwatch/window.rb +0 -66
  315. data/app/views/layouts/railwatch/dashboard.html.erb +0 -25
  316. data/db/railwatch_migrate/20260916000000_create_railwatch_tables.rb +0 -151
  317. data/db/railwatch_migrate/20260917000000_create_railwatch_maintenance_tasks.rb +0 -18
  318. data/db/railwatch_migrate/20260917120000_create_railwatch_followup_receipts.rb +0 -20
  319. data/db/railwatch_migrate/20260918120000_widen_host_user_ids.rb +0 -71
  320. data/db/railwatch_telemetry_migrate/20260903000000_enable_incremental_vacuum.rb +0 -62
  321. data/db/railwatch_telemetry_migrate/20260903000001_create_telemetry.rb +0 -481
  322. data/db/railwatch_telemetry_migrate/20260903000002_rename_tenant_to_app_tenant.rb +0 -14
  323. data/db/railwatch_telemetry_migrate/20260903000003_add_statement_count_to_transactions.rb +0 -9
  324. data/db/railwatch_telemetry_migrate/20260903000004_add_role_and_channel.rb +0 -10
  325. data/db/railwatch_telemetry_migrate/20260903000005_add_locals_to_exceptions.rb +0 -9
  326. data/db/railwatch_telemetry_migrate/20260903000006_add_spans_health_vitals_and_fts.rb +0 -82
  327. data/db/railwatch_telemetry_migrate/20260903000007_rename_span_attributes_to_payload.rb +0 -10
  328. data/db/railwatch_telemetry_migrate/20260903000008_add_profiles_and_attachments.rb +0 -60
  329. data/db/railwatch_telemetry_migrate/20260903000009_add_truncated_to_attachments.rb +0 -9
  330. data/db/railwatch_telemetry_migrate/20260903000010_create_sessions_and_release_health.rb +0 -51
  331. data/db/railwatch_telemetry_migrate/20260903000011_add_fingerprint_to_exceptions.rb +0 -11
  332. data/db/railwatch_telemetry_migrate/20260904000012_add_failed_to_broadcasts.rb +0 -10
  333. data/db/railwatch_telemetry_migrate/20260904010000_add_filter_cursor_indexes.rb +0 -37
  334. data/db/railwatch_telemetry_migrate/20260904020000_add_n_plus_ones_execution_id_index.rb +0 -11
  335. data/db/railwatch_telemetry_migrate/20260904120000_create_query_shapes.rb +0 -15
  336. data/db/railwatch_telemetry_migrate/20260906120000_add_backpressure_factor_to_ingest_batches.rb +0 -9
  337. data/db/railwatch_telemetry_migrate/20260907000000_rename_lantern_version_on_processes.rb +0 -10
  338. data/db/railwatch_telemetry_migrate/20260913000000_rename_nightrail_version_on_processes.rb +0 -9
  339. data/db/railwatch_telemetry_migrate/20260914000000_drop_orphan_durable_ingest_tables.rb +0 -18
  340. data/db/railwatch_telemetry_migrate/20260914010000_drop_orphan_durable_ingest_columns.rb +0 -25
  341. data/db/railwatch_telemetry_migrate/20260915000000_create_llm_calls.rb +0 -55
  342. data/db/railwatch_telemetry_migrate/20260915120000_add_detail_to_llm_calls.rb +0 -21
  343. data/db/railwatch_telemetry_migrate/20260915200000_add_explained_index_to_queries.rb +0 -16
  344. data/db/railwatch_telemetry_migrate/20260915210000_add_slowest_index_to_queries.rb +0 -18
  345. data/db/railwatch_telemetry_migrate/20260917010000_add_batch_ledger_to_ingest_batches.rb +0 -16
  346. data/db/railwatch_telemetry_migrate/20260919000100_create_export_queue.rb +0 -146
  347. data/db/railwatch_telemetry_migrate/20260922000000_add_covering_indexes_for_dashboard_aggregates.rb +0 -34
  348. data/db/railwatch_telemetry_migrate/20260923000000_add_people_index.rb +0 -15
  349. data/db/railwatch_telemetry_migrate/20260925000000_add_tenant_summary_index.rb +0 -17
  350. data/db/railwatch_telemetry_migrate/20261008000000_add_in_transaction_to_outgoing_requests.rb +0 -10
  351. data/docs/embedded.md +0 -503
  352. data/lib/puma/plugin/railwatch.rb +0 -215
  353. data/lib/railwatch/dashboard_assets.rb +0 -45
  354. data/lib/railwatch/embedded.rb +0 -50
  355. data/lib/railwatch/export/client.rb +0 -124
  356. data/lib/railwatch/export/lease.rb +0 -56
  357. data/lib/railwatch/export/outbox.rb +0 -361
  358. data/lib/railwatch/export/policy.rb +0 -79
  359. data/lib/railwatch/export/sender.rb +0 -130
  360. data/lib/railwatch/ingest_request_body_limit.rb +0 -10
  361. data/lib/railwatch/maintenance.rb +0 -194
  362. data/lib/railwatch/patches/migration_busy_timeout.rb +0 -73
  363. data/lib/railwatch/transport/local.rb +0 -78
  364. data/lib/railwatch/transport/socket.rb +0 -183
  365. data/lib/railwatch/writer.rb +0 -370
  366. data/public/railwatch/assets/CommitMono-Bold-D6h61ieg.woff2 +0 -0
  367. data/public/railwatch/assets/CommitMono-Regular-zr8w7Obm.woff2 +0 -0
  368. data/public/railwatch/assets/Roboto-Black-auA4GeOK.woff2 +0 -0
  369. data/public/railwatch/assets/Roboto-Bold-CJLnO8j1.woff2 +0 -0
  370. data/public/railwatch/assets/Roboto-Medium-Cm2bwKpj.woff2 +0 -0
  371. data/public/railwatch/assets/Roboto-Regular-Chaq1-PV.woff2 +0 -0
  372. data/public/railwatch/assets/app-layout-by7G3sa1.js +0 -41
  373. data/public/railwatch/assets/application-Cc5v_Vk9.css +0 -1
  374. data/public/railwatch/assets/arrow-up-DCZ7emux.js +0 -1
  375. data/public/railwatch/assets/braces-CykT5_5u.js +0 -1
  376. data/public/railwatch/assets/card-C-PPSA0g.js +0 -1
  377. data/public/railwatch/assets/chart-Cov79YC5.js +0 -39
  378. data/public/railwatch/assets/chart-hover-DdK4E-2h.js +0 -1
  379. data/public/railwatch/assets/chart-panel-BPaYRXJB.js +0 -1
  380. data/public/railwatch/assets/code-BYjC4YZ_.js +0 -1
  381. data/public/railwatch/assets/copy-id-LPfoj9cC.js +0 -1
  382. data/public/railwatch/assets/cursor-load-more-DSdhgpGl.js +0 -1
  383. data/public/railwatch/assets/data-table-CQ_YRWQs.js +0 -1
  384. data/public/railwatch/assets/env-layout-CdMWbUkm.js +0 -1
  385. data/public/railwatch/assets/execution-path-7MYt-Qbn.js +0 -1
  386. data/public/railwatch/assets/filter-bar-CrzpQ_vD.js +0 -1
  387. data/public/railwatch/assets/flamegraph-BIFEdTAg.js +0 -2
  388. data/public/railwatch/assets/format-B9SDkrWj.js +0 -1
  389. data/public/railwatch/assets/frames-C5t-x4f0.js +0 -1
  390. data/public/railwatch/assets/index--NQ7us-L.js +0 -1
  391. data/public/railwatch/assets/index-2kgYe_99.js +0 -1
  392. data/public/railwatch/assets/index-4YEPHxtO.js +0 -1
  393. data/public/railwatch/assets/index-AOCC1GDJ.js +0 -1
  394. data/public/railwatch/assets/index-BEo-u0eO.js +0 -1
  395. data/public/railwatch/assets/index-BJ1V3w2N.js +0 -1
  396. data/public/railwatch/assets/index-BPoHsBKb.js +0 -1
  397. data/public/railwatch/assets/index-BZzyGUM3.js +0 -1
  398. data/public/railwatch/assets/index-BgVq7yKL.js +0 -1
  399. data/public/railwatch/assets/index-BqFGEZvW.js +0 -1
  400. data/public/railwatch/assets/index-ByuHJ1CH.js +0 -1
  401. data/public/railwatch/assets/index-C2j50AL2.js +0 -1
  402. data/public/railwatch/assets/index-CLEdTkvW.js +0 -1
  403. data/public/railwatch/assets/index-CWgq8qBu.js +0 -1
  404. data/public/railwatch/assets/index-CXQ7_oVj.js +0 -2
  405. data/public/railwatch/assets/index-CmyYrjS2.js +0 -1
  406. data/public/railwatch/assets/index-Cn9_HjDo.js +0 -1
  407. data/public/railwatch/assets/index-CsMAm9UK.js +0 -1
  408. data/public/railwatch/assets/index-D0Kk_oGY.js +0 -1
  409. data/public/railwatch/assets/index-DC9ZptJh.js +0 -1
  410. data/public/railwatch/assets/index-DNzg7jmV.js +0 -1
  411. data/public/railwatch/assets/index-DQ8uJO5f.js +0 -1
  412. data/public/railwatch/assets/index-Deq14BxB.js +0 -1
  413. data/public/railwatch/assets/index-IaV3Blzp.js +0 -1
  414. data/public/railwatch/assets/index-TYNWcJQs.js +0 -1
  415. data/public/railwatch/assets/index-WonH2fcZ.js +0 -1
  416. data/public/railwatch/assets/index-WxWUaH_d.js +0 -1
  417. data/public/railwatch/assets/index-mUNrl4ky.js +0 -1
  418. data/public/railwatch/assets/inertia-DfNRARuA.js +0 -97
  419. data/public/railwatch/assets/json-viewer-DMsF5glp.js +0 -1
  420. data/public/railwatch/assets/klass-CmHYk5rz.js +0 -1
  421. data/public/railwatch/assets/origin-identity-1R3bqa3R.js +0 -1
  422. data/public/railwatch/assets/percentile-picker-73z5PAps.js +0 -1
  423. data/public/railwatch/assets/relative-time-Dsc_cCdX.js +0 -1
  424. data/public/railwatch/assets/release-health-BV5OaOWd.js +0 -1
  425. data/public/railwatch/assets/route-CWh58C7K.js +0 -1
  426. data/public/railwatch/assets/segmented-DB4zh-Am.js +0 -1
  427. data/public/railwatch/assets/select-DBKjFlOX.js +0 -1
  428. data/public/railwatch/assets/series-chart-BaiDG795.js +0 -1
  429. data/public/railwatch/assets/show-B4ICCFGh.js +0 -1
  430. data/public/railwatch/assets/show-B5lOU9Gv.js +0 -1
  431. data/public/railwatch/assets/show-BYPB74t4.js +0 -2
  432. data/public/railwatch/assets/show-C7A0m2M8.js +0 -1
  433. data/public/railwatch/assets/show-DT5X1zqE.js +0 -1
  434. data/public/railwatch/assets/show-D_NBdXsn.js +0 -2
  435. data/public/railwatch/assets/show-DgPCnRg8.js +0 -1
  436. data/public/railwatch/assets/show-Yl69HF0x.js +0 -1
  437. data/public/railwatch/assets/show-_QxuUQCm.js +0 -3
  438. data/public/railwatch/assets/show-g__jnN36.js +0 -1
  439. data/public/railwatch/assets/show-l4ztfjl9.js +0 -1
  440. data/public/railwatch/assets/sort-header-BcG8ulEH.js +0 -1
  441. data/public/railwatch/assets/source-link-B2183i2-.js +0 -1
  442. data/public/railwatch/assets/sparkline-cell-B47ipscB.js +0 -1
  443. data/public/railwatch/assets/stat-DT2hhsqS.js +0 -1
  444. data/public/railwatch/assets/status-badge-CmbRKlY7.js +0 -1
  445. data/public/railwatch/assets/tenant-path-C4rNGauE.js +0 -1
  446. data/public/railwatch/assets/use-clipboard-oTNeP4ax.js +0 -1
  447. data/public/railwatch/assets/use-live-CLZZj245.js +0 -1
  448. data/public/railwatch/icon.png +0 -0
  449. data/public/railwatch/icon.svg +0 -5
  450. data/public/railwatch/manifest.json +0 -1245
  451. data/public/railwatch/rails-vite.json +0 -1
  452. /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
- }