@wopr-network/platform-ui-core 1.27.8 → 1.27.9

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 (353) hide show
  1. package/next.config.ts +1 -2
  2. package/package.json +17 -17
  3. package/src/__tests__/account-switcher.test.tsx +21 -20
  4. package/src/__tests__/activity-page.test.tsx +2 -6
  5. package/src/__tests__/add-payment-method-dialog.test.tsx +9 -32
  6. package/src/__tests__/admin-api.test.ts +1 -6
  7. package/src/__tests__/admin-gpu-api.test.ts +1 -3
  8. package/src/__tests__/admin-marketplace-api.test.ts +1 -4
  9. package/src/__tests__/admin-middleware.test.ts +76 -83
  10. package/src/__tests__/affiliate-dashboard.test.tsx +3 -3
  11. package/src/__tests__/api-401-redirect.test.ts +46 -9
  12. package/src/__tests__/api-client.test.ts +3 -5
  13. package/src/__tests__/api-config.test.ts +22 -42
  14. package/src/__tests__/api-fleet-resources.test.ts +1 -2
  15. package/src/__tests__/api-fleet-trpc.test.ts +2 -8
  16. package/src/__tests__/api-null-guards.test.ts +3 -1
  17. package/src/__tests__/audit-log-table-pagination.test.tsx +2 -6
  18. package/src/__tests__/auth-password-reset.test.tsx +7 -21
  19. package/src/__tests__/auth-redirect.test.tsx +8 -2
  20. package/src/__tests__/auth.test.tsx +25 -23
  21. package/src/__tests__/auto-topup-card.test.tsx +4 -12
  22. package/src/__tests__/backups-tab.test.tsx +3 -4
  23. package/src/__tests__/billing-layout-nav-hidden.test.tsx +5 -37
  24. package/src/__tests__/billing-payment-org-invoices.test.tsx +2 -18
  25. package/src/__tests__/billing.test.tsx +8 -39
  26. package/src/__tests__/bot-settings/resources-tab.test.tsx +1 -3
  27. package/src/__tests__/bot-settings/storage-tab.test.tsx +1 -3
  28. package/src/__tests__/bot-settings/vps-upgrade-card.test.tsx +1 -3
  29. package/src/__tests__/bot-settings-restart.test.tsx +1 -3
  30. package/src/__tests__/bot-settings.test.tsx +2 -6
  31. package/src/__tests__/brand.test.ts +6 -26
  32. package/src/__tests__/buy-credits-panel.test.tsx +1 -3
  33. package/src/__tests__/buy-crypto-credits-panel.test.tsx +101 -119
  34. package/src/__tests__/capability-conflicts.test.ts +2 -8
  35. package/src/__tests__/capability-resolver.test.tsx +2 -12
  36. package/src/__tests__/channel-wizard.test.tsx +4 -17
  37. package/src/__tests__/chat/chat-panel.test.tsx +1 -4
  38. package/src/__tests__/chat-store.test.ts +5 -15
  39. package/src/__tests__/command-center.test.tsx +10 -12
  40. package/src/__tests__/compliance-retention-edit.test.tsx +3 -6
  41. package/src/__tests__/confirmation-tracker.test.tsx +3 -18
  42. package/src/__tests__/coupon-input.test.tsx +1 -3
  43. package/src/__tests__/create-instance.test.tsx +1 -3
  44. package/src/__tests__/credit-balance.test.tsx +4 -12
  45. package/src/__tests__/credits.test.tsx +32 -85
  46. package/src/__tests__/email-verification-banner.test.tsx +2 -6
  47. package/src/__tests__/error-boundaries.test.tsx +0 -1
  48. package/src/__tests__/fetch-pricing.test.ts +2 -1
  49. package/src/__tests__/field-oauth.test.tsx +2 -6
  50. package/src/__tests__/fixtures/mock-manifests-data.js +1 -3
  51. package/src/__tests__/fixtures/mock-manifests.ts +2 -4
  52. package/src/__tests__/fleet-health-timestamp.test.tsx +1 -8
  53. package/src/__tests__/fleet-health-update.test.tsx +1 -8
  54. package/src/__tests__/gpu-dashboard.test.tsx +2 -6
  55. package/src/__tests__/instance-detail.test.tsx +3 -9
  56. package/src/__tests__/instance-list.test.tsx +1 -5
  57. package/src/__tests__/layout-snapshots.test.tsx +64 -11
  58. package/src/__tests__/marketplace-admin.test.tsx +2 -6
  59. package/src/__tests__/marketplace.test.tsx +11 -35
  60. package/src/__tests__/merge-api-rates.test.ts +1 -6
  61. package/src/__tests__/middleware.test.ts +32 -219
  62. package/src/__tests__/next-config-headers.test.ts +1 -3
  63. package/src/__tests__/notifications.test.tsx +4 -11
  64. package/src/__tests__/oauth-buttons.test.tsx +36 -59
  65. package/src/__tests__/oauth-error-mapping.test.tsx +2 -6
  66. package/src/__tests__/observability.test.tsx +23 -36
  67. package/src/__tests__/onboarding-page.test.tsx +4 -6
  68. package/src/__tests__/org-billing-api.test.tsx +1 -6
  69. package/src/__tests__/plugin-install-flow.test.tsx +28 -58
  70. package/src/__tests__/plugin-registry.test.tsx +3 -11
  71. package/src/__tests__/plugin-tool-sync.test.ts +1 -3
  72. package/src/__tests__/plugins-catalog-error.test.tsx +2 -6
  73. package/src/__tests__/plugins-toggle-race.test.tsx +3 -5
  74. package/src/__tests__/portfolio-chart.test.tsx +2 -6
  75. package/src/__tests__/promotion-form.test.tsx +2 -6
  76. package/src/__tests__/promotions-list.test.tsx +1 -3
  77. package/src/__tests__/provider-key-api.test.ts +2 -1
  78. package/src/__tests__/resend-verification-button.test.tsx +8 -24
  79. package/src/__tests__/secrets-audit-pagination.test.tsx +1 -3
  80. package/src/__tests__/settings.test.tsx +11 -21
  81. package/src/__tests__/setup-checklist.test.tsx +3 -9
  82. package/src/__tests__/setup.ts +25 -6
  83. package/src/__tests__/snapshot-api.test.ts +2 -1
  84. package/src/__tests__/step-superpowers.test.tsx +1 -3
  85. package/src/__tests__/tenant-context.test.tsx +1 -6
  86. package/src/__tests__/tenant-keys-api.test.ts +3 -4
  87. package/src/__tests__/tenant-table-pagination.test.tsx +2 -6
  88. package/src/__tests__/terminal-log-cleanup.test.tsx +0 -1
  89. package/src/__tests__/transaction-history.test.tsx +190 -238
  90. package/src/__tests__/trpc-types.test.ts +2 -6
  91. package/src/__tests__/use-chat.test.ts +1 -3
  92. package/src/__tests__/use-plugin-setup-chat-stale-closure.test.ts +1 -4
  93. package/src/__tests__/use-sidecar-bridge.test.tsx +105 -0
  94. package/src/__tests__/use-webmcp.test.ts +1 -3
  95. package/src/__tests__/validate-elevenlabs-key.test.ts +2 -1
  96. package/src/__tests__/verify-page.test.tsx +4 -13
  97. package/src/__tests__/verify-redirect.test.tsx +2 -6
  98. package/src/app/(auth)/error.tsx +1 -7
  99. package/src/app/(auth)/forgot-password/page.tsx +4 -18
  100. package/src/app/(auth)/login/page.tsx +5 -22
  101. package/src/app/(auth)/reset-password/page.tsx +2 -12
  102. package/src/app/(auth)/signup/page.tsx +10 -44
  103. package/src/app/(auth)/verify/page.tsx +47 -0
  104. package/src/app/(dashboard)/billing/credits/page.tsx +14 -67
  105. package/src/app/(dashboard)/billing/error.tsx +2 -10
  106. package/src/app/(dashboard)/billing/layout.tsx +12 -62
  107. package/src/app/(dashboard)/billing/payment/page.tsx +17 -68
  108. package/src/app/(dashboard)/billing/plans/page.tsx +3 -9
  109. package/src/app/(dashboard)/billing/usage/hosted/page.tsx +8 -25
  110. package/src/app/(dashboard)/billing/usage/page.tsx +63 -103
  111. package/src/app/(dashboard)/changesets/[id]/changeset-detail-client.tsx +9 -27
  112. package/src/app/(dashboard)/changesets/[id]/error.tsx +2 -6
  113. package/src/app/(dashboard)/changesets/error.tsx +1 -7
  114. package/src/app/(dashboard)/chat/page.tsx +2 -6
  115. package/src/app/(dashboard)/dashboard/network/page.tsx +5 -19
  116. package/src/app/(dashboard)/error.tsx +1 -7
  117. package/src/app/(dashboard)/layout.tsx +15 -36
  118. package/src/app/(dashboard)/marketplace/[plugin]/page.tsx +14 -51
  119. package/src/app/(dashboard)/marketplace/error.tsx +1 -7
  120. package/src/app/(dashboard)/marketplace/page.tsx +6 -27
  121. package/src/app/(dashboard)/not-found.tsx +2 -5
  122. package/src/app/(dashboard)/onboarding/page.tsx +5 -22
  123. package/src/app/(dashboard)/settings/account/page.tsx +1 -6
  124. package/src/app/(dashboard)/settings/activity/page.tsx +8 -34
  125. package/src/app/(dashboard)/settings/api-keys/page.tsx +15 -60
  126. package/src/app/(dashboard)/settings/brain/page.tsx +9 -31
  127. package/src/app/(dashboard)/settings/error.tsx +2 -10
  128. package/src/app/(dashboard)/settings/notifications/page.tsx +2 -6
  129. package/src/app/(dashboard)/settings/org/page.tsx +13 -56
  130. package/src/app/(dashboard)/settings/page.tsx +1 -0
  131. package/src/app/(dashboard)/settings/profile/page.tsx +126 -73
  132. package/src/app/(dashboard)/settings/providers/page.tsx +21 -78
  133. package/src/app/(dashboard)/settings/secrets/page.tsx +13 -58
  134. package/src/app/(dashboard)/settings/security/page.tsx +31 -111
  135. package/src/app/admin/email-templates/email-templates-client.tsx +15 -58
  136. package/src/app/admin/error.tsx +1 -7
  137. package/src/app/admin/fleet-updates/error.tsx +1 -7
  138. package/src/app/admin/fleet-updates/fleet-updates-client.tsx +10 -50
  139. package/src/app/admin/layout.tsx +4 -0
  140. package/src/app/admin/payment-methods/page.tsx +9 -38
  141. package/src/app/admin/products/error.tsx +2 -7
  142. package/src/app/admin/products/page.tsx +1 -4
  143. package/src/app/admin/promotions/[id]/page.tsx +9 -38
  144. package/src/app/admin/promotions/page.tsx +9 -36
  145. package/src/app/admin/rate-overrides/page.tsx +9 -45
  146. package/src/app/auth/callback/[provider]/page.tsx +1 -8
  147. package/src/app/auth/verify/page.tsx +9 -36
  148. package/src/app/channels/error.tsx +2 -10
  149. package/src/app/channels/layout.tsx +9 -0
  150. package/src/app/channels/page.tsx +8 -20
  151. package/src/app/channels/setup/[plugin]/page.tsx +3 -5
  152. package/src/app/error.tsx +1 -7
  153. package/src/app/fleet/error.tsx +1 -7
  154. package/src/app/fleet/layout.tsx +5 -0
  155. package/src/app/fleet/settings/page.tsx +1 -3
  156. package/src/app/global-error.tsx +2 -10
  157. package/src/app/globals.css +1 -4
  158. package/src/app/instances/[id]/instance-detail-client.tsx +51 -125
  159. package/src/app/instances/error.tsx +2 -10
  160. package/src/app/instances/instance-list-client.tsx +20 -69
  161. package/src/app/instances/layout.tsx +9 -0
  162. package/src/app/instances/new/create-instance-client.tsx +10 -31
  163. package/src/app/layout.tsx +2 -10
  164. package/src/app/not-found.tsx +1 -3
  165. package/src/app/page.tsx +1 -2
  166. package/src/app/plugins/error.tsx +2 -10
  167. package/src/app/plugins/layout.tsx +5 -0
  168. package/src/app/plugins/page.tsx +16 -48
  169. package/src/app/pricing/error.tsx +1 -7
  170. package/src/app/privacy/page.tsx +93 -150
  171. package/src/app/status/error.tsx +1 -7
  172. package/src/app/terms/page.tsx +89 -144
  173. package/src/components/account-switcher.tsx +25 -52
  174. package/src/components/admin/accounting-dashboard.tsx +1 -3
  175. package/src/components/admin/admin-guard.tsx +1 -3
  176. package/src/components/admin/admin-nav.tsx +1 -3
  177. package/src/components/admin/affiliate-dashboard.tsx +25 -94
  178. package/src/components/admin/audit-log-table.tsx +13 -49
  179. package/src/components/admin/billing-health-dashboard.tsx +7 -25
  180. package/src/components/admin/bulk-actions-bar.test.tsx +1 -7
  181. package/src/components/admin/bulk-actions-bar.tsx +1 -3
  182. package/src/components/admin/bulk-export-dialog.test.tsx +1 -7
  183. package/src/components/admin/bulk-export-dialog.tsx +6 -32
  184. package/src/components/admin/bulk-grant-dialog.test.tsx +2 -6
  185. package/src/components/admin/bulk-grant-dialog.tsx +4 -15
  186. package/src/components/admin/bulk-preview-dialog.tsx +3 -12
  187. package/src/components/admin/bulk-reactivate-dialog.tsx +1 -7
  188. package/src/components/admin/bulk-select-all-banner.tsx +1 -6
  189. package/src/components/admin/bulk-suspend-dialog.tsx +5 -12
  190. package/src/components/admin/bulk-undo-toast.tsx +1 -2
  191. package/src/components/admin/compliance-dashboard.tsx +31 -101
  192. package/src/components/admin/gpu-dashboard.tsx +21 -70
  193. package/src/components/admin/grant-credits-dialog.tsx +4 -17
  194. package/src/components/admin/incident-dashboard.tsx +10 -25
  195. package/src/components/admin/inference-dashboard.tsx +14 -54
  196. package/src/components/admin/marketplace-admin.tsx +18 -60
  197. package/src/components/admin/migrations-dashboard.tsx +9 -42
  198. package/src/components/admin/onboarding-dashboard.tsx +14 -64
  199. package/src/components/admin/pool-config-dashboard.tsx +4 -10
  200. package/src/components/admin/products/fleet-form.tsx +2 -11
  201. package/src/components/admin/products/nav-editor.tsx +3 -10
  202. package/src/components/admin/promotions/promotion-form.tsx +9 -42
  203. package/src/components/admin/roles-dashboard.tsx +7 -34
  204. package/src/components/admin/suspend-dialog.tsx +4 -11
  205. package/src/components/admin/tenant-notes-panel.tsx +1 -3
  206. package/src/components/admin/tenant-row-actions.tsx +4 -20
  207. package/src/components/admin/tenant-table.tsx +12 -49
  208. package/src/components/auth/auth-redirect.tsx +11 -3
  209. package/src/components/auth/email-verification-result-banner.tsx +1 -3
  210. package/src/components/auth/resend-verification-button.tsx +2 -10
  211. package/src/components/auth/wopr-wordmark.tsx +1 -3
  212. package/src/components/billing/add-payment-method-dialog.tsx +1 -2
  213. package/src/components/billing/affiliate-dashboard.tsx +4 -16
  214. package/src/components/billing/amount-selector.tsx +1 -3
  215. package/src/components/billing/auto-topup-card.tsx +2 -11
  216. package/src/components/billing/buy-credits-panel.tsx +4 -14
  217. package/src/components/billing/byok-callout.tsx +6 -8
  218. package/src/components/billing/confirmation-tracker.tsx +4 -14
  219. package/src/components/billing/credit-balance-badge.tsx +22 -0
  220. package/src/components/billing/credit-balance.tsx +3 -9
  221. package/src/components/billing/crypto-checkout.tsx +5 -24
  222. package/src/components/billing/degraded-state-banner.tsx +1 -3
  223. package/src/components/billing/deposit-view.tsx +301 -41
  224. package/src/components/billing/dividend-banner.tsx +1 -3
  225. package/src/components/billing/dividend-eligibility.tsx +3 -12
  226. package/src/components/billing/dividend-pool-stats.tsx +6 -20
  227. package/src/components/billing/first-dividend-dialog.tsx +2 -2
  228. package/src/components/billing/org-billing-page.tsx +8 -31
  229. package/src/components/billing/payment-method-picker.tsx +2 -10
  230. package/src/components/billing/suspension-banner.tsx +2 -7
  231. package/src/components/billing/transaction-history.tsx +10 -58
  232. package/src/components/billing/unified-checkout.tsx +547 -0
  233. package/src/components/bot-settings/backups-tab.tsx +9 -33
  234. package/src/components/bot-settings/bot-settings-client.tsx +32 -134
  235. package/src/components/bot-settings/resources-tab.tsx +2 -9
  236. package/src/components/bot-settings/storage-tab.tsx +19 -48
  237. package/src/components/bot-settings/vps-info-panel.tsx +3 -11
  238. package/src/components/bot-settings/vps-upgrade-card.tsx +3 -4
  239. package/src/components/brand-hydrator.tsx +13 -0
  240. package/src/components/channel-wizard/field-interactive.tsx +1 -3
  241. package/src/components/channel-wizard/field-qr.tsx +10 -39
  242. package/src/components/channel-wizard/step-renderer.tsx +5 -28
  243. package/src/components/channel-wizard/wizard.tsx +6 -31
  244. package/src/components/chat/chat-message.tsx +1 -4
  245. package/src/components/chat/chat-panel.tsx +4 -18
  246. package/src/components/chat/chat-widget.tsx +3 -14
  247. package/src/components/dashboard/command-center.tsx +15 -61
  248. package/src/components/fleet/update-settings-card.tsx +7 -23
  249. package/src/components/instance-update-banner.tsx +130 -0
  250. package/src/components/instances/friends-tab.test.tsx +2 -9
  251. package/src/components/instances/friends-tab.tsx +18 -74
  252. package/src/components/instances/update-available-badge.tsx +2 -11
  253. package/src/components/landing/hero.tsx +3 -9
  254. package/src/components/landing/landing-page.tsx +1 -3
  255. package/src/components/landing/portfolio-chart.tsx +4 -9
  256. package/src/components/landing/story-sections.tsx +1 -3
  257. package/src/components/landing/terminal-sequence.tsx +4 -17
  258. package/src/components/marketplace/empty-state.tsx +2 -6
  259. package/src/components/marketplace/first-visit-hero.tsx +1 -3
  260. package/src/components/marketplace/install-wizard.tsx +20 -77
  261. package/src/components/marketplace/marketplace-tabs.tsx +1 -4
  262. package/src/components/marketplace/plugin-card.tsx +2 -9
  263. package/src/components/marketplace/superpower-content.tsx +1 -3
  264. package/src/components/marketplace/terminal-search.tsx +2 -8
  265. package/src/components/oauth-buttons.tsx +29 -14
  266. package/src/components/observability/fleet-health.tsx +5 -18
  267. package/src/components/observability/health-overview.tsx +7 -20
  268. package/src/components/observability/logs-viewer.tsx +8 -32
  269. package/src/components/observability/metrics-dashboard.tsx +2 -15
  270. package/src/components/onboarding/fallback-setup.tsx +6 -25
  271. package/src/components/onboarding/setup-checklist.tsx +18 -51
  272. package/src/components/onboarding/step-superpowers.tsx +1 -4
  273. package/src/components/plugin-setup/setup-chat-panel.tsx +6 -22
  274. package/src/components/pricing/dividend-calculator.tsx +6 -12
  275. package/src/components/pricing/dividend-stats.tsx +5 -17
  276. package/src/components/pricing/pricing-page.tsx +17 -36
  277. package/src/components/settings/create-org-wizard.tsx +2 -5
  278. package/src/components/sidebar.tsx +7 -42
  279. package/src/components/sidecar-frame.tsx +78 -0
  280. package/src/components/status/status-page.tsx +6 -28
  281. package/src/components/ui/alert-dialog.tsx +8 -25
  282. package/src/components/ui/badge.tsx +2 -8
  283. package/src/components/ui/banner.tsx +1 -6
  284. package/src/components/ui/card.tsx +5 -24
  285. package/src/components/ui/checkbox.tsx +1 -5
  286. package/src/components/ui/collapsible.tsx +3 -8
  287. package/src/components/ui/dialog.tsx +4 -10
  288. package/src/components/ui/dropdown-menu.tsx +9 -18
  289. package/src/components/ui/form.tsx +2 -16
  290. package/src/components/ui/popover.tsx +3 -23
  291. package/src/components/ui/progress.tsx +1 -5
  292. package/src/components/ui/radio-group.tsx +3 -15
  293. package/src/components/ui/select.tsx +4 -17
  294. package/src/components/ui/sheet.tsx +5 -19
  295. package/src/components/ui/skeleton.tsx +1 -7
  296. package/src/components/ui/table.tsx +5 -22
  297. package/src/components/ui/tabs.tsx +3 -13
  298. package/src/components/ui/tooltip.tsx +1 -1
  299. package/src/components/unified-sidebar.tsx +493 -0
  300. package/src/hooks/__tests__/use-fleet-sse.test.ts +1 -4
  301. package/src/hooks/__tests__/use-save-queue.test.ts +2 -8
  302. package/src/hooks/use-credit-balance.ts +27 -0
  303. package/src/hooks/use-my-org-role.ts +1 -3
  304. package/src/hooks/use-plugin-registry.ts +8 -14
  305. package/src/hooks/use-plugin-setup-chat.ts +2 -5
  306. package/src/hooks/use-sidecar-bridge.tsx +148 -0
  307. package/src/hooks/use-webmcp.ts +1 -4
  308. package/src/lib/__tests__/admin-api.test.ts +1 -3
  309. package/src/lib/__tests__/api-bot-crud.test.ts +8 -18
  310. package/src/lib/__tests__/api-fetch.test.ts +4 -16
  311. package/src/lib/__tests__/org-billing-api.test.ts +1 -3
  312. package/src/lib/__tests__/pricing-data.test.ts +0 -8
  313. package/src/lib/__tests__/settings-api.test.ts +1 -3
  314. package/src/lib/admin-affiliate-api.ts +2 -7
  315. package/src/lib/admin-api.ts +6 -26
  316. package/src/lib/admin-incident-api.ts +11 -19
  317. package/src/lib/admin-marketplace-api.ts +1 -5
  318. package/src/lib/api-config.test.ts +5 -50
  319. package/src/lib/api.ts +143 -122
  320. package/src/lib/auth-client.ts +1 -2
  321. package/src/lib/bot-settings-data.ts +11 -36
  322. package/src/lib/brand-config.ts +56 -115
  323. package/src/lib/brand.ts +2 -15
  324. package/src/lib/chat/use-chat.ts +2 -7
  325. package/src/lib/cost-comparison-data.test.ts +1 -3
  326. package/src/lib/cost-comparison-data.ts +1 -4
  327. package/src/lib/errors.ts +1 -4
  328. package/src/lib/fetch-utils.test.ts +26 -9
  329. package/src/lib/fetch-utils.ts +40 -11
  330. package/src/lib/logger.ts +2 -0
  331. package/src/lib/marketplace-data.ts +3 -11
  332. package/src/lib/oauth-errors.ts +2 -4
  333. package/src/lib/onboarding-data.ts +3 -11
  334. package/src/lib/org-api.ts +2 -10
  335. package/src/lib/org-billing-api.ts +5 -19
  336. package/src/lib/plugin/tool-definitions.ts +1 -2
  337. package/src/lib/require-auth.ts +57 -0
  338. package/src/lib/settings-api.ts +1 -4
  339. package/src/lib/sidecar-routes.ts +43 -0
  340. package/src/lib/trpc-server.ts +49 -0
  341. package/src/lib/trpc-types.ts +4 -6
  342. package/src/lib/trpc.tsx +12 -4
  343. package/src/lib/validate-redirect-url.ts +1 -4
  344. package/src/lib/webmcp/marketplace-onboarding-tools.ts +6 -16
  345. package/src/lib/webmcp/register.ts +1 -4
  346. package/src/lib/webmcp/tools.ts +2 -9
  347. package/src/proxy.ts +35 -212
  348. package/src/types/missing-deps.d.ts +2 -8
  349. package/tsconfig.json +1 -8
  350. package/biome.json +0 -52
  351. package/src/__tests__/__snapshots__/layout-snapshots.test.tsx.snap +0 -741
  352. package/src/__tests__/billing-byok-callout.test.tsx +0 -76
  353. package/src/lib/__tests__/__snapshots__/pricing-data.test.ts.snap +0 -112
