@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
@@ -5,22 +5,20 @@ import { CameraIcon, CheckIcon } from "lucide-react";
5
5
  import { type FormEvent, useCallback, useEffect, useRef, useState } from "react";
6
6
  import { Button } from "@/components/ui/button";
7
7
  import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
8
- import {
9
- Dialog,
10
- DialogClose,
11
- DialogContent,
12
- DialogDescription,
13
- DialogFooter,
14
- DialogHeader,
15
- DialogTitle,
16
- DialogTrigger,
17
- } from "@/components/ui/dialog";
18
8
  import { Input } from "@/components/ui/input";
19
9
  import { Label } from "@/components/ui/label";
20
10
  import { Separator } from "@/components/ui/separator";
21
11
  import { Skeleton } from "@/components/ui/skeleton";
22
- import type { UserProfile } from "@/lib/api";
23
- import { changePassword, deleteAccount, getProfile, updateProfile, uploadAvatar } from "@/lib/api";
12
+ import type { Instance, UserProfile } from "@/lib/api";
13
+ import {
14
+ changePassword,
15
+ controlInstance,
16
+ deleteAccount,
17
+ getProfile,
18
+ listInstances,
19
+ updateProfile,
20
+ uploadAvatar,
21
+ } from "@/lib/api";
24
22
  import { linkSocial, listAccounts, unlinkAccount } from "@/lib/auth-client";
25
23
 
