@proofhound/web-ui 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/hooks/annotation.d.ts +37 -16
  2. package/dist/hooks/annotation.d.ts.map +1 -1
  3. package/dist/hooks/canary-release.d.ts +62 -37
  4. package/dist/hooks/canary-release.d.ts.map +1 -1
  5. package/dist/hooks/dataset.d.ts +101 -0
  6. package/dist/hooks/dataset.d.ts.map +1 -1
  7. package/dist/hooks/dataset.js +27 -0
  8. package/dist/hooks/dataset.js.map +1 -1
  9. package/dist/hooks/optimization.d.ts +1 -1
  10. package/dist/hooks/production-release.d.ts +8 -4
  11. package/dist/hooks/production-release.d.ts.map +1 -1
  12. package/dist/hooks/prompt.d.ts +149 -38
  13. package/dist/hooks/prompt.d.ts.map +1 -1
  14. package/dist/hooks/prompt.js +20 -0
  15. package/dist/hooks/prompt.js.map +1 -1
  16. package/dist/hooks/release-line.d.ts +2522 -72
  17. package/dist/hooks/release-line.d.ts.map +1 -1
  18. package/dist/hooks/release-line.js +125 -0
  19. package/dist/hooks/release-line.js.map +1 -1
  20. package/dist/hooks/run-result.d.ts +9 -6
  21. package/dist/hooks/run-result.d.ts.map +1 -1
  22. package/dist/hooks/run-result.js +2 -1
  23. package/dist/hooks/run-result.js.map +1 -1
  24. package/dist/i18n/index.d.ts +652 -160
  25. package/dist/i18n/index.d.ts.map +1 -1
  26. package/dist/i18n/index.js +652 -160
  27. package/dist/i18n/index.js.map +1 -1
  28. package/dist/lib/releases/release-line-model.d.ts +8 -2
  29. package/dist/lib/releases/release-line-model.d.ts.map +1 -1
  30. package/dist/lib/releases/release-line-model.js +66 -29
  31. package/dist/lib/releases/release-line-model.js.map +1 -1
  32. package/dist/screens/annotations/annotation-detail-page.js +1 -1
  33. package/dist/screens/annotations/annotation-new-page.d.ts.map +1 -1
  34. package/dist/screens/annotations/annotation-new-page.js +213 -49
  35. package/dist/screens/annotations/annotation-new-page.js.map +1 -1
  36. package/dist/screens/annotations/annotation-task-model.d.ts +3 -2
  37. package/dist/screens/annotations/annotation-task-model.d.ts.map +1 -1
  38. package/dist/screens/annotations/annotation-task-model.js +5 -4
  39. package/dist/screens/annotations/annotation-task-model.js.map +1 -1
  40. package/dist/screens/annotations/annotation-ui.d.ts.map +1 -1
  41. package/dist/screens/annotations/annotation-ui.js +9 -4
  42. package/dist/screens/annotations/annotation-ui.js.map +1 -1
  43. package/dist/screens/annotations/annotations-list-page.js +1 -1
  44. package/dist/screens/connectors/connector-detail-page.js +2 -2
  45. package/dist/screens/connectors/connector-detail-page.js.map +1 -1
  46. package/dist/screens/connectors/connector-form-page.js +1 -1
  47. package/dist/screens/connectors/connector-form-page.js.map +1 -1
  48. package/dist/screens/connectors/connector-ui.d.ts +6 -0
  49. package/dist/screens/connectors/connector-ui.d.ts.map +1 -1
  50. package/dist/screens/connectors/connector-ui.js +7 -1
  51. package/dist/screens/connectors/connector-ui.js.map +1 -1
  52. package/dist/screens/connectors/connectors-list-page.d.ts.map +1 -1
  53. package/dist/screens/connectors/connectors-list-page.js +5 -5
  54. package/dist/screens/connectors/connectors-list-page.js.map +1 -1
  55. package/dist/screens/dashboard/dashboard-screen.d.ts.map +1 -1
  56. package/dist/screens/dashboard/dashboard-screen.js +27 -15
  57. package/dist/screens/dashboard/dashboard-screen.js.map +1 -1
  58. package/dist/screens/datasets/dataset-mappers.js +1 -1
  59. package/dist/screens/datasets/dataset-mappers.js.map +1 -1
  60. package/dist/screens/datasets/dataset-types.d.ts +1 -1
  61. package/dist/screens/datasets/dataset-types.d.ts.map +1 -1
  62. package/dist/screens/datasets/dataset-ui.d.ts +1 -1
  63. package/dist/screens/datasets/dataset-ui.d.ts.map +1 -1
  64. package/dist/screens/datasets/dataset-ui.js +2 -2
  65. package/dist/screens/datasets/dataset-ui.js.map +1 -1
  66. package/dist/screens/datasets/datasets-list-page.d.ts.map +1 -1
  67. package/dist/screens/datasets/datasets-list-page.js +35 -24
  68. package/dist/screens/datasets/datasets-list-page.js.map +1 -1
  69. package/dist/screens/experiments/experiment-detail-page.js +1 -1
  70. package/dist/screens/experiments/experiment-detail-page.js.map +1 -1
  71. package/dist/screens/experiments/run-result-labels.d.ts.map +1 -1
  72. package/dist/screens/experiments/run-result-labels.js +3 -4
  73. package/dist/screens/experiments/run-result-labels.js.map +1 -1
  74. package/dist/screens/prompts/prompt-detail-page.d.ts.map +1 -1
  75. package/dist/screens/prompts/prompt-detail-page.js +7 -8
  76. package/dist/screens/prompts/prompt-detail-page.js.map +1 -1
  77. package/dist/screens/prompts/prompt-model.d.ts +5 -2
  78. package/dist/screens/prompts/prompt-model.d.ts.map +1 -1
  79. package/dist/screens/prompts/prompt-model.js +3 -1
  80. package/dist/screens/prompts/prompt-model.js.map +1 -1
  81. package/dist/screens/prompts/prompts-list-page.d.ts.map +1 -1
  82. package/dist/screens/prompts/prompts-list-page.js +44 -20
  83. package/dist/screens/prompts/prompts-list-page.js.map +1 -1
  84. package/dist/screens/releases/release-input-route-editor.d.ts +39 -0
  85. package/dist/screens/releases/release-input-route-editor.d.ts.map +1 -0
  86. package/dist/screens/releases/release-input-route-editor.js +355 -0
  87. package/dist/screens/releases/release-input-route-editor.js.map +1 -0
  88. package/dist/screens/releases/release-line-detail-page.d.ts +62 -0
  89. package/dist/screens/releases/release-line-detail-page.d.ts.map +1 -1
  90. package/dist/screens/releases/release-line-detail-page.js +1877 -323
  91. package/dist/screens/releases/release-line-detail-page.js.map +1 -1
  92. package/dist/screens/releases/release-line-ui.d.ts.map +1 -1
  93. package/dist/screens/releases/release-line-ui.js +55 -39
  94. package/dist/screens/releases/release-line-ui.js.map +1 -1
  95. package/dist/screens/releases/release-new-model.d.ts.map +1 -1
  96. package/dist/screens/releases/release-new-model.js +1 -6
  97. package/dist/screens/releases/release-new-model.js.map +1 -1
  98. package/dist/screens/releases/release-new-page.d.ts.map +1 -1
  99. package/dist/screens/releases/release-new-page.js +101 -66
  100. package/dist/screens/releases/release-new-page.js.map +1 -1
  101. package/dist/screens/releases/release-topology-canvas.d.ts +11 -2
  102. package/dist/screens/releases/release-topology-canvas.d.ts.map +1 -1
  103. package/dist/screens/releases/release-topology-canvas.js +1015 -174
  104. package/dist/screens/releases/release-topology-canvas.js.map +1 -1
  105. package/dist/screens/releases/releases-list-page.d.ts.map +1 -1
  106. package/dist/screens/releases/releases-list-page.js +81 -32
  107. package/dist/screens/releases/releases-list-page.js.map +1 -1
  108. 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":"AAyCA,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAmkCD,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,EAAE,mBAAmB,2CAmhChE"}
