Skip to content

Commit 368134f

Browse files
committed
fix(tui): validate empty input in SecretInput before triggering cancel
Previously, pressing Enter with an empty value in SecretInput would call onCancel (which navigates back) even when customValidation rejected empty values. Now validation runs first, showing the error message instead of silently going back. Fixes #1618
1 parent de94f49 commit 368134f

2 files changed

Lines changed: 24 additions & 2 deletions

File tree

src/cli/tui/components/SecretInput.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,15 @@ export interface SecretInputProps {
3838
}
3939

4040
function validateValue(value: string, schema?: ZodString, customValidation?: CustomValidation): string | undefined {
41-
if (!value) return undefined;
42-
4341
if (customValidation) {
4442
const result = customValidation(value);
4543
if (result !== true) {
4644
return result;
4745
}
4846
}
4947

48+
if (!value) return undefined;
49+
5050
if (schema) {
5151
const parseResult = schema.safeParse(value);
5252
if (!parseResult.success) {
@@ -89,6 +89,11 @@ export function SecretInput({
8989
onSubmit: val => {
9090
const trimmed = val.trim();
9191
if (!trimmed) {
92+
const validationError = validateValue(trimmed, schema, customValidation);
93+
if (validationError) {
94+
setShowError(true);
95+
return;
96+
}
9297
if (onSkip) {
9398
onSkip();
9499
} else {

src/cli/tui/components/__tests__/SecretInput.test.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,23 @@ describe('SecretInput', () => {
150150
expect(onCancel).toHaveBeenCalledTimes(1);
151151
});
152152

153+
it('shows validation error instead of calling onCancel when customValidation rejects empty value', async () => {
154+
const onCancel = vi.fn();
155+
const onSubmit = vi.fn();
156+
const customValidation = (val: string) => val.trim().length > 0 || 'API key is required';
157+
const { lastFrame, stdin } = render(
158+
<SecretInput prompt="API Key" customValidation={customValidation} onSubmit={onSubmit} onCancel={onCancel} />
159+
);
160+
161+
await delay();
162+
stdin.write(ENTER);
163+
await delay();
164+
165+
expect(onCancel).not.toHaveBeenCalled();
166+
expect(onSubmit).not.toHaveBeenCalled();
167+
expect(lastFrame()).toContain('API key is required');
168+
});
169+
153170
it('shows skip hint when onSkip is provided', () => {
154171
const { lastFrame } = render(<SecretInput prompt="Key" onSubmit={vi.fn()} onCancel={vi.fn()} onSkip={vi.fn()} />);
155172

0 commit comments

Comments
 (0)