railwatch 0.6.1 → 0.7.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 (345) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/app/frontend/components/app-content.tsx +26 -0
  4. data/app/frontend/components/app-logo-icon.tsx +23 -0
  5. data/app/frontend/components/app-logo.tsx +14 -0
  6. data/app/frontend/components/app-shell.tsx +38 -0
  7. data/app/frontend/components/app-sidebar-header.tsx +54 -0
  8. data/app/frontend/components/app-sidebar.tsx +94 -0
  9. data/app/frontend/components/app-wordmark.tsx +29 -0
  10. data/app/frontend/components/breadcrumbs.tsx +46 -0
  11. data/app/frontend/components/icon.tsx +16 -0
  12. data/app/frontend/components/input-error.tsx +18 -0
  13. data/app/frontend/components/nav-footer.tsx +46 -0
  14. data/app/frontend/components/nav-main.tsx +41 -0
  15. data/app/frontend/components/nav-user.tsx +50 -0
  16. data/app/frontend/components/railwatch/chart-hover.tsx +34 -0
  17. data/app/frontend/components/railwatch/chart-panel.tsx +170 -0
  18. data/app/frontend/components/railwatch/code.tsx +28 -0
  19. data/app/frontend/components/railwatch/command-palette.tsx +132 -0
  20. data/app/frontend/components/railwatch/copy-block.tsx +52 -0
  21. data/app/frontend/components/railwatch/copy-id.tsx +49 -0
  22. data/app/frontend/components/railwatch/cursor-load-more.tsx +39 -0
  23. data/app/frontend/components/railwatch/data-table.tsx +195 -0
  24. data/app/frontend/components/railwatch/digit-roll.tsx +312 -0
  25. data/app/frontend/components/railwatch/empty-state.tsx +159 -0
  26. data/app/frontend/components/railwatch/env-nav.tsx +130 -0
  27. data/app/frontend/components/railwatch/env-switcher.tsx +145 -0
  28. data/app/frontend/components/railwatch/filter-bar.tsx +153 -0
  29. data/app/frontend/components/railwatch/flamegraph.tsx +324 -0
  30. data/app/frontend/components/railwatch/frames.tsx +295 -0
  31. data/app/frontend/components/railwatch/json-viewer.tsx +159 -0
  32. data/app/frontend/components/railwatch/live-dot.tsx +78 -0
  33. data/app/frontend/components/railwatch/live-toggle.tsx +76 -0
  34. data/app/frontend/components/railwatch/metric-chart.tsx +112 -0
  35. data/app/frontend/components/railwatch/mobile-page-switcher.tsx +89 -0
  36. data/app/frontend/components/railwatch/onboarding.tsx +91 -0
  37. data/app/frontend/components/railwatch/origin-identity.tsx +84 -0
  38. data/app/frontend/components/railwatch/page-header.tsx +42 -0
  39. data/app/frontend/components/railwatch/percentile-picker.tsx +18 -0
  40. data/app/frontend/components/railwatch/relative-time.tsx +18 -0
  41. data/app/frontend/components/railwatch/saved-views.tsx +232 -0
  42. data/app/frontend/components/railwatch/segmented.tsx +64 -0
  43. data/app/frontend/components/railwatch/series-chart.tsx +400 -0
  44. data/app/frontend/components/railwatch/shortcuts-dialog.tsx +89 -0
  45. data/app/frontend/components/railwatch/signal-toast.tsx +121 -0
  46. data/app/frontend/components/railwatch/sort-header.tsx +37 -0
  47. data/app/frontend/components/railwatch/source-link.tsx +57 -0
  48. data/app/frontend/components/railwatch/sparkline-cell.tsx +14 -0
  49. data/app/frontend/components/railwatch/sql-block.tsx +116 -0
  50. data/app/frontend/components/railwatch/stat.tsx +173 -0
  51. data/app/frontend/components/railwatch/status-badge.tsx +79 -0
  52. data/app/frontend/components/railwatch/step-picker.tsx +57 -0
  53. data/app/frontend/components/railwatch/timeline.tsx +405 -0
  54. data/app/frontend/components/railwatch/utilisation-bar.tsx +44 -0
  55. data/app/frontend/components/railwatch/window-picker.tsx +147 -0
  56. data/app/frontend/components/ui/avatar.tsx +51 -0
  57. data/app/frontend/components/ui/badge.tsx +46 -0
  58. data/app/frontend/components/ui/breadcrumb.tsx +109 -0
  59. data/app/frontend/components/ui/button.tsx +60 -0
  60. data/app/frontend/components/ui/card.tsx +92 -0
  61. data/app/frontend/components/ui/chart.tsx +374 -0
  62. data/app/frontend/components/ui/checkbox.tsx +32 -0
  63. data/app/frontend/components/ui/collapsible.tsx +31 -0
  64. data/app/frontend/components/ui/command.tsx +182 -0
  65. data/app/frontend/components/ui/dialog.tsx +158 -0
  66. data/app/frontend/components/ui/dropdown-menu.tsx +255 -0
  67. data/app/frontend/components/ui/hover-card.tsx +42 -0
  68. data/app/frontend/components/ui/input.tsx +21 -0
  69. data/app/frontend/components/ui/label.tsx +24 -0
  70. data/app/frontend/components/ui/popover.tsx +87 -0
  71. data/app/frontend/components/ui/select.tsx +185 -0
  72. data/app/frontend/components/ui/separator.tsx +28 -0
  73. data/app/frontend/components/ui/sheet.tsx +137 -0
  74. data/app/frontend/components/ui/sidebar.tsx +726 -0
  75. data/app/frontend/components/ui/skeleton.tsx +13 -0
  76. data/app/frontend/components/ui/sonner.tsx +41 -0
  77. data/app/frontend/components/ui/table.tsx +114 -0
  78. data/app/frontend/components/ui/tabs.tsx +91 -0
  79. data/app/frontend/components/ui/textarea.tsx +18 -0
  80. data/app/frontend/components/ui/tooltip.tsx +61 -0
  81. data/app/frontend/components/user-info.tsx +32 -0
  82. data/app/frontend/components/user-menu-content.tsx +94 -0
  83. data/app/frontend/entrypoints/application.css +244 -0
  84. data/app/frontend/entrypoints/inertia.tsx +95 -0
  85. data/app/frontend/fonts/CommitMono-Bold.woff2 +0 -0
  86. data/app/frontend/fonts/CommitMono-Regular.woff2 +0 -0
  87. data/app/frontend/fonts/Roboto-Black.woff2 +0 -0
  88. data/app/frontend/fonts/Roboto-Bold.woff2 +0 -0
  89. data/app/frontend/fonts/Roboto-Medium.woff2 +0 -0
  90. data/app/frontend/fonts/Roboto-Regular.woff2 +0 -0
  91. data/app/frontend/hooks/use-appearance.tsx +67 -0
  92. data/app/frontend/hooks/use-clipboard.ts +32 -0
  93. data/app/frontend/hooks/use-flash.tsx +23 -0
  94. data/app/frontend/hooks/use-hotkeys.ts +63 -0
  95. data/app/frontend/hooks/use-initials.tsx +15 -0
  96. data/app/frontend/hooks/use-live.ts +179 -0
  97. data/app/frontend/hooks/use-mobile-navigation.ts +8 -0
  98. data/app/frontend/hooks/use-mobile.ts +21 -0
  99. data/app/frontend/hooks/use-percentile.ts +24 -0
  100. data/app/frontend/hooks/use-reduced-motion.ts +25 -0
  101. data/app/frontend/hooks/use-row-nav.ts +106 -0
  102. data/app/frontend/hooks/use-step.ts +27 -0
  103. data/app/frontend/hooks/use-ticker.ts +12 -0
  104. data/app/frontend/hooks/use-window.ts +58 -0
  105. data/app/frontend/layouts/app/app-sidebar-layout.tsx +107 -0
  106. data/app/frontend/layouts/app-layout.tsx +21 -0
  107. data/app/frontend/layouts/env-layout.tsx +53 -0
  108. data/app/frontend/layouts/persistent-layout.tsx +18 -0
  109. data/app/frontend/lib/cable.ts +10 -0
  110. data/app/frontend/lib/env-pages.ts +236 -0
  111. data/app/frontend/lib/execution-path.ts +55 -0
  112. data/app/frontend/lib/explain.ts +50 -0
  113. data/app/frontend/lib/filter.ts +25 -0
  114. data/app/frontend/lib/flamegraph.ts +155 -0
  115. data/app/frontend/lib/format.ts +71 -0
  116. data/app/frontend/lib/keyboard.ts +18 -0
  117. data/app/frontend/lib/source-link.ts +217 -0
  118. data/app/frontend/lib/utils.ts +6 -0
  119. data/app/frontend/pages/alerts/index.tsx +171 -0
  120. data/app/frontend/pages/broadcasts/index.tsx +171 -0
  121. data/app/frontend/pages/cache_events/index.tsx +127 -0
  122. data/app/frontend/pages/commands/index.tsx +143 -0
  123. data/app/frontend/pages/deploys/index.tsx +94 -0
  124. data/app/frontend/pages/deploys/show.tsx +309 -0
  125. data/app/frontend/pages/deprecations/index.tsx +176 -0
  126. data/app/frontend/pages/exceptions/index.tsx +271 -0
  127. data/app/frontend/pages/executions/show.tsx +821 -0
  128. data/app/frontend/pages/issues/index.tsx +399 -0
  129. data/app/frontend/pages/issues/show.tsx +1367 -0
  130. data/app/frontend/pages/jobs/index.tsx +381 -0
  131. data/app/frontend/pages/jobs/klass.tsx +215 -0
  132. data/app/frontend/pages/llm_calls/index.tsx +664 -0
  133. data/app/frontend/pages/logs/index.tsx +303 -0
  134. data/app/frontend/pages/mails/index.tsx +218 -0
  135. data/app/frontend/pages/notifications/index.tsx +161 -0
  136. data/app/frontend/pages/outgoing_requests/index.tsx +309 -0
  137. data/app/frontend/pages/overview/show.tsx +333 -0
  138. data/app/frontend/pages/people/index.tsx +102 -0
  139. data/app/frontend/pages/people/show.tsx +149 -0
  140. data/app/frontend/pages/processes/index.tsx +335 -0
  141. data/app/frontend/pages/profiles/index.tsx +110 -0
  142. data/app/frontend/pages/profiles/show.tsx +105 -0
  143. data/app/frontend/pages/queries/index.tsx +492 -0
  144. data/app/frontend/pages/queries/show.tsx +276 -0
  145. data/app/frontend/pages/releases/index.tsx +190 -0
  146. data/app/frontend/pages/releases/release-health.tsx +68 -0
  147. data/app/frontend/pages/releases/release-path.ts +25 -0
  148. data/app/frontend/pages/releases/show.tsx +262 -0
  149. data/app/frontend/pages/requests/index.tsx +235 -0
  150. data/app/frontend/pages/requests/route.tsx +159 -0
  151. data/app/frontend/pages/scheduled_tasks/index.tsx +220 -0
  152. data/app/frontend/pages/spans/index.tsx +229 -0
  153. data/app/frontend/pages/spans/show.tsx +220 -0
  154. data/app/frontend/pages/storage_ops/index.tsx +150 -0
  155. data/app/frontend/pages/tenants/index.tsx +236 -0
  156. data/app/frontend/pages/tenants/show.tsx +477 -0
  157. data/app/frontend/pages/tenants/tenant-path.ts +26 -0
  158. data/app/frontend/pages/thresholds/index.tsx +414 -0
  159. data/app/frontend/pages/traces/show.tsx +208 -0
  160. data/app/frontend/pages/transactions/index.tsx +220 -0
  161. data/app/frontend/pages/view_renders/index.tsx +241 -0
  162. data/app/frontend/pages/visits/index.tsx +321 -0
  163. data/app/frontend/public/icon.png +0 -0
  164. data/app/frontend/public/icon.svg +5 -0
  165. data/app/frontend/routes/index.d.ts +2136 -0
  166. data/app/frontend/routes/index.js +2112 -0
  167. data/app/frontend/types/globals.d.ts +9 -0
  168. data/app/frontend/types/index.ts +288 -0
  169. data/app/frontend/types/vite-env.d.ts +9 -0
  170. data/lib/railwatch/version.rb +1 -1
  171. data/lib/railwatch.rb +8 -3
  172. data/public/railwatch/assets/app-layout-LvxN9xSS.js +41 -0
  173. data/public/railwatch/assets/application-Cc5v_Vk9.css +1 -0
  174. data/public/railwatch/assets/{arrow-up-CLQ-7heQ.js → arrow-up-DG01k9AL.js} +1 -1
  175. data/public/railwatch/assets/{braces-rSYydpLY.js → braces-C3w7pfxS.js} +1 -1
  176. data/public/railwatch/assets/{card-DPjFKfen.js → card-Dpwlr0uY.js} +1 -1
  177. data/public/railwatch/assets/{chart-DWh7l8yM.js → chart-DJHv3R7W.js} +1 -1
  178. data/public/railwatch/assets/{chart-hover-CfoZUY4J.js → chart-hover-CEH-DtXO.js} +1 -1
  179. data/public/railwatch/assets/{chart-panel-CC49WTQL.js → chart-panel-CUdIzJvk.js} +1 -1
  180. data/public/railwatch/assets/code-BRZprwun.js +1 -0
  181. data/public/railwatch/assets/copy-id-CwhGGiwF.js +1 -0
  182. data/public/railwatch/assets/cursor-load-more-uF1_955Q.js +1 -0
  183. data/public/railwatch/assets/data-table-DYi-N0hm.js +1 -0
  184. data/public/railwatch/assets/env-layout-HdcOaPPX.js +1 -0
  185. data/public/railwatch/assets/{execution-path-FAuIzOXB.js → execution-path-CElXXFO_.js} +1 -1
  186. data/public/railwatch/assets/filter-bar-DEv0G_34.js +1 -0
  187. data/public/railwatch/assets/{flamegraph-EaGkP2NT.js → flamegraph-SKD9yxW9.js} +2 -2
  188. data/public/railwatch/assets/frames-CUpyJQDy.js +1 -0
  189. data/public/railwatch/assets/index-2W-ppwap.js +1 -0
  190. data/public/railwatch/assets/index-74ocuU5d.js +1 -0
  191. data/public/railwatch/assets/{index-C8Cggnbw.js → index-B8NA62Lz.js} +2 -2
  192. data/public/railwatch/assets/index-BBCEkLqp.js +1 -0
  193. data/public/railwatch/assets/index-BDcglJzX.js +1 -0
  194. data/public/railwatch/assets/index-B_KFb9LS.js +1 -0
  195. data/public/railwatch/assets/index-BqK_VKom.js +1 -0
  196. data/public/railwatch/assets/index-BxCXBHP2.js +1 -0
  197. data/public/railwatch/assets/index-C1jc1OoH.js +1 -0
  198. data/public/railwatch/assets/index-C7zREldp.js +1 -0
  199. data/public/railwatch/assets/index-CEetm4oC.js +1 -0
  200. data/public/railwatch/assets/index-CIaZkokF.js +1 -0
  201. data/public/railwatch/assets/index-CNH85TZp.js +1 -0
  202. data/public/railwatch/assets/index-Ce4SB5AB.js +1 -0
  203. data/public/railwatch/assets/index-CiRMSYMn.js +1 -0
  204. data/public/railwatch/assets/index-CjxXgOs-.js +1 -0
  205. data/public/railwatch/assets/index-ClL-PYEV.js +1 -0
  206. data/public/railwatch/assets/index-CteZ6fop.js +1 -0
  207. data/public/railwatch/assets/index-CvqfEExO.js +1 -0
  208. data/public/railwatch/assets/index-CxTLT-Qh.js +1 -0
  209. data/public/railwatch/assets/index-DJd3OUSd.js +1 -0
  210. data/public/railwatch/assets/index-DPD-rLp6.js +1 -0
  211. data/public/railwatch/assets/index-DYK_dps4.js +1 -0
  212. data/public/railwatch/assets/index-DrayARrI.js +1 -0
  213. data/public/railwatch/assets/index-HRXGir-0.js +1 -0
  214. data/public/railwatch/assets/index-UJOUALr_.js +1 -0
  215. data/public/railwatch/assets/index-d-3J7gQ5.js +1 -0
  216. data/public/railwatch/assets/index-oQrvBpOm.js +1 -0
  217. data/public/railwatch/assets/inertia-FoqYZAk8.js +97 -0
  218. data/public/railwatch/assets/json-viewer-CxqMojEm.js +1 -0
  219. data/public/railwatch/assets/klass-DEF-Vat5.js +1 -0
  220. data/public/railwatch/assets/origin-identity-Y6gvfQVR.js +1 -0
  221. data/public/railwatch/assets/{percentile-picker-CeQgllxD.js → percentile-picker-E2aUdLxx.js} +1 -1
  222. data/public/railwatch/assets/relative-time-DcJbkKlN.js +1 -0
  223. data/public/railwatch/assets/{release-health-uP-GF3_V.js → release-health-C8WSCDKD.js} +1 -1
  224. data/public/railwatch/assets/route-qO5vX1p-.js +1 -0
  225. data/public/railwatch/assets/{segmented-BeIe4uqk.js → segmented-BWee8uc9.js} +1 -1
  226. data/public/railwatch/assets/select-G7rNBzv0.js +1 -0
  227. data/public/railwatch/assets/series-chart-C5nXIUc5.js +1 -0
  228. data/public/railwatch/assets/show-BEWisLQw.js +1 -0
  229. data/public/railwatch/assets/show-BEa9PGu1.js +2 -0
  230. data/public/railwatch/assets/{show-YsNpqbcI.js → show-BiT_Aloc.js} +3 -3
  231. data/public/railwatch/assets/show-BpCO49d3.js +1 -0
  232. data/public/railwatch/assets/show-CH7yxt7R.js +1 -0
  233. data/public/railwatch/assets/show-CTO8Lvd2.js +1 -0
  234. data/public/railwatch/assets/show-DnYsDMUt.js +2 -0
  235. data/public/railwatch/assets/show-DyzHM527.js +1 -0
  236. data/public/railwatch/assets/show-Nfpxs8su.js +1 -0
  237. data/public/railwatch/assets/show-ddjUMo9G.js +1 -0
  238. data/public/railwatch/assets/show-ksjbSzDH.js +1 -0
  239. data/public/railwatch/assets/{sort-header-mEJUM3Av.js → sort-header-uOq5VlrB.js} +1 -1
  240. data/public/railwatch/assets/{sparkline-cell-Dwg7awwh.js → sparkline-cell-DgGij0cu.js} +1 -1
  241. data/public/railwatch/assets/stat-BTzNKTm2.js +1 -0
  242. data/public/railwatch/assets/status-badge-BDkOXa-C.js +1 -0
  243. data/public/railwatch/assets/{tenant-path-CQoP-BeF.js → tenant-path-DU0ezKSU.js} +1 -1
  244. data/public/railwatch/assets/{use-clipboard-DNefo-ky.js → use-clipboard-DoENmlWY.js} +1 -1
  245. data/public/railwatch/assets/{use-live-DMTuhKfB.js → use-live-CE_fN5_6.js} +1 -1
  246. data/public/railwatch/manifest.json +612 -1591
  247. metadata +242 -117
  248. data/public/railwatch/assets/app-layout-Zc0v-hYh.js +0 -1
  249. data/public/railwatch/assets/app-wordmark-BA_60AVb.js +0 -1
  250. data/public/railwatch/assets/appearance-CcfP9tZ7.js +0 -1
  251. data/public/railwatch/assets/application-BrN3Sz94.css +0 -1
  252. data/public/railwatch/assets/auth-layout-C05gEBIQ.js +0 -1
  253. data/public/railwatch/assets/badge-DRae8XwK.js +0 -1
  254. data/public/railwatch/assets/checkbox-DPkLUiwM.js +0 -1
  255. data/public/railwatch/assets/code-CLmYS6FU.js +0 -1
  256. data/public/railwatch/assets/copy-DaQMJWoT.js +0 -1
  257. data/public/railwatch/assets/copy-block-CGcXxp8J.js +0 -1
  258. data/public/railwatch/assets/copy-id-vBYHQwxg.js +0 -1
  259. data/public/railwatch/assets/cursor-load-more-Ddwxe5dZ.js +0 -1
  260. data/public/railwatch/assets/data-table-CzKTEE-O.js +0 -1
  261. data/public/railwatch/assets/edit-B1kmWkzd.js +0 -8
  262. data/public/railwatch/assets/edit-D9cx4pbG.js +0 -1
  263. data/public/railwatch/assets/edit-yv6j9p-V.js +0 -1
  264. data/public/railwatch/assets/empty-state-CW4wclK_.js +0 -1
  265. data/public/railwatch/assets/env-layout-Kz7wks1x.js +0 -1
  266. data/public/railwatch/assets/filter-bar-CJDjWFib.js +0 -1
  267. data/public/railwatch/assets/frames-zZuIaNH9.js +0 -1
  268. data/public/railwatch/assets/google-sign-in-button-2_zgbgVy.js +0 -1
  269. data/public/railwatch/assets/index-B49SWz7K.js +0 -1
  270. data/public/railwatch/assets/index-BHlY4wKe.js +0 -1
  271. data/public/railwatch/assets/index-BZpPtyFY.js +0 -1
  272. data/public/railwatch/assets/index-BeVK6jCL.js +0 -1
  273. data/public/railwatch/assets/index-BfbSo01U.js +0 -1
  274. data/public/railwatch/assets/index-BfgncAv6.js +0 -1
  275. data/public/railwatch/assets/index-BhNszK1k.js +0 -1
  276. data/public/railwatch/assets/index-Bu01uWvw.js +0 -1
  277. data/public/railwatch/assets/index-C1s_hK3p.js +0 -1
  278. data/public/railwatch/assets/index-CBip6V4z.js +0 -1
  279. data/public/railwatch/assets/index-CMJGss5R.js +0 -1
  280. data/public/railwatch/assets/index-CRo3yK20.js +0 -1
  281. data/public/railwatch/assets/index-CWB_p2J8.js +0 -1
  282. data/public/railwatch/assets/index-CWHpndGc.js +0 -1
  283. data/public/railwatch/assets/index-Ca_S4Sc3.js +0 -1
  284. data/public/railwatch/assets/index-CanPDDOa.js +0 -1
  285. data/public/railwatch/assets/index-Cie90Yat.js +0 -1
  286. data/public/railwatch/assets/index-CiepQ_pR.js +0 -1
  287. data/public/railwatch/assets/index-Cm1uCIGN.js +0 -1
  288. data/public/railwatch/assets/index-CzitnnSC.js +0 -1
  289. data/public/railwatch/assets/index-DEUfClv3.js +0 -1
  290. data/public/railwatch/assets/index-DJKwo-mI.js +0 -1
  291. data/public/railwatch/assets/index-DK6y0YHp.js +0 -1
  292. data/public/railwatch/assets/index-DMNPpLH9.js +0 -1
  293. data/public/railwatch/assets/index-DZO1mSfX.js +0 -1
  294. data/public/railwatch/assets/index-Db5wj3M5.js +0 -1
  295. data/public/railwatch/assets/index-Dcy5WktB.js +0 -1
  296. data/public/railwatch/assets/index-DvG0-7Lx.js +0 -1
  297. data/public/railwatch/assets/index-Dvj1wuka.js +0 -1
  298. data/public/railwatch/assets/index-KyZX46qX.js +0 -1
  299. data/public/railwatch/assets/index-Ze-KP-sl.js +0 -1
  300. data/public/railwatch/assets/index-mhRbWLBM.js +0 -1
  301. data/public/railwatch/assets/index-x099JL5f.js +0 -1
  302. data/public/railwatch/assets/index-x28zb_nf.js +0 -1
  303. data/public/railwatch/assets/inertia-Cuyz2ZHO.js +0 -97
  304. data/public/railwatch/assets/input-error-hog6gGxg.js +0 -1
  305. data/public/railwatch/assets/json-viewer-DH2W9HXf.js +0 -1
  306. data/public/railwatch/assets/klass-DHbDelLk.js +0 -1
  307. data/public/railwatch/assets/label-DdCBgiUn.js +0 -1
  308. data/public/railwatch/assets/layout-Cueyl7c5.js +0 -1
  309. data/public/railwatch/assets/live-dot-BZgYTYdt.js +0 -41
  310. data/public/railwatch/assets/nav-BSSGObDZ.js +0 -1
  311. data/public/railwatch/assets/new-B8FSb8Bl.js +0 -1
  312. data/public/railwatch/assets/new-C39_v2Ll.js +0 -1
  313. data/public/railwatch/assets/new-DVOPwaC5.js +0 -1
  314. data/public/railwatch/assets/new-Dd40nvJR.js +0 -1
  315. data/public/railwatch/assets/new-SxnYe1SE.js +0 -1
  316. data/public/railwatch/assets/new-eP5vKD3Y.js +0 -1
  317. data/public/railwatch/assets/onboarding-CUpZl5KB.js +0 -1
  318. data/public/railwatch/assets/origin-identity-BYt2uiuo.js +0 -1
  319. data/public/railwatch/assets/relative-time-D5UbF4oO.js +0 -1
  320. data/public/railwatch/assets/route-DQAY8JEr.js +0 -1
  321. data/public/railwatch/assets/select-2R16457Z.js +0 -1
  322. data/public/railwatch/assets/separator-D5I0UCB5.js +0 -1
  323. data/public/railwatch/assets/series-chart-gnrzhmM6.js +0 -1
  324. data/public/railwatch/assets/show-2BkeNRUC.js +0 -2
  325. data/public/railwatch/assets/show-B0X1hRQH.js +0 -1
  326. data/public/railwatch/assets/show-BKUV5l5q.js +0 -1
  327. data/public/railwatch/assets/show-BQJD_CsF.js +0 -6
  328. data/public/railwatch/assets/show-BhmD6Sxp.js +0 -1
  329. data/public/railwatch/assets/show-C3KcnVo2.js +0 -1
  330. data/public/railwatch/assets/show-C95cHd06.js +0 -2
  331. data/public/railwatch/assets/show-CdB4uVQS.js +0 -1
  332. data/public/railwatch/assets/show-CoCqcVIp.js +0 -1
  333. data/public/railwatch/assets/show-D2LqjEsU.js +0 -1
  334. data/public/railwatch/assets/show-DNpnKyTh.js +0 -1
  335. data/public/railwatch/assets/show-DOlTxbig.js +0 -1
  336. data/public/railwatch/assets/show-DQCkttL8.js +0 -1
  337. data/public/railwatch/assets/show-DcxesipC.js +0 -1
  338. data/public/railwatch/assets/show-IGJoc_X0.js +0 -1
  339. data/public/railwatch/assets/show-qNV6H8SH.js +0 -2
  340. data/public/railwatch/assets/stat-ZtxGU8lE.js +0 -1
  341. data/public/railwatch/assets/status-badge-CH5P-Xkj.js +0 -1
  342. data/public/railwatch/assets/text-link-DHJ8BXx5.js +0 -1
  343. data/public/railwatch/assets/textarea-BeQtQyl5.js +0 -1
  344. data/public/railwatch/assets/timeline-CaKQVu48.js +0 -1
  345. data/public/railwatch/assets/transition-ksDpqhKJ.js +0 -5