@@ -3,10 +3,10 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import Link from 'next/link';
4
4
  import { useRouter, useSearchParams } from 'next/navigation';
5
5
  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';
6
+ import { DEFAULT_PROMPT_LANGUAGE, canaryReleaseFilterRulesSchema, } from '@proofhound/shared';
7
+ import { AlertCircle, Check, ImageIcon, Loader2, Plus, Search } from 'lucide-react';
8
8
  import { Main } from '@proofhound/ui/layout';
9
- import { ModalityIconGroup, Button, Input, Label, cn, } from '@proofhound/ui';
9
+ import { ModalityIconGroup, Button, Input, Label, cn } from '@proofhound/ui';
10
10
  import { PromptVersionPickerRow, PromptVersionPickerTag } from '../../components';
11
11
  import { useConnector, useConnectors } from '../../hooks';
12
12
  import { useCreateCanaryRelease, useStartCanaryRelease } from '../../hooks';
@@ -21,6 +21,7 @@ import { getApiErrorMessage, getReleaseLineId } from '../../lib';
21
21
  import { composePromptPreview } from '../prompts/prompt-preview';
22
22
  import { renderPromptPreviewParts } from '../prompts/prompt-preview-parts';
23
23
  import { VARIABLE_TONE_CLASSES } from '../prompts/prompt-ui';
