@proofhound/web-ui 0.1.6

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 (483) hide show
  1. package/LICENSE +190 -0
  2. package/dist/components/annotations/annotation-claim-dialog.d.ts +13 -0
  3. package/dist/components/annotations/annotation-claim-dialog.d.ts.map +1 -0
  4. package/dist/components/annotations/annotation-claim-dialog.js +60 -0
  5. package/dist/components/annotations/annotation-claim-dialog.js.map +1 -0
  6. package/dist/components/charts/source-legend.d.ts +10 -0
  7. package/dist/components/charts/source-legend.d.ts.map +1 -0
  8. package/dist/components/charts/source-legend.js +15 -0
  9. package/dist/components/charts/source-legend.js.map +1 -0
  10. package/dist/components/charts/source-stacked-bar.d.ts +22 -0
  11. package/dist/components/charts/source-stacked-bar.d.ts.map +1 -0
  12. package/dist/components/charts/source-stacked-bar.js +43 -0
  13. package/dist/components/charts/source-stacked-bar.js.map +1 -0
  14. package/dist/components/index.d.ts +15 -0
  15. package/dist/components/index.d.ts.map +1 -0
  16. package/dist/components/index.js +17 -0
  17. package/dist/components/index.js.map +1 -0
  18. package/dist/components/json-object-textarea.d.ts +11 -0
  19. package/dist/components/json-object-textarea.d.ts.map +1 -0
  20. package/dist/components/json-object-textarea.js +82 -0
  21. package/dist/components/json-object-textarea.js.map +1 -0
  22. package/dist/components/model-context-window-input.d.ts +15 -0
  23. package/dist/components/model-context-window-input.d.ts.map +1 -0
  24. package/dist/components/model-context-window-input.js +57 -0
  25. package/dist/components/model-context-window-input.js.map +1 -0
  26. package/dist/components/model-probe-status.d.ts +11 -0
  27. package/dist/components/model-probe-status.d.ts.map +1 -0
  28. package/dist/components/model-probe-status.js +34 -0
  29. package/dist/components/model-probe-status.js.map +1 -0
  30. package/dist/components/prompt-diff/prompt-diff-split-view.d.ts +28 -0
  31. package/dist/components/prompt-diff/prompt-diff-split-view.d.ts.map +1 -0
  32. package/dist/components/prompt-diff/prompt-diff-split-view.js +101 -0
  33. package/dist/components/prompt-diff/prompt-diff-split-view.js.map +1 -0
  34. package/dist/components/prompt-language-select.d.ts +13 -0
  35. package/dist/components/prompt-language-select.d.ts.map +1 -0
  36. package/dist/components/prompt-language-select.js +14 -0
  37. package/dist/components/prompt-language-select.js.map +1 -0
  38. package/dist/components/prompt-version-picker-row.d.ts +27 -0
  39. package/dist/components/prompt-version-picker-row.d.ts.map +1 -0
  40. package/dist/components/prompt-version-picker-row.js +50 -0
  41. package/dist/components/prompt-version-picker-row.js.map +1 -0
  42. package/dist/components/prompt-version-status-badge.d.ts +8 -0
  43. package/dist/components/prompt-version-status-badge.d.ts.map +1 -0
  44. package/dist/components/prompt-version-status-badge.js +31 -0
  45. package/dist/components/prompt-version-status-badge.js.map +1 -0
  46. package/dist/components/quick-fill/quick-fill-picker.d.ts +42 -0
  47. package/dist/components/quick-fill/quick-fill-picker.d.ts.map +1 -0
  48. package/dist/components/quick-fill/quick-fill-picker.js +46 -0
  49. package/dist/components/quick-fill/quick-fill-picker.js.map +1 -0
  50. package/dist/components/time-zone-preference-menu.d.ts +10 -0
  51. package/dist/components/time-zone-preference-menu.d.ts.map +1 -0
  52. package/dist/components/time-zone-preference-menu.js +33 -0
  53. package/dist/components/time-zone-preference-menu.js.map +1 -0
  54. package/dist/contracts/index.d.ts +13 -0
  55. package/dist/contracts/index.d.ts.map +1 -0
  56. package/dist/contracts/index.js +7 -0
  57. package/dist/contracts/index.js.map +1 -0
  58. package/dist/features/index.d.ts +3 -0
  59. package/dist/features/index.d.ts.map +1 -0
  60. package/dist/features/index.js +4 -0
  61. package/dist/features/index.js.map +1 -0
  62. package/dist/features/model-quick-fill/model-preset-draft.d.ts +19 -0
  63. package/dist/features/model-quick-fill/model-preset-draft.d.ts.map +1 -0
  64. package/dist/features/model-quick-fill/model-preset-draft.js +22 -0
  65. package/dist/features/model-quick-fill/model-preset-draft.js.map +1 -0
  66. package/dist/features/model-quick-fill/model-preset-quick-fill.d.ts +7 -0
  67. package/dist/features/model-quick-fill/model-preset-quick-fill.d.ts.map +1 -0
  68. package/dist/features/model-quick-fill/model-preset-quick-fill.js +73 -0
  69. package/dist/features/model-quick-fill/model-preset-quick-fill.js.map +1 -0
  70. package/dist/hooks/annotation.d.ts +253 -0
  71. package/dist/hooks/annotation.d.ts.map +1 -0
  72. package/dist/hooks/annotation.js +79 -0
  73. package/dist/hooks/annotation.js.map +1 -0
  74. package/dist/hooks/canary-release.d.ts +674 -0
  75. package/dist/hooks/canary-release.d.ts.map +1 -0
  76. package/dist/hooks/canary-release.js +142 -0
  77. package/dist/hooks/canary-release.js.map +1 -0
  78. package/dist/hooks/connector.d.ts +585 -0
  79. package/dist/hooks/connector.d.ts.map +1 -0
  80. package/dist/hooks/connector.js +157 -0
  81. package/dist/hooks/connector.js.map +1 -0
  82. package/dist/hooks/dataset.d.ts +138 -0
  83. package/dist/hooks/dataset.d.ts.map +1 -0
  84. package/dist/hooks/dataset.js +84 -0
  85. package/dist/hooks/dataset.js.map +1 -0
  86. package/dist/hooks/experiment.d.ts +376 -0
  87. package/dist/hooks/experiment.d.ts.map +1 -0
  88. package/dist/hooks/experiment.js +58 -0
  89. package/dist/hooks/experiment.js.map +1 -0
  90. package/dist/hooks/index.d.ts +18 -0
  91. package/dist/hooks/index.d.ts.map +1 -0
  92. package/dist/hooks/index.js +18 -0
  93. package/dist/hooks/index.js.map +1 -0
  94. package/dist/hooks/model.d.ts +327 -0
  95. package/dist/hooks/model.d.ts.map +1 -0
  96. package/dist/hooks/model.js +103 -0
  97. package/dist/hooks/model.js.map +1 -0
  98. package/dist/hooks/optimization.d.ts +557 -0
  99. package/dist/hooks/optimization.d.ts.map +1 -0
  100. package/dist/hooks/optimization.js +94 -0
  101. package/dist/hooks/optimization.js.map +1 -0
  102. package/dist/hooks/production-release.d.ts +141 -0
  103. package/dist/hooks/production-release.d.ts.map +1 -0
  104. package/dist/hooks/production-release.js +51 -0
  105. package/dist/hooks/production-release.js.map +1 -0
  106. package/dist/hooks/project-monitoring.d.ts +199 -0
  107. package/dist/hooks/project-monitoring.d.ts.map +1 -0
  108. package/dist/hooks/project-monitoring.js +55 -0
  109. package/dist/hooks/project-monitoring.js.map +1 -0
  110. package/dist/hooks/prompt.d.ts +509 -0
  111. package/dist/hooks/prompt.d.ts.map +1 -0
  112. package/dist/hooks/prompt.js +127 -0
  113. package/dist/hooks/prompt.js.map +1 -0
  114. package/dist/hooks/quick-start.d.ts +219 -0
  115. package/dist/hooks/quick-start.d.ts.map +1 -0
  116. package/dist/hooks/quick-start.js +35 -0
  117. package/dist/hooks/quick-start.js.map +1 -0
  118. package/dist/hooks/release-line.d.ts +819 -0
  119. package/dist/hooks/release-line.d.ts.map +1 -0
  120. package/dist/hooks/release-line.js +52 -0
  121. package/dist/hooks/release-line.js.map +1 -0
  122. package/dist/hooks/run-result.d.ts +118 -0
  123. package/dist/hooks/run-result.d.ts.map +1 -0
  124. package/dist/hooks/run-result.js +56 -0
  125. package/dist/hooks/run-result.js.map +1 -0
  126. package/dist/hooks/token.d.ts +58 -0
  127. package/dist/hooks/token.d.ts.map +1 -0
  128. package/dist/hooks/token.js +39 -0
  129. package/dist/hooks/token.js.map +1 -0
  130. package/dist/hooks/use-auto-refresh.d.ts +30 -0
  131. package/dist/hooks/use-auto-refresh.d.ts.map +1 -0
  132. package/dist/hooks/use-auto-refresh.js +175 -0
  133. package/dist/hooks/use-auto-refresh.js.map +1 -0
  134. package/dist/hooks/use-date-time-formatter.d.ts +11 -0
  135. package/dist/hooks/use-date-time-formatter.d.ts.map +1 -0
  136. package/dist/hooks/use-date-time-formatter.js +24 -0
  137. package/dist/hooks/use-date-time-formatter.js.map +1 -0
  138. package/dist/hooks/use-delayed-loading.d.ts +25 -0
  139. package/dist/hooks/use-delayed-loading.d.ts.map +1 -0
  140. package/dist/hooks/use-delayed-loading.js +95 -0
  141. package/dist/hooks/use-delayed-loading.js.map +1 -0
  142. package/dist/i18n/index.d.ts +5678 -0
  143. package/dist/i18n/index.d.ts.map +1 -0
  144. package/dist/i18n/index.js +5712 -0
  145. package/dist/i18n/index.js.map +1 -0
  146. package/dist/i18n/language.d.ts +17 -0
  147. package/dist/i18n/language.d.ts.map +1 -0
  148. package/dist/i18n/language.js +43 -0
  149. package/dist/i18n/language.js.map +1 -0
  150. package/dist/index.d.ts +2 -0
  151. package/dist/index.d.ts.map +1 -0
  152. package/dist/index.js +2 -0
  153. package/dist/index.js.map +1 -0
  154. package/dist/lib/api-error.d.ts +2 -0
  155. package/dist/lib/api-error.d.ts.map +1 -0
  156. package/dist/lib/api-error.js +38 -0
  157. package/dist/lib/api-error.js.map +1 -0
  158. package/dist/lib/format.d.ts +30 -0
  159. package/dist/lib/format.d.ts.map +1 -0
  160. package/dist/lib/format.js +157 -0
  161. package/dist/lib/format.js.map +1 -0
  162. package/dist/lib/index.d.ts +8 -0
  163. package/dist/lib/index.d.ts.map +1 -0
  164. package/dist/lib/index.js +8 -0
  165. package/dist/lib/index.js.map +1 -0
  166. package/dist/lib/model-number.d.ts +2 -0
  167. package/dist/lib/model-number.d.ts.map +1 -0
  168. package/dist/lib/model-number.js +18 -0
  169. package/dist/lib/model-number.js.map +1 -0
  170. package/dist/lib/model-provider-type.d.ts +7 -0
  171. package/dist/lib/model-provider-type.d.ts.map +1 -0
  172. package/dist/lib/model-provider-type.js +28 -0
  173. package/dist/lib/model-provider-type.js.map +1 -0
  174. package/dist/lib/project-name.d.ts +7 -0
  175. package/dist/lib/project-name.d.ts.map +1 -0
  176. package/dist/lib/project-name.js +14 -0
  177. package/dist/lib/project-name.js.map +1 -0
  178. package/dist/lib/releases/release-line-model.d.ts +55 -0
  179. package/dist/lib/releases/release-line-model.d.ts.map +1 -0
  180. package/dist/lib/releases/release-line-model.js +476 -0
  181. package/dist/lib/releases/release-line-model.js.map +1 -0
  182. package/dist/lib/time-zone.d.ts +14 -0
  183. package/dist/lib/time-zone.d.ts.map +1 -0
  184. package/dist/lib/time-zone.js +118 -0
  185. package/dist/lib/time-zone.js.map +1 -0
  186. package/dist/lib/uuid.d.ts +2 -0
  187. package/dist/lib/uuid.d.ts.map +1 -0
  188. package/dist/lib/uuid.js +5 -0
  189. package/dist/lib/uuid.js.map +1 -0
  190. package/dist/providers/display-preferences-provider.d.ts +18 -0
  191. package/dist/providers/display-preferences-provider.d.ts.map +1 -0
  192. package/dist/providers/display-preferences-provider.js +46 -0
  193. package/dist/providers/display-preferences-provider.js.map +1 -0
  194. package/dist/providers/index.d.ts +5 -0
  195. package/dist/providers/index.d.ts.map +1 -0
  196. package/dist/providers/index.js +5 -0
  197. package/dist/providers/index.js.map +1 -0
  198. package/dist/providers/project-context-provider.d.ts +8 -0
  199. package/dist/providers/project-context-provider.d.ts.map +1 -0
  200. package/dist/providers/project-context-provider.js +15 -0
  201. package/dist/providers/project-context-provider.js.map +1 -0
  202. package/dist/providers/proofhound-web-provider.d.ts +9 -0
  203. package/dist/providers/proofhound-web-provider.d.ts.map +1 -0
  204. package/dist/providers/proofhound-web-provider.js +44 -0
  205. package/dist/providers/proofhound-web-provider.js.map +1 -0
  206. package/dist/providers/refine-provider.d.ts +5 -0
  207. package/dist/providers/refine-provider.d.ts.map +1 -0
  208. package/dist/providers/refine-provider.js +23 -0
  209. package/dist/providers/refine-provider.js.map +1 -0
  210. package/dist/screens/annotations/annotation-detail-page.d.ts +5 -0
  211. package/dist/screens/annotations/annotation-detail-page.d.ts.map +1 -0
  212. package/dist/screens/annotations/annotation-detail-page.js +379 -0
  213. package/dist/screens/annotations/annotation-detail-page.js.map +1 -0
  214. package/dist/screens/annotations/annotation-new-page.d.ts +4 -0
  215. package/dist/screens/annotations/annotation-new-page.d.ts.map +1 -0
  216. package/dist/screens/annotations/annotation-new-page.js +125 -0
  217. package/dist/screens/annotations/annotation-new-page.js.map +1 -0
  218. package/dist/screens/annotations/annotation-task-model.d.ts +39 -0
  219. package/dist/screens/annotations/annotation-task-model.d.ts.map +1 -0
  220. package/dist/screens/annotations/annotation-task-model.js +88 -0
  221. package/dist/screens/annotations/annotation-task-model.js.map +1 -0
  222. package/dist/screens/annotations/annotation-ui.d.ts +33 -0
  223. package/dist/screens/annotations/annotation-ui.d.ts.map +1 -0
  224. package/dist/screens/annotations/annotation-ui.js +92 -0
  225. package/dist/screens/annotations/annotation-ui.js.map +1 -0
  226. package/dist/screens/annotations/annotations-list-page.d.ts +4 -0
  227. package/dist/screens/annotations/annotations-list-page.d.ts.map +1 -0
  228. package/dist/screens/annotations/annotations-list-page.js +82 -0
  229. package/dist/screens/annotations/annotations-list-page.js.map +1 -0
  230. package/dist/screens/connectors/connector-detail-page.d.ts +5 -0
  231. package/dist/screens/connectors/connector-detail-page.d.ts.map +1 -0
  232. package/dist/screens/connectors/connector-detail-page.js +838 -0
  233. package/dist/screens/connectors/connector-detail-page.js.map +1 -0
  234. package/dist/screens/connectors/connector-form-page.d.ts +8 -0
  235. package/dist/screens/connectors/connector-form-page.d.ts.map +1 -0
  236. package/dist/screens/connectors/connector-form-page.js +328 -0
  237. package/dist/screens/connectors/connector-form-page.js.map +1 -0
  238. package/dist/screens/connectors/connector-peek-dialog.d.ts +8 -0
  239. package/dist/screens/connectors/connector-peek-dialog.d.ts.map +1 -0
  240. package/dist/screens/connectors/connector-peek-dialog.js +24 -0
  241. package/dist/screens/connectors/connector-peek-dialog.js.map +1 -0
  242. package/dist/screens/connectors/connector-types.d.ts +36 -0
  243. package/dist/screens/connectors/connector-types.d.ts.map +1 -0
  244. package/dist/screens/connectors/connector-types.js +48 -0
  245. package/dist/screens/connectors/connector-types.js.map +1 -0
  246. package/dist/screens/connectors/connector-ui.d.ts +14 -0
  247. package/dist/screens/connectors/connector-ui.d.ts.map +1 -0
  248. package/dist/screens/connectors/connector-ui.js +40 -0
  249. package/dist/screens/connectors/connector-ui.js.map +1 -0
  250. package/dist/screens/connectors/connectors-list-page.d.ts +4 -0
  251. package/dist/screens/connectors/connectors-list-page.d.ts.map +1 -0
  252. package/dist/screens/connectors/connectors-list-page.js +220 -0
  253. package/dist/screens/connectors/connectors-list-page.js.map +1 -0
  254. package/dist/screens/dashboard/dashboard-screen.d.ts +5 -0
  255. package/dist/screens/dashboard/dashboard-screen.d.ts.map +1 -0
  256. package/dist/screens/dashboard/dashboard-screen.js +524 -0
  257. package/dist/screens/dashboard/dashboard-screen.js.map +1 -0
  258. package/dist/screens/datasets/dataset-detail-helpers.d.ts +10 -0
  259. package/dist/screens/datasets/dataset-detail-helpers.d.ts.map +1 -0
  260. package/dist/screens/datasets/dataset-detail-helpers.js +84 -0
  261. package/dist/screens/datasets/dataset-detail-helpers.js.map +1 -0
  262. package/dist/screens/datasets/dataset-detail-page.d.ts +6 -0
  263. package/dist/screens/datasets/dataset-detail-page.d.ts.map +1 -0
  264. package/dist/screens/datasets/dataset-detail-page.js +379 -0
  265. package/dist/screens/datasets/dataset-detail-page.js.map +1 -0
  266. package/dist/screens/datasets/dataset-import-runner.d.ts +17 -0
  267. package/dist/screens/datasets/dataset-import-runner.d.ts.map +1 -0
  268. package/dist/screens/datasets/dataset-import-runner.js +33 -0
  269. package/dist/screens/datasets/dataset-import-runner.js.map +1 -0
  270. package/dist/screens/datasets/dataset-mappers.d.ts +5 -0
  271. package/dist/screens/datasets/dataset-mappers.d.ts.map +1 -0
  272. package/dist/screens/datasets/dataset-mappers.js +79 -0
  273. package/dist/screens/datasets/dataset-mappers.js.map +1 -0
  274. package/dist/screens/datasets/dataset-samples-table.d.ts +21 -0
  275. package/dist/screens/datasets/dataset-samples-table.d.ts.map +1 -0
  276. package/dist/screens/datasets/dataset-samples-table.js +59 -0
  277. package/dist/screens/datasets/dataset-samples-table.js.map +1 -0
  278. package/dist/screens/datasets/dataset-transfer-progress.d.ts +30 -0
  279. package/dist/screens/datasets/dataset-transfer-progress.d.ts.map +1 -0
  280. package/dist/screens/datasets/dataset-transfer-progress.js +157 -0
  281. package/dist/screens/datasets/dataset-transfer-progress.js.map +1 -0
  282. package/dist/screens/datasets/dataset-types.d.ts +59 -0
  283. package/dist/screens/datasets/dataset-types.d.ts.map +1 -0
  284. package/dist/screens/datasets/dataset-types.js +15 -0
  285. package/dist/screens/datasets/dataset-types.js.map +1 -0
  286. package/dist/screens/datasets/dataset-ui.d.ts +49 -0
  287. package/dist/screens/datasets/dataset-ui.d.ts.map +1 -0
  288. package/dist/screens/datasets/dataset-ui.js +163 -0
  289. package/dist/screens/datasets/dataset-ui.js.map +1 -0
  290. package/dist/screens/datasets/dataset-upload-page.d.ts +4 -0
  291. package/dist/screens/datasets/dataset-upload-page.d.ts.map +1 -0
  292. package/dist/screens/datasets/dataset-upload-page.js +425 -0
  293. package/dist/screens/datasets/dataset-upload-page.js.map +1 -0
  294. package/dist/screens/datasets/dataset-upload-parser.d.ts +21 -0
  295. package/dist/screens/datasets/dataset-upload-parser.d.ts.map +1 -0
  296. package/dist/screens/datasets/dataset-upload-parser.js +536 -0
  297. package/dist/screens/datasets/dataset-upload-parser.js.map +1 -0
  298. package/dist/screens/datasets/datasets-list-page.d.ts +4 -0
  299. package/dist/screens/datasets/datasets-list-page.d.ts.map +1 -0
  300. package/dist/screens/datasets/datasets-list-page.js +249 -0
  301. package/dist/screens/datasets/datasets-list-page.js.map +1 -0
  302. package/dist/screens/experiments/experiment-detail-page.d.ts +5 -0
  303. package/dist/screens/experiments/experiment-detail-page.d.ts.map +1 -0
  304. package/dist/screens/experiments/experiment-detail-page.js +460 -0
  305. package/dist/screens/experiments/experiment-detail-page.js.map +1 -0
  306. package/dist/screens/experiments/experiment-new-page.d.ts +21 -0
  307. package/dist/screens/experiments/experiment-new-page.d.ts.map +1 -0
  308. package/dist/screens/experiments/experiment-new-page.js +427 -0
  309. package/dist/screens/experiments/experiment-new-page.js.map +1 -0
  310. package/dist/screens/experiments/experiment-option-adapter.d.ts +68 -0
  311. package/dist/screens/experiments/experiment-option-adapter.d.ts.map +1 -0
  312. package/dist/screens/experiments/experiment-option-adapter.js +225 -0
  313. package/dist/screens/experiments/experiment-option-adapter.js.map +1 -0
  314. package/dist/screens/experiments/experiment-progress.d.ts +5 -0
  315. package/dist/screens/experiments/experiment-progress.d.ts.map +1 -0
  316. package/dist/screens/experiments/experiment-progress.js +15 -0
  317. package/dist/screens/experiments/experiment-progress.js.map +1 -0
  318. package/dist/screens/experiments/experiment-repeat-href.d.ts +17 -0
  319. package/dist/screens/experiments/experiment-repeat-href.d.ts.map +1 -0
  320. package/dist/screens/experiments/experiment-repeat-href.js +32 -0
  321. package/dist/screens/experiments/experiment-repeat-href.js.map +1 -0
  322. package/dist/screens/experiments/experiment-theme.d.ts +43 -0
  323. package/dist/screens/experiments/experiment-theme.d.ts.map +1 -0
  324. package/dist/screens/experiments/experiment-theme.js +43 -0
  325. package/dist/screens/experiments/experiment-theme.js.map +1 -0
  326. package/dist/screens/experiments/experiment-ui.d.ts +36 -0
  327. package/dist/screens/experiments/experiment-ui.d.ts.map +1 -0
  328. package/dist/screens/experiments/experiment-ui.js +46 -0
  329. package/dist/screens/experiments/experiment-ui.js.map +1 -0
  330. package/dist/screens/experiments/experiment-view-model.d.ts +118 -0
  331. package/dist/screens/experiments/experiment-view-model.d.ts.map +1 -0
  332. package/dist/screens/experiments/experiment-view-model.js +114 -0
  333. package/dist/screens/experiments/experiment-view-model.js.map +1 -0
  334. package/dist/screens/experiments/experiments-comparison-view.d.ts +10 -0
  335. package/dist/screens/experiments/experiments-comparison-view.d.ts.map +1 -0
  336. package/dist/screens/experiments/experiments-comparison-view.js +215 -0
  337. package/dist/screens/experiments/experiments-comparison-view.js.map +1 -0
  338. package/dist/screens/experiments/experiments-list-page.d.ts +4 -0
  339. package/dist/screens/experiments/experiments-list-page.d.ts.map +1 -0
  340. package/dist/screens/experiments/experiments-list-page.js +364 -0
  341. package/dist/screens/experiments/experiments-list-page.js.map +1 -0
  342. package/dist/screens/experiments/experiments-table.d.ts +18 -0
  343. package/dist/screens/experiments/experiments-table.d.ts.map +1 -0
  344. package/dist/screens/experiments/experiments-table.js +97 -0
  345. package/dist/screens/experiments/experiments-table.js.map +1 -0
  346. package/dist/screens/experiments/run-result-detail-sheet.d.ts +9 -0
  347. package/dist/screens/experiments/run-result-detail-sheet.d.ts.map +1 -0
  348. package/dist/screens/experiments/run-result-detail-sheet.js +89 -0
  349. package/dist/screens/experiments/run-result-detail-sheet.js.map +1 -0
  350. package/dist/screens/experiments/run-result-display.d.ts +28 -0
  351. package/dist/screens/experiments/run-result-display.d.ts.map +1 -0
  352. package/dist/screens/experiments/run-result-display.js +124 -0
  353. package/dist/screens/experiments/run-result-display.js.map +1 -0
  354. package/dist/screens/experiments/run-result-labels.d.ts +16 -0
  355. package/dist/screens/experiments/run-result-labels.d.ts.map +1 -0
  356. package/dist/screens/experiments/run-result-labels.js +52 -0
  357. package/dist/screens/experiments/run-result-labels.js.map +1 -0
  358. package/dist/screens/index.d.ts +29 -0
  359. package/dist/screens/index.d.ts.map +1 -0
  360. package/dist/screens/index.js +43 -0
  361. package/dist/screens/index.js.map +1 -0
  362. package/dist/screens/models/model-form-page.d.ts +9 -0
  363. package/dist/screens/models/model-form-page.d.ts.map +1 -0
  364. package/dist/screens/models/model-form-page.js +876 -0
  365. package/dist/screens/models/model-form-page.js.map +1 -0
  366. package/dist/screens/models/model-view-model.d.ts +66 -0
  367. package/dist/screens/models/model-view-model.d.ts.map +1 -0
  368. package/dist/screens/models/model-view-model.js +36 -0
  369. package/dist/screens/models/model-view-model.js.map +1 -0
  370. package/dist/screens/models/models-list-page.d.ts +4 -0
  371. package/dist/screens/models/models-list-page.d.ts.map +1 -0
  372. package/dist/screens/models/models-list-page.js +352 -0
  373. package/dist/screens/models/models-list-page.js.map +1 -0
  374. package/dist/screens/models/project-model-adapter.d.ts +5 -0
  375. package/dist/screens/models/project-model-adapter.d.ts.map +1 -0
  376. package/dist/screens/models/project-model-adapter.js +63 -0
  377. package/dist/screens/models/project-model-adapter.js.map +1 -0
  378. package/dist/screens/monitoring/big-chart-card.d.ts +36 -0
  379. package/dist/screens/monitoring/big-chart-card.d.ts.map +1 -0
  380. package/dist/screens/monitoring/big-chart-card.js +32 -0
  381. package/dist/screens/monitoring/big-chart-card.js.map +1 -0
  382. package/dist/screens/monitoring/monitoring-filter-strip.d.ts +14 -0
  383. package/dist/screens/monitoring/monitoring-filter-strip.d.ts.map +1 -0
  384. package/dist/screens/monitoring/monitoring-filter-strip.js +36 -0
  385. package/dist/screens/monitoring/monitoring-filter-strip.js.map +1 -0
  386. package/dist/screens/monitoring/project-monitoring-page.d.ts +9 -0
  387. package/dist/screens/monitoring/project-monitoring-page.d.ts.map +1 -0
  388. package/dist/screens/monitoring/project-monitoring-page.js +240 -0
  389. package/dist/screens/monitoring/project-monitoring-page.js.map +1 -0
  390. package/dist/screens/monitoring/ranking-cards.d.ts +23 -0
  391. package/dist/screens/monitoring/ranking-cards.d.ts.map +1 -0
  392. package/dist/screens/monitoring/ranking-cards.js +78 -0
  393. package/dist/screens/monitoring/ranking-cards.js.map +1 -0
  394. package/dist/screens/optimizations/optimization-detail-page.d.ts +5 -0
  395. package/dist/screens/optimizations/optimization-detail-page.d.ts.map +1 -0
  396. package/dist/screens/optimizations/optimization-detail-page.js +934 -0
  397. package/dist/screens/optimizations/optimization-detail-page.js.map +1 -0
  398. package/dist/screens/optimizations/optimization-mappers.d.ts +56 -0
  399. package/dist/screens/optimizations/optimization-mappers.d.ts.map +1 -0
  400. package/dist/screens/optimizations/optimization-mappers.js +142 -0
  401. package/dist/screens/optimizations/optimization-mappers.js.map +1 -0
  402. package/dist/screens/optimizations/optimization-new-page.d.ts +8 -0
  403. package/dist/screens/optimizations/optimization-new-page.d.ts.map +1 -0
  404. package/dist/screens/optimizations/optimization-new-page.js +732 -0
  405. package/dist/screens/optimizations/optimization-new-page.js.map +1 -0
  406. package/dist/screens/optimizations/optimization-theme.d.ts +43 -0
  407. package/dist/screens/optimizations/optimization-theme.d.ts.map +1 -0
  408. package/dist/screens/optimizations/optimization-theme.js +46 -0
  409. package/dist/screens/optimizations/optimization-theme.js.map +1 -0
  410. package/dist/screens/optimizations/optimization-ui.d.ts +60 -0
  411. package/dist/screens/optimizations/optimization-ui.d.ts.map +1 -0
  412. package/dist/screens/optimizations/optimization-ui.js +164 -0
  413. package/dist/screens/optimizations/optimization-ui.js.map +1 -0
  414. package/dist/screens/optimizations/optimizations-list-page.d.ts +4 -0
  415. package/dist/screens/optimizations/optimizations-list-page.d.ts.map +1 -0
  416. package/dist/screens/optimizations/optimizations-list-page.js +358 -0
  417. package/dist/screens/optimizations/optimizations-list-page.js.map +1 -0
  418. package/dist/screens/prompts/prompt-body-editor.d.ts +15 -0
  419. package/dist/screens/prompts/prompt-body-editor.d.ts.map +1 -0
  420. package/dist/screens/prompts/prompt-body-editor.js +165 -0
  421. package/dist/screens/prompts/prompt-body-editor.js.map +1 -0
  422. package/dist/screens/prompts/prompt-dataset-variables.d.ts +4 -0
  423. package/dist/screens/prompts/prompt-dataset-variables.d.ts.map +1 -0
  424. package/dist/screens/prompts/prompt-dataset-variables.js +27 -0
  425. package/dist/screens/prompts/prompt-dataset-variables.js.map +1 -0
  426. package/dist/screens/prompts/prompt-detail-page.d.ts +5 -0
  427. package/dist/screens/prompts/prompt-detail-page.d.ts.map +1 -0
  428. package/dist/screens/prompts/prompt-detail-page.js +1013 -0
  429. package/dist/screens/prompts/prompt-detail-page.js.map +1 -0
  430. package/dist/screens/prompts/prompt-model.d.ts +77 -0
  431. package/dist/screens/prompts/prompt-model.d.ts.map +1 -0
  432. package/dist/screens/prompts/prompt-model.js +152 -0
  433. package/dist/screens/prompts/prompt-model.js.map +1 -0
  434. package/dist/screens/prompts/prompt-preview-parts.d.ts +12 -0
  435. package/dist/screens/prompts/prompt-preview-parts.d.ts.map +1 -0
  436. package/dist/screens/prompts/prompt-preview-parts.js +32 -0
  437. package/dist/screens/prompts/prompt-preview-parts.js.map +1 -0
  438. package/dist/screens/prompts/prompt-preview.d.ts +10 -0
  439. package/dist/screens/prompts/prompt-preview.d.ts.map +1 -0
  440. package/dist/screens/prompts/prompt-preview.js +16 -0
  441. package/dist/screens/prompts/prompt-preview.js.map +1 -0
  442. package/dist/screens/prompts/prompt-ui.d.ts +30 -0
  443. package/dist/screens/prompts/prompt-ui.d.ts.map +1 -0
  444. package/dist/screens/prompts/prompt-ui.js +51 -0
  445. package/dist/screens/prompts/prompt-ui.js.map +1 -0
  446. package/dist/screens/prompts/prompts-list-page.d.ts +5 -0
  447. package/dist/screens/prompts/prompts-list-page.d.ts.map +1 -0
  448. package/dist/screens/prompts/prompts-list-page.js +208 -0
  449. package/dist/screens/prompts/prompts-list-page.js.map +1 -0
  450. package/dist/screens/quick-start/quick-start-screen.d.ts +2 -0
  451. package/dist/screens/quick-start/quick-start-screen.d.ts.map +1 -0
  452. package/dist/screens/quick-start/quick-start-screen.js +486 -0
  453. package/dist/screens/quick-start/quick-start-screen.js.map +1 -0
  454. package/dist/screens/releases/release-line-detail-page.d.ts +5 -0
  455. package/dist/screens/releases/release-line-detail-page.d.ts.map +1 -0
  456. package/dist/screens/releases/release-line-detail-page.js +973 -0
  457. package/dist/screens/releases/release-line-detail-page.js.map +1 -0
  458. package/dist/screens/releases/release-line-ui.d.ts +30 -0
  459. package/dist/screens/releases/release-line-ui.d.ts.map +1 -0
  460. package/dist/screens/releases/release-line-ui.js +197 -0
  461. package/dist/screens/releases/release-line-ui.js.map +1 -0
  462. package/dist/screens/releases/release-new-model.d.ts +5 -0
  463. package/dist/screens/releases/release-new-model.d.ts.map +1 -0
  464. package/dist/screens/releases/release-new-model.js +18 -0
  465. package/dist/screens/releases/release-new-model.js.map +1 -0
  466. package/dist/screens/releases/release-new-page.d.ts +6 -0
  467. package/dist/screens/releases/release-new-page.d.ts.map +1 -0
  468. package/dist/screens/releases/release-new-page.js +816 -0
  469. package/dist/screens/releases/release-new-page.js.map +1 -0
  470. package/dist/screens/releases/release-topology-canvas.d.ts +13 -0
  471. package/dist/screens/releases/release-topology-canvas.d.ts.map +1 -0
  472. package/dist/screens/releases/release-topology-canvas.js +856 -0
  473. package/dist/screens/releases/release-topology-canvas.js.map +1 -0
  474. package/dist/screens/releases/releases-list-page.d.ts +4 -0
  475. package/dist/screens/releases/releases-list-page.d.ts.map +1 -0
  476. package/dist/screens/releases/releases-list-page.js +86 -0
  477. package/dist/screens/releases/releases-list-page.js.map +1 -0
  478. package/dist/screens/settings/settings-page.d.ts +2 -0
  479. package/dist/screens/settings/settings-page.d.ts.map +1 -0
  480. package/dist/screens/settings/settings-page.js +250 -0
  481. package/dist/screens/settings/settings-page.js.map +1 -0
  482. package/dist/styles/globals.css +961 -0
  483. package/package.json +84 -0