@@ -3,28 +3,10 @@
3
3
  import { motion } from "framer-motion";
4
4
  import { Check } from "lucide-react";
5
5
  import { useCallback, useEffect, useRef, useState } from "react";
6
- import {
7
- Area,
8
- AreaChart,
9
- CartesianGrid,
10
- ResponsiveContainer,
11
- Tooltip,
12
- XAxis,
13
- YAxis,
14
- } from "recharts";
6
+ import { Area, AreaChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
15
7
  import { Button } from "@/components/ui/button";
16
- import type {
17
- CacheStats,
18
- DailyCostAggregate,
19
- PageCostAggregate,
20
- SessionCostSummary,
21
- } from "@/lib/admin-inference-api";
22
- import {
23
- getCacheStats,
24
- getDailyCost,
25
- getPageCost,
26
- getSessionCost,
27
- } from "@/lib/admin-inference-api";
8
+ import type { CacheStats, DailyCostAggregate, PageCostAggregate, SessionCostSummary } from "@/lib/admin-inference-api";
9
+ import { getCacheStats, getDailyCost, getPageCost, getSessionCost } from "@/lib/admin-inference-api";
28
10
  import { cn } from "@/lib/utils";
29
11
 
30
12
  // ---- Time ranges ----
@@ -88,9 +70,7 @@ function KpiCard({ label, value, subtext, valueClassName, loading, index }: KpiC
88
70
  {loading ? (
89
71
  <div className="h-8 w-24 bg-muted animate-pulse rounded-sm" />
90
72
  ) : (
91
- <div className={`text-2xl font-bold tabular-nums ${valueClassName ?? "text-foreground"}`}>
92
- {value}
93
- </div>
73
+ <div className={`text-2xl font-bold tabular-nums ${valueClassName ?? "text-foreground"}`}>{value}</div>
94
74
  )}
95
75
  {subtext && <div className="text-xs text-muted-foreground mt-1">{subtext}</div>}
96
76
  </motion.div>
@@ -112,9 +92,7 @@ function ChartTooltip({
112
92
  return (
113
93
  <div className="bg-card border border-terminal/30 rounded-sm shadow-lg shadow-terminal/5 px-3 py-2">
114
94
  <div className="text-xs text-muted-foreground">{label}</div>
115
- <div className="text-sm font-bold tabular-nums text-foreground">
116
- ${payload[0].value.toFixed(4)}
117
- </div>
95
+ <div className="text-sm font-bold tabular-nums text-foreground">${payload[0].value.toFixed(4)}</div>
118
96
  </div>
119
97
  );
120
98
  }
@@ -198,9 +176,7 @@ export function InferenceDashboard() {
198
176
 
199
177
  {/* Error state */}
200
178
  {error && (
201
- <div className="mx-6 p-4 bg-card border border-destructive/30 rounded-sm text-destructive text-sm">
202
- {error}
203
- </div>
179
+ <div className="mx-6 p-4 bg-card border border-destructive/30 rounded-sm text-destructive text-sm">{error}</div>
204
180
  )}
205
181
 
206
182
  {/* KPI Cards */}
@@ -247,9 +223,7 @@ export function InferenceDashboard() {
247
223
  transition={{ duration: 0.4, delay: 0.2, ease: "easeOut" }}
248
224
  className="mx-6 bg-card border border-border rounded-sm p-4"
249
225
  >
250
- <div className="text-xs uppercase tracking-widest text-muted-foreground mb-3">
251
- DAILY COST
252
- </div>
226
+ <div className="text-xs uppercase tracking-widest text-muted-foreground mb-3">DAILY COST</div>
253
227
  {loading ? (
254
228
  <div className="h-[280px] bg-muted/20 animate-pulse rounded-sm" />
255
229
  ) : dailyCost.length === 0 ? (
@@ -294,9 +268,7 @@ export function InferenceDashboard() {
294
268
  <div className="grid grid-cols-1 xl:grid-cols-2 gap-4 px-6 pb-6">
295
269
  {/* Page Cost Table */}
296
270
  <div className="bg-card border border-border rounded-sm p-4">
297
- <div className="text-xs uppercase tracking-widest text-muted-foreground mb-3">
298
- COST BY PAGE
299
- </div>
271
+ <div className="text-xs uppercase tracking-widest text-muted-foreground mb-3">COST BY PAGE</div>
300
272
  {loading ? (
301
273
  <div className="space-y-3">
302
274
  {["sk-1", "sk-2", "sk-3", "sk-4", "sk-5"].map((id) => (
@@ -320,14 +292,10 @@ export function InferenceDashboard() {
320
292
  >
321
293
  <div className="flex-1 text-sm font-medium">{p.page || "/unknown"}</div>
322
294
  <div className="w-20 text-right tabular-nums text-sm">{p.callCount}</div>
323
- <div className="w-24 text-right tabular-nums text-sm">
324
- ${p.avgCostUsd.toFixed(4)}
325
- </div>
295
+ <div className="w-24 text-right tabular-nums text-sm">${p.avgCostUsd.toFixed(4)}</div>
326
296
  <div
327
297
  className={`w-24 text-right tabular-nums text-sm font-medium ${
328
- p.totalCostUsd === maxPageCost && maxPageCost > 0
329
- ? "text-amber-400"
330
- : "text-foreground"
298
+ p.totalCostUsd === maxPageCost && maxPageCost > 0 ? "text-amber-400" : "text-foreground"
331
299
  }`}
332
300
  >
333
301
  ${p.totalCostUsd.toFixed(4)}
@@ -340,9 +308,7 @@ export function InferenceDashboard() {
340
308
 
341
309
  {/* Cache Performance Panel */}
342
310
  <div className="bg-card border border-border rounded-sm p-4">
343
- <div className="text-xs uppercase tracking-widest text-muted-foreground mb-3">
344
- CACHE PERFORMANCE
345
- </div>
311
+ <div className="text-xs uppercase tracking-widest text-muted-foreground mb-3">CACHE PERFORMANCE</div>
346
312
  {loading ? (
347
313
  <div className="space-y-4">
348
314
  <div className="h-10 w-24 bg-muted animate-pulse rounded-sm" />
@@ -353,9 +319,7 @@ export function InferenceDashboard() {
353
319
  <div className="text-4xl font-bold text-terminal tabular-nums">
354
320
  {((cacheStats?.hitRate ?? 0) * 100).toFixed(1)}%
355
321
  </div>
356
- <div className="text-xs text-muted-foreground mb-4">
357
- of input tokens served from cache
358
- </div>
322
+ <div className="text-xs text-muted-foreground mb-4">of input tokens served from cache</div>
359
323
 
360
324
  {/* Hit rate bar */}
361
325
  <div className="relative mb-4">
@@ -373,9 +337,7 @@ export function InferenceDashboard() {
373
337
  style={{ left: "60%" }}
374
338
  >
375
339
  TARGET: 60%
376
- {(cacheStats?.hitRate ?? 0) >= 0.6 && (
377
- <Check className="text-terminal" size={10} />
378
- )}
340
+ {(cacheStats?.hitRate ?? 0) >= 0.6 && <Check className="text-terminal" size={10} />}
379
341
  </div>
380
342
  </div>
381
343
 
@@ -402,9 +364,7 @@ export function InferenceDashboard() {
402
364
  </div>
403
365
 
404
366
  {(cacheStats?.hitRate ?? 0) === 0 && (
405
- <div className="text-xs text-muted-foreground mt-4">
406
- Awaiting first cached request
407
- </div>
367
+ <div className="text-xs text-muted-foreground mt-4">Awaiting first cached request</div>
408
368
  )}
409
369
  </>
410
370
  )}
@@ -18,14 +18,7 @@ import {
18
18
  import { Input } from "@/components/ui/input";
19
19
  import { Skeleton } from "@/components/ui/skeleton";
20
20
  import { Switch } from "@/components/ui/switch";
21
- import {
22
- Table,
23
- TableBody,
24
- TableCell,
25
- TableHead,
26
- TableHeader,
27
- TableRow,
28
- } from "@/components/ui/table";
21
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
29
22
  import { Textarea } from "@/components/ui/textarea";
30
23
  import {
31
24
  type AdminPlugin,
@@ -352,9 +345,7 @@ export function MarketplaceAdmin() {
352
345
  <DialogContent>
353
346
  <DialogHeader>
354
347
  <DialogTitle>Add Plugin by npm Package</DialogTitle>
355
- <DialogDescription>
356
- Paste the npm package name to add it to the discovery queue.
357
- </DialogDescription>
348
+ <DialogDescription>Paste the npm package name to add it to the discovery queue.</DialogDescription>
358
349
  </DialogHeader>
359
350
  <Input
360
351
  className="font-mono"
@@ -387,9 +378,7 @@ export function MarketplaceAdmin() {
387
378
  {queue.length > 0 && (
388
379
  <div className="space-y-2">
389
380
  <div className="flex items-center gap-2">
390
- <h2 className="text-sm font-medium uppercase tracking-wider text-muted-foreground">
391
- Discovery Queue
392
- </h2>
381
+ <h2 className="text-sm font-medium uppercase tracking-wider text-muted-foreground">Discovery Queue</h2>
393
382
  <Badge
394
383
  variant="secondary"
395
384
  className="bg-amber-500/15 text-amber-400 border border-amber-500/20 text-xs"
@@ -403,9 +392,7 @@ export function MarketplaceAdmin() {
403
392
  <TableRow className="bg-amber-500/5 hover:bg-amber-500/5">
404
393
  <TableHead className="text-xs uppercase tracking-wider">Package</TableHead>
405
394
  <TableHead className="text-xs uppercase tracking-wider">Category</TableHead>
406
- <TableHead className="text-xs uppercase tracking-wider text-right">
407
- Actions
408
- </TableHead>
395
+ <TableHead className="text-xs uppercase tracking-wider text-right">Actions</TableHead>
409
396
  </TableRow>
410
397
  </TableHeader>
411
398
  <TableBody>
@@ -421,16 +408,11 @@ export function MarketplaceAdmin() {
421
408
  <TableCell>
422
409
  <div>
423
410
  <div className="text-sm font-medium">{plugin.name}</div>
424
- <div className="text-xs text-muted-foreground font-mono">
425
- {plugin.npm_package}
426
- </div>
411
+ <div className="text-xs text-muted-foreground font-mono">{plugin.npm_package}</div>
427
412
  </div>
428
413
  </TableCell>
429
414
  <TableCell>
430
- <Badge
431
- variant="outline"
432
- className={cn("text-xs", categoryBadgeClass(plugin.category))}
433
- >
415
+ <Badge variant="outline" className={cn("text-xs", categoryBadgeClass(plugin.category))}>
434
416
  {plugin.category}
435
417
  </Badge>
436
418
  </TableCell>
@@ -470,9 +452,7 @@ export function MarketplaceAdmin() {
470
452
 
471
453
  {/* Enabled Plugins */}
472
454
  <div className="space-y-2">
473
- <h2 className="text-sm font-medium uppercase tracking-wider text-muted-foreground">
474
- Enabled Plugins
475
- </h2>
455
+ <h2 className="text-sm font-medium uppercase tracking-wider text-muted-foreground">Enabled Plugins</h2>
476
456
  <div className="border border-terminal/10 rounded-sm">
477
457
  <Table>
478
458
  <TableHeader>
@@ -489,9 +469,7 @@ export function MarketplaceAdmin() {
489
469
  {enabled.length === 0 ? (
490
470
  <TableRow>
491
471
  <TableCell colSpan={6} className="text-center py-8">
492
- <span className="text-sm text-muted-foreground font-mono">
493
- &gt; No plugins enabled yet
494
- </span>
472
+ <span className="text-sm text-muted-foreground font-mono">&gt; No plugins enabled yet</span>
495
473
  </TableCell>
496
474
  </TableRow>
497
475
  ) : (
@@ -515,10 +493,7 @@ export function MarketplaceAdmin() {
515
493
  <div className="text-sm font-medium">{plugin.name}</div>
516
494
  </TableCell>
517
495
  <TableCell>
518
- <Badge
519
- variant="outline"
520
- className={cn("text-xs", categoryBadgeClass(plugin.category))}
521
- >
496
+ <Badge variant="outline" className={cn("text-xs", categoryBadgeClass(plugin.category))}>
522
497
  {plugin.category}
523
498
  </Badge>
524
499
  </TableCell>
@@ -531,9 +506,7 @@ export function MarketplaceAdmin() {
531
506
  />
532
507
  </TableCell>
533
508
  <TableCell>
534
- <span className="text-xs text-muted-foreground font-mono">
535
- v{plugin.version}
536
- </span>
509
+ <span className="text-xs text-muted-foreground font-mono">v{plugin.version}</span>
537
510
  </TableCell>
538
511
  <TableCell>
539
512
  <Switch
@@ -596,19 +569,13 @@ export function MarketplaceAdmin() {
596
569
  {!installStatusLoading && installStatus && (
597
570
  <div className="flex items-center gap-2">
598
571
  {installStatus.status === "pending" && (
599
- <Badge
600
- variant="outline"
601
- className="border-amber-500/30 text-amber-400 text-xs animate-pulse"
602
- >
572
+ <Badge variant="outline" className="border-amber-500/30 text-amber-400 text-xs animate-pulse">
603
573
  Installing...
604
574
  </Badge>
605
575
  )}
606
576
  {installStatus.status === "installed" && (
607
577
  <div className="flex items-center gap-2">
608
- <Badge
609
- variant="outline"
610
- className="border-terminal/30 text-terminal text-xs"
611
- >
578
+ <Badge variant="outline" className="border-terminal/30 text-terminal text-xs">
612
579
  Installed
613
580
  </Badge>
614
581
  {installStatus.installedAt && (
@@ -620,16 +587,11 @@ export function MarketplaceAdmin() {
620
587
  )}
621
588
  {installStatus.status === "failed" && (
622
589
  <div className="space-y-1">
623
- <Badge
624
- variant="outline"
625
- className="border-destructive/50 text-destructive text-xs"
626
- >
590
+ <Badge variant="outline" className="border-destructive/50 text-destructive text-xs">
627
591
  Install failed
628
592
  </Badge>
629
593
  {installStatus.installError && (
630
- <p className="text-xs text-destructive font-mono">
631
- {installStatus.installError}
632
- </p>
594
+ <p className="text-xs text-destructive font-mono">{installStatus.installError}</p>
633
595
  )}
634
596
  <Button
635
597
  variant="ghost"
@@ -683,9 +645,7 @@ export function MarketplaceAdmin() {
683
645
 
684
646
  {/* Notes */}
685
647
  <div className="space-y-1.5">
686
- <h3 className="text-xs font-medium uppercase tracking-wider text-muted-foreground">
687
- Internal Notes
688
- </h3>
648
+ <h3 className="text-xs font-medium uppercase tracking-wider text-muted-foreground">Internal Notes</h3>
689
649
  <Textarea
690
650
  className="min-h-[80px] text-sm bg-black/30 border-border focus:border-terminal"
691
651
  placeholder="Add internal notes about this plugin..."
@@ -723,8 +683,8 @@ export function MarketplaceAdmin() {
723
683
  <DialogHeader>
724
684
  <DialogTitle>Delete Plugin</DialogTitle>
725
685
  <DialogDescription>
726
- Are you sure you want to delete <strong>{selected.name}</strong>? This
727
- action cannot be undone.
686
+ Are you sure you want to delete <strong>{selected.name}</strong>? This action cannot be
687
+ undone.
728
688
  </DialogDescription>
729
689
  </DialogHeader>
730
690
  <DialogFooter>
@@ -752,9 +712,7 @@ export function MarketplaceAdmin() {
752
712
  exit={{ opacity: 0 }}
753
713
  className="flex items-center justify-center h-full"
754
714
  >
755
- <span className="text-sm text-muted-foreground font-mono">
756
- &gt; Select a plugin to preview
757
- </span>
715
+ <span className="text-sm text-muted-foreground font-mono">&gt; Select a plugin to preview</span>
758
716
  </motion.div>
759
717
  )}
760
718
  </AnimatePresence>
@@ -1,29 +1,13 @@
1
1
  "use client";
2
2
 
3
- import {
4
- AlertCircle,
5
- CheckCircle2,
6
- Clock,
7
- Database,
8
- History,
9
- Loader2,
10
- RotateCcw,
11
- Search,
12
- } from "lucide-react";
3
+ import { AlertCircle, CheckCircle2, Clock, Database, History, Loader2, RotateCcw, Search } from "lucide-react";
13
4
  import { useCallback, useEffect, useState } from "react";
14
5
  import { toast } from "sonner";
15
6
  import { Badge } from "@/components/ui/badge";
16
7
  import { Button } from "@/components/ui/button";
17
8
  import { Input } from "@/components/ui/input";
18
9
  import { Skeleton } from "@/components/ui/skeleton";
19
- import {
20
- Table,
21
- TableBody,
22
- TableCell,
23
- TableHead,
24
- TableHeader,
25
- TableRow,
26
- } from "@/components/ui/table";
10
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
27
11
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
28
12
  import type { MigrationRecord, MigrationRestoreRecord, MigrationSnapshot } from "@/lib/admin-api";
29
13
  import {
@@ -85,10 +69,7 @@ function StatusBadge({ status }: { status: string }) {
85
69
  );
86
70
  default:
87
71
  return (
88
- <Badge
89
- variant="secondary"
90
- className="bg-muted text-muted-foreground inline-flex items-center gap-1"
91
- >
72
+ <Badge variant="secondary" className="bg-muted text-muted-foreground inline-flex items-center gap-1">
92
73
  <Clock className="h-3 w-3" />
93
74
  pending
94
75
  </Badge>
@@ -133,9 +114,7 @@ function MigrationsList({ migrations }: { migrations: MigrationRecord[] }) {
133
114
  <TableCell className="text-xs text-muted-foreground tabular-nums">
134
115
  {fmtDuration(m.duration_ms)}
135
116
  </TableCell>
136
- <TableCell className="text-xs text-red-400 max-w-xs truncate">
137
- {m.error ?? "—"}
138
- </TableCell>
117
+ <TableCell className="text-xs text-red-400 max-w-xs truncate">{m.error ?? "—"}</TableCell>
139
118
  </TableRow>
140
119
  ))
141
120
  )}
@@ -161,10 +140,7 @@ function SnapshotBrowser({ tenantId }: SnapshotBrowserProps) {
161
140
  if (!tenantId) return;
162
141
  setLoading(true);
163
142
  try {
164
- const [snaps, hist] = await Promise.all([
165
- getMigrationSnapshots(tenantId),
166
- getMigrationRestoreHistory(tenantId),
167
- ]);
143
+ const [snaps, hist] = await Promise.all([getMigrationSnapshots(tenantId), getMigrationRestoreHistory(tenantId)]);
168
144
  setSnapshots(snaps);
169
145
  setHistory(hist);
170
146
  } catch (err) {
@@ -179,10 +155,7 @@ function SnapshotBrowser({ tenantId }: SnapshotBrowserProps) {
179
155
  }, [load]);
180
156
 
181
157
  async function handleRestore(snapshotId: string, snapshotName: string) {
182
- if (
183
- !confirm(`Restore snapshot "${snapshotName}" for tenant ${tenantId}? This cannot be undone.`)
184
- )
185
- return;
158
+ if (!confirm(`Restore snapshot "${snapshotName}" for tenant ${tenantId}? This cannot be undone.`)) return;
186
159
  setRestoring(snapshotId);
187
160
  try {
188
161
  await restoreMigrationSnapshot(tenantId, snapshotId);
@@ -297,9 +270,7 @@ function SnapshotBrowser({ tenantId }: SnapshotBrowserProps) {
297
270
  <TableCell className="text-xs text-muted-foreground">
298
271
  {new Date(r.restored_at).toLocaleString()}
299
272
  </TableCell>
300
- <TableCell className="text-xs text-red-400 max-w-xs truncate">
301
- {r.error ?? "—"}
302
- </TableCell>
273
+ <TableCell className="text-xs text-red-400 max-w-xs truncate">{r.error ?? "—"}</TableCell>
303
274
  </TableRow>
304
275
  ))
305
276
  )}
@@ -343,9 +314,7 @@ export function MigrationsDashboard() {
343
314
  <div className="space-y-6 p-6">
344
315
  <div>
345
316
  <h1 className="text-2xl font-bold">Migrations</h1>
346
- <p className="text-muted-foreground text-sm">
347
- Platform migration status and per-tenant snapshot management
348
- </p>
317
+ <p className="text-muted-foreground text-sm">Platform migration status and per-tenant snapshot management</p>
349
318
  </div>
350
319
 
351
320
  <Tabs defaultValue="migrations">
@@ -392,9 +361,7 @@ export function MigrationsDashboard() {
392
361
  ) : (
393
362
  <div className="rounded-lg border border-border border-dashed py-16 text-center">
394
363
  <Database className="h-8 w-8 text-muted-foreground mx-auto mb-2" />
395
- <p className="text-sm text-muted-foreground">
396
- Enter a tenant ID to browse snapshots.
397
- </p>
364
+ <p className="text-sm text-muted-foreground">Enter a tenant ID to browse snapshots.</p>
398
365
  </div>
399
366
  )}
400
367
  </TabsContent>
@@ -1,16 +1,6 @@
1
1
  "use client";
2
2
 
3
- import {
4
- BookOpen,
5
- CheckCircle2,
6
- Clock,
7
- Edit2,
8
- Plus,
9
- Save,
10
- TrendingUp,
11
- Users,
12
- X,
13
- } from "lucide-react";
3
+ import { BookOpen, CheckCircle2, Clock, Edit2, Plus, Save, TrendingUp, Users, X } from "lucide-react";
14
4
  import { useCallback, useEffect, useState } from "react";
15
5
  import { toast } from "sonner";
16
6
  import { Badge } from "@/components/ui/badge";
@@ -20,11 +10,7 @@ import { Skeleton } from "@/components/ui/skeleton";
20
10
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
21
11
  import { Textarea } from "@/components/ui/textarea";
22
12
  import type { OnboardingFunnelStats, OnboardingScript } from "@/lib/admin-api";
23
- import {
24
- getOnboardingFunnelStats,
25
- getOnboardingScripts,
26
- saveOnboardingScript,
27
- } from "@/lib/admin-api";
13
+ import { getOnboardingFunnelStats, getOnboardingScripts, saveOnboardingScript } from "@/lib/admin-api";
28
14
  import { toUserMessage } from "@/lib/errors";
29
15
 
30
16
  // ---- Utilities ----
@@ -82,16 +68,8 @@ function FunnelView({ stats }: { stats: OnboardingFunnelStats }) {
82
68
  value={stats.total_completed.toLocaleString()}
83
69
  sub={fmtPct(stats.overall_completion_rate)}
84
70
  />
85
- <StatCard
86
- icon={TrendingUp}
87
- label="Completion Rate"
88
- value={fmtPct(stats.overall_completion_rate)}
89
- />
90
- <StatCard
91
- icon={Clock}
92
- label="Time to First Bot"
93
- value={fmtMs(stats.time_to_first_bot_ms)}
94
- />
71
+ <StatCard icon={TrendingUp} label="Completion Rate" value={fmtPct(stats.overall_completion_rate)} />
72
+ <StatCard icon={Clock} label="Time to First Bot" value={fmtMs(stats.time_to_first_bot_ms)} />
95
73
  </div>
96
74
 
97
75
  <div className="rounded-lg border border-border overflow-hidden">
@@ -100,14 +78,10 @@ function FunnelView({ stats }: { stats: OnboardingFunnelStats }) {
100
78
  <tr className="border-b border-border bg-muted/40 text-left">
101
79
  <th className="px-4 py-2.5 font-medium text-muted-foreground">Step</th>
102
80
  <th className="px-4 py-2.5 font-medium text-muted-foreground text-right">Started</th>
103
- <th className="px-4 py-2.5 font-medium text-muted-foreground text-right">
104
- Completed
105
- </th>
81
+ <th className="px-4 py-2.5 font-medium text-muted-foreground text-right">Completed</th>
106
82
  <th className="px-4 py-2.5 font-medium text-muted-foreground text-right">Dropped</th>
107
83
  <th className="px-4 py-2.5 font-medium text-muted-foreground text-right">Rate</th>
108
- <th className="px-4 py-2.5 font-medium text-muted-foreground text-right">
109
- Avg Duration
110
- </th>
84
+ <th className="px-4 py-2.5 font-medium text-muted-foreground text-right">Avg Duration</th>
111
85
  <th className="px-4 py-2.5 font-medium text-muted-foreground">Funnel</th>
112
86
  </tr>
113
87
  </thead>
@@ -125,17 +99,13 @@ function FunnelView({ stats }: { stats: OnboardingFunnelStats }) {
125
99
  className="border-b border-border last:border-b-0 hover:bg-muted/20 transition-colors"
126
100
  >
127
101
  <td className="px-4 py-3 font-medium">{step.label}</td>
128
- <td className="px-4 py-3 text-right tabular-nums">
129
- {step.started.toLocaleString()}
130
- </td>
102
+ <td className="px-4 py-3 text-right tabular-nums">{step.started.toLocaleString()}</td>
131
103
  <td className="px-4 py-3 text-right tabular-nums text-green-400">
132
104
  {step.completed.toLocaleString()}
133
105
  </td>
134
106
  <td className="px-4 py-3 text-right tabular-nums text-red-400">
135
107
  {step.dropped.toLocaleString()}
136
- {idx > 0 && dropPct > 0 && (
137
- <span className="text-xs text-muted-foreground ml-1">({dropPct}%)</span>
138
- )}
108
+ {idx > 0 && dropPct > 0 && <span className="text-xs text-muted-foreground ml-1">({dropPct}%)</span>}
139
109
  </td>
140
110
  <td className="px-4 py-3 text-right tabular-nums">
141
111
  <Badge
@@ -156,10 +126,7 @@ function FunnelView({ stats }: { stats: OnboardingFunnelStats }) {
156
126
  </td>
157
127
  <td className="px-4 py-3 w-32">
158
128
  <div className="h-2 rounded-full bg-muted overflow-hidden">
159
- <div
160
- className="h-full rounded-full bg-terminal/70 transition-all"
161
- style={{ width: `${pct}%` }}
162
- />
129
+ <div className="h-full rounded-full bg-terminal/70 transition-all" style={{ width: `${pct}%` }} />
163
130
  </div>
164
131
  </td>
165
132
  </tr>
@@ -213,11 +180,7 @@ function ScriptEditor({ scripts, onSaved }: ScriptEditorProps) {
213
180
  }
214
181
  setSaving(true);
215
182
  try {
216
- const saved = await saveOnboardingScript(
217
- editing && selected ? selected.id : null,
218
- name.trim(),
219
- content,
220
- );
183
+ const saved = await saveOnboardingScript(editing && selected ? selected.id : null, name.trim(), content);
221
184
  onSaved(saved);
222
185
  setEditing(false);
223
186
  setSelected(saved);
@@ -268,9 +231,7 @@ function ScriptEditor({ scripts, onSaved }: ScriptEditorProps) {
268
231
  New Script
269
232
  </Button>
270
233
  </div>
271
- {scripts.length === 0 && (
272
- <p className="text-sm text-muted-foreground py-4 text-center">No scripts yet.</p>
273
- )}
234
+ {scripts.length === 0 && <p className="text-sm text-muted-foreground py-4 text-center">No scripts yet.</p>}
274
235
  <div className="space-y-2">
275
236
  {scripts.map((s) => (
276
237
  <button
@@ -284,10 +245,7 @@ function ScriptEditor({ scripts, onSaved }: ScriptEditorProps) {
284
245
  <BookOpen className="h-3.5 w-3.5 text-muted-foreground" />
285
246
  <span className="text-sm font-medium">{s.name}</span>
286
247
  {s.active && (
287
- <Badge
288
- variant="secondary"
289
- className="bg-green-500/15 text-green-400 border-green-500/20 text-xs"
290
- >
248
+ <Badge variant="secondary" className="bg-green-500/15 text-green-400 border-green-500/20 text-xs">
291
249
  active
292
250
  </Badge>
293
251
  )}
@@ -332,10 +290,7 @@ export function OnboardingDashboard() {
332
290
  const load = useCallback(async () => {
333
291
  setLoading(true);
334
292
  try {
335
- const [funnelStats, scriptList] = await Promise.all([
336
- getOnboardingFunnelStats(days),
337
- getOnboardingScripts(),
338
- ]);
293
+ const [funnelStats, scriptList] = await Promise.all([getOnboardingFunnelStats(days), getOnboardingScripts()]);
339
294
  setStats(funnelStats);
340
295
  setScripts(scriptList);
341
296
  } catch (err) {
@@ -370,12 +325,7 @@ export function OnboardingDashboard() {
370
325
  </div>
371
326
  <div className="flex gap-1">
372
327
  {[7, 30, 90].map((d) => (
373
- <Button
374
- key={d}
375
- size="sm"
376
- variant={days === d ? "secondary" : "outline"}
377
- onClick={() => setDays(d)}
378
- >
328
+ <Button key={d} size="sm" variant={days === d ? "secondary" : "outline"} onClick={() => setDays(d)}>
379
329
  {d}d
380
330
  </Button>
381
331
  ))}
@@ -70,8 +70,8 @@ export function PoolConfigDashboard() {
70
70
  <h2 className="text-lg font-semibold mb-2">Hot Pool</h2>
71
71
  <p className="text-muted-foreground">
72
72
  Hot pool is not enabled for this product. Enable the{" "}
73
- <code className="text-xs bg-muted px-1 py-0.5 rounded">hotPool</code> feature flag in the
74
- boot config to use pre-provisioned instances.
73
+ <code className="text-xs bg-muted px-1 py-0.5 rounded">hotPool</code> feature flag in the boot config to use
74
+ pre-provisioned instances.
75
75
  </p>
76
76
  </div>
77
77
  );
@@ -81,9 +81,7 @@ export function PoolConfigDashboard() {
81
81
  <div className="space-y-6 p-6">
82
82
  <div>
83
83
  <h2 className="text-lg font-semibold">Hot Pool</h2>
84
- <p className="text-sm text-muted-foreground">
85
- Pre-provisioned warm containers for instant instance creation.
86
- </p>
84
+ <p className="text-sm text-muted-foreground">Pre-provisioned warm containers for instant instance creation.</p>
87
85
  </div>
88
86
 
89
87
  <div className="grid grid-cols-1 gap-4 sm:grid-cols-3">
@@ -122,11 +120,7 @@ export function PoolConfigDashboard() {
122
120
  onChange={(e) => setSizeInput(e.target.value)}
123
121
  className="w-24"
124
122
  />
125
- <Button
126
- onClick={handleSave}
127
- disabled={saving || sizeInput === String(config.poolSize)}
128
- size="sm"
129
- >
123
+ <Button onClick={handleSave} disabled={saving || sizeInput === String(config.poolSize)} size="sm">
130
124
  {saving ? "Saving..." : "Update"}
131
125
  </Button>
132
126
  <span className="text-xs text-muted-foreground">
@@ -6,13 +6,7 @@ import { Button } from "@/components/ui/button";
6
6
  import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
7
7
  import { Input } from "@/components/ui/input";
8
8
  import { Label } from "@/components/ui/label";
9
- import {
10
- Select,
11
- SelectContent,
12
- SelectItem,
13
- SelectTrigger,
14
- SelectValue,
15
- } from "@/components/ui/select";
9
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
16
10
  import { toUserMessage } from "@/lib/errors";
17
11
 
18
12
  interface FleetConfig {
@@ -124,10 +118,7 @@ export function FleetForm({ initial, onSave }: FleetFormProps) {
124
118
 
125
119
  <div className="space-y-1.5">
126
120
  <Label htmlFor="fleet-placementStrategy">Placement Strategy</Label>
127
- <Select
128
- value={form.placementStrategy}
129
- onValueChange={(v) => setStr("placementStrategy", v)}
130
- >
121
+ <Select value={form.placementStrategy} onValueChange={(v) => setStr("placementStrategy", v)}>
131
122
  <SelectTrigger id="fleet-placementStrategy">
132
123
  <SelectValue placeholder="Select strategy" />
133
124
  </SelectTrigger>