24
+ import { FieldMappingTable, FilterRulesBuilder, ReadOnlyFilterRules } from './release-input-route-editor';
24
25
  import { deriveRecordCategoryOptions, releaseRecordModeFromCategories } from './release-new-model';
25
26
  const IMAGE_PROMPT_VARIABLE_TYPES = new Set(['image', 'image_url', 'image_base64']);
26
27
  const DEFAULT_RPM = 60;
@@ -89,6 +90,29 @@ function trafficPercentFromText(value) {
89
90
  const parsed = Number(value.trim());
90
91
  return Number.isInteger(parsed) && parsed > 0 && parsed <= 100 ? parsed : null;
91
92
  }
93
+ function stopConditionsFromDraft(useMaxSamples, useMaxDurationSeconds, maxSamples, maxDurationSeconds) {
94
+ if (!useMaxSamples && !useMaxDurationSeconds)
95
+ return null;
96
+ const parsedMaxSamples = useMaxSamples ? positiveIntegerFromText(maxSamples) : null;
97
+ const parsedMaxDurationSeconds = useMaxDurationSeconds ? positiveIntegerFromText(maxDurationSeconds) : null;
98
+ if ((useMaxSamples && parsedMaxSamples === null) || (useMaxDurationSeconds && parsedMaxDurationSeconds === null)) {
99
+ return null;
100
+ }
101
+ return {
102
+ maxSamples: parsedMaxSamples,
103
+ maxDurationSeconds: parsedMaxDurationSeconds,
104
+ };
105
+ }
106
+ function formatStopConditionSummary(stopConditions, labels) {
107
+ if (!stopConditions)
108
+ return labels.manual;
109
+ const parts = [];
110
+ if (stopConditions.maxSamples)
111
+ parts.push(`${labels.byCount} · ${stopConditions.maxSamples}`);
112
+ if (stopConditions.maxDurationSeconds)
113
+ parts.push(`${labels.byTime} · ${stopConditions.maxDurationSeconds}s`);
114
+ return parts.length > 0 ? parts.join(' / ') : labels.manual;
115
+ }
92
116
  function initialTrafficPercentFromParams(params) {
93
117
  const percent = params.get('trafficPercent');
94
118
  if (percent && trafficPercentFromText(percent) !== null)
@@ -358,60 +382,6 @@ function ConnectorOptionRow({ connector, selected, multiple = false, onSelect, }
358
382
  function ReadOnlyConnectorRow({ connector, name, type, emptyLabel, }) {
359
383
  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
384
  }
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
385
  function RecordCategoriesField({ value, options, onChange, }) {
416
386
  const { t } = useI18n();
417
387
  const allSelected = options.length > 0 && options.every((option) => value.includes(option));
@@ -443,6 +413,31 @@ function TrafficSelectionField({ isQueueInput, value, trafficMode, showTrafficMo
443
413
  : 'border-border bg-muted text-muted-foreground hover:bg-muted/70'), children: [preset, "%"] }, preset));
444
414
  }) })] }));
