@proofhound/web-ui 0.1.7 → 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.
- package/dist/hooks/annotation.d.ts +37 -16
- package/dist/hooks/annotation.d.ts.map +1 -1
- package/dist/hooks/canary-release.d.ts +62 -37
- package/dist/hooks/canary-release.d.ts.map +1 -1
- package/dist/hooks/dataset.d.ts +101 -0
- package/dist/hooks/dataset.d.ts.map +1 -1
- package/dist/hooks/dataset.js +27 -0
- package/dist/hooks/dataset.js.map +1 -1
- package/dist/hooks/optimization.d.ts +1 -1
- package/dist/hooks/production-release.d.ts +8 -4
- package/dist/hooks/production-release.d.ts.map +1 -1
- package/dist/hooks/prompt.d.ts +149 -38
- package/dist/hooks/prompt.d.ts.map +1 -1
- package/dist/hooks/prompt.js +20 -0
- package/dist/hooks/prompt.js.map +1 -1
- package/dist/hooks/release-line.d.ts +2522 -72
- package/dist/hooks/release-line.d.ts.map +1 -1
- package/dist/hooks/release-line.js +125 -0
- package/dist/hooks/release-line.js.map +1 -1
- package/dist/hooks/run-result.d.ts +9 -6
- package/dist/hooks/run-result.d.ts.map +1 -1
- package/dist/hooks/run-result.js +2 -1
- package/dist/hooks/run-result.js.map +1 -1
- package/dist/i18n/index.d.ts +652 -160
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js +652 -160
- package/dist/i18n/index.js.map +1 -1
- package/dist/lib/releases/release-line-model.d.ts +8 -2
- package/dist/lib/releases/release-line-model.d.ts.map +1 -1
- package/dist/lib/releases/release-line-model.js +66 -29
- package/dist/lib/releases/release-line-model.js.map +1 -1
- package/dist/screens/annotations/annotation-detail-page.js +1 -1
- package/dist/screens/annotations/annotation-new-page.d.ts.map +1 -1
- package/dist/screens/annotations/annotation-new-page.js +213 -49
- package/dist/screens/annotations/annotation-new-page.js.map +1 -1
- package/dist/screens/annotations/annotation-task-model.d.ts +3 -2
- package/dist/screens/annotations/annotation-task-model.d.ts.map +1 -1
- package/dist/screens/annotations/annotation-task-model.js +5 -4
- package/dist/screens/annotations/annotation-task-model.js.map +1 -1
- package/dist/screens/annotations/annotation-ui.d.ts.map +1 -1
- package/dist/screens/annotations/annotation-ui.js +9 -4
- package/dist/screens/annotations/annotation-ui.js.map +1 -1
- package/dist/screens/annotations/annotations-list-page.js +1 -1
- package/dist/screens/connectors/connector-detail-page.js +2 -2
- package/dist/screens/connectors/connector-detail-page.js.map +1 -1
- package/dist/screens/connectors/connector-form-page.js +1 -1
- package/dist/screens/connectors/connector-form-page.js.map +1 -1
- package/dist/screens/connectors/connector-ui.d.ts +6 -0
- package/dist/screens/connectors/connector-ui.d.ts.map +1 -1
- package/dist/screens/connectors/connector-ui.js +7 -1
- package/dist/screens/connectors/connector-ui.js.map +1 -1
- package/dist/screens/connectors/connectors-list-page.d.ts.map +1 -1
- package/dist/screens/connectors/connectors-list-page.js +5 -5
- package/dist/screens/connectors/connectors-list-page.js.map +1 -1
- package/dist/screens/dashboard/dashboard-screen.d.ts.map +1 -1
- package/dist/screens/dashboard/dashboard-screen.js +27 -15
- package/dist/screens/dashboard/dashboard-screen.js.map +1 -1
- package/dist/screens/datasets/dataset-mappers.js +1 -1
- package/dist/screens/datasets/dataset-mappers.js.map +1 -1
- package/dist/screens/datasets/dataset-types.d.ts +1 -1
- package/dist/screens/datasets/dataset-types.d.ts.map +1 -1
- package/dist/screens/datasets/dataset-ui.d.ts +1 -1
- package/dist/screens/datasets/dataset-ui.d.ts.map +1 -1
- package/dist/screens/datasets/dataset-ui.js +2 -2
- package/dist/screens/datasets/dataset-ui.js.map +1 -1
- package/dist/screens/datasets/datasets-list-page.d.ts.map +1 -1
- package/dist/screens/datasets/datasets-list-page.js +35 -24
- package/dist/screens/datasets/datasets-list-page.js.map +1 -1
- package/dist/screens/experiments/experiment-detail-page.js +1 -1
- package/dist/screens/experiments/experiment-detail-page.js.map +1 -1
- package/dist/screens/experiments/run-result-labels.d.ts.map +1 -1
- package/dist/screens/experiments/run-result-labels.js +3 -4
- package/dist/screens/experiments/run-result-labels.js.map +1 -1
- package/dist/screens/prompts/prompt-detail-page.d.ts.map +1 -1
- package/dist/screens/prompts/prompt-detail-page.js +9 -10
- package/dist/screens/prompts/prompt-detail-page.js.map +1 -1
- package/dist/screens/prompts/prompt-model.d.ts +5 -2
- package/dist/screens/prompts/prompt-model.d.ts.map +1 -1
- package/dist/screens/prompts/prompt-model.js +3 -1
- package/dist/screens/prompts/prompt-model.js.map +1 -1
- package/dist/screens/prompts/prompts-list-page.d.ts.map +1 -1
- package/dist/screens/prompts/prompts-list-page.js +44 -20
- package/dist/screens/prompts/prompts-list-page.js.map +1 -1
- package/dist/screens/releases/release-input-route-editor.d.ts +39 -0
- package/dist/screens/releases/release-input-route-editor.d.ts.map +1 -0
- package/dist/screens/releases/release-input-route-editor.js +355 -0
- package/dist/screens/releases/release-input-route-editor.js.map +1 -0
- package/dist/screens/releases/release-line-detail-page.d.ts +62 -0
- package/dist/screens/releases/release-line-detail-page.d.ts.map +1 -1
- package/dist/screens/releases/release-line-detail-page.js +1877 -323
- package/dist/screens/releases/release-line-detail-page.js.map +1 -1
- package/dist/screens/releases/release-line-ui.d.ts.map +1 -1
- package/dist/screens/releases/release-line-ui.js +55 -39
- package/dist/screens/releases/release-line-ui.js.map +1 -1
- package/dist/screens/releases/release-new-model.d.ts.map +1 -1
- package/dist/screens/releases/release-new-model.js +1 -6
- package/dist/screens/releases/release-new-model.js.map +1 -1
- package/dist/screens/releases/release-new-page.d.ts.map +1 -1
- package/dist/screens/releases/release-new-page.js +101 -66
- package/dist/screens/releases/release-new-page.js.map +1 -1
- package/dist/screens/releases/release-topology-canvas.d.ts +11 -2
- package/dist/screens/releases/release-topology-canvas.d.ts.map +1 -1
- package/dist/screens/releases/release-topology-canvas.js +1015 -174
- package/dist/screens/releases/release-topology-canvas.js.map +1 -1
- package/dist/screens/releases/releases-list-page.d.ts.map +1 -1
- package/dist/screens/releases/releases-list-page.js +81 -32
- package/dist/screens/releases/releases-list-page.js.map +1 -1
- 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 {
|
|
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
|
-
|
|
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 '
|
|
79
|
-
return 'releases.status.
|
|
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
|
|
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 (
|
|
169
|
-
return (_jsx("div", { className: "flex
|
|
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
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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":"AAAA,YAAY,CAAC;;
|
|
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;
|
|
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
|
-
|
|
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,
|
|
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":"
|
|
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 {
|
|
7
|
-
import { AlertCircle, Check,
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
600
|
-
|
|
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 &&
|
|
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
|
|
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')
|