26
24
  export default function ProfilePage() {
@@ -45,6 +43,9 @@ export default function ProfilePage() {
45
43
  const [changingPw, setChangingPw] = useState(false);
46
44
 
47
45
  const [deleteConfirm, setDeleteConfirm] = useState("");
46
+ const [resetConfirm, setResetConfirm] = useState("");
47
+ const [instances, setInstances] = useState<Instance[]>([]);
48
+ const [resetting, setResetting] = useState(false);
48
49
  const [uploading, setUploading] = useState(false);
49
50
  const fileInputRef = useRef<HTMLInputElement>(null);
50
51
  const saveSuccessTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
@@ -67,15 +68,16 @@ export default function ProfilePage() {
67
68
  setEmail(p.email);
68
69
  try {
69
70
  const accounts = await listAccounts();
70
- const providerIds = ((accounts.data ?? []) as { providerId: string }[]).map(
71
- (a) => a.providerId,
72
- );
71
+ const providerIds = ((accounts.data ?? []) as { providerId: string }[]).map((a) => a.providerId);
73
72
  const providers = new Set<string>(providerIds);
74
73
  setConnectedProviders(providers);
75
74
  } catch {
76
- setConnectedProviders(
77
- new Set(p.oauthConnections.filter((c) => c.connected).map((c) => c.provider)),
78
- );
75
+ setConnectedProviders(new Set(p.oauthConnections.filter((c) => c.connected).map((c) => c.provider)));
76
+ }
77
+ try {
78
+ setInstances(await listInstances());
79
+ } catch {
80
+ // Non-fatal — instances may not be available
79
81
  }
80
82
  } catch {
81
83
  setLoadError(true);
@@ -176,11 +178,39 @@ export default function ProfilePage() {
176
178
  }
177
179
  }
178
180
 
181
+ async function handleResetInstance() {
182
+ setResetting(true);
183
+ setError(null);
184
+ try {
185
+ for (const inst of instances) {
186
+ try {
187
+ await controlInstance(inst.id, "destroy");
188
+ } catch {
189
+ // Instance may already be gone
190
+ }
191
+ }
192
+ window.location.href = "/dashboard";
193
+ } catch {
194
+ setError("Failed to reset instance. Please try again.");
195
+ } finally {
196
+ setResetting(false);
197
+ }
198
+ }
199
+
179
200
  async function handleDelete() {
180
201
  setError(null);
181
202
  try {
203
+ for (const inst of instances) {
204
+ try {
205
+ await controlInstance(inst.id, "destroy");
206
+ } catch {
207
+ // Instance may already be gone
208
+ }
209
+ }
210
+ // 2. Delete account (sessions, DB rows)
182
211
  await deleteAccount();
183
- window.location.href = "/login";
212
+ // 3. Sign out and redirect to home
213
+ window.location.href = "/";
184
214
  } catch {
185
215
  setError("Failed to delete account. Please try again.");
186
216
  }
@@ -222,8 +252,8 @@ export default function ProfilePage() {
222
252
  return (
223
253
  <div className="max-w-2xl space-y-6">
224
254
  <div>
225
- <h1 className="text-2xl font-bold tracking-tight">Profile</h1>
226
- <p className="text-sm text-muted-foreground">Manage your account settings</p>
255
+ <h1 className="text-2xl font-bold tracking-tight">Settings</h1>
256
+ <p className="text-sm text-muted-foreground">Manage your profile, security, and account</p>
227
257
  </div>
228
258
 
229
259
  <AnimatePresence>
@@ -254,11 +284,7 @@ export default function ProfilePage() {
254
284
  >
255
285
  {profile.avatarUrl ? (
256
286
  // biome-ignore lint/performance/noImgElement: external avatar URL — domain not configured for next/image
257
- <img
258
- src={profile.avatarUrl}
259
- alt={profile.name}
260
- className="size-full object-cover"
261
- />
287
+ <img src={profile.avatarUrl} alt={profile.name} className="size-full object-cover" />
262
288
  ) : (
263
289
  <span className="text-xl font-semibold text-muted-foreground">
264
290
  {profile.name.charAt(0).toUpperCase()}
@@ -292,12 +318,7 @@ export default function ProfilePage() {
292
318
  <form onSubmit={handleSaveProfile} className="flex flex-col gap-4">
293
319
  <div className="flex flex-col gap-2">
294
320
  <Label htmlFor="profile-name">Display name</Label>
295
- <Input
296
- id="profile-name"
297
- value={name}
298
- onChange={(e) => setName(e.target.value)}
299
- required
300
- />
321
+ <Input id="profile-name" value={name} onChange={(e) => setName(e.target.value)} required />
301
322
  </div>
302
323
  <div className="flex flex-col gap-2">
303
324
  <Label htmlFor="profile-email">Email</Label>
@@ -336,12 +357,7 @@ export default function ProfilePage() {
336
357
  Saved
337
358
  </motion.span>
338
359
  ) : (
339
- <motion.span
340
- key="save"
341
- initial={{ opacity: 0 }}
342
- animate={{ opacity: 1 }}
343
- exit={{ opacity: 0 }}
344
- >
360
+ <motion.span key="save" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}>
345
361
  {saving ? "Saving..." : "Save changes"}
346
362
  </motion.span>
347
363
  )}
@@ -415,12 +431,7 @@ export default function ProfilePage() {
415
431
  Changed
416
432
  </motion.span>
417
433
  ) : (
418
- <motion.span
419
- key="default"
420
- initial={{ opacity: 0 }}
421
- animate={{ opacity: 1 }}
422
- exit={{ opacity: 0 }}
423
- >
434
+ <motion.span key="default" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}>
424
435
  {changingPw ? "Changing..." : "Change password"}
425
436
  </motion.span>
426
437
  )}
@@ -445,9 +456,7 @@ export default function ProfilePage() {
445
456
  <Button
446
457
  variant={connected ? "outline" : "default"}
447
458
  size="sm"
448
- onClick={() =>
449
- connected ? handleOauthDisconnect(provider) : handleOauthConnect(provider)
450
- }
459
+ onClick={() => (connected ? handleOauthDisconnect(provider) : handleOauthConnect(provider))}
451
460
  >
452
461
  {connected ? "Disconnect" : "Connect"}
453
462
  </Button>
@@ -465,6 +474,53 @@ export default function ProfilePage() {
465
474
  <Separator className="flex-1 bg-destructive/30" />
466
475
  </div>
467
476
 
477
+ {instances.length > 0 && (
478
+ <Card className="border-destructive/50 bg-destructive/5">
479
+ <CardHeader>
480
+ <CardTitle className="text-destructive">Reset Instance</CardTitle>
481
+ <CardDescription>
482
+ Destroy all running instances and start fresh. Your account, credits, and settings are preserved.
483
+ </CardDescription>
484
+ </CardHeader>
485
+ <CardContent className="space-y-4">
486
+ {resetConfirm === "" ? (
487
+ <Button variant="destructive" onClick={() => setResetConfirm("pending")}>
488
+ Reset instance
489
+ </Button>
490
+ ) : (
491
+ <div className="rounded-lg border border-destructive/50 bg-destructive/10 p-4 space-y-3">
492
+ <p className="text-sm text-destructive font-medium">
493
+ This will permanently destroy{" "}
494
+ {instances.length === 1 ? "your instance" : `all ${instances.length} instances`} and their data (agent
495
+ history, issues, documents). Your account and credits are kept.
496
+ </p>
497
+ <p className="text-sm text-muted-foreground">
498
+ Type <strong className="text-destructive">reset</strong> to confirm.
499
+ </p>
500
+ <Input
501
+ placeholder="reset"
502
+ value={resetConfirm === "pending" ? "" : resetConfirm}
503
+ onChange={(e) => setResetConfirm(e.target.value)}
504
+ autoFocus
505
+ />
506
+ <div className="flex gap-2">
507
+ <Button variant="outline" onClick={() => setResetConfirm("")}>
508
+ Cancel
509
+ </Button>
510
+ <Button
511
+ variant="destructive"
512
+ disabled={resetConfirm !== "reset" || resetting}
513
+ onClick={handleResetInstance}
514
+ >
515
+ {resetting ? "Destroying..." : "Confirm reset"}
516
+ </Button>
517
+ </div>
518
+ </div>
519
+ )}
520
+ </CardContent>
521
+ </Card>
522
+ )}
523
+
468
524
  <Card className="border-destructive/50 bg-destructive/5">
469
525
  <CardHeader>
470
526
  <CardTitle className="text-destructive">Delete Account</CardTitle>
@@ -472,38 +528,35 @@ export default function ProfilePage() {
472
528
  Permanently delete your account and all associated data. This action cannot be undone.
473
529
  </CardDescription>
474
530
  </CardHeader>
475
- <CardContent>
476
- <Dialog>
477
- <DialogTrigger asChild>
478
- <Button variant="destructive">Delete account</Button>
479
- </DialogTrigger>
480
- <DialogContent>
481
- <DialogHeader>
482
- <DialogTitle>Are you absolutely sure?</DialogTitle>
483
- <DialogDescription>
484
- This will permanently delete your account, all instances, and data. Type{" "}
485
- <strong>delete my account</strong> to confirm.
486
- </DialogDescription>
487
- </DialogHeader>
531
+ <CardContent className="space-y-4">
532
+ {deleteConfirm === "" ? (
533
+ <Button variant="destructive" onClick={() => setDeleteConfirm("pending")}>
534
+ Delete account
535
+ </Button>
536
+ ) : (
537
+ <div className="rounded-lg border border-destructive/50 bg-destructive/10 p-4 space-y-3">
538
+ <p className="text-sm text-destructive font-medium">
539
+ This will permanently delete your account, all instances, and data. This cannot be undone.
540
+ </p>
541
+ <p className="text-sm text-muted-foreground">
542
+ Type <strong className="text-destructive">delete my account</strong> to confirm.
543
+ </p>
488
544
  <Input
489
545
  placeholder="delete my account"
490
- value={deleteConfirm}
546
+ value={deleteConfirm === "pending" ? "" : deleteConfirm}
491
547
  onChange={(e) => setDeleteConfirm(e.target.value)}
548
+ autoFocus
492
549
  />
493
- <DialogFooter>
494
- <DialogClose asChild>
495
- <Button variant="outline">Cancel</Button>
496
- </DialogClose>
497
- <Button
498
- variant="destructive"
499
- disabled={deleteConfirm !== "delete my account"}
500
- onClick={handleDelete}
501
- >
550
+ <div className="flex gap-2">
551
+ <Button variant="outline" onClick={() => setDeleteConfirm("")}>
552
+ Cancel
553
+ </Button>
554
+ <Button variant="destructive" disabled={deleteConfirm !== "delete my account"} onClick={handleDelete}>
502
555
  Delete permanently
503
556
  </Button>
504
- </DialogFooter>
505
- </DialogContent>
506
- </Dialog>
557
+ </div>
558
+ </div>
559
+ )}
507
560
  </CardContent>
508
561
  </Card>
509
562
  </div>
@@ -21,22 +21,10 @@ import {
21
21
  import { Input } from "@/components/ui/input";
22
22
  import { Label } from "@/components/ui/label";
23
23
  import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
24
- import {
25
- Select,
26
- SelectContent,
27
- SelectItem,
28
- SelectTrigger,
29
- SelectValue,
30
- } from "@/components/ui/select";
24
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
31
25
  import { Skeleton } from "@/components/ui/skeleton";
32
26
  import { useCapabilityMeta } from "@/hooks/use-capability-meta";
33
- import type {
34
- CapabilityMetaEntry,
35
- CapabilityMode,
36
- CapabilityName,
37
- CapabilitySetting,
38
- ProviderKey,
39
- } from "@/lib/api";
27
+ import type { CapabilityMetaEntry, CapabilityMode, CapabilityName, CapabilitySetting, ProviderKey } from "@/lib/api";
40
28
  import {
41
29
  getBillingInfo,
42
30
  getCreditBalance,
@@ -47,11 +35,7 @@ import {
47
35
  updateProviderModel,
48
36
  } from "@/lib/api";
49
37
  import { brandName } from "@/lib/brand-config";
50
- import {
51
- listCapabilities,
52
- testProviderKey as testCapabilityViaTrpc,
53
- updateCapability,
54
- } from "@/lib/settings-api";
38
+ import { listCapabilities, testProviderKey as testCapabilityViaTrpc, updateCapability } from "@/lib/settings-api";
55
39
  import { cn } from "@/lib/utils";
56
40
 
57
41
  // --- Helpers ---
@@ -193,10 +177,7 @@ export default function ProvidersPage() {
193
177
  setTestCapResult((prev) => ({ ...prev, [capability]: "fail" }));
194
178
  }
195
179
  setTestingCap(null);
196
- testCapResultTimer.current = setTimeout(
197
- () => setTestCapResult((prev) => ({ ...prev, [capability]: null })),
198
- 2000,
199
- );
180
+ testCapResultTimer.current = setTimeout(() => setTestCapResult((prev) => ({ ...prev, [capability]: null })), 2000);
200
181
  }
201
182
 
202
183
  async function handleTest(id: string) {
@@ -214,10 +195,7 @@ export default function ProvidersPage() {
214
195
  const provs = await listProviderKeys();
215
196
  setProviders(provs);
216
197
  setTesting(null);
217
- testResultTimer.current = setTimeout(
218
- () => setTestResult((prev) => ({ ...prev, [id]: null })),
219
- 2000,
220
- );
198
+ testResultTimer.current = setTimeout(() => setTestResult((prev) => ({ ...prev, [id]: null })), 2000);
221
199
  }
222
200
 
223
201
  async function handleRemove(id: string, providerName: string) {
@@ -279,8 +257,7 @@ export default function ProvidersPage() {
279
257
  <div>
280
258
  <h1 className="text-2xl font-bold tracking-tight">Provider Settings</h1>
281
259
  <p className="text-sm text-muted-foreground">
282
- Choose {brandName()} Hosted or Bring Your Own Key for each capability. Changes take effect
283
- immediately.
260
+ Choose {brandName()} Hosted or Bring Your Own Key for each capability. Changes take effect immediately.
284
261
  </p>
285
262
  </div>
286
263
 
@@ -329,10 +306,7 @@ export default function ProvidersPage() {
329
306
  <RadioGroupItem value="hosted" id={`mode-${capName}-hosted`} className="mt-1" />
330
307
  <div className="flex-1">
331
308
  <div className="flex items-center gap-2">
332
- <Label
333
- htmlFor={`mode-${capName}-hosted`}
334
- className="text-sm font-medium cursor-pointer"
335
- >
309
+ <Label htmlFor={`mode-${capName}-hosted`} className="text-sm font-medium cursor-pointer">
336
310
  {brandName()} Hosted
337
311
  </Label>
338
312
  <Badge variant="outline">{meta.pricing}</Badge>
@@ -350,15 +324,10 @@ export default function ProvidersPage() {
350
324
  >
351
325
  <RadioGroupItem value="byok" id={`mode-${capName}-byok`} className="mt-1" />
352
326
  <div className="flex-1">
353
- <Label
354
- htmlFor={`mode-${capName}-byok`}
355
- className="text-sm font-medium cursor-pointer"
356
- >
327
+ <Label htmlFor={`mode-${capName}-byok`} className="text-sm font-medium cursor-pointer">
357
328
  Bring Your Own Key
358
329
  </Label>
359
- {cap?.provider && (
360
- <span className="ml-2 text-xs text-muted-foreground">({cap.provider})</span>
361
- )}
330
+ {cap?.provider && <span className="ml-2 text-xs text-muted-foreground">({cap.provider})</span>}
362
331
  </div>
363
332
  </div>
364
333
  </RadioGroup>
@@ -375,21 +344,15 @@ export default function ProvidersPage() {
375
344
  {cap?.maskedKey && (
376
345
  <div className="flex items-center gap-2">
377
346
  <code className="text-xs text-muted-foreground">{cap.maskedKey}</code>
378
- {cap.keyStatus && (
379
- <Badge variant={keyStatusVariant(cap.keyStatus)}>{cap.keyStatus}</Badge>
380
- )}
347
+ {cap.keyStatus && <Badge variant={keyStatusVariant(cap.keyStatus)}>{cap.keyStatus}</Badge>}
381
348
  </div>
382
349
  )}
383
350
  <div className="flex gap-2">
384
351
  <Input
385
352
  type="password"
386
- placeholder={
387
- cap?.maskedKey ? "Enter new key to replace" : "Enter your API key"
388
- }
353
+ placeholder={cap?.maskedKey ? "Enter new key to replace" : "Enter your API key"}
389
354
  value={byokKey}
390
- onChange={(e) =>
391
- setByokKeys((prev) => ({ ...prev, [capName]: e.target.value }))
392
- }
355
+ onChange={(e) => setByokKeys((prev) => ({ ...prev, [capName]: e.target.value }))}
393
356
  className="flex-1"
394
357
  aria-label={`${meta.label} API key`}
395
358
  />
@@ -433,11 +396,7 @@ export default function ProvidersPage() {
433
396
  >
434
397
  <AnimatePresence mode="wait">
435
398
  {isTesting ? (
436
- <motion.span
437
- key="testing"
438
- initial={{ opacity: 0 }}
439
- animate={{ opacity: 1 }}
440
- >
399
+ <motion.span key="testing" initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
441
400
  Testing...
442
401
  </motion.span>
443
402
  ) : capTestResult === "success" ? (
@@ -461,11 +420,7 @@ export default function ProvidersPage() {
461
420
  Failed
462
421
  </motion.span>
463
422
  ) : (
464
- <motion.span
465
- key="idle"
466
- initial={{ opacity: 0 }}
467
- animate={{ opacity: 1 }}
468
- >
423
+ <motion.span key="idle" initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
469
424
  Test Key
470
425
  </motion.span>
471
426
  )}
@@ -494,8 +449,7 @@ export default function ProvidersPage() {
494
449
  <div className="border-t pt-8">
495
450
  <h2 className="text-xl font-bold tracking-tight">Provider Keys</h2>
496
451
  <p className="text-sm text-muted-foreground">
497
- Manage your BYOK API keys directly. Keys are stored securely and never leave your
498
- environment.
452
+ Manage your BYOK API keys directly. Keys are stored securely and never leave your environment.
499
453
  </p>
500
454
  </div>
501
455
 
@@ -516,9 +470,7 @@ export default function ProvidersPage() {
516
470
  <CardTitle>{provider.provider}</CardTitle>
517
471
  </div>
518
472
  <Badge variant={providerKeyStatusVariant(provider.status)}>
519
- {provider.status === "unchecked" && !provider.maskedKey
520
- ? "Not configured"
521
- : provider.status}
473
+ {provider.status === "unchecked" && !provider.maskedKey ? "Not configured" : provider.status}
522
474
  </Badge>
523
475
  </div>
524
476
  {provider.maskedKey && (
@@ -533,10 +485,7 @@ export default function ProvidersPage() {
533
485
  <>
534
486
  <div className="flex flex-col gap-2">
535
487
  <Label htmlFor={`model-${provider.id}`}>Default model</Label>
536
- <Select
537
- value={provider.defaultModel ?? ""}
538
- onValueChange={(v) => handleModelChange(provider.id, v)}
539
- >
488
+ <Select value={provider.defaultModel ?? ""} onValueChange={(v) => handleModelChange(provider.id, v)}>
540
489
  <SelectTrigger id={`model-${provider.id}`} className="w-full">
541
490
  <SelectValue placeholder="Select a model" />
542
491
  </SelectTrigger>
@@ -558,11 +507,7 @@ export default function ProvidersPage() {
558
507
  >
559
508
  <AnimatePresence mode="wait">
560
509
  {testing === provider.id ? (
561
- <motion.span
562
- key="testing"
563
- initial={{ opacity: 0 }}
564
- animate={{ opacity: 1 }}
565
- >
510
+ <motion.span key="testing" initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
566
511
  Testing...
567
512
  </motion.span>
568
513
  ) : testResult[provider.id] === "success" ? (
@@ -656,8 +601,8 @@ function BillingGateDialog({
656
601
  Enable {brandName()} Hosted for {meta.label}?
657
602
  </DialogTitle>
658
603
  <DialogDescription>
659
- {brandName()} Hosted for {meta.label.toLowerCase()} costs {meta.pricing}. This will be
660
- billed to your payment method on file.
604
+ {brandName()} Hosted for {meta.label.toLowerCase()} costs {meta.pricing}. This will be billed to your
605
+ payment method on file.
661
606
  </DialogDescription>
662
607
  </DialogHeader>
663
608
 
@@ -810,9 +755,7 @@ function RotateKeyDialog({ provider, onSaved }: { provider: ProviderKey; onSaved
810
755
  <DialogContent>
811
756
  <DialogHeader>
812
757
  <DialogTitle>Rotate {provider.provider} Key</DialogTitle>
813
- <DialogDescription>
814
- Paste your new API key. The old key will be replaced after validation.
815
- </DialogDescription>
758
+ <DialogDescription>Paste your new API key. The old key will be replaced after validation.</DialogDescription>
816
759
  </DialogHeader>
817
760
  <form onSubmit={handleSubmit} className="flex flex-col gap-4">
818
761
  <div className="flex flex-col gap-2">
@@ -18,22 +18,9 @@ import {
18
18
  } from "@/components/ui/dialog";
19
19
  import { Input } from "@/components/ui/input";
20
20
  import { Label } from "@/components/ui/label";
21
- import {
22
- Select,
23
- SelectContent,
24
- SelectItem,
25
- SelectTrigger,
26
- SelectValue,
27
- } from "@/components/ui/select";
21
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
28
22
  import { Skeleton } from "@/components/ui/skeleton";
29
- import {
30
- Table,
31
- TableBody,
32
- TableCell,
33
- TableHead,
34
- TableHeader,
35
- TableRow,
36
- } from "@/components/ui/table";
23
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
37
24
  import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
38
25
  import {
39
26
  createSecret,
@@ -141,9 +128,7 @@ export default function SecretsPage() {
141
128
  <div className="flex items-center justify-between">
142
129
  <div>
143
130
  <h1 className="text-2xl font-bold tracking-tight">Secrets Vault</h1>
144
- <p className="text-sm text-muted-foreground">
145
- Manage encrypted credentials for plugins and integrations
146
- </p>
131
+ <p className="text-sm text-muted-foreground">Manage encrypted credentials for plugins and integrations</p>
147
132
  </div>
148
133
  <CreateSecretDialog
149
134
  onCreated={(plaintextValue) => {
@@ -167,29 +152,18 @@ export default function SecretsPage() {
167
152
  Your new secret has been created. Copy it now -- it will not be shown again.
168
153
  </p>
169
154
  <div className="flex items-center gap-2">
170
- <code className="flex-1 rounded bg-muted px-3 py-2 text-sm font-mono break-all">
171
- {revealedValue}
172
- </code>
155
+ <code className="flex-1 rounded bg-muted px-3 py-2 text-sm font-mono break-all">{revealedValue}</code>
173
156
  <Tooltip open={copied}>
174
157
  <TooltipTrigger asChild>
175
158
  <Button variant="outline" size="sm" onClick={handleCopy}>
176
- {copied ? (
177
- <CheckIcon className="size-4" />
178
- ) : (
179
- <CopyIcon className="size-4" />
180
- )}
159
+ {copied ? <CheckIcon className="size-4" /> : <CopyIcon className="size-4" />}
181
160
  {copied ? "Copied" : "Copy"}
182
161
  </Button>
183
162
  </TooltipTrigger>
184
163
  <TooltipContent>Copied!</TooltipContent>
185
164
  </Tooltip>
186
165
  </div>
187
- <Button
188
- variant="ghost"
189
- size="sm"
190
- className="mt-2"
191
- onClick={() => setRevealedValue(null)}
192
- >
166
+ <Button variant="ghost" size="sm" className="mt-2" onClick={() => setRevealedValue(null)}>
193
167
  Dismiss
194
168
  </Button>
195
169
  </CardContent>
@@ -280,9 +254,7 @@ export default function SecretsPage() {
280
254
  key={secret.id}
281
255
  secret={secret}
282
256
  isAuditExpanded={expandedAudit === secret.id}
283
- onToggleAudit={() =>
284
- setExpandedAudit(expandedAudit === secret.id ? null : secret.id)
285
- }
257
+ onToggleAudit={() => setExpandedAudit(expandedAudit === secret.id ? null : secret.id)}
286
258
  onRotate={() => handleRotate(secret.id)}
287
259
  onDelete={() => handleDelete(secret.id)}
288
260
  />
@@ -332,12 +304,7 @@ function SecretRow({
332
304
  <div className="flex items-center gap-1">
333
305
  <Tooltip>
334
306
  <TooltipTrigger asChild>
335
- <Button
336
- variant="ghost"
337
- size="icon-sm"
338
- aria-label="Access log"
339
- onClick={onToggleAudit}
340
- >
307
+ <Button variant="ghost" size="icon-sm" aria-label="Access log" onClick={onToggleAudit}>
341
308
  <HistoryIcon className="size-4" />
342
309
  </Button>
343
310
  </TooltipTrigger>
@@ -399,9 +366,7 @@ function AuditPanel({ secretId }: { secretId: string }) {
399
366
 
400
367
  return (
401
368
  <div className="px-4 py-3 space-y-2">
402
- <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">
403
- Access Log
404
- </p>
369
+ <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">Access Log</p>
405
370
  {loading ? (
406
371
  <div className="space-y-2">
407
372
  {Array.from({ length: 3 }, (_, i) => `audit-sk-${i}`).map((id) => (
@@ -409,9 +374,7 @@ function AuditPanel({ secretId }: { secretId: string }) {
409
374
  ))}
410
375
  </div>
411
376
  ) : unavailable ? (
412
- <p className="py-4 text-center text-xs text-muted-foreground">
413
- Audit log not available yet.
414
- </p>
377
+ <p className="py-4 text-center text-xs text-muted-foreground">Audit log not available yet.</p>
415
378
  ) : entries.length === 0 ? (
416
379
  <p className="py-4 text-center text-xs text-muted-foreground">No access recorded yet.</p>
417
380
  ) : (
@@ -580,8 +543,7 @@ function RotateDialog({ secretName, onRotate }: { secretName: string; onRotate:
580
543
  <DialogHeader>
581
544
  <DialogTitle>Rotate Secret</DialogTitle>
582
545
  <DialogDescription>
583
- Generate a new value for <strong>{secretName}</strong>. The current value will be
584
- immediately invalidated.
546
+ Generate a new value for <strong>{secretName}</strong>. The current value will be immediately invalidated.
585
547
  </DialogDescription>
586
548
  </DialogHeader>
587
549
  <div className="rounded-sm border border-chart-3/20 bg-chart-3/10 px-3 py-2 text-sm text-chart-3">
@@ -606,13 +568,7 @@ function RotateDialog({ secretName, onRotate }: { secretName: string; onRotate:
606
568
  );
607
569
  }
608
570
 
609
- function DeleteSecretDialog({
610
- secretName,
611
- onDelete,
612
- }: {
613
- secretName: string;
614
- onDelete: () => void;
615
- }) {
571
+ function DeleteSecretDialog({ secretName, onDelete }: { secretName: string; onDelete: () => void }) {
616
572
  const [open, setOpen] = useState(false);
617
573
 
618
574
  return (
@@ -631,8 +587,7 @@ function DeleteSecretDialog({
631
587
  <DialogHeader>
632
588
  <DialogTitle>Delete Secret</DialogTitle>
633
589
  <DialogDescription>
634
- Are you sure you want to delete <strong>{secretName}</strong>? This action cannot be
635
- undone.
590
+ Are you sure you want to delete <strong>{secretName}</strong>? This action cannot be undone.
636
591
  </DialogDescription>
637
592
  </DialogHeader>
638
593
  <div className="rounded-sm border border-destructive/20 bg-destructive/10 px-3 py-2 text-sm text-destructive">