@proofhound/web-ui 0.1.8 → 0.1.10

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 (159) hide show
  1. package/dist/components/navigation/link.d.ts +15 -0
  2. package/dist/components/navigation/link.d.ts.map +1 -0
  3. package/dist/components/navigation/link.js +23 -0
  4. package/dist/components/navigation/link.js.map +1 -0
  5. package/dist/contracts/index.d.ts +2 -0
  6. package/dist/contracts/index.d.ts.map +1 -1
  7. package/dist/contracts/index.js.map +1 -1
  8. package/dist/hooks/annotation.d.ts +37 -16
  9. package/dist/hooks/annotation.d.ts.map +1 -1
  10. package/dist/hooks/canary-release.d.ts +62 -37
  11. package/dist/hooks/canary-release.d.ts.map +1 -1
  12. package/dist/hooks/dataset.d.ts +101 -0
  13. package/dist/hooks/dataset.d.ts.map +1 -1
  14. package/dist/hooks/dataset.js +27 -0
  15. package/dist/hooks/dataset.js.map +1 -1
  16. package/dist/hooks/optimization.d.ts +1 -1
  17. package/dist/hooks/production-release.d.ts +8 -4
  18. package/dist/hooks/production-release.d.ts.map +1 -1
  19. package/dist/hooks/prompt.d.ts +149 -38
  20. package/dist/hooks/prompt.d.ts.map +1 -1
  21. package/dist/hooks/prompt.js +20 -0
  22. package/dist/hooks/prompt.js.map +1 -1
  23. package/dist/hooks/release-line.d.ts +2522 -72
  24. package/dist/hooks/release-line.d.ts.map +1 -1
  25. package/dist/hooks/release-line.js +125 -0
  26. package/dist/hooks/release-line.js.map +1 -1
  27. package/dist/hooks/run-result.d.ts +9 -6
  28. package/dist/hooks/run-result.d.ts.map +1 -1
  29. package/dist/hooks/run-result.js +2 -1
  30. package/dist/hooks/run-result.js.map +1 -1
  31. package/dist/hooks/use-router.d.ts +17 -0
  32. package/dist/hooks/use-router.d.ts.map +1 -0
  33. package/dist/hooks/use-router.js +30 -0
  34. package/dist/hooks/use-router.js.map +1 -0
  35. package/dist/i18n/index.d.ts +652 -160
  36. package/dist/i18n/index.d.ts.map +1 -1
  37. package/dist/i18n/index.js +652 -160
  38. package/dist/i18n/index.js.map +1 -1
  39. package/dist/lib/releases/release-line-model.d.ts +8 -2
  40. package/dist/lib/releases/release-line-model.d.ts.map +1 -1
  41. package/dist/lib/releases/release-line-model.js +66 -29
  42. package/dist/lib/releases/release-line-model.js.map +1 -1
  43. package/dist/providers/index.d.ts +1 -0
  44. package/dist/providers/index.d.ts.map +1 -1
  45. package/dist/providers/index.js +1 -0
  46. package/dist/providers/index.js.map +1 -1
  47. package/dist/providers/navigation-provider.d.ts +27 -0
  48. package/dist/providers/navigation-provider.d.ts.map +1 -0
  49. package/dist/providers/navigation-provider.js +17 -0
  50. package/dist/providers/navigation-provider.js.map +1 -0
  51. package/dist/providers/proofhound-web-provider.d.ts.map +1 -1
  52. package/dist/providers/proofhound-web-provider.js +2 -1
  53. package/dist/providers/proofhound-web-provider.js.map +1 -1
  54. package/dist/screens/annotations/annotation-detail-page.d.ts.map +1 -1
  55. package/dist/screens/annotations/annotation-detail-page.js +4 -3
  56. package/dist/screens/annotations/annotation-detail-page.js.map +1 -1
  57. package/dist/screens/annotations/annotation-new-page.d.ts.map +1 -1
  58. package/dist/screens/annotations/annotation-new-page.js +216 -51
  59. package/dist/screens/annotations/annotation-new-page.js.map +1 -1
  60. package/dist/screens/annotations/annotation-task-model.d.ts +3 -2
  61. package/dist/screens/annotations/annotation-task-model.d.ts.map +1 -1
  62. package/dist/screens/annotations/annotation-task-model.js +5 -4
  63. package/dist/screens/annotations/annotation-task-model.js.map +1 -1
  64. package/dist/screens/annotations/annotation-ui.d.ts.map +1 -1
  65. package/dist/screens/annotations/annotation-ui.js +9 -4
  66. package/dist/screens/annotations/annotation-ui.js.map +1 -1
  67. package/dist/screens/annotations/annotations-list-page.js +3 -3
  68. package/dist/screens/annotations/annotations-list-page.js.map +1 -1
  69. package/dist/screens/connectors/connector-detail-page.d.ts.map +1 -1
  70. package/dist/screens/connectors/connector-detail-page.js +8 -4
  71. package/dist/screens/connectors/connector-detail-page.js.map +1 -1
  72. package/dist/screens/connectors/connector-form-page.js +3 -3
  73. package/dist/screens/connectors/connector-form-page.js.map +1 -1
  74. package/dist/screens/connectors/connector-ui.d.ts +6 -0
  75. package/dist/screens/connectors/connector-ui.d.ts.map +1 -1
  76. package/dist/screens/connectors/connector-ui.js +7 -1
  77. package/dist/screens/connectors/connector-ui.js.map +1 -1
  78. package/dist/screens/connectors/connectors-list-page.d.ts.map +1 -1
  79. package/dist/screens/connectors/connectors-list-page.js +8 -7
  80. package/dist/screens/connectors/connectors-list-page.js.map +1 -1
  81. package/dist/screens/dashboard/dashboard-screen.d.ts.map +1 -1
  82. package/dist/screens/dashboard/dashboard-screen.js +29 -17
  83. package/dist/screens/dashboard/dashboard-screen.js.map +1 -1
  84. package/dist/screens/datasets/dataset-detail-page.js +1 -1
  85. package/dist/screens/datasets/dataset-detail-page.js.map +1 -1
  86. package/dist/screens/datasets/dataset-mappers.js +1 -1
  87. package/dist/screens/datasets/dataset-mappers.js.map +1 -1
  88. package/dist/screens/datasets/dataset-types.d.ts +1 -1
  89. package/dist/screens/datasets/dataset-types.d.ts.map +1 -1
  90. package/dist/screens/datasets/dataset-ui.d.ts +1 -1
  91. package/dist/screens/datasets/dataset-ui.d.ts.map +1 -1
  92. package/dist/screens/datasets/dataset-ui.js +2 -2
  93. package/dist/screens/datasets/dataset-ui.js.map +1 -1
  94. package/dist/screens/datasets/dataset-upload-page.js +2 -2
  95. package/dist/screens/datasets/dataset-upload-page.js.map +1 -1
  96. package/dist/screens/datasets/datasets-list-page.d.ts.map +1 -1
  97. package/dist/screens/datasets/datasets-list-page.js +37 -26
  98. package/dist/screens/datasets/datasets-list-page.js.map +1 -1
  99. package/dist/screens/experiments/experiment-detail-page.js +3 -3
  100. package/dist/screens/experiments/experiment-detail-page.js.map +1 -1
  101. package/dist/screens/experiments/experiment-new-page.js +2 -2
  102. package/dist/screens/experiments/experiment-new-page.js.map +1 -1
  103. package/dist/screens/experiments/experiments-list-page.d.ts.map +1 -1
  104. package/dist/screens/experiments/experiments-list-page.js +3 -2
  105. package/dist/screens/experiments/experiments-list-page.js.map +1 -1
  106. package/dist/screens/experiments/experiments-table.js +1 -1
  107. package/dist/screens/experiments/experiments-table.js.map +1 -1
  108. package/dist/screens/experiments/run-result-labels.d.ts.map +1 -1
  109. package/dist/screens/experiments/run-result-labels.js +3 -4
  110. package/dist/screens/experiments/run-result-labels.js.map +1 -1
  111. package/dist/screens/models/model-form-page.js +2 -2
  112. package/dist/screens/models/model-form-page.js.map +1 -1
  113. package/dist/screens/models/models-list-page.d.ts.map +1 -1
  114. package/dist/screens/models/models-list-page.js +3 -2
  115. package/dist/screens/models/models-list-page.js.map +1 -1
  116. package/dist/screens/optimizations/optimization-detail-page.js +2 -2
  117. package/dist/screens/optimizations/optimization-detail-page.js.map +1 -1
  118. package/dist/screens/optimizations/optimization-new-page.js +2 -2
  119. package/dist/screens/optimizations/optimization-new-page.js.map +1 -1
  120. package/dist/screens/optimizations/optimizations-list-page.d.ts.map +1 -1
  121. package/dist/screens/optimizations/optimizations-list-page.js +3 -2
  122. package/dist/screens/optimizations/optimizations-list-page.js.map +1 -1
  123. package/dist/screens/prompts/prompt-detail-page.d.ts.map +1 -1
  124. package/dist/screens/prompts/prompt-detail-page.js +10 -10
  125. package/dist/screens/prompts/prompt-detail-page.js.map +1 -1
  126. package/dist/screens/prompts/prompt-model.d.ts +5 -2
  127. package/dist/screens/prompts/prompt-model.d.ts.map +1 -1
  128. package/dist/screens/prompts/prompt-model.js +3 -1
  129. package/dist/screens/prompts/prompt-model.js.map +1 -1
  130. package/dist/screens/prompts/prompts-list-page.d.ts.map +1 -1
  131. package/dist/screens/prompts/prompts-list-page.js +46 -21
  132. package/dist/screens/prompts/prompts-list-page.js.map +1 -1
  133. package/dist/screens/quick-start/quick-start-screen.js +2 -2
  134. package/dist/screens/quick-start/quick-start-screen.js.map +1 -1
  135. package/dist/screens/releases/release-input-route-editor.d.ts +39 -0
  136. package/dist/screens/releases/release-input-route-editor.d.ts.map +1 -0
  137. package/dist/screens/releases/release-input-route-editor.js +355 -0
  138. package/dist/screens/releases/release-input-route-editor.js.map +1 -0
  139. package/dist/screens/releases/release-line-detail-page.d.ts +62 -0
  140. package/dist/screens/releases/release-line-detail-page.d.ts.map +1 -1
  141. package/dist/screens/releases/release-line-detail-page.js +1880 -325
  142. package/dist/screens/releases/release-line-detail-page.js.map +1 -1
  143. package/dist/screens/releases/release-line-ui.d.ts.map +1 -1
  144. package/dist/screens/releases/release-line-ui.js +55 -39
  145. package/dist/screens/releases/release-line-ui.js.map +1 -1
  146. package/dist/screens/releases/release-new-model.d.ts.map +1 -1
  147. package/dist/screens/releases/release-new-model.js +1 -6
  148. package/dist/screens/releases/release-new-model.js.map +1 -1
  149. package/dist/screens/releases/release-new-page.d.ts.map +1 -1
  150. package/dist/screens/releases/release-new-page.js +104 -68
  151. package/dist/screens/releases/release-new-page.js.map +1 -1
  152. package/dist/screens/releases/release-topology-canvas.d.ts +11 -2
  153. package/dist/screens/releases/release-topology-canvas.d.ts.map +1 -1
  154. package/dist/screens/releases/release-topology-canvas.js +1015 -174
  155. package/dist/screens/releases/release-topology-canvas.js.map +1 -1
  156. package/dist/screens/releases/releases-list-page.d.ts.map +1 -1
  157. package/dist/screens/releases/releases-list-page.js +82 -33
  158. package/dist/screens/releases/releases-list-page.js.map +1 -1
  159. package/package.json +5 -4