@@ -0,0 +1,856 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useMemo, useState } from 'react';
4
+ import { Background, Controls, Handle, MarkerType, Position, ReactFlow, } from '@xyflow/react';
5
+ import { Cable, FlaskConical, Plus, RadioTower, Rocket, Save, Split } from 'lucide-react';
6
+ import { Button, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, cn, } from '@proofhound/ui';
7
+ import { useDateTimeFormatter } from '../../hooks';
8
+ import { useI18n } from '../../i18n';
9
+ import { getApiErrorMessage } from '../../lib';
10
+ import { ReleasePill, formatPercent } from './release-line-ui';
11
+ const TONE_STYLES = {
12
+ neutral: {
13
+ bg: 'var(--card)',
14
+ fg: 'var(--foreground)',
15
+ bd: 'var(--border)',
16
+ dot: 'var(--muted-foreground)',
17
+ },
18
+ production: {
19
+ bg: 'color-mix(in srgb, var(--status-running-dot) 5%, var(--card))',
20
+ fg: 'var(--status-running-fg)',
21
+ bd: 'color-mix(in srgb, var(--status-running-dot) 35%, var(--border))',
22
+ dot: 'var(--status-running-dot)',
23
+ },
24
+ canary: {
25
+ bg: 'color-mix(in srgb, var(--status-canary-dot) 5%, var(--card))',
26
+ fg: 'var(--status-canary-fg)',
27
+ bd: 'color-mix(in srgb, var(--status-canary-dot) 35%, var(--border))',
28
+ dot: 'var(--status-canary-dot)',
29
+ },
30
+ muted: {
31
+ bg: 'color-mix(in srgb, var(--muted) 58%, var(--card))',
32
+ fg: 'var(--muted-foreground)',
33
+ bd: 'var(--border)',
34
+ dot: 'var(--muted-foreground)',
35
+ },
36
+ };
37
+ const EDGE_STYLES = {
38
+ neutral: 'var(--muted-foreground)',
39
+ production: 'var(--status-running-dot)',
40
+ canary: 'var(--status-canary-dot)',
41
+ muted: 'var(--border)',
42
+ };
43
+ const NODE_ICONS = {
44
+ upstream: RadioTower,
45
+ router: Split,
46
+ production: Rocket,
47
+ canary: FlaskConical,
48
+ downstream: Cable,
49
+ addCanary: Plus,
50
+ };
51
+ function ReleaseTopologyNodeCard({ data, selected }) {
52
+ const token = TONE_STYLES[data.tone];
53
+ const Icon = NODE_ICONS[data.icon];
54
+ const borderColor = data.mutedBorder ? 'var(--border)' : token.bd;
55
+ return (_jsxs("div", { className: cn('relative h-[116px] w-[236px] cursor-pointer rounded-lg border px-3 py-3 shadow-sm transition', data.tone === 'muted' && 'border-dashed opacity-80', data.action === 'addCanary' && 'hover:border-[var(--status-canary-bd)] hover:opacity-100', selected && 'ring-2 ring-primary/25'), style: { background: token.bg, borderColor }, children: [_jsx(Handle, { type: "target", position: Position.Left, className: "!size-2 !border !bg-card !opacity-0", style: { borderColor: token.bd } }), _jsx(Handle, { type: "source", position: Position.Right, className: "!size-2 !border !bg-card !opacity-0", style: { borderColor: token.bd } }), _jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx("span", { className: "mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-md border", style: { background: 'var(--background)', borderColor: token.bd, color: token.dot }, children: _jsx(Icon, { className: "size-4" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex min-w-0 items-center justify-between gap-2", children: [_jsx("span", { className: "truncate text-[11.5px] font-medium text-muted-foreground", children: data.label }), data.badges?.[0] ? (_jsx(ReleasePill, { tone: data.tone === 'production' ? 'production' : data.tone === 'canary' ? 'canary' : 'neutral', className: "max-w-[92px] shrink-0 truncate", children: data.badges[0] })) : null] }), _jsx("div", { className: "mt-1 truncate font-mono text-[13px] font-semibold", title: data.title, children: data.title }), data.meta ? (_jsx("div", { className: "mt-1 truncate font-mono text-[11.5px] text-muted-foreground", title: data.meta, children: data.meta })) : null, data.detail ? (_jsx("div", { className: "mt-1.5 truncate text-[11.5px] font-medium", style: { color: token.fg }, title: data.detail, children: data.detail })) : null] })] })] }));
56
+ }
57
+ const nodeTypes = {
58
+ releaseTopology: ReleaseTopologyNodeCard,
59
+ };
60
+ function createEdge({ id, source, target, label, tone = 'neutral', dashed = false, animated, }) {
61
+ const color = EDGE_STYLES[tone];
62
+ return {
63
+ id,
64
+ source,
65
+ target,
66
+ label,
67
+ type: 'smoothstep',
68
+ animated: animated ?? (tone === 'production' || tone === 'canary'),
69
+ markerEnd: { type: MarkerType.ArrowClosed, color },
70
+ style: {
71
+ stroke: color,
72
+ strokeWidth: tone === 'muted' ? 1.3 : 2,
73
+ strokeDasharray: dashed ? '6 5' : undefined,
74
+ },
75
+ labelStyle: {
76
+ fill: 'var(--muted-foreground)',
77
+ fontSize: 11,
78
+ fontFamily: 'var(--font-mono), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
79
+ fontWeight: 600,
80
+ },
81
+ labelBgStyle: {
82
+ fill: 'var(--card)',
83
+ fillOpacity: 0.92,
84
+ },
85
+ labelBgPadding: [6, 4],
86
+ labelBgBorderRadius: 6,
87
+ };
88
+ }
89
+ function outputNodePosition(index, total) {
90
+ const compact = total <= 2;
91
+ const step = compact ? 126 : 108;
92
+ const startY = 136 - ((total - 1) * step) / 2;
93
+ return { x: 1240, y: startY + index * step };
94
+ }
95
+ function clampTrafficRatio(value) {
96
+ return typeof value === 'number' && Number.isFinite(value) ? Math.max(0, Math.min(1, value)) : 0;
97
+ }
98
+ function getTrafficState(line) {
99
+ const hasProduction = Boolean(line.production?.currentEvent);
100
+ const canaryRatio = line.canary ? clampTrafficRatio(line.canary.trafficRatio) : 0;
101
+ const productionRatio = hasProduction
102
+ ? !line.canary || line.canary.trafficMode === 'dual_run'
103
+ ? 1
104
+ : Math.max(0, 1 - canaryRatio)
105
+ : 0;
106
+ return {
107
+ productionRatio,
108
+ canaryRatio,
109
+ productionHasTraffic: productionRatio > 0,
110
+ canaryHasTraffic: Boolean(line.canary) && canaryRatio > 0,
111
+ };
112
+ }
113
+ function buildTopology(line, labels) {
114
+ const traffic = getTrafficState(line);
115
+ const canaryTraffic = line.canary ? formatPercent(traffic.canaryRatio, 0) : labels.noTraffic;
116
+ const canAddCanary = !line.canary && line.production?.currentEvent?.status === 'running';
117
+ const nodes = [
118
+ {
119
+ id: 'upstream',
120
+ type: 'releaseTopology',
121
+ position: { x: 0, y: 136 },
122
+ data: {
123
+ icon: 'upstream',
124
+ label: labels.upstream,
125
+ title: line.inputConnectorName ?? labels.unconfigured,
126
+ tone: line.inputConnectorName ? 'neutral' : 'muted',
127
+ },
128
+ },
129
+ {
130
+ id: 'input-route',
131
+ type: 'releaseTopology',
132
+ position: { x: 310, y: 136 },
133
+ data: {
134
+ icon: 'router',
135
+ label: labels.inputRoute,
136
+ title: `${labels.productionTrafficLabel} ${labels.productionTraffic}`,
137
+ meta: `${labels.canaryTrafficLabel} ${canaryTraffic}`,
138
+ tone: 'neutral',
139
+ },
140
+ },
141
+ ];
142
+ const edges = [
143
+ createEdge({
144
+ id: 'upstream-router',
145
+ source: 'upstream',
146
+ target: 'input-route',
147
+ label: labels.ingress,
148
+ }),
149
+ ];
150
+ if (line.production?.currentEvent) {
151
+ nodes.push({
152
+ id: 'production',
153
+ type: 'releaseTopology',
154
+ position: { x: 620, y: 62 },
155
+ data: {
156
+ icon: 'production',
157
+ label: labels.productionNode,
158
+ title: line.promptName,
159
+ meta: line.productionVersionLabel ?? labels.unconfigured,
160
+ detail: line.productionModelName ?? labels.noModel,
161
+ tone: 'production',
162
+ mutedBorder: !traffic.productionHasTraffic,
163
+ badges: [labels.productionBadge],
164
+ },
165
+ });
166
+ edges.push(createEdge({
167
+ id: 'router-production',
168
+ source: 'input-route',
169
+ target: 'production',
170
+ label: line.canary ? labels.productionTraffic : '100%',
171
+ tone: 'production',
172
+ animated: traffic.productionHasTraffic,
173
+ }));
174
+ }
175
+ else {
176
+ nodes.push({
177
+ id: 'production',
178
+ type: 'releaseTopology',
179
+ position: { x: 620, y: 62 },
180
+ data: {
181
+ icon: 'production',
182
+ label: labels.productionNode,
183
+ title: labels.noProduction,
184
+ tone: 'muted',
185
+ badges: [labels.productionBadge],
186
+ },
187
+ });
188
+ edges.push(createEdge({
189
+ id: 'router-production-empty',
190
+ source: 'input-route',
191
+ target: 'production',
192
+ label: labels.noTraffic,
193
+ tone: 'muted',
194
+ dashed: true,
195
+ }));
196
+ }
197
+ if (line.canary) {
198
+ nodes.push({
199
+ id: 'canary',
200
+ type: 'releaseTopology',
201
+ position: { x: 620, y: 210 },
202
+ data: {
203
+ icon: 'canary',
204
+ label: labels.canaryNode,
205
+ title: line.promptName,
206
+ meta: line.canaryVersionLabel ?? labels.unconfigured,
207
+ detail: line.canaryModelName ?? labels.noModel,
208
+ tone: 'canary',
209
+ mutedBorder: !traffic.canaryHasTraffic,
210
+ badges: [labels.canaryBadge],
211
+ },
212
+ });
213
+ edges.push(createEdge({
214
+ id: 'router-canary',
215
+ source: 'input-route',
216
+ target: 'canary',
217
+ label: formatPercent(traffic.canaryRatio, 0),
218
+ tone: 'canary',
219
+ animated: traffic.canaryHasTraffic,
220
+ }));
221
+ }
222
+ else {
223
+ nodes.push({
224
+ id: 'canary',
225
+ type: 'releaseTopology',
226
+ position: { x: 620, y: 210 },
227
+ data: {
228
+ icon: canAddCanary ? 'addCanary' : 'canary',
229
+ label: labels.canaryNode,
230
+ title: canAddCanary ? labels.addCanary : labels.noCanary,
231
+ meta: canAddCanary ? labels.noCanary : undefined,
232
+ detail: canAddCanary ? labels.readyForCandidate : undefined,
233
+ tone: 'muted',
234
+ badges: [labels.canaryBadge],
235
+ action: canAddCanary ? 'addCanary' : undefined,
236
+ },
237
+ });
238
+ edges.push(createEdge({
239
+ id: 'router-canary-empty',
240
+ source: 'input-route',
241
+ target: 'canary',
242
+ label: labels.noTraffic,
243
+ tone: 'muted',
244
+ dashed: true,
245
+ }));
246
+ }
247
+ const productionOutputIds = new Set((line.production?.outputConnectors ?? []).map((connector) => connector.id));
248
+ const canaryOutputIds = new Set((line.canary?.outputConnectors ?? []).map((connector) => connector.id));
249
+ nodes.push({
250
+ id: 'output-route',
251
+ type: 'releaseTopology',
252
+ position: { x: 930, y: 136 },
253
+ data: {
254
+ icon: 'router',
255
+ label: labels.outputRoute,
256
+ title: labels.outputRouteTitle,
257
+ meta: labels.outputMapping,
258
+ detail: line.canary?.outputMapping.length ? `${line.canary.outputMapping.length}` : labels.outputMappingEmpty,
259
+ tone: 'neutral',
260
+ badges: [labels.outputDirection],
261
+ },
262
+ });
263
+ edges.push(createEdge({
264
+ id: 'production-output-route',
265
+ source: 'production',
266
+ target: 'output-route',
267
+ label: 'production',
268
+ tone: line.production?.currentEvent ? 'production' : 'muted',
269
+ animated: traffic.productionHasTraffic,
270
+ dashed: !line.production?.currentEvent,
271
+ }), createEdge({
272
+ id: 'canary-output-route',
273
+ source: 'canary',
274
+ target: 'output-route',
275
+ label: 'gray',
276
+ tone: line.canary ? 'canary' : 'muted',
277
+ animated: traffic.canaryHasTraffic,
278
+ dashed: !line.canary,
279
+ }));
280
+ const outputs = line.outputConnectors.length > 0
281
+ ? line.outputConnectors
282
+ : [{ id: 'empty-output', name: labels.noDownstream, type: 'output' }];
283
+ outputs.forEach((connector, index) => {
284
+ const id = `output-${connector.id}`;
285
+ const isEmpty = connector.id === 'empty-output';
286
+ const inProduction = productionOutputIds.has(connector.id);
287
+ const inCanary = canaryOutputIds.has(connector.id);
288
+ nodes.push({
289
+ id,
290
+ type: 'releaseTopology',
291
+ position: outputNodePosition(index, outputs.length),
292
+ data: {
293
+ icon: 'downstream',
294
+ label: labels.downstream,
295
+ title: connector.name,
296
+ meta: connector.type,
297
+ detail: isEmpty
298
+ ? labels.noDownstreamDetail
299
+ : [inProduction ? 'production' : null, inCanary ? 'gray' : null].filter(Boolean).join(' + '),
300
+ tone: isEmpty ? 'muted' : 'neutral',
301
+ badges: [connector.type],
302
+ },
303
+ });
304
+ if (isEmpty) {
305
+ edges.push(createEdge({
306
+ id: 'output-route-empty-output',
307
+ source: 'output-route',
308
+ target: id,
309
+ tone: 'muted',
310
+ dashed: true,
311
+ }));
312
+ return;
313
+ }
314
+ edges.push(createEdge({
315
+ id: `output-route-${id}`,
316
+ source: 'output-route',
317
+ target: id,
318
+ label: [inProduction ? 'production' : null, inCanary ? 'gray' : null].filter(Boolean).join(' + ') || undefined,
319
+ tone: inCanary ? 'canary' : inProduction ? 'production' : 'neutral',
320
+ animated: (inProduction && traffic.productionHasTraffic) || (inCanary && traffic.canaryHasTraffic),
321
+ }));
322
+ });
323
+ return { nodes, edges };
324
+ }
325
+ function useTopologyLabels(line) {
326
+ const { t } = useI18n();
327
+ const traffic = getTrafficState(line);
328
+ const productionTraffic = formatPercent(traffic.productionRatio, 0);
329
+ return {
330
+ upstream: t('releases.detail.field.upstream'),
331
+ downstream: t('releases.detail.field.downstream'),
332
+ model: t('releases.detail.field.model'),
333
+ externalId: t('releases.detail.field.externalId'),
334
+ startedAt: t('releases.detail.field.startedAt'),
335
+ status: t('releases.detail.field.status'),
336
+ trafficRatio: t('releases.detail.field.trafficRatio'),
337
+ updatedAt: t('releases.detail.field.updatedAt'),
338
+ production: t('releases.detail.topology.node.production'),
339
+ canary: t('releases.detail.topology.node.canary'),
340
+ productionNode: t('releases.detail.topology.node.production'),
341
+ canaryNode: t('releases.detail.topology.node.canary'),
342
+ productionBadge: t('releases.detail.topology.badge.production'),
343
+ canaryBadge: t('releases.detail.topology.badge.canary'),
344
+ productionTrafficLabel: t('releases.detail.topology.traffic.production'),
345
+ canaryTrafficLabel: t('releases.detail.topology.traffic.canary'),
346
+ router: t('releases.detail.topology.router'),
347
+ inputRoute: t('releases.detail.topology.inputRoute'),
348
+ inputRouteMeta: t('releases.detail.topology.inputRouteMeta'),
349
+ outputRoute: t('releases.detail.topology.outputRoute'),
350
+ outputRouteTitle: t('releases.detail.topology.outputRouteTitle'),
351
+ ingress: t('releases.detail.topology.ingress'),
352
+ routeMeta: t('releases.detail.topology.routeMeta'),
353
+ latestEvent: t('releases.detail.topology.latestEvent'),
354
+ singleUpstream: t('releases.detail.topology.singleUpstream'),
355
+ productionTraffic,
356
+ noTraffic: t('releases.detail.topology.noTraffic'),
357
+ noProduction: t('releases.detail.topology.noProduction'),
358
+ noCanary: t('releases.detail.topology.noCanary'),
359
+ addCanary: t('releases.detail.action.addCanary'),
360
+ noDownstream: t('releases.detail.topology.noDownstream'),
361
+ noDownstreamDetail: t('releases.detail.topology.noDownstreamDetail'),
362
+ unconfigured: t('releases.detail.topology.unconfigured'),
363
+ noModel: t('releases.detail.topology.noModel'),
364
+ passThrough: t('releases.traffic.passThrough'),
365
+ offline: t('releases.traffic.offline'),
366
+ readyForCandidate: t('releases.detail.topology.readyForCandidate'),
367
+ inspector: t('releases.detail.topology.inspector'),
368
+ clickHint: t('releases.detail.topology.clickHint'),
369
+ connectorId: t('releases.detail.topology.field.connectorId'),
370
+ connectorName: t('releases.detail.topology.field.connectorName'),
371
+ connectorType: t('releases.detail.topology.field.connectorType'),
372
+ direction: t('releases.detail.topology.field.direction'),
373
+ inputDirection: t('releases.detail.topology.direction.input'),
374
+ outputDirection: t('releases.detail.topology.direction.output'),
375
+ prompt: t('releases.detail.topology.field.prompt'),
376
+ promptVersion: t('releases.detail.topology.field.promptVersion'),
377
+ eventId: t('releases.detail.topology.field.eventId'),
378
+ canaryId: t('releases.detail.topology.field.canaryId'),
379
+ rpmLimit: t('releases.detail.topology.field.rpmLimit'),
380
+ tpmLimit: t('releases.detail.topology.field.tpmLimit'),
381
+ concurrency: t('releases.detail.topology.field.concurrency'),
382
+ temperature: t('releases.detail.topology.field.temperature'),
383
+ recordMode: t('releases.detail.topology.field.recordMode'),
384
+ trafficMode: t('releases.detail.topology.field.trafficMode'),
385
+ outputScope: t('releases.detail.topology.field.outputScope'),
386
+ productionScope: t('releases.detail.topology.scope.production'),
387
+ canaryScope: t('releases.detail.topology.scope.canary'),
388
+ routeStatus: t('releases.detail.topology.field.routeStatus'),
389
+ fieldMapping: t('releases.detail.topology.field.fieldMapping'),
390
+ fieldMappingEmpty: t('releases.detail.config.mappingEmpty'),
391
+ filterRules: t('releases.detail.topology.field.filterRules'),
392
+ filterEmpty: t('releases.detail.topology.filterEmpty'),
393
+ outputMapping: t('releases.detail.topology.field.outputMapping'),
394
+ outputMappingEmpty: t('releases.detail.topology.outputMappingEmpty'),
395
+ adjustTraffic: t('releases.detail.action.adjustTraffic'),
396
+ trafficBox: t('releases.detail.topology.trafficBox'),
397
+ noCanaryToAdjust: t('releases.detail.topology.noCanaryToAdjust'),
398
+ trafficInvalid: t('releases.detail.trafficDialog.invalid'),
399
+ trafficUpdateFailed: t('releases.detail.trafficDialog.updateFailed'),
400
+ runConfigTitle: t('releases.detail.topology.runConfig.title'),
401
+ runConfigInvalid: t('releases.detail.topology.runConfig.invalid'),
402
+ runConfigUpdateFailed: t('releases.detail.topology.runConfig.updateFailed'),
403
+ runConfigModelUnavailable: t('releases.detail.topology.runConfig.modelUnavailable'),
404
+ modelLimit: (limit) => t('releases.detail.topology.runConfig.modelLimit').replace('{limit}', limit),
405
+ unlimited: t('releases.detail.topology.runConfig.unlimited'),
406
+ loading: t('common.loading'),
407
+ trafficPercentInput: t('releases.detail.trafficDialog.percentInput'),
408
+ trafficPercentAriaLabel: t('releases.detail.trafficDialog.percentAriaLabel'),
409
+ save: t('common.save'),
410
+ savePending: t('common.savePending'),
411
+ canaryMode: (mode) => mode === 'dual_run' ? t('releases.detail.topology.mode.dualRun') : t('releases.detail.topology.mode.split'),
412
+ };
413
+ }
414
+ function toDisplayValue(value) {
415
+ if (value === null || value === undefined || value === '')
416
+ return '—';
417
+ return String(value);
418
+ }
419
+ function stringifyConfig(value, emptyLabel) {
420
+ if (value === null || value === undefined)
421
+ return emptyLabel;
422
+ if (typeof value === 'string')
423
+ return value.trim() || emptyLabel;
424
+ if (Array.isArray(value) && value.length === 0)
425
+ return emptyLabel;
426
+ if (typeof value === 'object' && Object.keys(value).length === 0)
427
+ return emptyLabel;
428
+ return JSON.stringify(value, null, 2);
429
+ }
430
+ function getVariableMappingBody(line, emptyLabel) {
431
+ if (line.canary) {
432
+ if (line.canary.variableMapping.length === 0)
433
+ return emptyLabel;
434
+ return line.canary.variableMapping
435
+ .map((item) => {
436
+ const required = item.required ? ' *' : '';
437
+ const defaultValue = item.defaultValue === undefined ? '' : ` = ${stringifyConfig(item.defaultValue, '')}`;
438
+ return `${item.source} -> ${item.target}${required}${defaultValue}`;
439
+ })
440
+ .join('\n');
441
+ }
442
+ const productionMapping = line.production?.currentEvent?.variableMapping ?? {};
443
+ const entries = Object.entries(productionMapping);
444
+ if (entries.length === 0)
445
+ return emptyLabel;
446
+ return entries.map(([target, source]) => `${source} -> ${target}${target === 'id' ? ' *' : ''}`).join('\n');
447
+ }
448
+ function getFilterRulesBody(line, labels) {
449
+ const filterRules = line.canary?.filterRules ?? line.production?.currentEvent?.filterRules ?? null;
450
+ return stringifyConfig(filterRules, labels.filterEmpty);
451
+ }
452
+ function getOutputMappingBody(line, labels) {
453
+ const canaryMapping = line.canary?.outputMapping ?? [];
454
+ if (canaryMapping.length > 0) {
455
+ return canaryMapping.map((item) => `${item.source} -> ${item.target}`).join('\n');
456
+ }
457
+ return labels.outputMappingEmpty;
458
+ }
459
+ function trafficPercentFromText(value, max = 100) {
460
+ const parsed = Number(value.trim());
461
+ return Number.isInteger(parsed) && parsed >= 0 && parsed <= max ? parsed : null;
462
+ }
463
+ function trafficPercentFromRatio(value) {
464
+ const percent = Math.round(value * 100);
465
+ return String(Math.min(100, Math.max(0, percent)));
466
+ }
467
+ function getProductionTrafficPercent(canaryPercent) {
468
+ return Math.max(0, 100 - canaryPercent);
469
+ }
470
+ function isAdjustableCanary(canary) {
471
+ return canary?.status === 'pending' || canary?.status === 'running' || canary?.status === 'stopped';
472
+ }
473
+ function TrafficRatioControl({ line, labels, onUpdateTrafficRatio, pending, }) {
474
+ const canary = line.canary;
475
+ const maxTrafficPercent = 100;
476
+ const currentPercent = canary ? Math.round(canary.trafficRatio * 100) : 0;
477
+ const [trafficPercent, setTrafficPercent] = useState(canary ? trafficPercentFromRatio(canary.trafficRatio) : '');
478
+ const [trafficError, setTrafficError] = useState(null);
479
+ const [lockedAfterPromotion, setLockedAfterPromotion] = useState(false);
480
+ const [saving, setSaving] = useState(false);
481
+ const [savedPercent, setSavedPercent] = useState(currentPercent);
482
+ const parsedTrafficPercent = trafficPercentFromText(trafficPercent, maxTrafficPercent);
483
+ const displayCanaryPercent = parsedTrafficPercent ?? currentPercent;
484
+ const displayProductionPercent = getProductionTrafficPercent(displayCanaryPercent);
485
+ const productionPercent = parsedTrafficPercent === null ? '' : String(displayProductionPercent);
486
+ const canEditTraffic = Boolean(canary) && Boolean(onUpdateTrafficRatio) && isAdjustableCanary(canary) && !lockedAfterPromotion;
487
+ const isSavingTraffic = pending || saving;
488
+ const hasTrafficDraft = parsedTrafficPercent !== null && savedPercent !== parsedTrafficPercent;
489
+ const canSaveTraffic = canEditTraffic && !isSavingTraffic && parsedTrafficPercent !== null && hasTrafficDraft;
490
+ async function saveTrafficRatio() {
491
+ if (isSavingTraffic)
492
+ return;
493
+ if (!canEditTraffic || !canary || !onUpdateTrafficRatio)
494
+ return;
495
+ if (parsedTrafficPercent === null) {
496
+ setTrafficError(labels.trafficInvalid);
497
+ return;
498
+ }
499
+ if (!hasTrafficDraft)
500
+ return;
501
+ setTrafficError(null);
502
+ setSaving(true);
503
+ try {
504
+ await onUpdateTrafficRatio(canary, parsedTrafficPercent / 100);
505
+ setSavedPercent(parsedTrafficPercent);
506
+ if (canary.trafficMode === 'split' && parsedTrafficPercent >= 100) {
507
+ setLockedAfterPromotion(true);
508
+ }
509
+ }
510
+ catch (error) {
511
+ setTrafficError(getApiErrorMessage(error) ?? labels.trafficUpdateFailed);
512
+ }
513
+ finally {
514
+ setSaving(false);
515
+ }
516
+ }
517
+ function setCanaryPercentText(value) {
518
+ setTrafficPercent(value);
519
+ setTrafficError(null);
520
+ }
521
+ function setProductionPercentText(value) {
522
+ const parsed = trafficPercentFromText(value, 100);
523
+ setTrafficPercent(parsed === null ? '' : String(100 - parsed));
524
+ setTrafficError(null);
525
+ }
526
+ return (_jsxs("section", { className: "mt-4 rounded-lg border bg-card", children: [_jsx("div", { className: "border-b px-3 py-2 text-[12px] font-semibold", children: labels.trafficBox }), _jsxs("div", { className: "space-y-3 p-3", children: [_jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("div", { className: "rounded-md border bg-muted/40 px-3 py-2", children: [_jsx("div", { className: "text-[11px] font-medium text-muted-foreground", children: labels.productionTrafficLabel }), _jsxs("label", { className: "mt-1 flex items-center gap-2", children: [_jsx(Input, { type: "number", min: 0, max: 100, value: productionPercent, onChange: (event) => setProductionPercentText(event.target.value), onKeyDown: (event) => {
527
+ if (event.key === 'Enter')
528
+ void saveTrafficRatio();
529
+ }, disabled: !canEditTraffic || isSavingTraffic, "aria-label": labels.productionTrafficLabel, className: "h-8 font-mono text-xs" }), _jsx("span", { className: "font-mono text-xs text-muted-foreground", children: "%" })] })] }), _jsxs("div", { className: "rounded-md border bg-muted/40 px-3 py-2", children: [_jsx("div", { className: "text-[11px] font-medium text-muted-foreground", children: labels.canaryTrafficLabel }), _jsxs("label", { className: "mt-1 flex items-center gap-2", children: [_jsx(Input, { type: "number", min: 0, max: 100, value: trafficPercent, onChange: (event) => setCanaryPercentText(event.target.value), onKeyDown: (event) => {
530
+ if (event.key === 'Enter')
531
+ void saveTrafficRatio();
532
+ }, disabled: !canEditTraffic || isSavingTraffic, "aria-label": labels.canaryTrafficLabel, className: "h-8 font-mono text-xs" }), _jsx("span", { className: "font-mono text-xs text-muted-foreground", children: "%" })] })] })] }), canary ? (_jsxs(_Fragment, { children: [_jsx("input", { type: "range", min: 0, max: maxTrafficPercent, step: 1, value: parsedTrafficPercent ?? currentPercent, "aria-label": labels.trafficPercentAriaLabel, onChange: (event) => setCanaryPercentText(event.target.value), disabled: !canEditTraffic || isSavingTraffic, className: "w-full accent-primary disabled:opacity-50" }), _jsxs("div", { className: "flex items-center justify-between font-mono text-[11px] text-muted-foreground", children: [_jsxs("span", { children: [labels.productionTrafficLabel, " 100%"] }), _jsxs("span", { children: [labels.canaryTrafficLabel, " 100%"] })] }), _jsx("div", { className: "flex justify-end", children: _jsxs(Button, { type: "button", size: "sm", onClick: saveTrafficRatio, disabled: !canSaveTraffic, children: [_jsx(Save, { className: "size-3.5" }), isSavingTraffic ? labels.savePending : labels.save] }) })] })) : (_jsx("div", { className: "rounded-md border border-dashed bg-muted/30 px-3 py-2 text-[12px] text-muted-foreground", children: labels.noCanaryToAdjust })), trafficError ? _jsx("p", { className: "text-[12px] text-destructive", children: trafficError }) : null] })] }));
533
+ }
534
+ function numberText(value) {
535
+ return typeof value === 'number' && Number.isFinite(value) ? String(value) : '';
536
+ }
537
+ function runConfigDraftFromRecord(config, modelId) {
538
+ const record = (config ?? {});
539
+ return {
540
+ modelId: modelId ?? '',
541
+ rpmLimit: numberText(record.rpmLimit),
542
+ tpmLimit: numberText(record.tpmLimit),
543
+ concurrency: numberText(record.concurrency),
544
+ temperature: numberText(record.temperature) || '0.3',
545
+ };
546
+ }
547
+ function parsePositiveInteger(value) {
548
+ const parsed = Number(value);
549
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
550
+ }
551
+ function parseTemperature(value) {
552
+ const parsed = Number(value);
553
+ return Number.isFinite(parsed) && parsed >= 0 && parsed <= 2 ? parsed : null;
554
+ }
555
+ function buildRunConfigUpdate(laneType, draft) {
556
+ const rpmLimit = parsePositiveInteger(draft.rpmLimit);
557
+ const tpmLimit = parsePositiveInteger(draft.tpmLimit);
558
+ const concurrency = parsePositiveInteger(draft.concurrency);
559
+ if (rpmLimit === null || tpmLimit === null || concurrency === null)
560
+ return null;
561
+ const temperature = parseTemperature(draft.temperature);
562
+ if (temperature === null)
563
+ return null;
564
+ return {
565
+ laneType,
566
+ modelId: draft.modelId || undefined,
567
+ runConfig: {
568
+ rpmLimit,
569
+ tpmLimit,
570
+ concurrency,
571
+ temperature,
572
+ },
573
+ };
574
+ }
575
+ function runConfigSignature(input) {
576
+ return input ? JSON.stringify({ modelId: input.modelId ?? null, runConfig: input.runConfig }) : null;
577
+ }
578
+ function modelOptionFromProjectModel(model) {
579
+ return {
580
+ id: model.id,
581
+ name: model.name,
582
+ providerType: model.providerType,
583
+ providerModelId: model.providerModelId,
584
+ status: model.status,
585
+ rpmLimit: model.rpm.limit,
586
+ tpmLimit: model.tpm.limit,
587
+ };
588
+ }
589
+ function buildRuntimeModelOptions(models, currentModelId, currentModelName) {
590
+ const options = models
591
+ .filter((model) => model.status !== 'disabled' || model.id === currentModelId)
592
+ .map(modelOptionFromProjectModel);
593
+ if (currentModelId && !options.some((model) => model.id === currentModelId)) {
594
+ options.unshift({
595
+ id: currentModelId,
596
+ name: currentModelName ?? currentModelId,
597
+ providerType: null,
598
+ providerModelId: null,
599
+ status: 'unknown',
600
+ rpmLimit: null,
601
+ tpmLimit: null,
602
+ });
603
+ }
604
+ return options;
605
+ }
606
+ function formatModelLimitValue(value, labels) {
607
+ if (value === null || value === undefined)
608
+ return '—';
609
+ if (value === -1)
610
+ return labels.unlimited;
611
+ return String(value);
612
+ }
613
+ function modelOptionLabel(option) {
614
+ return [option.name, option.providerModelId].filter(Boolean).join(' · ');
615
+ }
616
+ function RuntimeConfigEditor({ laneType, config, currentModelId, currentModelName, models, modelsLoading, labels, canEdit, pending, onUpdateRunConfig, }) {
617
+ const modelOptions = useMemo(() => buildRuntimeModelOptions(models, currentModelId, currentModelName), [currentModelId, currentModelName, models]);
618
+ const [draft, setDraft] = useState(() => runConfigDraftFromRecord(config, currentModelId));
619
+ const [error, setError] = useState(null);
620
+ const initialSignature = runConfigSignature(buildRunConfigUpdate(laneType, runConfigDraftFromRecord(config, currentModelId)));
621
+ const [savedSignature, setSavedSignature] = useState(initialSignature);
622
+ const nextUpdate = buildRunConfigUpdate(laneType, draft);
623
+ const nextSignature = runConfigSignature(nextUpdate);
624
+ const isChanged = nextSignature !== null && nextSignature !== savedSignature;
625
+ const canSubmit = canEdit && Boolean(onUpdateRunConfig) && !pending && (isChanged || nextUpdate === null);
626
+ const selectedModel = modelOptions.find((model) => model.id === draft.modelId) ?? null;
627
+ const rpmModelLimit = selectedModel ? labels.modelLimit(formatModelLimitValue(selectedModel.rpmLimit, labels)) : '—';
628
+ const tpmModelLimit = selectedModel ? labels.modelLimit(formatModelLimitValue(selectedModel.tpmLimit, labels)) : '—';
629
+ function setField(field, value) {
630
+ setDraft((current) => ({ ...current, [field]: value }));
631
+ setError(null);
632
+ }
633
+ async function saveRunConfig() {
634
+ if (!canEdit || !onUpdateRunConfig || pending)
635
+ return;
636
+ if (!nextUpdate) {
637
+ setError(labels.runConfigInvalid);
638
+ return;
639
+ }
640
+ if (nextSignature === savedSignature)
641
+ return;
642
+ setError(null);
643
+ try {
644
+ await onUpdateRunConfig(nextUpdate);
645
+ setSavedSignature(nextSignature);
646
+ }
647
+ catch (saveError) {
648
+ setError(getApiErrorMessage(saveError) ?? labels.runConfigUpdateFailed);
649
+ }
650
+ }
651
+ return (_jsxs("section", { className: "mt-4 rounded-lg border bg-card", children: [_jsx("div", { className: "border-b px-3 py-2 text-[12px] font-semibold", children: labels.runConfigTitle }), _jsxs("div", { className: "space-y-3 p-3", children: [_jsxs("div", { className: "rounded-md border bg-muted/40 px-3 py-2", children: [_jsx("div", { className: "text-[11px] font-medium text-muted-foreground", children: labels.model }), _jsxs(Select, { value: draft.modelId, onValueChange: (value) => setField('modelId', value), disabled: !canEdit || pending || modelOptions.length === 0, children: [_jsx(SelectTrigger, { className: "mt-1 h-8 bg-background text-xs", "aria-label": labels.model, children: _jsx(SelectValue, { placeholder: modelsLoading ? labels.loading : labels.runConfigModelUnavailable }) }), _jsx(SelectContent, { children: modelOptions.map((option) => (_jsx(SelectItem, { value: option.id, children: modelOptionLabel(option) }, option.id))) })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(RuntimeNumberField, { label: labels.rpmLimit, hint: rpmModelLimit, value: draft.rpmLimit, min: 1, step: 1, disabled: !canEdit || pending, onChange: (value) => setField('rpmLimit', value), onCommit: saveRunConfig }), _jsx(RuntimeNumberField, { label: labels.tpmLimit, hint: tpmModelLimit, value: draft.tpmLimit, min: 1, step: 1, disabled: !canEdit || pending, onChange: (value) => setField('tpmLimit', value), onCommit: saveRunConfig }), _jsx(RuntimeNumberField, { label: labels.concurrency, value: draft.concurrency, min: 1, step: 1, disabled: !canEdit || pending, onChange: (value) => setField('concurrency', value), onCommit: saveRunConfig }), _jsx(RuntimeNumberField, { label: labels.temperature, value: draft.temperature, min: 0, max: 2, step: 0.1, disabled: !canEdit || pending, onChange: (value) => setField('temperature', value), onCommit: saveRunConfig })] }), error ? _jsx("p", { className: "text-[12px] text-destructive", children: error }) : null, _jsx("div", { className: "flex justify-end", children: _jsxs(Button, { type: "button", size: "sm", onClick: saveRunConfig, disabled: !canSubmit, children: [_jsx(Save, { className: "size-3.5" }), pending ? labels.savePending : labels.save] }) })] })] }));
652
+ }
653
+ function RuntimeNumberField({ label, hint, value, min, max, step, disabled, onChange, onCommit, }) {
654
+ return (_jsxs("label", { className: "rounded-md border bg-muted/40 px-3 py-2", children: [_jsxs("span", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-[11px] font-medium text-muted-foreground", children: label }), hint ? _jsx("span", { className: "truncate text-right text-[10.5px] text-muted-foreground", children: hint }) : null] }), _jsx(Input, { type: "number", min: min, max: max, step: step, value: value, onChange: (event) => onChange(event.target.value), onBlur: onCommit, onKeyDown: (event) => {
655
+ if (event.key === 'Enter')
656
+ onCommit();
657
+ }, disabled: disabled, "aria-label": label, className: "mt-1 h-8 font-mono text-xs" })] }));
658
+ }
659
+ function getOutputConnector(line, nodeId) {
660
+ if (!nodeId.startsWith('output-'))
661
+ return null;
662
+ const connectorId = nodeId.slice('output-'.length);
663
+ if (connectorId === 'empty-output')
664
+ return { id: connectorId, name: null, type: 'output' };
665
+ return line.outputConnectors.find((connector) => connector.id === connectorId) ?? null;
666
+ }
667
+ function getOutputScope(line, connectorId, labels) {
668
+ const inProduction = (line.production?.outputConnectors ?? []).some((connector) => connector.id === connectorId);
669
+ const inCanary = (line.canary?.outputConnectors ?? []).some((connector) => connector.id === connectorId);
670
+ return ([inProduction ? labels.productionScope : null, inCanary ? labels.canaryScope : null].filter(Boolean).join(' + ') ||
671
+ null);
672
+ }
673
+ function buildInspectorDetail({ line, selectedNodeId, labels, formatDateTimeOrDash, onUpdateTrafficRatio, trafficRatioPending, onUpdateRunConfig, runConfigPending, models, modelsLoading, onAddCanary, }) {
674
+ if (selectedNodeId === 'upstream') {
675
+ return {
676
+ icon: 'upstream',
677
+ label: labels.upstream,
678
+ title: line.inputConnectorName ?? labels.unconfigured,
679
+ tone: line.inputConnectorName ? 'neutral' : 'muted',
680
+ rows: [
681
+ { label: labels.connectorName, value: line.inputConnectorName },
682
+ { label: labels.connectorId, value: line.inputConnectorId },
683
+ { label: labels.connectorType, value: line.inputConnectorType ?? 'connector' },
684
+ { label: labels.direction, value: labels.inputDirection, mono: false },
685
+ { label: labels.prompt, value: line.promptName },
686
+ ],
687
+ };
688
+ }
689
+ if (selectedNodeId === 'input-route') {
690
+ return {
691
+ icon: 'router',
692
+ label: labels.trafficBox,
693
+ tone: 'neutral',
694
+ rows: [],
695
+ hideSummary: true,
696
+ content: (_jsx(TrafficRatioControl, { line: line, labels: labels, onUpdateTrafficRatio: onUpdateTrafficRatio, pending: trafficRatioPending }, `${line.canary?.id ?? 'no-canary'}:${line.canary?.trafficRatio ?? 0}`)),
697
+ blocks: [
698
+ {
699
+ title: labels.fieldMapping,
700
+ body: getVariableMappingBody(line, labels.fieldMappingEmpty),
701
+ },
702
+ {
703
+ title: labels.filterRules,
704
+ body: getFilterRulesBody(line, labels),
705
+ },
706
+ ],
707
+ };
708
+ }
709
+ if (selectedNodeId === 'output-route') {
710
+ return {
711
+ icon: 'router',
712
+ label: labels.outputRoute,
713
+ title: labels.outputRouteTitle,
714
+ subtitle: labels.outputMapping,
715
+ tone: 'neutral',
716
+ rows: [
717
+ {
718
+ label: labels.outputScope,
719
+ value: line.outputConnectors.map((connector) => connector.name).join(', ') || null,
720
+ },
721
+ {
722
+ label: labels.productionScope,
723
+ value: line.production?.outputConnectors?.length ? String(line.production.outputConnectors.length) : '0',
724
+ },
725
+ {
726
+ label: labels.canaryScope,
727
+ value: line.canary?.outputConnectors.length ? String(line.canary.outputConnectors.length) : '0',
728
+ },
729
+ ],
730
+ blocks: [
731
+ {
732
+ title: labels.outputMapping,
733
+ body: getOutputMappingBody(line, labels),
734
+ },
735
+ ],
736
+ };
737
+ }
738
+ if (selectedNodeId === 'production') {
739
+ const event = line.production?.currentEvent ?? null;
740
+ return {
741
+ icon: 'production',
742
+ label: labels.production,
743
+ title: line.productionVersionLabel ?? labels.noProduction,
744
+ subtitle: line.productionModelName ?? labels.noModel,
745
+ tone: event ? 'production' : 'muted',
746
+ rows: [
747
+ { label: labels.prompt, value: line.promptName },
748
+ { label: labels.promptVersion, value: line.productionVersionLabel },
749
+ { label: labels.model, value: line.productionModelName },
750
+ { label: labels.eventId, value: event?.id },
751
+ { label: labels.status, value: event?.status ?? line.production?.aggregateStatus },
752
+ { label: labels.externalId, value: event?.externalIdField },
753
+ { label: labels.recordMode, value: event?.recordMode },
754
+ { label: labels.startedAt, value: formatDateTimeOrDash(event?.startedAt) },
755
+ { label: labels.updatedAt, value: formatDateTimeOrDash(event?.updatedAt) },
756
+ ],
757
+ runtimeEditor: event ? (_jsx(RuntimeConfigEditor, { laneType: "production", config: event.runConfig, currentModelId: event.modelId, currentModelName: line.productionModelName, models: models, modelsLoading: modelsLoading, labels: labels, canEdit: event.status === 'running', pending: runConfigPending, onUpdateRunConfig: onUpdateRunConfig }, `production:${event.id}:${event.updatedAt}`)) : undefined,
758
+ };
759
+ }
760
+ if (selectedNodeId === 'canary') {
761
+ const canary = line.canary;
762
+ const canAddCanary = !canary && line.production?.currentEvent?.status === 'running' && Boolean(onAddCanary);
763
+ return {
764
+ icon: canAddCanary ? 'addCanary' : 'canary',
765
+ label: labels.canary,
766
+ title: canAddCanary ? labels.addCanary : (line.canaryVersionLabel ?? labels.noCanary),
767
+ subtitle: line.canaryModelName ?? labels.readyForCandidate,
768
+ tone: canary ? 'canary' : 'muted',
769
+ rows: [
770
+ { label: labels.prompt, value: line.promptName },
771
+ { label: labels.promptVersion, value: line.canaryVersionLabel },
772
+ { label: labels.model, value: line.canaryModelName },
773
+ { label: labels.canaryId, value: canary?.id },
774
+ { label: labels.status, value: canary?.status },
775
+ { label: labels.trafficRatio, value: canary ? formatPercent(canary.trafficRatio, 0) : labels.noTraffic },
776
+ { label: labels.trafficMode, value: canary ? labels.canaryMode(canary.trafficMode) : null },
777
+ { label: labels.externalId, value: canary?.externalIdField },
778
+ { label: labels.recordMode, value: canary?.recordMode },
779
+ { label: labels.startedAt, value: formatDateTimeOrDash(canary?.startedAt) },
780
+ { label: labels.updatedAt, value: formatDateTimeOrDash(canary?.updatedAt) },
781
+ ],
782
+ runtimeEditor: canary ? (_jsx(RuntimeConfigEditor, { laneType: "canary", config: canary.runConfig, currentModelId: canary.modelId, currentModelName: canary.modelName, models: models, modelsLoading: modelsLoading, labels: labels, canEdit: isAdjustableCanary(canary), pending: runConfigPending, onUpdateRunConfig: onUpdateRunConfig }, `canary:${canary.id}:${canary.updatedAt}`)) : undefined,
783
+ action: canAddCanary ? (_jsxs(Button, { type: "button", onClick: onAddCanary, children: [_jsx(Plus, { className: "size-4" }), labels.addCanary] })) : undefined,
784
+ };
785
+ }
786
+ const connector = getOutputConnector(line, selectedNodeId);
787
+ return {
788
+ icon: 'downstream',
789
+ label: labels.downstream,
790
+ title: connector?.name ?? labels.noDownstream,
791
+ subtitle: connector?.type ?? labels.noDownstreamDetail,
792
+ tone: connector?.name ? 'neutral' : 'muted',
793
+ rows: [
794
+ { label: labels.connectorName, value: connector?.name ?? labels.noDownstream },
795
+ { label: labels.connectorId, value: connector?.id === 'empty-output' ? null : connector?.id },
796
+ { label: labels.connectorType, value: connector?.type },
797
+ { label: labels.direction, value: labels.outputDirection, mono: false },
798
+ { label: labels.outputScope, value: connector?.id ? getOutputScope(line, connector.id, labels) : null },
799
+ ],
800
+ };
801
+ }
802
+ function InspectorRowView({ row }) {
803
+ return (_jsxs("div", { className: "grid grid-cols-[112px_minmax(0,1fr)] gap-2 text-[12px]", children: [_jsx("span", { className: "text-muted-foreground", children: row.label }), _jsx("span", { className: cn('min-w-0 truncate', row.mono !== false && 'font-mono'), title: toDisplayValue(row.value), children: toDisplayValue(row.value) })] }));
804
+ }
805
+ function TopologyInspector({ detail, labels, }) {
806
+ const token = TONE_STYLES[detail.tone];
807
+ const Icon = NODE_ICONS[detail.icon];
808
+ return (_jsxs("aside", { className: "flex min-h-[360px] flex-col bg-background/60 p-4", children: [_jsxs("div", { className: "mb-3 flex items-center justify-between gap-2", children: [_jsx("h3", { className: "text-[14px] font-semibold", children: labels.inspector }), _jsx("span", { className: "text-[11.5px] text-muted-foreground", children: labels.clickHint })] }), !detail.hideSummary ? (_jsx("div", { className: "rounded-lg border bg-card p-3", style: { borderColor: token.bd }, children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-md border", style: { background: token.bg, borderColor: token.bd, color: token.dot }, children: _jsx(Icon, { className: "size-4" }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-[11.5px] font-medium text-muted-foreground", children: detail.label }), detail.title ? (_jsx("div", { className: "mt-1 truncate font-mono text-[13px] font-semibold", title: detail.title, children: detail.title })) : null, detail.subtitle ? (_jsx("div", { className: "mt-1 truncate text-[12px] text-muted-foreground", title: detail.subtitle, children: detail.subtitle })) : null] })] }) })) : null, detail.content, detail.rows.length ? (_jsx("div", { className: "mt-4 space-y-2 rounded-lg border bg-card p-3", children: detail.rows.map((row) => (_jsx(InspectorRowView, { row: row }, `${detail.label}:${row.label}`))) })) : null, detail.runtimeEditor, detail.blocks?.length ? (_jsx("div", { className: "mt-4 space-y-3", children: detail.blocks.map((block) => (_jsxs("section", { className: "rounded-lg border bg-card", children: [_jsx("div", { className: "border-b px-3 py-2 text-[12px] font-semibold", children: block.title }), _jsx("pre", { className: "max-h-36 overflow-auto whitespace-pre-wrap break-words p-3 font-mono text-[11.5px] leading-5 text-muted-foreground", children: block.body })] }, `${detail.label}:${block.title}`))) })) : null, detail.action ? _jsx("div", { className: "mt-4 flex justify-end", children: detail.action }) : null] }));
809
+ }
810
+ export function ReleaseTopologyCanvas({ line, models = [], modelsLoading = false, onUpdateTrafficRatio, onUpdateRunConfig, onAddCanary, trafficRatioPending = false, runConfigPending = false, }) {
811
+ const labels = useTopologyLabels(line);
812
+ const { formatDateTime } = useDateTimeFormatter();
813
+ const formatDateTimeOrDash = useMemo(() => (value) => (value ? formatDateTime(value, { fallback: '—' }) : '—'), [formatDateTime]);
814
+ const topology = useMemo(() => buildTopology(line, labels), [labels, line]);
815
+ const [rawSelectedNodeId, setSelectedNodeId] = useState('input-route');
816
+ const selectedNodeId = topology.nodes.some((node) => node.id === rawSelectedNodeId)
817
+ ? rawSelectedNodeId
818
+ : 'input-route';
819
+ const nodes = useMemo(() => topology.nodes.map((node) => ({
820
+ ...node,
821
+ selected: node.id === selectedNodeId,
822
+ })), [selectedNodeId, topology.nodes]);
823
+ const detail = useMemo(() => buildInspectorDetail({
824
+ line,
825
+ selectedNodeId,
826
+ labels,
827
+ formatDateTimeOrDash,
828
+ onUpdateTrafficRatio,
829
+ trafficRatioPending,
830
+ onUpdateRunConfig,
831
+ runConfigPending,
832
+ models,
833
+ modelsLoading,
834
+ onAddCanary,
835
+ }), [
836
+ labels,
837
+ formatDateTimeOrDash,
838
+ line,
839
+ onAddCanary,
840
+ onUpdateRunConfig,
841
+ onUpdateTrafficRatio,
842
+ models,
843
+ modelsLoading,
844
+ runConfigPending,
845
+ selectedNodeId,
846
+ trafficRatioPending,
847
+ ]);
848
+ return (_jsxs("div", { className: "release-topology-canvas rounded-lg border bg-card", "data-testid": "release-topology-canvas", children: [_jsx("div", { className: "border-b px-4 py-3", children: _jsx("h2", { className: "text-[14px] font-semibold", children: labels.routeMeta }) }), _jsxs("div", { className: "grid grid-cols-1 xl:grid-cols-[minmax(0,1fr)_380px]", children: [_jsx("div", { className: "h-[500px] min-h-[380px] w-full border-b xl:border-b-0 xl:border-r", children: _jsxs(ReactFlow, { nodes: nodes, edges: topology.edges, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, elementsSelectable: false, onNodeClick: (_, node) => {
849
+ if (node.data.action === 'addCanary' && onAddCanary) {
850
+ onAddCanary();
851
+ return;
852
+ }
853
+ setSelectedNodeId(node.id);
854
+ }, fitView: true, minZoom: 0.55, maxZoom: 1.15, defaultViewport: { x: 0, y: 0, zoom: 0.82 }, fitViewOptions: { padding: 0.16, minZoom: 0.55, maxZoom: 1.05 }, proOptions: { hideAttribution: true }, children: [_jsx(Background, { color: "var(--border)", gap: 24, size: 1 }), _jsx(Controls, { showInteractive: false, className: "!rounded-md !border !border-border !bg-muted !shadow-sm" })] }) }), _jsx(TopologyInspector, { detail: detail, labels: labels })] })] }));
855
+ }
856
+ //# sourceMappingURL=release-topology-canvas.js.map