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,726 +0,0 @@
1
- "use client"
2
-
3
- import { Slot } from "@radix-ui/react-slot"
4
- import { type VariantProps, cva } from "class-variance-authority"
5
- import { PanelLeftIcon } from "lucide-react"
6
- import * as React from "react"
7
-
8
- import { Button } from "@/components/ui/button"
9
- import { Input } from "@/components/ui/input"
10
- import { Separator } from "@/components/ui/separator"
11
- import {
12
- Sheet,
13
- SheetContent,
14
- SheetDescription,
15
- SheetHeader,
16
- SheetTitle,
17
- } from "@/components/ui/sheet"
18
- import { Skeleton } from "@/components/ui/skeleton"
19
- import {
20
- Tooltip,
21
- TooltipContent,
22
- TooltipProvider,
23
- TooltipTrigger,
24
- } from "@/components/ui/tooltip"
25
- import { useIsMobile } from "@/hooks/use-mobile"
26
- import { cn } from "@/lib/utils"
27
-
28
- const SIDEBAR_COOKIE_NAME = "sidebar_state"
29
- const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
30
- const SIDEBAR_WIDTH = "14.25rem"
31
- const SIDEBAR_WIDTH_MOBILE = "18rem"
32
- const SIDEBAR_WIDTH_ICON = "3rem"
33
- const SIDEBAR_KEYBOARD_SHORTCUT = "b"
34
-
35
- interface SidebarContextProps {
36
- state: "expanded" | "collapsed"
37
- open: boolean
38
- setOpen: (open: boolean) => void
39
- openMobile: boolean
40
- setOpenMobile: (open: boolean) => void
41
- isMobile: boolean
42
- toggleSidebar: () => void
43
- }
44
-
45
- const SidebarContext = React.createContext<SidebarContextProps | null>(null)
46
-
47
- function useSidebar() {
48
- const context = React.useContext(SidebarContext)
49
- if (!context) {
50
- throw new Error("useSidebar must be used within a SidebarProvider.")
51
- }
52
-
53
- return context
54
- }
55
-
56
- function SidebarProvider({
57
- defaultOpen = true,
58
- open: openProp,
59
- onOpenChange: setOpenProp,
60
- className,
61
- style,
62
- children,
63
- ...props
64
- }: React.ComponentProps<"div"> & {
65
- defaultOpen?: boolean
66
- open?: boolean
67
- onOpenChange?: (open: boolean) => void
68
- }) {
69
- const isMobile = useIsMobile()
70
- const [openMobile, setOpenMobile] = React.useState(false)
71
-
72
- // This is the internal state of the sidebar.
73
- // We use openProp and setOpenProp for control from outside the component.
74
- const [_open, _setOpen] = React.useState(defaultOpen)
75
- const open = openProp ?? _open
76
- const setOpen = React.useCallback(
77
- (value: boolean | ((value: boolean) => boolean)) => {
78
- const openState = typeof value === "function" ? value(open) : value
79
- if (setOpenProp) {
80
- setOpenProp(openState)
81
- } else {
82
- _setOpen(openState)
83
- }
84
-
85
- // This sets the cookie to keep the sidebar state.
86
- document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
87
- },
88
- [setOpenProp, open],
89
- )
90
-
91
- // Helper to toggle the sidebar.
92
- const toggleSidebar = React.useCallback(() => {
93
- return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)
94
- }, [isMobile, setOpen, setOpenMobile])
95
-
96
- // Adds a keyboard shortcut to toggle the sidebar.
97
- React.useEffect(() => {
98
- const handleKeyDown = (event: KeyboardEvent) => {
99
- if (
100
- event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
101
- (event.metaKey || event.ctrlKey)
102
- ) {
103
- event.preventDefault()
104
- toggleSidebar()
105
- }
106
- }
107
-
108
- window.addEventListener("keydown", handleKeyDown)
109
- return () => window.removeEventListener("keydown", handleKeyDown)
110
- }, [toggleSidebar])
111
-
112
- // We add a state so that we can do data-state="expanded" or "collapsed".
113
- // This makes it easier to style the sidebar with Tailwind classes.
114
- const state = open ? "expanded" : "collapsed"
115
-
116
- const contextValue = React.useMemo<SidebarContextProps>(
117
- () => ({
118
- state,
119
- open,
120
- setOpen,
121
- isMobile,
122
- openMobile,
123
- setOpenMobile,
124
- toggleSidebar,
125
- }),
126
- [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],
127
- )
128
-
129
- return (
130
- <SidebarContext.Provider value={contextValue}>
131
- <TooltipProvider delayDuration={0}>
132
- <div
133
- data-slot="sidebar-wrapper"
134
- style={
135
- {
136
- "--sidebar-width": SIDEBAR_WIDTH,
137
- "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
138
- ...style,
139
- } as React.CSSProperties
140
- }
141
- className={cn(
142
- "group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",
143
- className,
144
- )}
145
- {...props}
146
- >
147
- {children}
148
- </div>
149
- </TooltipProvider>
150
- </SidebarContext.Provider>
151
- )
152
- }
153
-
154
- function Sidebar({
155
- side = "left",
156
- variant = "sidebar",
157
- collapsible = "offcanvas",
158
- className,
159
- children,
160
- ...props
161
- }: React.ComponentProps<"div"> & {
162
- side?: "left" | "right"
163
- variant?: "sidebar" | "floating" | "inset"
164
- collapsible?: "offcanvas" | "icon" | "none"
165
- }) {
166
- const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
167
-
168
- if (collapsible === "none") {
169
- return (
170
- <div
171
- data-slot="sidebar"
172
- className={cn(
173
- "bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",
174
- className,
175
- )}
176
- {...props}
177
- >
178
- {children}
179
- </div>
180
- )
181
- }
182
-
183
- if (isMobile) {
184
- return (
185
- <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
186
- <SheetContent
187
- data-sidebar="sidebar"
188
- data-slot="sidebar"
189
- data-mobile="true"
190
- className="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
191
- style={
192
- {
193
- "--sidebar-width": SIDEBAR_WIDTH_MOBILE,
194
- } as React.CSSProperties
195
- }
196
- side={side}
197
- >
198
- <SheetHeader className="sr-only">
199
- <SheetTitle>Sidebar</SheetTitle>
200
- <SheetDescription>Displays the mobile sidebar.</SheetDescription>
201
- </SheetHeader>
202
- <div className="flex h-full w-full flex-col">{children}</div>
203
- </SheetContent>
204
- </Sheet>
205
- )
206
- }
207
-
208
- return (
209
- <div
210
- className="group peer text-sidebar-foreground hidden md:block"
211
- data-state={state}
212
- data-collapsible={state === "collapsed" ? collapsible : ""}
213
- data-variant={variant}
214
- data-side={side}
215
- data-slot="sidebar"
216
- >
217
- {/* This is what handles the sidebar gap on desktop */}
218
- <div
219
- data-slot="sidebar-gap"
220
- className={cn(
221
- "relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
222
- "group-data-[collapsible=offcanvas]:w-0",
223
- "group-data-[side=right]:rotate-180",
224
- variant === "floating" || variant === "inset"
225
- ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]"
226
- : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
227
- )}
228
- />
229
- <div
230
- data-slot="sidebar-container"
231
- className={cn(
232
- "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
233
- side === "left"
234
- ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
235
- : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
236
- // Adjust the padding for floating and inset variants.
237
- variant === "floating" || variant === "inset"
238
- ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
239
- : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
240
- className,
241
- )}
242
- {...props}
243
- >
244
- <div
245
- data-sidebar="sidebar"
246
- data-slot="sidebar-inner"
247
- className="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm"
248
- >
249
- {children}
250
- </div>
251
- </div>
252
- </div>
253
- )
254
- }
255
-
256
- function SidebarTrigger({
257
- className,
258
- onClick,
259
- ...props
260
- }: React.ComponentProps<typeof Button>) {
261
- const { toggleSidebar } = useSidebar()
262
-
263
- return (
264
- <Button
265
- data-sidebar="trigger"
266
- data-slot="sidebar-trigger"
267
- variant="ghost"
268
- size="icon"
269
- className={cn("size-7", className)}
270
- onClick={(event) => {
271
- onClick?.(event)
272
- toggleSidebar()
273
- }}
274
- {...props}
275
- >
276
- <PanelLeftIcon />
277
- <span className="sr-only">Toggle Sidebar</span>
278
- </Button>
279
- )
280
- }
281
-
282
- function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
283
- const { toggleSidebar } = useSidebar()
284
-
285
- return (
286
- <button
287
- data-sidebar="rail"
288
- data-slot="sidebar-rail"
289
- aria-label="Toggle Sidebar"
290
- tabIndex={-1}
291
- onClick={toggleSidebar}
292
- title="Toggle Sidebar"
293
- className={cn(
294
- "hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex",
295
- "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
296
- "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
297
- "hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full",
298
- "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
299
- "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
300
- className,
301
- )}
302
- {...props}
303
- />
304
- )
305
- }
306
-
307
- function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
308
- return (
309
- <main
310
- data-slot="sidebar-inset"
311
- className={cn(
312
- "bg-background relative flex w-full flex-1 flex-col",
313
- "md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
314
- className,
315
- )}
316
- {...props}
317
- />
318
- )
319
- }
320
-
321
- function SidebarInput({
322
- className,
323
- ...props
324
- }: React.ComponentProps<typeof Input>) {
325
- return (
326
- <Input
327
- data-slot="sidebar-input"
328
- data-sidebar="input"
329
- className={cn("bg-background h-8 w-full shadow-none", className)}
330
- {...props}
331
- />
332
- )
333
- }
334
-
335
- function SidebarHeader({ className, ...props }: React.ComponentProps<"div">) {
336
- return (
337
- <div
338
- data-slot="sidebar-header"
339
- data-sidebar="header"
340
- className={cn("flex flex-col gap-2 p-2", className)}
341
- {...props}
342
- />
343
- )
344
- }
345
-
346
- function SidebarFooter({ className, ...props }: React.ComponentProps<"div">) {
347
- return (
348
- <div
349
- data-slot="sidebar-footer"
350
- data-sidebar="footer"
351
- className={cn("flex flex-col gap-2 p-2", className)}
352
- {...props}
353
- />
354
- )
355
- }
356
-
357
- function SidebarSeparator({
358
- className,
359
- ...props
360
- }: React.ComponentProps<typeof Separator>) {
361
- return (
362
- <Separator
363
- data-slot="sidebar-separator"
364
- data-sidebar="separator"
365
- className={cn("bg-sidebar-border mx-2 w-auto", className)}
366
- {...props}
367
- />
368
- )
369
- }
370
-
371
- function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
372
- return (
373
- <div
374
- data-slot="sidebar-content"
375
- data-sidebar="content"
376
- className={cn(
377
- "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
378
- className,
379
- )}
380
- {...props}
381
- />
382
- )
383
- }
384
-
385
- function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
386
- return (
387
- <div
388
- data-slot="sidebar-group"
389
- data-sidebar="group"
390
- className={cn("relative flex w-full min-w-0 flex-col p-2", className)}
391
- {...props}
392
- />
393
- )
394
- }
395
-
396
- function SidebarGroupLabel({
397
- className,
398
- asChild = false,
399
- ...props
400
- }: React.ComponentProps<"div"> & { asChild?: boolean }) {
401
- const Comp = asChild ? Slot : "div"
402
-
403
- return (
404
- <Comp
405
- data-slot="sidebar-group-label"
406
- data-sidebar="group-label"
407
- className={cn(
408
- "text-muted-foreground ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 pt-2 text-xs font-semibold outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
409
- "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
410
- className,
411
- )}
412
- {...props}
413
- />
414
- )
415
- }
416
-
417
- function SidebarGroupAction({
418
- className,
419
- asChild = false,
420
- ...props
421
- }: React.ComponentProps<"button"> & { asChild?: boolean }) {
422
- const Comp = asChild ? Slot : "button"
423
-
424
- return (
425
- <Comp
426
- data-slot="sidebar-group-action"
427
- data-sidebar="group-action"
428
- className={cn(
429
- "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
430
- // Increases the hit area of the button on mobile.
431
- "after:absolute after:-inset-2 md:after:hidden",
432
- "group-data-[collapsible=icon]:hidden",
433
- className,
434
- )}
435
- {...props}
436
- />
437
- )
438
- }
439
-
440
- function SidebarGroupContent({
441
- className,
442
- ...props
443
- }: React.ComponentProps<"div">) {
444
- return (
445
- <div
446
- data-slot="sidebar-group-content"
447
- data-sidebar="group-content"
448
- className={cn("w-full text-sm", className)}
449
- {...props}
450
- />
451
- )
452
- }
453
-
454
- function SidebarMenu({ className, ...props }: React.ComponentProps<"ul">) {
455
- return (
456
- <ul
457
- data-slot="sidebar-menu"
458
- data-sidebar="menu"
459
- className={cn("flex w-full min-w-0 flex-col gap-1", className)}
460
- {...props}
461
- />
462
- )
463
- }
464
-
465
- function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
466
- return (
467
- <li
468
- data-slot="sidebar-menu-item"
469
- data-sidebar="menu-item"
470
- className={cn("group/menu-item relative", className)}
471
- {...props}
472
- />
473
- )
474
- }
475
-
476
- const sidebarMenuButtonVariants = cva(
477
- "peer/menu-button flex w-full items-center gap-3 overflow-hidden rounded-md border border-transparent px-2 text-left text-sm text-sidebar-foreground outline-hidden ring-sidebar-ring transition-colors hover:text-sidebar-accent-foreground focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:border-sidebar-border data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground data-[active=true]:shadow-lg data-[active=true]:shadow-black/4 data-[state=open]:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:opacity-70 data-[active=true]:[&>svg]:opacity-100",
478
- {
479
- variants: {
480
- variant: {
481
- default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
482
- outline:
483
- "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
484
- },
485
- size: {
486
- default: "h-9 text-sm",
487
- sm: "h-7 text-xs",
488
- lg: "h-14 text-sm group-data-[collapsible=icon]:p-0!",
489
- },
490
- },
491
- defaultVariants: {
492
- variant: "default",
493
- size: "default",
494
- },
495
- },
496
- )
497
-
498
- function SidebarMenuButton({
499
- asChild = false,
500
- isActive = false,
501
- variant = "default",
502
- size = "default",
503
- tooltip,
504
- className,
505
- ...props
506
- }: React.ComponentProps<"button"> & {
507
- asChild?: boolean
508
- isActive?: boolean
509
- tooltip?: string | React.ComponentProps<typeof TooltipContent>
510
- } & VariantProps<typeof sidebarMenuButtonVariants>) {
511
- const Comp = asChild ? Slot : "button"
512
- const { isMobile, state } = useSidebar()
513
-
514
- const button = (
515
- <Comp
516
- data-slot="sidebar-menu-button"
517
- data-sidebar="menu-button"
518
- data-size={size}
519
- data-active={isActive}
520
- className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
521
- {...props}
522
- />
523
- )
524
-
525
- if (!tooltip) {
526
- return button
527
- }
528
-
529
- if (typeof tooltip === "string") {
530
- tooltip = {
531
- children: tooltip,
532
- }
533
- }
534
-
535
- return (
536
- <Tooltip>
537
- <TooltipTrigger asChild>{button}</TooltipTrigger>
538
- <TooltipContent
539
- side="right"
540
- align="center"
541
- hidden={state !== "collapsed" || isMobile}
542
- {...tooltip}
543
- />
544
- </Tooltip>
545
- )
546
- }
547
-
548
- function SidebarMenuAction({
549
- className,
550
- asChild = false,
551
- showOnHover = false,
552
- ...props
553
- }: React.ComponentProps<"button"> & {
554
- asChild?: boolean
555
- showOnHover?: boolean
556
- }) {
557
- const Comp = asChild ? Slot : "button"
558
-
559
- return (
560
- <Comp
561
- data-slot="sidebar-menu-action"
562
- data-sidebar="menu-action"
563
- className={cn(
564
- "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
565
- // Increases the hit area of the button on mobile.
566
- "after:absolute after:-inset-2 md:after:hidden",
567
- "peer-data-[size=sm]/menu-button:top-1",
568
- "peer-data-[size=default]/menu-button:top-1.5",
569
- "peer-data-[size=lg]/menu-button:top-2.5",
570
- "group-data-[collapsible=icon]:hidden",
571
- showOnHover &&
572
- "peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0",
573
- className,
574
- )}
575
- {...props}
576
- />
577
- )
578
- }
579
-
580
- function SidebarMenuBadge({
581
- className,
582
- ...props
583
- }: React.ComponentProps<"div">) {
584
- return (
585
- <div
586
- data-slot="sidebar-menu-badge"
587
- data-sidebar="menu-badge"
588
- className={cn(
589
- "text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none",
590
- "peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
591
- "peer-data-[size=sm]/menu-button:top-1",
592
- "peer-data-[size=default]/menu-button:top-1.5",
593
- "peer-data-[size=lg]/menu-button:top-2.5",
594
- "group-data-[collapsible=icon]:hidden",
595
- className,
596
- )}
597
- {...props}
598
- />
599
- )
600
- }
601
-
602
- function SidebarMenuSkeleton({
603
- className,
604
- showIcon = false,
605
- ...props
606
- }: React.ComponentProps<"div"> & {
607
- showIcon?: boolean
608
- }) {
609
- // wrapping in useState to ensure the width is stable across renders
610
- // also ensures we have a stable reference to the style object
611
- const [skeletonStyle] = React.useState(
612
- () =>
613
- ({
614
- "--skeleton-width": `${Math.floor(Math.random() * 40) + 50}%`, // Random width between 50 to 90%.
615
- }) as React.CSSProperties,
616
- )
617
-
618
- return (
619
- <div
620
- data-slot="sidebar-menu-skeleton"
621
- data-sidebar="menu-skeleton"
622
- className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)}
623
- {...props}
624
- >
625
- {showIcon && (
626
- <Skeleton
627
- className="size-4 rounded-md"
628
- data-sidebar="menu-skeleton-icon"
629
- />
630
- )}
631
- <Skeleton
632
- className="h-4 max-w-(--skeleton-width) flex-1"
633
- data-sidebar="menu-skeleton-text"
634
- style={skeletonStyle}
635
- />
636
- </div>
637
- )
638
- }
639
-
640
- function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
641
- return (
642
- <ul
643
- data-slot="sidebar-menu-sub"
644
- data-sidebar="menu-sub"
645
- className={cn(
646
- "flex min-w-0 flex-col gap-0.5 py-0.5 pl-6",
647
- "group-data-[collapsible=icon]:hidden",
648
- className,
649
- )}
650
- {...props}
651
- />
652
- )
653
- }
654
-
655
- function SidebarMenuSubItem({
656
- className,
657
- ...props
658
- }: React.ComponentProps<"li">) {
659
- return (
660
- <li
661
- data-slot="sidebar-menu-sub-item"
662
- data-sidebar="menu-sub-item"
663
- className={cn("group/menu-sub-item relative", className)}
664
- {...props}
665
- />
666
- )
667
- }
668
-
669
- function SidebarMenuSubButton({
670
- asChild = false,
671
- size = "md",
672
- isActive = false,
673
- className,
674
- ...props
675
- }: React.ComponentProps<"a"> & {
676
- asChild?: boolean
677
- size?: "sm" | "md"
678
- isActive?: boolean
679
- }) {
680
- const Comp = asChild ? Slot : "a"
681
-
682
- return (
683
- <Comp
684
- data-slot="sidebar-menu-sub-button"
685
- data-sidebar="menu-sub-button"
686
- data-size={size}
687
- data-active={isActive}
688
- className={cn(
689
- "text-sidebar-foreground ring-sidebar-ring hover:text-sidebar-accent-foreground flex h-8 min-w-0 items-center gap-2 overflow-hidden rounded-md border border-transparent px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
690
- "data-[active=true]:border-sidebar-border data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground data-[active=true]:shadow-lg data-[active=true]:shadow-black/4",
691
- size === "sm" && "text-xs",
692
- size === "md" && "text-sm",
693
- "group-data-[collapsible=icon]:hidden",
694
- className,
695
- )}
696
- {...props}
697
- />
698
- )
699
- }
700
-
701
- export {
702
- Sidebar,
703
- SidebarContent,
704
- SidebarFooter,
705
- SidebarGroup,
706
- SidebarGroupAction,
707
- SidebarGroupContent,
708
- SidebarGroupLabel,
709
- SidebarHeader,
710
- SidebarInput,
711
- SidebarInset,
712
- SidebarMenu,
713
- SidebarMenuAction,
714
- SidebarMenuBadge,
715
- SidebarMenuButton,
716
- SidebarMenuItem,
717
- SidebarMenuSkeleton,
718
- SidebarMenuSub,
719
- SidebarMenuSubButton,
720
- SidebarMenuSubItem,
721
- SidebarProvider,
722
- SidebarRail,
723
- SidebarSeparator,
724
- SidebarTrigger,
725
- useSidebar,
726
- }