@@ -1,30 +1,17 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { cn } from '@proofhound/ui';
3
+ import { GitCompareArrows, Rocket, Split } from 'lucide-react';
4
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, cn } from '@proofhound/ui';
4
5
  import { formatDateTime } from '../../lib';
5
6
  import { useI18n } from '../../i18n';
6
7
  const STATUS_TOKENS = {
7
- production: {
8
+ running: {
8
9
  bg: 'var(--status-running-bg)',
9
10
  fg: 'var(--status-running-fg)',
10
11
  bd: 'var(--status-running-bd)',
11
12
  dot: 'var(--status-running-dot)',
12
13
  pulse: true,
13
14
  },
14
- production_canary: {
15
- bg: 'var(--status-canary-bg)',
16
- fg: 'var(--status-canary-fg)',
17
- bd: 'var(--status-canary-bd)',
18
- dot: 'var(--status-canary-dot)',
19
- pulse: true,
20
- },
21
- canary: {
22
- bg: 'var(--status-pending-bg)',
23
- fg: 'var(--status-pending-fg)',
24
- bd: 'var(--status-pending-bd)',
25
- dot: 'var(--status-pending-dot)',
26
- pulse: true,
27
- },
28
15
  stopped: {
29
16
  bg: 'var(--status-archived-bg)',
30
17
  fg: 'var(--status-archived-fg)',
@@ -32,6 +19,13 @@ const STATUS_TOKENS = {
32
19
  dot: 'var(--status-archived-dot)',
33
20
  pulse: false,
34
21
  },
22
+ archived: {
23
+ bg: 'var(--status-archived-bg)',
24
+ fg: 'var(--status-archived-fg)',
25
+ bd: 'var(--status-archived-bd)',
26
+ dot: 'var(--status-archived-dot)',
27
+ pulse: false,
28
+ },
35
29
  };
36
30
  const CONNECTOR_TOKENS = {
37
31
  kafka: {
@@ -70,19 +64,20 @@ const RELEASE_LINE_OPERATION_KEYS = {
70
64
  cancel_canary: 'releases.event.operation.cancelCanary',
71
65
  promote_canary: 'productionReleases.eventType.from_canary',
72
66
  rollback: 'productionReleases.eventType.rollback',
67
+ restore_to_production: 'releases.event.operation.restoreToProduction',
68
+ restore_to_canary: 'releases.event.operation.restoreToCanary',
73
69
  force_stop: 'productionReleases.eventType.force_stop',
74
70
  archive_line: 'releases.event.operation.archiveLine',
71
+ unarchive_line: 'releases.event.operation.unarchiveLine',
75
72
  };
76
73
  function statusLabelKey(status) {
77
74
  switch (status) {
78
- case 'production':
79
- return 'releases.status.production';
80
- case 'production_canary':
81
- return 'releases.status.productionCanary';
82
- case 'canary':
83
- return 'releases.status.canary';
75
+ case 'running':
76
+ return 'releases.status.running';
84
77
  case 'stopped':
85
78
  return 'releases.status.stopped';
79
+ case 'archived':
80
+ return 'releases.status.archived';
86
81
  }
87
82
  }
88
83
  function eventLabelKey(event) {
@@ -157,31 +152,52 @@ export function ReleaseMetricCard({ label, value, detail, tone = 'neutral', }) {
157
152
  : undefined;
158
153
  return (_jsxs("div", { className: "rounded-lg border bg-card px-4 py-3", style: style, children: [_jsx("div", { className: "text-[11.5px] font-medium text-muted-foreground", children: label }), _jsx("div", { className: "mt-1 font-mono text-[26px] font-semibold leading-none tabular-nums", children: value }), detail ? _jsx("div", { className: "mt-1.5 text-[11.5px] text-muted-foreground", children: detail }) : null] }));
159
154
  }
155
+ const TRAFFIC_LANE_TOKENS = {
156
+ production: {
157
+ fg: 'var(--status-running-fg)',
158
+ bd: 'color-mix(in srgb, var(--status-running-dot) 22%, var(--border))',
159
+ iconBg: 'color-mix(in srgb, var(--status-running-dot) 12%, var(--card))',
160
+ },
161
+ canary: {
162
+ fg: 'var(--status-canary-fg)',
163
+ bd: 'color-mix(in srgb, var(--status-canary-dot) 28%, var(--border))',
164
+ iconBg: 'color-mix(in srgb, var(--status-canary-dot) 14%, var(--card))',
165
+ },
166
+ muted: {
167
+ fg: 'var(--muted-foreground)',
168
+ bd: 'var(--border)',
169
+ iconBg: 'var(--card)',
170
+ },
171
+ };
172
+ function clampTrafficPercent(value) {
173
+ return Math.max(0, Math.min(100, value));
174
+ }
175
+ function TrafficAllocationRow({ icon: Icon, label, percent, tone, }) {
176
+ const value = clampTrafficPercent(percent);
177
+ const tokens = TRAFFIC_LANE_TOKENS[tone];
178
+ return (_jsxs("div", { className: "inline-flex h-5 w-fit items-center gap-1.5", "aria-label": `${label} ${value}%`, children: [_jsx(TooltipProvider, { delayDuration: 120, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex size-5 shrink-0 items-center justify-center rounded-md border", style: { background: tokens.iconBg, color: tokens.fg, borderColor: tokens.bd }, title: label, "aria-label": label, children: _jsx(Icon, { className: "size-3", "aria-hidden": "true", strokeWidth: 2.2 }) }) }), _jsx(TooltipContent, { side: "top", children: label })] }) }), _jsxs("span", { className: "shrink-0 tabular-nums", style: { color: tokens.fg }, children: [value, "%"] })] }));
179
+ }
160
180
  export function ReleaseTrafficBar({ line }) {
161
181
  const { t } = useI18n();
162
182
  const ratio = Math.max(0, Math.min(1, line.trafficRatio ?? 0));
163
183
  const canaryPercent = Math.round(ratio * 100);
164
184
  const prodPercent = Math.max(0, 100 - canaryPercent);
165
- if (line.status === 'stopped') {
185
+ if (line.status !== 'running') {
186
+ return (_jsx("div", { className: "flex h-7 items-center justify-center rounded-md border bg-muted font-mono text-[11px] font-semibold text-muted-foreground", children: t('releases.traffic.offline') }));
187
+ }
188
+ const hasRunningProduction = line.production?.currentEvent?.status === 'running';
189
+ const hasRunningCanary = line.canary?.status === 'running';
190
+ if (!hasRunningProduction && !hasRunningCanary) {
166
191
  return (_jsx("div", { className: "flex h-7 items-center justify-center rounded-md border bg-muted font-mono text-[11px] font-semibold text-muted-foreground", children: t('releases.traffic.offline') }));
167
192
  }
168
- if (line.status === 'production') {
169
- return (_jsx("div", { className: "flex h-7 overflow-hidden rounded-md border font-mono text-[11px] font-semibold", children: _jsx("div", { className: "flex flex-1 items-center justify-center", style: {
170
- background: 'color-mix(in srgb, var(--status-running-dot) 18%, var(--card))',
171
- color: 'var(--status-running-fg)',
172
- }, children: t('releases.traffic.productionFull') }) }));
193
+ if (hasRunningProduction && !hasRunningCanary) {
194
+ return (_jsx("div", { className: "inline-flex font-mono text-[10.5px] font-semibold leading-none", children: _jsx(TrafficAllocationRow, { icon: Rocket, label: t('releases.traffic.productionLane'), percent: 100, tone: "production" }) }));
173
195
  }
174
- const showProdSegment = line.status === 'production_canary';
175
- return (_jsxs("div", { className: "flex h-7 overflow-hidden rounded-md border font-mono text-[11px] font-semibold", children: [showProdSegment ? (_jsx("div", { className: "flex min-w-8 items-center justify-center", style: {
176
- width: `${prodPercent}%`,
177
- background: 'color-mix(in srgb, var(--status-running-dot) 18%, var(--card))',
178
- color: 'var(--status-running-fg)',
179
- }, title: `${t('releases.lane.production')} ${prodPercent}%`, children: prodPercent >= 18 ? `${prodPercent}%` : '' })) : null, _jsxs("div", { className: "flex min-w-8 items-center justify-center border-l border-dashed", style: {
180
- width: `${Math.max(canaryPercent, showProdSegment ? 4 : canaryPercent)}%`,
181
- flex: showProdSegment ? undefined : canaryPercent,
182
- background: 'color-mix(in srgb, var(--status-canary-dot) 22%, var(--card))',
183
- color: 'var(--status-canary-fg)',
184
- }, title: `${t('releases.lane.canary')} ${canaryPercent}%`, children: [canaryPercent, "%"] }), !showProdSegment ? (_jsx("div", { className: "flex flex-1 items-center justify-center border-l border-dashed bg-muted text-muted-foreground", children: t('releases.traffic.passThrough') })) : null] }));
196
+ const isDualRun = line.canary?.trafficMode === 'dual_run';
197
+ const productionPercent = hasRunningProduction ? (isDualRun ? 100 : prodPercent) : Math.max(0, 100 - canaryPercent);
198
+ const CanaryIcon = isDualRun ? GitCompareArrows : Split;
199
+ const canaryLabel = t(isDualRun ? 'releases.traffic.canaryDualRun' : 'releases.traffic.canarySplit');
200
+ return (_jsxs("div", { className: "inline-flex flex-col items-start gap-1 font-mono text-[10.5px] font-semibold leading-none", children: [hasRunningProduction ? (_jsx(TrafficAllocationRow, { icon: Rocket, label: t('releases.traffic.productionLane'), percent: productionPercent, tone: "production" })) : (_jsx(TrafficAllocationRow, { icon: Split, label: t('releases.traffic.passThrough'), percent: Math.max(0, 100 - canaryPercent), tone: "muted" })), _jsx(TrafficAllocationRow, { icon: CanaryIcon, label: canaryLabel, percent: canaryPercent, tone: "canary" })] }));
185
201
  }
186
202
  export function formatCount(value) {
187
203
  return new Intl.NumberFormat('en-US', { notation: value >= 100000 ? 'compact' : 'standard' }).format(value);
@@ -1 +1 @@
1
- {"version":3,"file":"release-line-ui.js","sourceRoot":"","sources":["../../../src/screens/releases/release-line-ui.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"release-line-ui.js","sourceRoot":"","sources":["../../../src/screens/releases/release-line-ui.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"release-new-model.d.ts","sourceRoot":"","sources":["../../../src/screens/releases/release-new-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,+BAA+B,EACpC,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAC;AAE5B,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAEjE;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,EAAE,CAEnF;AAMD,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,MAAM,EAAE,EAClB,GAAG,EAAE,MAAM,EAAE,GACZ,+BAA+B,CAAC,YAAY,CAAC,CAI/C"}
1
+ {"version":3,"file":"release-new-model.d.ts","sourceRoot":"","sources":["../../../src/screens/releases/release-new-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,+BAA+B,EACpC,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAC;AAE5B,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAEjE;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,EAAE,CAEnF;AAED,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,MAAM,EAAE,EAClB,GAAG,EAAE,MAAM,EAAE,GACZ,+BAA+B,CAAC,YAAY,CAAC,CAG/C"}
@@ -5,14 +5,9 @@ export function extractRecordCategoryValues(raw) {
5
5
  export function deriveRecordCategoryOptions(schema) {
6
6
  return deriveClassificationOptionsFromPromptOutputSchema(schema);
7
7
  }
8
- function isCorrectCategory(category) {
9
- return /^(correct|true|pass|yes|正确|通过|是)$/iu.test(category.trim());
10
- }
11
8
  export function releaseRecordModeFromCategories(selected, all) {
12
9
  if (all.length === 0 || selected.length === all.length)
13
10
  return 'all';
14
- if (selected.length === 1 && isCorrectCategory(selected[0] ?? ''))
15
- return 'correct_only';
16
- return 'all';
11
+ return 'selected_categories';
17
12
  }
18
13
  //# sourceMappingURL=release-new-model.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"release-new-model.js","sourceRoot":"","sources":["../../../src/screens/releases/release-new-model.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iDAAiD,EACjD,oCAAoC,GAGrC,MAAM,oBAAoB,CAAC;AAE5B,MAAM,UAAU,2BAA2B,CAAC,GAAW;IACrD,OAAO,oCAAoC,CAAC,GAAG,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,MAA6B;IACvE,OAAO,iDAAiD,CAAC,MAAM,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAgB;IACzC,OAAO,qCAAqC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC7C,QAAkB,EAClB,GAAa;IAEb,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACrE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAAE,OAAO,cAAc,CAAC;IACzF,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"release-new-model.js","sourceRoot":"","sources":["../../../src/screens/releases/release-new-model.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iDAAiD,EACjD,oCAAoC,GAGrC,MAAM,oBAAoB,CAAC;AAE5B,MAAM,UAAU,2BAA2B,CAAC,GAAW;IACrD,OAAO,oCAAoC,CAAC,GAAG,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,MAA6B;IACvE,OAAO,iDAAiD,CAAC,MAAM,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC7C,QAAkB,EAClB,GAAa;IAEb,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACrE,OAAO,qBAAqB,CAAC;AAC/B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"release-new-page.d.ts","sourceRoot":"","sources":["../../../src/screens/releases/release-new-page.tsx"],"names":[],"mappings":"AAiDA,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAkyCD,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,EAAE,mBAAmB,2CA68BhE"}
1
+ {"version":3,"file":"release-new-page.d.ts","sourceRoot":"","sources":["../../../src/screens/releases/release-new-page.tsx"],"names":[],"mappings":"AA0CA,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAmkCD,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,EAAE,mBAAmB,2CAmhChE"}
@@ -1,12 +1,13 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import Link from 'next/link';
4
- import { useRouter, useSearchParams } from 'next/navigation';
3
+ import { Link } from '../../components/navigation/link';
4
+ import { useSearchParams } from 'next/navigation';
5
+ import { useRouter } from '../../hooks/use-router';
5
6
  import { useMemo, useState } from 'react';
6
- import { CANARY_RELEASE_FILTER_MAX_DEPTH, CANARY_RELEASE_FILTER_OPS, DEFAULT_PROMPT_LANGUAGE, canaryReleaseFilterRulesSchema, } from '@proofhound/shared';
7
- import { AlertCircle, Check, Filter, ImageIcon, Loader2, Plus, Search, X } from 'lucide-react';
7
+ import { DEFAULT_PROMPT_LANGUAGE, canaryReleaseFilterRulesSchema, } from '@proofhound/shared';
8
+ import { AlertCircle, Check, ImageIcon, Loader2, Plus, Search } from 'lucide-react';
8
9
  import { Main } from '@proofhound/ui/layout';
9
- import { ModalityIconGroup, Button, Input, Label, cn, } from '@proofhound/ui';
10
+ import { ModalityIconGroup, Button, Input, Label, cn } from '@proofhound/ui';
10
11
  import { PromptVersionPickerRow, PromptVersionPickerTag } from '../../components';
11
12
  import { useConnector, useConnectors } from '../../hooks';
12
13
  import { useCreateCanaryRelease, useStartCanaryRelease } from '../../hooks';
@@ -21,6 +22,7 @@ import { getApiErrorMessage, getReleaseLineId } from '../../lib';
21
22
  import { composePromptPreview } from '../prompts/prompt-preview';
22
23
  import { renderPromptPreviewParts } from '../prompts/prompt-preview-parts';
23
24
  import { VARIABLE_TONE_CLASSES } from '../prompts/prompt-ui';
25
+ import { FieldMappingTable, FilterRulesBuilder, ReadOnlyFilterRules } from './release-input-route-editor';
24
26
  import { deriveRecordCategoryOptions, releaseRecordModeFromCategories } from './release-new-model';
25
27
  const IMAGE_PROMPT_VARIABLE_TYPES = new Set(['image', 'image_url', 'image_base64']);
26
28
  const DEFAULT_RPM = 60;
@@ -89,6 +91,29 @@ function trafficPercentFromText(value) {
89
91
  const parsed = Number(value.trim());
90
92
  return Number.isInteger(parsed) && parsed > 0 && parsed <= 100 ? parsed : null;
91
93
  }
94
+ function stopConditionsFromDraft(useMaxSamples, useMaxDurationSeconds, maxSamples, maxDurationSeconds) {
95
+ if (!useMaxSamples && !useMaxDurationSeconds)
96
+ return null;
97
+ const parsedMaxSamples = useMaxSamples ? positiveIntegerFromText(maxSamples) : null;
98
+ const parsedMaxDurationSeconds = useMaxDurationSeconds ? positiveIntegerFromText(maxDurationSeconds) : null;
99
+ if ((useMaxSamples && parsedMaxSamples === null) || (useMaxDurationSeconds && parsedMaxDurationSeconds === null)) {
100
+ return null;
101
+ }
102
+ return {
103
+ maxSamples: parsedMaxSamples,
104
+ maxDurationSeconds: parsedMaxDurationSeconds,
105
+ };
106
+ }
107
+ function formatStopConditionSummary(stopConditions, labels) {
108
+ if (!stopConditions)
109
+ return labels.manual;
110
+ const parts = [];
111
+ if (stopConditions.maxSamples)
112
+ parts.push(`${labels.byCount} · ${stopConditions.maxSamples}`);
113
+ if (stopConditions.maxDurationSeconds)
114
+ parts.push(`${labels.byTime} · ${stopConditions.maxDurationSeconds}s`);
115
+ return parts.length > 0 ? parts.join(' / ') : labels.manual;
116
+ }
92
117
  function initialTrafficPercentFromParams(params) {
93
118
  const percent = params.get('trafficPercent');
94
119
  if (percent && trafficPercentFromText(percent) !== null)
@@ -358,60 +383,6 @@ function ConnectorOptionRow({ connector, selected, multiple = false, onSelect, }
358
383
  function ReadOnlyConnectorRow({ connector, name, type, emptyLabel, }) {
359
384
  return (_jsxs("div", { className: "grid w-full grid-cols-[minmax(140px,0.85fr)_minmax(0,1.15fr)] gap-3 rounded-md border bg-muted/35 px-3 py-2.5 text-left", children: [_jsxs("div", { className: "flex min-w-0 items-start gap-2.5", children: [_jsx(CheckBox, { checked: true }), _jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate font-mono text-[13px] font-semibold", children: connector?.name ?? name ?? emptyLabel }), connector?.description ? (_jsx("div", { className: "mt-0.5 truncate text-[11.5px] text-muted-foreground", children: connector.description })) : null] })] }), _jsxs("div", { className: "min-w-0 text-[11.5px] text-muted-foreground", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [_jsx(Tag, { children: connector?.type ?? type ?? 'connector' }), connector ? _jsx(Tag, { children: connector.healthStatus }) : null] }), _jsx("div", { className: "mt-1 truncate font-mono", children: connector?.configSummary ?? '—' })] })] }));
360
385
  }
361
- function FieldMappingTable({ fields, promptVariables, externalIdField, mapping, readOnly = false, onExternalIdFieldChange, onMappingChange, }) {
362
- const { t } = useI18n();
363
- return (_jsxs("div", { className: "space-y-3", children: [_jsx("div", { className: "rounded-md border bg-background p-3", children: _jsxs("label", { className: "grid grid-cols-1 items-center gap-2 md:grid-cols-[minmax(180px,0.8fr)_minmax(0,1.2fr)]", children: [_jsxs("span", { className: "text-xs font-medium", children: [t('canaryReleases.new.field.externalIdField'), " ", _jsx("span", { className: "text-destructive", children: "*" })] }), readOnly ? (_jsx("div", { className: "min-h-9 rounded-md border bg-muted/40 px-3 py-2 font-mono text-xs", children: externalIdField || '—' })) : (_jsxs("select", { value: externalIdField, onChange: (event) => onExternalIdFieldChange(event.target.value), className: "h-9 rounded-md border border-input bg-background px-3 font-mono text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring", "data-testid": "release-new-mapping-external-id", children: [_jsx("option", { value: "", children: t('canaryReleases.new.fieldSelectPlaceholder') }), fields.map((field) => (_jsx("option", { value: field.key, children: field.key }, field.key)))] }))] }) }), _jsxs("div", { className: "overflow-hidden rounded-md border bg-background", children: [_jsxs("div", { className: "grid grid-cols-[minmax(180px,0.9fr)_minmax(0,1.1fr)_96px] gap-2 border-b bg-muted/40 px-3 py-2 text-xs font-medium text-muted-foreground", children: [_jsx("span", { children: t('canaryReleases.new.mapping.variable') }), _jsx("span", { children: t('canaryReleases.new.mapping.source') }), _jsx("span", { children: t('canaryReleases.new.mapping.type') })] }), promptVariables.length === 0 ? (_jsx("div", { className: "px-3 py-4 text-center text-xs text-muted-foreground", children: t('canaryReleases.new.promptVariablesEmpty') })) : (promptVariables.map((variable) => (_jsxs("div", { className: "grid grid-cols-[minmax(180px,0.9fr)_minmax(0,1.1fr)_96px] items-center gap-2 border-t px-3 py-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate font-mono text-xs font-semibold", children: variable.name }), _jsx("div", { className: "text-[11px] text-muted-foreground", children: variable.required
364
- ? t('canaryReleases.new.mapping.required')
365
- : t('canaryReleases.new.mapping.optional') })] }), readOnly ? (_jsx("div", { className: "min-h-8 rounded-md border bg-muted/40 px-2 py-1.5 font-mono text-xs", children: mapping[variable.name] || t('canaryReleases.new.mapping.unmapped') })) : (_jsxs("select", { value: mapping[variable.name] ?? '', onChange: (event) => onMappingChange(variable.name, event.target.value), className: "h-8 rounded-md border border-input bg-background px-2 font-mono text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring", "data-testid": `release-new-mapping-source-${variable.name}`, children: [_jsx("option", { value: "", children: t('canaryReleases.new.mapping.unmapped') }), fields.map((field) => (_jsx("option", { value: field.key, children: field.key }, field.key)))] })), _jsx("span", { className: "font-mono text-[11px] text-muted-foreground", children: variable.type })] }, variable.name))))] })] }));
366
- }
367
- function ReadOnlyFilterRules({ value }) {
368
- const { t } = useI18n();
369
- if (!value) {
370
- return (_jsx("div", { className: "rounded-md border bg-muted/35 px-3 py-2 text-[12px] text-muted-foreground", children: t('canaryReleases.new.filter.empty') }));
371
- }
372
- return (_jsx("pre", { className: "max-h-[220px] overflow-auto whitespace-pre-wrap break-words rounded-md border bg-muted px-3 py-2 font-mono text-[11.5px] leading-relaxed text-foreground", children: JSON.stringify(value, null, 2) }));
373
- }
374
- function FilterRulesBuilder({ value, fields, onChange, }) {
375
- const { t } = useI18n();
376
- const createAtom = () => ({
377
- type: 'atom',
378
- field: fields[0]?.key ?? '',
379
- op: 'eq',
380
- value: '',
381
- });
382
- if (!value) {
383
- return (_jsx("div", { className: "rounded-md border border-dashed bg-background px-3 py-4", children: _jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("div", { className: "text-xs text-muted-foreground", children: t('canaryReleases.new.filter.empty') }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onChange({ type: 'and', children: [createAtom()] }), children: [_jsx(Filter, { className: "size-3.5" }), t('canaryReleases.new.filter.enable')] })] }) }));
384
- }
385
- return (_jsx("div", { className: "space-y-2 rounded-md border bg-background p-3", children: _jsx(FilterNodeEditor, { node: value, depth: 1, fields: fields, onChange: onChange, onRemove: () => onChange(null) }) }));
386
- }
387
- function FilterNodeEditor({ node, depth, fields, onChange, onRemove, }) {
388
- const { t } = useI18n();
389
- const canNest = depth < CANARY_RELEASE_FILTER_MAX_DEPTH;
390
- const createAtom = () => ({
391
- type: 'atom',
392
- field: fields[0]?.key ?? '',
393
- op: 'eq',
394
- value: '',
395
- });
396
- const createGroup = (type) => ({ type, children: [createAtom()] });
397
- if (node.type === 'atom') {
398
- const needsValue = node.op !== 'exists';
399
- return (_jsxs("div", { className: "grid grid-cols-1 items-center gap-2 rounded-md border bg-card p-2 md:grid-cols-[minmax(0,1fr)_132px_minmax(0,1fr)_32px]", children: [_jsxs("select", { value: node.field, onChange: (event) => onChange({ ...node, field: event.target.value }), className: "h-8 rounded-md border border-input bg-background px-2 font-mono text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [_jsx("option", { value: "", children: t('canaryReleases.new.fieldSelectPlaceholder') }), fields.map((field) => (_jsx("option", { value: field.key, children: field.key }, field.key)))] }), _jsx("select", { value: node.op, onChange: (event) => {
400
- const op = event.target.value;
401
- onChange(op === 'exists' ? { type: 'atom', field: node.field, op } : { ...node, op, value: node.value ?? '' });
402
- }, className: "h-8 rounded-md border border-input bg-background px-2 font-mono text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring", children: CANARY_RELEASE_FILTER_OPS.map((op) => (_jsx("option", { value: op, children: t(`canaryReleases.new.filter.op.${op}`) }, op))) }), _jsx(Input, { value: needsValue ? String(node.value ?? '') : '', disabled: !needsValue, onChange: (event) => onChange({ ...node, value: event.target.value }), placeholder: needsValue ? t('canaryReleases.new.filter.valuePlaceholder') : t('canaryReleases.new.filter.valueDisabled'), className: "h-8 font-mono text-xs" }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "size-8", onClick: onRemove, "aria-label": t('canaryReleases.new.filter.remove'), children: _jsx(X, { className: "size-3.5" }) })] }));
403
- }
404
- if (node.type === 'not') {
405
- return (_jsxs("div", { className: "space-y-2 rounded-md border bg-muted/25 p-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx(Tag, { tone: "warning", children: "NOT" }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "size-8", onClick: onRemove, "aria-label": t('canaryReleases.new.filter.remove'), children: _jsx(X, { className: "size-3.5" }) })] }), _jsx(FilterNodeEditor, { node: node.child, depth: depth + 1, fields: fields, onChange: (child) => onChange({ type: 'not', child }), onRemove: () => onChange({ type: 'not', child: createAtom() }) })] }));
406
- }
407
- return (_jsxs("div", { className: "space-y-2 rounded-md border bg-muted/25 p-2", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("select", { value: node.type, onChange: (event) => onChange({ type: event.target.value, children: node.children }), className: "h-8 rounded-md border border-input bg-background px-2 font-mono text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [_jsx("option", { value: "and", children: "AND" }), _jsx("option", { value: "or", children: "OR" })] }), _jsx("span", { className: "text-xs text-muted-foreground", children: formatTemplate(t('canaryReleases.new.filter.depth'), { depth }) })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [_jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "h-8", onClick: () => onChange({ ...node, children: [...node.children, createAtom()] }), children: [_jsx(Plus, { className: "size-3.5" }), t('canaryReleases.new.filter.addCondition')] }), canNest ? (_jsxs(_Fragment, { children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "h-8", onClick: () => onChange({ ...node, children: [...node.children, createGroup('and')] }), children: t('canaryReleases.new.filter.addGroup') }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "h-8", onClick: () => onChange({ ...node, children: [...node.children, { type: 'not', child: createAtom() }] }), children: "NOT" })] })) : null, _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "size-8", onClick: onRemove, "aria-label": t('canaryReleases.new.filter.remove'), children: _jsx(X, { className: "size-3.5" }) })] })] }), _jsx("div", { className: "space-y-2 border-l pl-3", children: node.children.map((child, index) => (_jsx(FilterNodeEditor, { node: child, depth: depth + 1, fields: fields, onChange: (nextChild) => onChange({
408
- ...node,
409
- children: node.children.map((item, itemIndex) => (itemIndex === index ? nextChild : item)),
410
- }), onRemove: () => {
411
- const nextChildren = node.children.filter((_, itemIndex) => itemIndex !== index);
412
- onChange({ ...node, children: nextChildren.length > 0 ? nextChildren : [createAtom()] });
413
- } }, index))) })] }));
414
- }
415
386
  function RecordCategoriesField({ value, options, onChange, }) {
416
387
  const { t } = useI18n();
417
388
  const allSelected = options.length > 0 && options.every((option) => value.includes(option));
@@ -443,6 +414,31 @@ function TrafficSelectionField({ isQueueInput, value, trafficMode, showTrafficMo
443
414
  : 'border-border bg-muted text-muted-foreground hover:bg-muted/70'), children: [preset, "%"] }, preset));
444
415
  }) })] }));
445
416
  }
417
+ function TerminationConditionField({ useMaxSamples, useMaxDurationSeconds, maxSamples, maxDurationSeconds, onUseMaxSamplesChange, onUseMaxDurationSecondsChange, onMaxSamplesChange, onMaxDurationSecondsChange, }) {
418
+ const { t } = useI18n();
419
+ return (_jsx("div", { className: "space-y-3 rounded-md border bg-background p-3", children: _jsx("div", { className: "grid gap-2 md:grid-cols-2", children: [
420
+ {
421
+ key: 'samples',
422
+ checked: useMaxSamples,
423
+ title: t('canaryReleases.new.field.termination.byCount'),
424
+ inputLabel: t('canaryReleases.new.field.termination.maxSamples'),
425
+ value: maxSamples,
426
+ placeholder: t('canaryReleases.new.field.termination.maxSamplesPlaceholder'),
427
+ onCheckedChange: onUseMaxSamplesChange,
428
+ onValueChange: onMaxSamplesChange,
429
+ },
430
+ {
431
+ key: 'duration',
432
+ checked: useMaxDurationSeconds,
433
+ title: t('canaryReleases.new.field.termination.byTime'),
434
+ inputLabel: t('canaryReleases.new.field.termination.maxDuration'),
435
+ value: maxDurationSeconds,
436
+ placeholder: t('canaryReleases.new.field.termination.maxDurationPlaceholder'),
437
+ onCheckedChange: onUseMaxDurationSecondsChange,
438
+ onValueChange: onMaxDurationSecondsChange,
439
+ },
440
+ ].map((option) => (_jsxs("div", { className: cn('rounded-md border transition-colors', option.checked ? 'border-primary bg-primary/10' : 'border-border bg-muted/30 hover:bg-muted/50'), children: [_jsx("button", { type: "button", onClick: () => option.onCheckedChange(!option.checked), "aria-pressed": option.checked, className: "w-full px-3 py-2 text-left", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(CheckBox, { checked: option.checked }), _jsx("div", { className: "min-w-0", children: _jsx("div", { className: "text-[13px] font-semibold", children: option.title }) })] }) }), option.checked ? (_jsxs("div", { className: "space-y-1.5 px-3 pb-3", children: [_jsxs(Label, { className: "text-[12.5px]", children: [option.inputLabel, " ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(Input, { type: "number", min: 1, step: 1, value: option.value, placeholder: option.placeholder, onChange: (event) => option.onValueChange(event.target.value), className: "h-9 font-mono text-[13px]" })] })) : null] }, option.key))) }) }));
441
+ }
446
442
  function SummaryRow({ label, value }) {
447
443
  return (_jsxs("div", { children: [_jsx("div", { className: "text-[11.5px] text-muted-foreground", children: label }), _jsx("div", { className: "mt-0.5 min-h-5 break-words text-[12.5px] font-medium", children: value })] }));
448
444
  }
@@ -495,6 +491,10 @@ export function ReleaseNewPage({ projectId }) {
495
491
  const [filterRules, setFilterRules] = useState(null);
496
492
  const [trafficPercent, setTrafficPercent] = useState(() => initialTrafficPercentFromParams(searchParams));
497
493
  const [trafficMode, setTrafficMode] = useState(() => initialTrafficModeFromParams(searchParams));
494
+ const [useStopMaxSamples, setUseStopMaxSamples] = useState(false);
495
+ const [useStopMaxDurationSeconds, setUseStopMaxDurationSeconds] = useState(false);
496
+ const [stopMaxSamples, setStopMaxSamples] = useState('');
497
+ const [stopMaxDurationSeconds, setStopMaxDurationSeconds] = useState('');
498
498
  const [recordCategorySelection, setRecordCategorySelection] = useState(null);
499
499
  const [rpm, setRpm] = useState(searchParams.get('rpmLimit') ?? '');
500
500
  const [tpm, setTpm] = useState(searchParams.get('tpmLimit') ?? '');
@@ -588,22 +588,25 @@ export function ReleaseNewPage({ projectId }) {
588
588
  const tpmValue = positiveIntegerFromText(tpm);
589
589
  const concurrencyValue = positiveIntegerFromText(concurrency);
590
590
  const temperatureValue = temperatureFromText(temperature);
591
- const sourceForVariable = (variable) => {
591
+ const stopConditions = stopConditionsFromDraft(useStopMaxSamples, useStopMaxDurationSeconds, stopMaxSamples, stopMaxDurationSeconds);
592
+ const sourceForVariableWithOverrides = (variable, overrides) => {
592
593
  if (isAddCanaryToProduction)
593
594
  return inheritedVariableMapping[variable.name] ?? '';
594
- const override = mappingOverrides[variable.name];
595
+ const override = overrides[variable.name];
595
596
  if (override && inputFieldKeySet.has(override))
596
597
  return override;
597
598
  return inferSourceForVariable(variable, inputFieldOptions);
598
599
  };
599
- const requiredVariableMappingComplete = !selectedVersion ||
600
- selectedVersion.variables.every((variable) => !variable.required || sourceForVariable(variable).trim().length > 0);
600
+ const sourceForVariable = (variable) => sourceForVariableWithOverrides(variable, mappingOverrides);
601
+ const requiredVariableMappingComplete = !selectedVersion || selectedVersion.variables.every((variable) => sourceForVariable(variable).trim().length > 0);
601
602
  const effectiveFilterRules = isAddCanaryToProduction ? inheritedFilterRules : filterRules;
602
603
  const filterRulesValid = canaryReleaseFilterRulesSchema.safeParse(effectiveFilterRules).success;
603
604
  const runConfigValid = numberTextWithinLimit(rpm, selectedModel?.rpm.limit) &&
604
605
  numberTextWithinLimit(tpm, selectedModel?.tpm.limit) &&
605
606
  numberTextWithinLimit(concurrency, selectedModel?.concurrency.limit) &&
606
607
  temperatureValue !== null;
608
+ const hasAutomaticStopConditions = useStopMaxSamples || useStopMaxDurationSeconds;
609
+ const stopConditionsValid = !hasAutomaticStopConditions || stopConditions !== null;
607
610
  const effectiveReleaseName = isAddCanaryToProduction ? '' : releaseName.trim();
608
611
  const effectiveDescription = isAddCanaryToProduction ? '' : description.trim();
609
612
  const basicComplete = Boolean((isAddCanaryToProduction || effectiveReleaseName) && selectedVersion && selectedModel);
@@ -613,7 +616,14 @@ export function ReleaseNewPage({ projectId }) {
613
616
  requiredVariableMappingComplete &&
614
617
  filterRulesValid &&
615
618
  trafficRatioValue !== null;
616
- const runtimeComplete = runConfigValid && (recordCategoryOptions.length === 0 || effectiveRecordCategories.length > 0);
619
+ const runtimeComplete = runConfigValid &&
620
+ (!shouldCreateCanaryRelease || stopConditionsValid) &&
621
+ (recordCategoryOptions.length === 0 || effectiveRecordCategories.length > 0);
622
+ const stopConditionSummary = formatStopConditionSummary(stopConditions, {
623
+ manual: t('canaryReleases.new.field.termination.manual'),
624
+ byCount: t('canaryReleases.new.field.termination.byCount'),
625
+ byTime: t('canaryReleases.new.field.termination.byTime'),
626
+ });
617
627
  const canSubmit = basicComplete && connectorComplete && runtimeComplete && !isSubmitting;
618
628
  const handlePromptSelect = (promptId) => {
619
629
  if (isAddCanaryToProduction)
@@ -644,6 +654,18 @@ export function ReleaseNewPage({ projectId }) {
644
654
  setExternalIdFieldOverride('');
645
655
  setFilterRules(null);
646
656
  };
657
+ const handleMappingTargetChange = (target, nextTarget) => {
658
+ const variables = selectedVersion?.variables ?? [];
659
+ const currentVariable = variables.find((variable) => variable.name === target);
660
+ const nextVariable = variables.find((variable) => variable.name === nextTarget);
661
+ if (!currentVariable || !nextVariable)
662
+ return;
663
+ setMappingOverrides((current) => ({
664
+ ...current,
665
+ [target]: sourceForVariableWithOverrides(nextVariable, current),
666
+ [nextTarget]: sourceForVariableWithOverrides(currentVariable, current),
667
+ }));
668
+ };
647
669
  const handleOutputConnectorToggle = (connectorId, selected) => {
648
670
  if (isAddCanaryToProduction) {
649
671
  if (trafficMode !== 'dual_run' || inheritedOutputConnectorIdSet.has(connectorId))
@@ -655,6 +677,14 @@ export function ReleaseNewPage({ projectId }) {
655
677
  const message = getApiErrorMessage(error);
656
678
  if (message === 'release_name_taken')
657
679
  return t('common.formError.nameTaken');
680
+ if (message?.startsWith('release_variable_mapping_missing_prompt_variables:')) {
681
+ return formatTemplate(t('releases.new.error.variableMappingMissing'), {
682
+ fields: message.split(':')[1] || '',
683
+ });
684
+ }
685
+ if (message?.startsWith('release_variable_mapping_')) {
686
+ return t('releases.new.error.variableMappingInvalid');
687
+ }
658
688
  return message ?? t('releases.new.error.createFailed');
659
689
  };
660
690
  const buildVariableMapping = () => {
@@ -696,6 +726,9 @@ export function ReleaseNewPage({ projectId }) {
696
726
  : effectiveReleaseName;
697
727
  const variableMapping = buildVariableMapping();
698
728
  const recordMode = releaseRecordModeFromCategories(effectiveRecordCategories, recordCategoryOptions);
729
+ const recordCategories = recordMode === 'selected_categories'
730
+ ? effectiveRecordCategories.filter((category) => recordCategoryOptions.includes(category))
731
+ : [];
699
732
  const productionRunConfig = {
700
733
  rpmLimit: rpmValue,
701
734
  tpmLimit: tpmValue,
@@ -707,6 +740,7 @@ export function ReleaseNewPage({ projectId }) {
707
740
  tpmLimit: tpmValue,
708
741
  concurrency: concurrencyValue,
709
742
  temperature: temperatureValue,
743
+ ...(stopConditions ? { stopConditions } : {}),
710
744
  };
711
745
  if (shouldCreateCanaryRelease) {
712
746
  const payload = {
@@ -724,10 +758,11 @@ export function ReleaseNewPage({ projectId }) {
724
758
  trafficMode,
725
759
  runMode: 'manual',
726
760
  recordMode,
761
+ recordCategories,
727
762
  variableMapping: buildCanaryVariableMapping(variableMapping),
728
763
  outputMapping: [],
729
764
  filterRules: effectiveFilterRules,
730
- stopConditions: null,
765
+ stopConditions,
731
766
  externalIdField: effectiveExternalIdField,
732
767
  annotationSchema: [],
733
768
  storageCategories: effectiveRecordCategories.length === recordCategoryOptions.length ? [] : effectiveRecordCategories,
@@ -755,6 +790,7 @@ export function ReleaseNewPage({ projectId }) {
755
790
  variableMapping,
756
791
  filterRules: effectiveFilterRules,
757
792
  recordMode,
793
+ recordCategories,
758
794
  externalIdField: effectiveExternalIdField || null,
759
795
  retentionDays: null,
760
796
  submitReason,
@@ -785,7 +821,7 @@ export function ReleaseNewPage({ projectId }) {
785
821
  : t('canaryReleases.new.field.variableMappingHelp') }), _jsx("div", { className: "mt-3", children: _jsx(FieldMappingTable, { fields: inputFieldOptions, promptVariables: selectedVersion?.variables ?? [], externalIdField: effectiveExternalIdField, mapping: Object.fromEntries((selectedVersion?.variables ?? []).map((variable) => [
786
822
  variable.name,
787
823
  sourceForVariable(variable),
788
- ])), readOnly: isAddCanaryToProduction, onExternalIdFieldChange: setExternalIdFieldOverride, onMappingChange: (target, source) => setMappingOverrides((current) => ({ ...current, [target]: source })) }) }), effectiveInputConnectorId && inputFieldOptions.length === 0 ? (_jsx("div", { className: "mt-2 text-[11.5px] text-muted-foreground", children: selectedInputConnector?.type === 'webhook'
824
+ ])), readOnly: isAddCanaryToProduction, testIdPrefix: "release-new", onExternalIdFieldChange: setExternalIdFieldOverride, onMappingChange: (target, source) => setMappingOverrides((current) => ({ ...current, [target]: source })), onMappingTargetChange: handleMappingTargetChange }) }), effectiveInputConnectorId && inputFieldOptions.length === 0 ? (_jsx("div", { className: "mt-2 text-[11.5px] text-muted-foreground", children: selectedInputConnector?.type === 'webhook'
789
825
  ? t('canaryReleases.new.fieldMappingEmptyWebhook')
790
826
  : t('canaryReleases.new.fieldMappingEmptyQueue') })) : null] }), _jsxs("div", { className: "border-t border-dashed pt-5", children: [_jsx(Label, { children: t('canaryReleases.new.field.filterRules') }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: isAddCanaryToProduction
791
827
  ? t('releases.new.canary.lockedFilterHelp')
@@ -797,7 +833,7 @@ export function ReleaseNewPage({ projectId }) {
797
833
  const selected = validOutputConnectorIds.includes(connector.id);
798
834
  const locked = isAddCanaryToProduction && inheritedOutputConnectorIdSet.has(connector.id);
799
835
  return (_jsx(ConnectorOptionRow, { connector: connector, multiple: true, selected: selected || locked, onSelect: () => handleOutputConnectorToggle(connector.id, selected) }, connector.id));
800
- })) }))] })] }), _jsxs(StepCard, { index: 3, done: runtimeComplete, title: t('releases.new.steps.runtime'), detail: t('releases.new.steps.runtimeDetail'), testId: "release-new-step-runtime", children: [_jsxs("div", { children: [_jsx(SubSectionHead, { label: t('productionReleases.new.section.runtime') }), _jsxs("div", { className: "grid grid-cols-2 gap-3 sm:grid-cols-4", children: [_jsx(RuntimeLimitField, { label: t('productionReleases.new.field.rpm'), value: rpm, modelLimit: selectedModel ? formatModelLimit(selectedModel.rpm.limit) : '—', onChange: setRpm }), _jsx(RuntimeLimitField, { label: t('productionReleases.new.field.tpm'), value: tpm, modelLimit: selectedModel ? formatModelLimit(selectedModel.tpm.limit) : '—', onChange: setTpm }), _jsx(RuntimeLimitField, { label: t('productionReleases.new.field.concurrency'), value: concurrency, modelLimit: selectedModel ? formatModelLimit(selectedModel.concurrency.limit) : '—', onChange: setConcurrency }), _jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { className: "text-[12.5px]", children: [t('productionReleases.new.field.temperature'), " ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(Input, { type: "number", min: 0, max: 2, step: 0.1, value: temperature, onChange: (event) => setTemperature(event.target.value), className: "h-9" })] })] })] }), _jsxs("div", { className: "border-t border-dashed pt-5", children: [_jsx(Label, { children: t('canaryReleases.new.field.recordCategories') }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: t('canaryReleases.new.field.recordCategoriesHelp') }), _jsx("div", { className: "mt-3", children: _jsx(RecordCategoriesField, { value: effectiveRecordCategories, options: recordCategoryOptions, onChange: setRecordCategorySelection }) })] })] })] }), _jsx("aside", { className: "flex flex-col gap-3 xl:sticky xl:top-20 xl:self-start", children: _jsxs("div", { className: "rounded-lg border bg-card p-4", children: [_jsx("h2", { className: "text-[14px] font-semibold", children: t('releases.new.section.summary') }), _jsxs("div", { className: "mt-4 space-y-3", children: [!isAddCanaryToProduction ? (_jsx(SummaryRow, { label: t('releases.new.field.name'), value: effectiveReleaseName || '—' })) : null, _jsx(SummaryRow, { label: t('releases.new.summary.prompt'), value: selectedPrompt && selectedVersion ? `${selectedPrompt.name} · ${selectedVersion.version}` : '—' }), _jsx(SummaryRow, { label: t('productionReleases.new.field.model'), value: selectedModel ? `${selectedModel.name} · ${selectedModel.providerModelId}` : '—' }), _jsx(SummaryRow, { label: t('releases.new.summary.connector'), value: selectedInputConnector?.name ?? '—' }), _jsx(SummaryRow, { label: t('releases.new.field.traffic'), value: trafficRatioValue === null
836
+ })) }))] })] }), _jsxs(StepCard, { index: 3, done: runtimeComplete, title: t('releases.new.steps.runtime'), detail: t('releases.new.steps.runtimeDetail'), testId: "release-new-step-runtime", children: [_jsxs("div", { children: [_jsx(SubSectionHead, { label: t('productionReleases.new.section.runtime') }), _jsxs("div", { className: "grid grid-cols-2 gap-3 sm:grid-cols-4", children: [_jsx(RuntimeLimitField, { label: t('productionReleases.new.field.rpm'), value: rpm, modelLimit: selectedModel ? formatModelLimit(selectedModel.rpm.limit) : '—', onChange: setRpm }), _jsx(RuntimeLimitField, { label: t('productionReleases.new.field.tpm'), value: tpm, modelLimit: selectedModel ? formatModelLimit(selectedModel.tpm.limit) : '—', onChange: setTpm }), _jsx(RuntimeLimitField, { label: t('productionReleases.new.field.concurrency'), value: concurrency, modelLimit: selectedModel ? formatModelLimit(selectedModel.concurrency.limit) : '—', onChange: setConcurrency }), _jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { className: "text-[12.5px]", children: [t('productionReleases.new.field.temperature'), " ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(Input, { type: "number", min: 0, max: 2, step: 0.1, value: temperature, onChange: (event) => setTemperature(event.target.value), className: "h-9" })] })] })] }), shouldCreateCanaryRelease ? (_jsxs("div", { className: "border-t border-dashed pt-5", children: [_jsx(Label, { children: t('canaryReleases.new.field.termination') }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: t('canaryReleases.new.field.terminationHelp') }), _jsx("div", { className: "mt-3", children: _jsx(TerminationConditionField, { useMaxSamples: useStopMaxSamples, useMaxDurationSeconds: useStopMaxDurationSeconds, maxSamples: stopMaxSamples, maxDurationSeconds: stopMaxDurationSeconds, onUseMaxSamplesChange: setUseStopMaxSamples, onUseMaxDurationSecondsChange: setUseStopMaxDurationSeconds, onMaxSamplesChange: setStopMaxSamples, onMaxDurationSecondsChange: setStopMaxDurationSeconds }) })] })) : null, _jsxs("div", { className: "border-t border-dashed pt-5", children: [_jsx(Label, { children: t('canaryReleases.new.field.recordCategories') }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: t('canaryReleases.new.field.recordCategoriesHelp') }), _jsx("div", { className: "mt-3", children: _jsx(RecordCategoriesField, { value: effectiveRecordCategories, options: recordCategoryOptions, onChange: setRecordCategorySelection }) })] })] })] }), _jsx("aside", { className: "flex flex-col gap-3 xl:sticky xl:top-20 xl:self-start", children: _jsxs("div", { className: "rounded-lg border bg-card p-4", children: [_jsx("h2", { className: "text-[14px] font-semibold", children: t('releases.new.section.summary') }), _jsxs("div", { className: "mt-4 space-y-3", children: [!isAddCanaryToProduction ? (_jsx(SummaryRow, { label: t('releases.new.field.name'), value: effectiveReleaseName || '—' })) : null, _jsx(SummaryRow, { label: t('releases.new.summary.prompt'), value: selectedPrompt && selectedVersion ? `${selectedPrompt.name} · ${selectedVersion.version}` : '—' }), _jsx(SummaryRow, { label: t('productionReleases.new.field.model'), value: selectedModel ? `${selectedModel.name} · ${selectedModel.providerModelId}` : '—' }), _jsx(SummaryRow, { label: t('releases.new.summary.connector'), value: selectedInputConnector?.name ?? '—' }), _jsx(SummaryRow, { label: t('releases.new.field.traffic'), value: trafficRatioValue === null
801
837
  ? '—'
802
838
  : isQueueInput
803
839
  ? `${Math.round(trafficRatioValue * 100)}%`
@@ -807,7 +843,7 @@ export function ReleaseNewPage({ projectId }) {
807
843
  ? String(validOutputConnectorIds.length)
808
844
  : t('productionReleases.new.noOutputConnector') }), _jsx(SummaryRow, { label: t('releases.new.summary.runtime'), value: rpmValue && tpmValue && concurrencyValue
809
845
  ? `${rpmValue} RPM / ${tpmValue} TPM / C${concurrencyValue}`
810
- : '—' })] }), _jsx("div", { className: "mt-4 rounded-md border bg-muted/35 px-3 py-2 text-[12px] text-muted-foreground", children: canSubmit ? t('releases.new.submitReady') : t('releases.new.submitDisabled') }), submitError ? (_jsxs("div", { className: "mt-3 flex gap-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-[12px] text-destructive", children: [_jsx(AlertCircle, { className: "mt-0.5 size-3.5 shrink-0" }), _jsx("span", { children: submitError })] })) : null, _jsx("p", { className: "mt-2 text-[11.5px] leading-5 text-muted-foreground", children: t('productionReleases.new.confirmIrreversible') })] }) })] }), _jsx("div", { className: "fixed bottom-0 left-0 right-0 z-30 border-t bg-background/95 px-4 py-3 shadow-[0_-8px_24px_rgb(15_23_42/0.08)] backdrop-blur supports-[backdrop-filter]:bg-background/80 md:left-[var(--sidebar-width)]", children: _jsxs("div", { className: "mx-auto flex w-full max-w-[1280px] flex-wrap items-center justify-between gap-3", children: [_jsx("p", { className: "text-[12px] text-muted-foreground", children: t('productionReleases.new.confirmIrreversible') }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "outline", asChild: true, children: _jsx(Link, { href: "/releases", children: t('common.cancel') }) }), _jsx(DeployButton, { canSubmit: canSubmit, isPending: isSubmitting, label: shouldCreateCanaryRelease
846
+ : '—' }), shouldCreateCanaryRelease ? (_jsx(SummaryRow, { label: t('canaryReleases.new.field.termination'), value: stopConditionSummary })) : null] }), _jsx("div", { className: "mt-4 rounded-md border bg-muted/35 px-3 py-2 text-[12px] text-muted-foreground", children: canSubmit ? t('releases.new.submitReady') : t('releases.new.submitDisabled') }), submitError ? (_jsxs("div", { className: "mt-3 flex gap-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-[12px] text-destructive", children: [_jsx(AlertCircle, { className: "mt-0.5 size-3.5 shrink-0" }), _jsx("span", { children: submitError })] })) : null, _jsx("p", { className: "mt-2 text-[11.5px] leading-5 text-muted-foreground", children: t('productionReleases.new.confirmIrreversible') })] }) })] }), _jsx("div", { className: "fixed bottom-0 left-0 right-0 z-30 border-t bg-background/95 px-4 py-3 shadow-[0_-8px_24px_rgb(15_23_42/0.08)] backdrop-blur supports-[backdrop-filter]:bg-background/80 md:left-[var(--sidebar-width)]", children: _jsxs("div", { className: "mx-auto flex w-full max-w-[1280px] flex-wrap items-center justify-between gap-3", children: [_jsx("p", { className: "text-[12px] text-muted-foreground", children: t('productionReleases.new.confirmIrreversible') }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "outline", asChild: true, children: _jsx(Link, { href: "/releases", children: t('common.cancel') }) }), _jsx(DeployButton, { canSubmit: canSubmit, isPending: isSubmitting, label: shouldCreateCanaryRelease
811
847
  ? t('canaryReleases.new.action.submit')
812
848
  : t('productionReleases.new.action.submit'), pendingLabel: shouldCreateCanaryRelease
813
849
  ? t('canaryReleases.new.action.submitting')