445
415
  }
416
+ function TerminationConditionField({ useMaxSamples, useMaxDurationSeconds, maxSamples, maxDurationSeconds, onUseMaxSamplesChange, onUseMaxDurationSecondsChange, onMaxSamplesChange, onMaxDurationSecondsChange, }) {
417
+ const { t } = useI18n();
418
+ 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: [
419
+ {
420
+ key: 'samples',
421
+ checked: useMaxSamples,
422
+ title: t('canaryReleases.new.field.termination.byCount'),
423
+ inputLabel: t('canaryReleases.new.field.termination.maxSamples'),
424
+ value: maxSamples,
425
+ placeholder: t('canaryReleases.new.field.termination.maxSamplesPlaceholder'),
426
+ onCheckedChange: onUseMaxSamplesChange,
427
+ onValueChange: onMaxSamplesChange,
428
+ },
429
+ {
430
+ key: 'duration',
431
+ checked: useMaxDurationSeconds,
432
+ title: t('canaryReleases.new.field.termination.byTime'),
433
+ inputLabel: t('canaryReleases.new.field.termination.maxDuration'),
434
+ value: maxDurationSeconds,
435
+ placeholder: t('canaryReleases.new.field.termination.maxDurationPlaceholder'),
436
+ onCheckedChange: onUseMaxDurationSecondsChange,
437
+ onValueChange: onMaxDurationSecondsChange,
438
+ },
439
+ ].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))) }) }));
440
+ }
446
441
  function SummaryRow({ label, value }) {
447
442
  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
443
  }