@@ -0,0 +1,321 @@
1
+ import { router, usePage } from "@inertiajs/react"
2
+ import { MonitorSmartphone } from "lucide-react"
3
+
4
+ import { DurationPanel, VolumePanel } from "@/components/railwatch/chart-panel"
5
+ import { DataTable } from "@/components/railwatch/data-table"
6
+ import { EmptyState } from "@/components/railwatch/empty-state"
7
+ import { FilterBar } from "@/components/railwatch/filter-bar"
8
+ import { PageHeader } from "@/components/railwatch/page-header"
9
+ import { PercentilePicker } from "@/components/railwatch/percentile-picker"
10
+ import { SortHeader } from "@/components/railwatch/sort-header"
11
+ import { SparklineCell } from "@/components/railwatch/sparkline-cell"
12
+ import { Stat, StatStrip } from "@/components/railwatch/stat"
13
+ import { StatusBadge } from "@/components/railwatch/status-badge"
14
+ import { usePercentile } from "@/hooks/use-percentile"
15
+ import EnvLayout from "@/layouts/env-layout"
16
+ import { bytes, count, ms, pct, when } from "@/lib/format"
17
+ import * as R from "@/routes"
18
+ import type { GroupRow, SeriesPoint, SharedProps } from "@/types"
19
+
20
+ interface Visit {
21
+ id: number
22
+ component: string
23
+ url: string
24
+ method: string
25
+ duration: number
26
+ status: string
27
+ partial: boolean
28
+ only: string[]
29
+ props_bytes: number | null
30
+ occurred_at: string
31
+ user_ref: string | null
32
+ lcp: number | null
33
+ cls: number | null
34
+ inp: number | null
35
+ ttfb: number | null
36
+ }
37
+ type VitalKey = "lcp" | "cls" | "inp" | "ttfb"
38
+ interface Vital {
39
+ value: number
40
+ rating: "good" | "needs-improvement" | "poor"
41
+ samples: number
42
+ }
43
+ interface Props {
44
+ components: (GroupRow & { lcp: number | null; inp: number | null })[]
45
+ series: SeriesPoint[]
46
+ recent: Visit[]
47
+ vitals: Partial<Record<VitalKey, Vital>>
48
+ sort: string
49
+ dir: string
50
+ q: string
51
+ }
52
+
53
+ const vitalKeys: VitalKey[] = ["lcp", "cls", "inp", "ttfb"]
54
+ const vitalLabels: Record<VitalKey, string> = {
55
+ lcp: "LCP",
56
+ cls: "CLS",
57
+ inp: "INP",
58
+ ttfb: "TTFB",
59
+ }
60
+ const ratingTones = {
61
+ good: "success",
62
+ "needs-improvement": "warning",
63
+ poor: "destructive",
64
+ } as const
65
+
66
+ // cls is a unitless layout-shift score; the rest are durations.
67
+ const vitalValue = (key: VitalKey, value: number) =>
68
+ key === "cls" ? value.toFixed(2) : ms(value)
69
+
70
+ const visitVitals = (v: Visit) =>
71
+ [
72
+ v.lcp === null ? null : `LCP ${ms(v.lcp)}`,
73
+ v.inp === null ? null : `INP ${ms(v.inp)}`,
74
+ v.cls === null ? null : `CLS ${v.cls.toFixed(2)}`,
75
+ ]
76
+ .filter((part): part is string => part !== null)
77
+ .join(" · ")
78
+
79
+ export default function Visits(p: Props) {
80
+ const { environment, window } = usePage<SharedProps>().props
81
+ const { percentile } = usePercentile()
82
+ const a = environment!.application_id
83
+ const e = environment!.id
84
+
85
+ const sortBy = (field: string) =>
86
+ router.visit(
87
+ R.applicationEnvironmentVisitsPath(a, e, {
88
+ window,
89
+ sort: field,
90
+ dir: p.sort === field && p.dir === "desc" ? "asc" : "desc",
91
+ }),
92
+ { preserveState: true },
93
+ )
94
+
95
+ const measured = vitalKeys.filter((key) => p.vitals[key])
96
+
97
+ return (
98
+ <EnvLayout title="Visits">
99
+ <PageHeader
100
+ title="Inertia visits"
101
+ description="Page-load timing measured in the browser: from router start to finish, per component, with prop payload size."
102
+ actions={<PercentilePicker />}
103
+ />
104
+ {measured.length > 0 ? (
105
+ <StatStrip>
106
+ {measured.map((key) => {
107
+ const vital = p.vitals[key]!
108
+ return (
109
+ <Stat
110
+ key={key}
111
+ label={vitalLabels[key]}
112
+ value={vitalValue(key, vital.value)}
113
+ tone={ratingTones[vital.rating]}
114
+ hint={`${vital.rating} · p75 of ${count(vital.samples)}`}
115
+ />
116
+ )
117
+ })}
118
+ </StatStrip>
119
+ ) : (
120
+ <p className="text-muted-foreground text-xs">
121
+ Web vitals are reported by the browser client from the initial page
122
+ load; update app/frontend/lib/railwatch.ts from{" "}
123
+ <span className="font-mono">
124
+ bin/rails generate railwatch:install
125
+ </span>
126
+ .
127
+ </p>
128
+ )}
129
+ <div className="grid gap-4 lg:grid-cols-2">
130
+ <VolumePanel
131
+ legend="outcome"
132
+ label="Visits"
133
+ seriesLabel="Visits"
134
+ data={p.series}
135
+ />
136
+ <DurationPanel
137
+ label="Duration"
138
+ data={p.series}
139
+ percentile={percentile}
140
+ />
141
+ </div>
142
+ <DataTable
143
+ rows={p.components}
144
+ rowKey={(c) => c.group_hash}
145
+ empty={
146
+ <EmptyState
147
+ icon={MonitorSmartphone}
148
+ title="No visits yet"
149
+ description="Call startRailwatch() from your Inertia entrypoint to track page visits."
150
+ />
151
+ }
152
+ columns={[
153
+ {
154
+ key: "c",
155
+ header: "Component",
156
+ cell: (c) => <span className="font-mono text-xs">{c.name}</span>,
157
+ },
158
+ {
159
+ key: "trend",
160
+ hideOnMobile: true,
161
+ header: "Trend",
162
+ cell: (c) => <SparklineCell data={c.sparkline} />,
163
+ },
164
+ {
165
+ key: "n",
166
+ header: (
167
+ <SortHeader
168
+ label="Visits"
169
+ active={p.sort === "count"}
170
+ dir={p.dir === "asc" ? "asc" : "desc"}
171
+ onClick={() => sortBy("count")}
172
+ />
173
+ ),
174
+ align: "right",
175
+ cell: (c) => count(c.count),
176
+ },
177
+ {
178
+ key: "e",
179
+ hideOnMobile: true,
180
+ header: "Errors",
181
+ align: "right",
182
+ cell: (c) => pct(c.errors, c.count),
183
+ },
184
+ {
185
+ key: "avg",
186
+ hideOnMobile: true,
187
+ header: (
188
+ <SortHeader
189
+ label="Avg"
190
+ active={p.sort === "avg"}
191
+ dir={p.dir === "asc" ? "asc" : "desc"}
192
+ onClick={() => sortBy("avg")}
193
+ />
194
+ ),
195
+ align: "right",
196
+ cell: (c) => ms(c.avg),
197
+ },
198
+ {
199
+ key: "lcp",
200
+ hideOnMobile: true,
201
+ header: "LCP",
202
+ align: "right",
203
+ cell: (c) => ms(c.lcp),
204
+ },
205
+ {
206
+ key: "inp",
207
+ hideOnMobile: true,
208
+ header: "INP",
209
+ align: "right",
210
+ cell: (c) => ms(c.inp),
211
+ },
212
+ {
213
+ key: percentile,
214
+ header: (
215
+ <SortHeader
216
+ label={percentile}
217
+ active={p.sort === percentile}
218
+ dir={p.dir === "asc" ? "asc" : "desc"}
219
+ onClick={() => sortBy(percentile)}
220
+ />
221
+ ),
222
+ align: "right",
223
+ cell: (c) => (
224
+ <span className="font-semibold">{ms(c[percentile])}</span>
225
+ ),
226
+ },
227
+ ]}
228
+ />
229
+ <h2 className="text-sm font-semibold">Recent</h2>
230
+ <FilterBar
231
+ value={p.q}
232
+ fields={[{ key: "component", label: "Component" }]}
233
+ onChange={(q) =>
234
+ router.visit(
235
+ R.applicationEnvironmentVisitsPath(a, e, {
236
+ window,
237
+ q: q || undefined,
238
+ }),
239
+ { preserveState: true },
240
+ )
241
+ }
242
+ placeholder="component:Widgets/Show"
243
+ />
244
+ <DataTable
245
+ rows={p.recent}
246
+ rowKey={(v) => v.id}
247
+ columns={[
248
+ {
249
+ key: "when",
250
+ header: "When",
251
+ cell: (v) => <span className="text-xs">{when(v.occurred_at)}</span>,
252
+ },
253
+ {
254
+ key: "st",
255
+ header: "",
256
+ cell: (v) => (
257
+ <StatusBadge
258
+ label={v.status}
259
+ outcome={
260
+ v.status === "error"
261
+ ? "failed"
262
+ : v.status === "success"
263
+ ? "processed"
264
+ : undefined
265
+ }
266
+ />
267
+ ),
268
+ },
269
+ {
270
+ key: "c",
271
+ header: "Component",
272
+ cell: (v) => (
273
+ <span className="font-mono text-xs">
274
+ {v.component}
275
+ {v.partial && (
276
+ <span className="text-muted-foreground">
277
+ {" "}
278
+ (partial: {v.only.join(", ")})
279
+ </span>
280
+ )}
281
+ </span>
282
+ ),
283
+ },
284
+ {
285
+ key: "u",
286
+ hideOnMobile: true,
287
+ header: "URL",
288
+ cell: (v) => (
289
+ <span className="font-mono text-xs">
290
+ {v.method.toUpperCase()} {v.url}
291
+ </span>
292
+ ),
293
+ },
294
+ {
295
+ key: "v",
296
+ hideOnMobile: true,
297
+ header: "Vitals",
298
+ cell: (v) => (
299
+ <span className="text-muted-foreground font-mono text-[11px] tabular-nums">
300
+ {visitVitals(v)}
301
+ </span>
302
+ ),
303
+ },
304
+ {
305
+ key: "b",
306
+ hideOnMobile: true,
307
+ header: "Props",
308
+ align: "right",
309
+ cell: (v) => bytes(v.props_bytes),
310
+ },
311
+ {
312
+ key: "d",
313
+ header: "Duration",
314
+ align: "right",
315
+ cell: (v) => ms(v.duration),
316
+ },
317
+ ]}
318
+ />
319
+ </EnvLayout>
320
+ )
321
+ }
Binary file
@@ -0,0 +1,5 @@
1
+ <svg width="512" height="512" viewBox="0 0 1254 1254" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="1254" height="1254" rx="274" fill="#020E24"/>
3
+ <path d="M 236 324.989 L 236 404.978 496.750 405.239 L 757.500 405.500 765.665 408.577 C 777.060 412.870, 784.110 417.355, 792.381 425.574 C 833.878 466.807, 812.048 538.520, 752.263 557.363 C 737.593 561.987, 732.018 562.115, 560.250 561.798 C 471.562 561.634, 399 561.557, 399 561.626 C 399 561.695, 406.313 568.648, 415.250 577.077 C 436.108 596.747, 508.719 665.823, 525 681.483 C 612.468 765.614, 693.318 845.033, 770.500 922.639 L 840.500 993.023 951.250 993.011 C 1012.163 993.005, 1062 992.732, 1062 992.404 C 1062 992.076, 1056.942 986.113, 1050.761 979.154 C 1039.889 966.913, 1035.649 962.220, 1005.428 928.979 C 997.688 920.465, 984.624 906.075, 976.396 897 C 933.021 849.161, 888.142 799.872, 868.953 779 C 857.071 766.075, 841.562 749.200, 834.490 741.500 C 827.417 733.800, 814.456 719.721, 805.686 710.213 C 796.916 700.705, 789.994 692.673, 790.303 692.363 C 790.613 692.054, 795.578 690.983, 801.338 689.983 C 895.506 673.637, 967.601 596.363, 980.578 497.866 C 982.637 482.242, 982.086 446.289, 979.576 432.500 C 960.757 329.105, 884.022 255.740, 784.576 246.063 C 777.168 245.342, 687.144 245, 504.826 245 L 236 245 236 324.989" fill="#fff"/>
4
+ <path d="M 243.550 507.838 C 244.072 508.299, 247.425 510.859, 251 513.526 C 294.327 545.849, 358.703 617.861, 503.521 796 C 560.192 865.711, 593.994 908.954, 627.414 954.500 L 642.090 974.500 689.045 975 C 714.871 975.275, 736 975.275, 735.999 975 C 735.994 973.773, 698.564 930.428, 663.901 891.507 C 571.946 788.257, 436.131 649.261, 367.500 588.162 C 325.285 550.581, 286.033 524.106, 252.457 510.567 C 243.188 506.829, 241.991 506.462, 243.550 507.838 M 236 520 C 236 521.800, 236.667 522, 242.655 522 C 249.247 522, 249.293 521.981, 247.500 520 C 246.164 518.524, 244.420 518, 240.845 518 C 236.667 518, 236 518.275, 236 520 M 236 532.500 L 236 537 249.067 537 L 262.134 537 258.446 532.500 L 254.759 528 245.380 528 L 236 528 236 532.500 M 236 553.500 L 236 562 258.500 562 C 270.875 562, 280.991 561.663, 280.981 561.250 C 280.970 560.837, 278.237 557.013, 274.908 552.750 L 268.854 545 252.427 545 L 236 545 236 553.500 M 235.909 585 C 235.859 589.950, 235.777 595.462, 235.727 597.250 L 235.636 600.500 273.840 600.762 L 312.044 601.024 302.772 588.569 L 293.500 576.114 264.750 576.057 L 236 576 235.909 585 M 235.570 627.477 C 235.212 629.389, 234.979 637.714, 235.053 645.977 L 235.188 661 295.571 661 L 355.955 661 342.326 642.500 L 328.698 624 282.460 624 L 236.223 624 235.570 627.477 M 236 717.750 L 236 741.500 324.591 741.326 C 373.315 741.230, 413.343 740.990, 413.541 740.792 C 413.739 740.594, 406.184 729.985, 396.752 717.216 L 379.603 694 307.802 694 L 236 694 236 717.750 M 236.235 813.250 L 236.500 842.500 362.358 842.754 C 472.189 842.975, 488.146 842.822, 487.658 841.552 C 487.351 840.751, 477.621 827.475, 466.036 812.048 L 444.973 784 340.471 784 L 235.970 784 236.235 813.250 M 235.683 898.750 C 234.872 900.147, 235.511 973.844, 236.341 974.675 C 237.491 975.825, 392.185 976.287, 495.665 975.450 L 581.829 974.753 578.959 970.126 C 575.681 964.845, 552.884 930.825, 539.500 911.243 L 530.500 898.075 383.309 898.038 C 302.354 898.017, 235.922 898.337, 235.683 898.750" fill="#FFC22B"/>
5
+ </svg>