@@ -495,6 +490,10 @@ export function ReleaseNewPage({ projectId }) {
495
490
  const [filterRules, setFilterRules] = useState(null);
496
491
  const [trafficPercent, setTrafficPercent] = useState(() => initialTrafficPercentFromParams(searchParams));
497
492
  const [trafficMode, setTrafficMode] = useState(() => initialTrafficModeFromParams(searchParams));
493
+ const [useStopMaxSamples, setUseStopMaxSamples] = useState(false);
494
+ const [useStopMaxDurationSeconds, setUseStopMaxDurationSeconds] = useState(false);
495
+ const [stopMaxSamples, setStopMaxSamples] = useState('');
496
+ const [stopMaxDurationSeconds, setStopMaxDurationSeconds] = useState('');
498
497
  const [recordCategorySelection, setRecordCategorySelection] = useState(null);
499
498
  const [rpm, setRpm] = useState(searchParams.get('rpmLimit') ?? '');
500
499
  const [tpm, setTpm] = useState(searchParams.get('tpmLimit') ?? '');
@@ -588,22 +587,25 @@ export function ReleaseNewPage({ projectId }) {
588
587
  const tpmValue = positiveIntegerFromText(tpm);
589
588
  const concurrencyValue = positiveIntegerFromText(concurrency);
590
589
  const temperatureValue = temperatureFromText(temperature);
591
- const sourceForVariable = (variable) => {
590
+ const stopConditions = stopConditionsFromDraft(useStopMaxSamples, useStopMaxDurationSeconds, stopMaxSamples, stopMaxDurationSeconds);
591
+ const sourceForVariableWithOverrides = (variable, overrides) => {
592
592
  if (isAddCanaryToProduction)
593
593
  return inheritedVariableMapping[variable.name] ?? '';
594
- const override = mappingOverrides[variable.name];
594
+ const override = overrides[variable.name];
595
595
  if (override && inputFieldKeySet.has(override))
596
596
  return override;
597
597
  return inferSourceForVariable(variable, inputFieldOptions);
598
598
  };
599
- const requiredVariableMappingComplete = !selectedVersion ||
600
- selectedVersion.variables.every((variable) => !variable.required || sourceForVariable(variable).trim().length > 0);
599
+ const sourceForVariable = (variable) => sourceForVariableWithOverrides(variable, mappingOverrides);
600
+ const requiredVariableMappingComplete = !selectedVersion || selectedVersion.variables.every((variable) => sourceForVariable(variable).trim().length > 0);
601
601
  const effectiveFilterRules = isAddCanaryToProduction ? inheritedFilterRules : filterRules;
602
602
  const filterRulesValid = canaryReleaseFilterRulesSchema.safeParse(effectiveFilterRules).success;
603
603
  const runConfigValid = numberTextWithinLimit(rpm, selectedModel?.rpm.limit) &&
604
604
  numberTextWithinLimit(tpm, selectedModel?.tpm.limit) &&
605
605
  numberTextWithinLimit(concurrency, selectedModel?.concurrency.limit) &&
606
606
  temperatureValue !== null;
607
+ const hasAutomaticStopConditions = useStopMaxSamples || useStopMaxDurationSeconds;
608
+ const stopConditionsValid = !hasAutomaticStopConditions || stopConditions !== null;
607
609
  const effectiveReleaseName = isAddCanaryToProduction ? '' : releaseName.trim();
608
610
  const effectiveDescription = isAddCanaryToProduction ? '' : description.trim();
609
611
  const basicComplete = Boolean((isAddCanaryToProduction || effectiveReleaseName) && selectedVersion && selectedModel);
@@ -613,7 +615,14 @@ export function ReleaseNewPage({ projectId }) {
613
615
  requiredVariableMappingComplete &&
614
616
  filterRulesValid &&
615
617
  trafficRatioValue !== null;
616
- const runtimeComplete = runConfigValid && (recordCategoryOptions.length === 0 || effectiveRecordCategories.length > 0);
618
+ const runtimeComplete = runConfigValid &&
619
+ (!shouldCreateCanaryRelease || stopConditionsValid) &&
620
+ (recordCategoryOptions.length === 0 || effectiveRecordCategories.length > 0);
621
+ const stopConditionSummary = formatStopConditionSummary(stopConditions, {
622
+ manual: t('canaryReleases.new.field.termination.manual'),
623
+ byCount: t('canaryReleases.new.field.termination.byCount'),
624
+ byTime: t('canaryReleases.new.field.termination.byTime'),
625
+ });
617
626
  const canSubmit = basicComplete && connectorComplete && runtimeComplete && !isSubmitting;
618
627
  const handlePromptSelect = (promptId) => {
619
628
  if (isAddCanaryToProduction)
@@ -644,6 +653,18 @@ export function ReleaseNewPage({ projectId }) {
644
653
  setExternalIdFieldOverride('');
645
654
  setFilterRules(null);
646
655
  };
656
+ const handleMappingTargetChange = (target, nextTarget) => {
657
+ const variables = selectedVersion?.variables ?? [];
658
+ const currentVariable = variables.find((variable) => variable.name === target);
659
+ const nextVariable = variables.find((variable) => variable.name === nextTarget);
660
+ if (!currentVariable || !nextVariable)
661
+ return;
662
+ setMappingOverrides((current) => ({
663
+ ...current,
664
+ [target]: sourceForVariableWithOverrides(nextVariable, current),
665
+ [nextTarget]: sourceForVariableWithOverrides(currentVariable, current),
666
+ }));
667
+ };
647
668
  const handleOutputConnectorToggle = (connectorId, selected) => {
648
669
  if (isAddCanaryToProduction) {
649
670
  if (trafficMode !== 'dual_run' || inheritedOutputConnectorIdSet.has(connectorId))
@@ -655,6 +676,14 @@ export function ReleaseNewPage({ projectId }) {
655
676
  const message = getApiErrorMessage(error);
656
677
  if (message === 'release_name_taken')
657
678
  return t('common.formError.nameTaken');
679
+ if (message?.startsWith('release_variable_mapping_missing_prompt_variables:')) {
680
+ return formatTemplate(t('releases.new.error.variableMappingMissing'), {
681
+ fields: message.split(':')[1] || '',
682
+ });
683
+ }
684
+ if (message?.startsWith('release_variable_mapping_')) {
685
+ return t('releases.new.error.variableMappingInvalid');
686
+ }
658
687
  return message ?? t('releases.new.error.createFailed');
659
688
  };
660
689
  const buildVariableMapping = () => {
@@ -696,6 +725,9 @@ export function ReleaseNewPage({ projectId }) {
696
725
  : effectiveReleaseName;
697
726
  const variableMapping = buildVariableMapping();
698
727
  const recordMode = releaseRecordModeFromCategories(effectiveRecordCategories, recordCategoryOptions);
728
+ const recordCategories = recordMode === 'selected_categories'
729
+ ? effectiveRecordCategories.filter((category) => recordCategoryOptions.includes(category))
730
+ : [];
699
731
  const productionRunConfig = {
700
732
  rpmLimit: rpmValue,
701
733
  tpmLimit: tpmValue,
@@ -707,6 +739,7 @@ export function ReleaseNewPage({ projectId }) {
707
739
  tpmLimit: tpmValue,
708
740
  concurrency: concurrencyValue,
709
741
  temperature: temperatureValue,
742
+ ...(stopConditions ? { stopConditions } : {}),
710
743
  };
711
744
  if (shouldCreateCanaryRelease) {
712
745
  const payload = {
@@ -724,10 +757,11 @@ export function ReleaseNewPage({ projectId }) {
724
757
  trafficMode,
725
758
  runMode: 'manual',
726
759
  recordMode,
760
+ recordCategories,
727
761
  variableMapping: buildCanaryVariableMapping(variableMapping),
728
762
  outputMapping: [],
729
763
  filterRules: effectiveFilterRules,
730
- stopConditions: null,
764
+ stopConditions,
731
765
  externalIdField: effectiveExternalIdField,
732
766
  annotationSchema: [],
733
767
  storageCategories: effectiveRecordCategories.length === recordCategoryOptions.length ? [] : effectiveRecordCategories,
@@ -755,6 +789,7 @@ export function ReleaseNewPage({ projectId }) {
755
789
  variableMapping,
756
790
  filterRules: effectiveFilterRules,
757
791
  recordMode,
792
+ recordCategories,
758
793
  externalIdField: effectiveExternalIdField || null,
759
794
  retentionDays: null,
760
795
  submitReason,
@@ -785,7 +820,7 @@ export function ReleaseNewPage({ projectId }) {
785
820
  : 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
821
  variable.name,
787
822
  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'
823
+ ])), 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
824
  ? t('canaryReleases.new.fieldMappingEmptyWebhook')
790
825
  : 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
826
  ? t('releases.new.canary.lockedFilterHelp')
@@ -797,7 +832,7 @@ export function ReleaseNewPage({ projectId }) {
797
832
  const selected = validOutputConnectorIds.includes(connector.id);
798
833
  const locked = isAddCanaryToProduction && inheritedOutputConnectorIdSet.has(connector.id);
799
834
  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
835
+ })) }))] })] }), _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
836
  ? '—'
802
837
  : isQueueInput
803
838
  ? `${Math.round(trafficRatioValue * 100)}%`
@@ -807,7 +842,7 @@ export function ReleaseNewPage({ projectId }) {
807
842
  ? String(validOutputConnectorIds.length)
808
843
  : t('productionReleases.new.noOutputConnector') }), _jsx(SummaryRow, { label: t('releases.new.summary.runtime'), value: rpmValue && tpmValue && concurrencyValue
809
844
  ? `${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
845
+ : '—' }), 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
846
  ? t('canaryReleases.new.action.submit')
812
847
  : t('productionReleases.new.action.submit'), pendingLabel: shouldCreateCanaryRelease
813
848
  ? t('canaryReleases.new.action.submitting')