Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions ink/configurationWizard/ApiKeyStep.test.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { useInput } from 'ink';
import { useStepperInput } from 'ink-stepper';
import { render } from 'ink-testing-library';
import React from 'react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { ApiKeyStep } from './ApiKeyStep';

vi.mock('ink-stepper', () => ({
useStepperInput: vi.fn(),
}));

vi.mock('ink', async () => {
const actual = await vi.importActual('ink');
return {
Expand All @@ -18,15 +13,8 @@ vi.mock('ink', async () => {
});

describe('ApiKeyStep', () => {
const mockDisableNavigation = vi.fn();
const mockEnableNavigation = vi.fn();

beforeEach(() => {
vi.clearAllMocks();
(useStepperInput as any).mockReturnValue({
disableNavigation: mockDisableNavigation,
enableNavigation: mockEnableNavigation,
});
});

it('renders API key prompt for OpenAI', () => {
Expand Down
10 changes: 1 addition & 9 deletions ink/configurationWizard/ApiKeyStep.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Box, Text, useInput } from 'ink';
import { useStepperInput } from 'ink-stepper';
import React, { useEffect } from 'react';
import React from 'react';
import { BlinkingTextInput } from '../components/BlinkingTextInput';
import { emitToListeners } from '../emitters/listener';
import type { ModelProvider } from '../models/config';
Expand All @@ -13,13 +12,6 @@ export function ApiKeyStep(
onBack: () => void;
},
) {
const { disableNavigation, enableNavigation } = useStepperInput();

useEffect(() => {
disableNavigation();
return () => enableNavigation();
}, [disableNavigation, enableNavigation]);

useInput((input, key) => {
if (key.escape) {
onBack();
Expand Down
12 changes: 0 additions & 12 deletions ink/configurationWizard/ApiUrlStep.test.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { useInput } from 'ink';
import { useStepperInput } from 'ink-stepper';
import { render } from 'ink-testing-library';
import React from 'react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { ApiUrlStep } from './ApiUrlStep';

vi.mock('ink-stepper', () => ({
useStepperInput: vi.fn(),
}));

vi.mock('ink', async () => {
const actual = await vi.importActual('ink');
return {
Expand All @@ -18,15 +13,8 @@ vi.mock('ink', async () => {
});

describe('ApiUrlStep', () => {
const mockDisableNavigation = vi.fn();
const mockEnableNavigation = vi.fn();

beforeEach(() => {
vi.clearAllMocks();
(useStepperInput as any).mockReturnValue({
disableNavigation: mockDisableNavigation,
enableNavigation: mockEnableNavigation,
});
});

it('renders API URL prompt for Ollama', () => {
Expand Down
10 changes: 1 addition & 9 deletions ink/configurationWizard/ApiUrlStep.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Box, Text, useInput } from 'ink';
import { useStepperInput } from 'ink-stepper';
import React, { useEffect } from 'react';
import React from 'react';
import { BlinkingTextInput } from '../components/BlinkingTextInput';
import { emitToListeners } from '../emitters/listener';
import type { ModelProvider } from '../models/config';
Expand All @@ -13,13 +12,6 @@ export function ApiUrlStep(
onBack: () => void;
},
) {
const { disableNavigation, enableNavigation } = useStepperInput();

useEffect(() => {
disableNavigation();
return () => enableNavigation();
}, [disableNavigation, enableNavigation]);

useInput((input, key) => {
if (key.escape) {
onBack();
Expand Down
10 changes: 10 additions & 0 deletions ink/configurationWizard/ConfigurationWizard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,14 @@ describe('ConfigurationWizard', () => {

expect(emitToListeners).toHaveBeenCalledWith('ExitUI', undefined);
});

it('does not complete the wizard on <esc> (each step owns back-navigation)', () => {
const onComplete = vi.fn();
render(<ConfigurationWizard onComplete={onComplete} />);

const inputHandler = (useInput as any).mock.calls[0][0];
inputHandler('', { escape: true });

expect(onComplete).not.toHaveBeenCalled();
});
});
14 changes: 10 additions & 4 deletions ink/configurationWizard/ConfigurationWizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ export function ConfigurationWizard({ onComplete }: Props) {
}
}, [provider]);

// <esc> is owned per-step (back-navigation, or leaving a sub-mode); the wizard only binds
// global exit keys here. Handling <esc> at this level too would double-fire with the active
// step — Ink delivers input to every mounted useInput — and complete the wizard instead.
useInput((input, key) => {
if (key.ctrl && input === 'x') {
emitToListeners('ExitUI', undefined);
}
if (key.escape) {
onComplete();
}
});

const models = provider === 'Ollama' && ollamaModels.length > 0
Expand All @@ -53,12 +53,18 @@ export function ConfigurationWizard({ onComplete }: Props) {
? [...new Set([...ollamaModels, ...compactorModelsByProvider[provider]])]
: compactorModelsByProvider[provider];

// Every step owns its own keys: its input widget consumes <enter> and advances by calling
// goNext() from onConfirm, and each step binds <esc> itself. The Stepper's built-in
// bindings would double-handle <enter> on top of that, which is why every step used to
// switch them off via disableNavigation() for its whole lifetime. Saying keyboardNav={false}
// once states that directly, and leaves goNext() free of however the library happens to
// gate its own navigation — ink-stepper 0.2.3 extended that gate to programmatic calls.
Comment thread
dawsontoth marked this conversation as resolved.
return (
<Box flexDirection="column" padding={1} minHeight={10}>
<Stepper
onComplete={onComplete}
onCancel={curryEmitToListeners('ExitUI', undefined)}
keyboardNav={true}
keyboardNav={false}
renderProgress={StepperProgress}
>
<Step name="AI Provider">
Expand Down
12 changes: 0 additions & 12 deletions ink/configurationWizard/EnvironmentSettingsStep.test.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { useInput } from 'ink';
import { useStepperInput } from 'ink-stepper';
import { render } from 'ink-testing-library';
import React from 'react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { EnvironmentSettingsStep } from './EnvironmentSettingsStep';

vi.mock('ink-stepper', () => ({
useStepperInput: vi.fn(),
}));

vi.mock('ink', async () => {
const actual = await vi.importActual('ink');
return {
Expand All @@ -18,15 +13,8 @@ vi.mock('ink', async () => {
});

describe('EnvironmentSettingsStep', () => {
const mockDisableNavigation = vi.fn();
const mockEnableNavigation = vi.fn();

beforeEach(() => {
vi.clearAllMocks();
(useStepperInput as any).mockReturnValue({
disableNavigation: mockDisableNavigation,
enableNavigation: mockEnableNavigation,
});
});

it('renders settings options', () => {
Expand Down
10 changes: 1 addition & 9 deletions ink/configurationWizard/EnvironmentSettingsStep.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { MultiSelect } from '@inkjs/ui';
import { Box, Text, useInput } from 'ink';
import { useStepperInput } from 'ink-stepper';
import React, { useEffect } from 'react';
import React from 'react';
import { updateEnv } from '../../utils/files/updateEnv';

interface Props {
Expand Down Expand Up @@ -38,13 +37,6 @@ const SETTINGS = [
];

export function EnvironmentSettingsStep({ onConfirm, onBack }: Props) {
const { disableNavigation, enableNavigation } = useStepperInput();

useEffect(() => {
disableNavigation();
return () => enableNavigation();
}, [disableNavigation, enableNavigation]);

useInput((_input, key) => {
if (key.escape) {
onBack();
Expand Down
12 changes: 0 additions & 12 deletions ink/configurationWizard/ModelSelectionStep.test.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { useInput } from 'ink';
import { useStepperInput } from 'ink-stepper';
import { render } from 'ink-testing-library';
import React from 'react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { ModelSelectionStep } from './ModelSelectionStep';

vi.mock('ink-stepper', () => ({
useStepperInput: vi.fn(),
}));

vi.mock('ink', async () => {
const actual = await vi.importActual('ink');
return {
Expand All @@ -18,15 +13,8 @@ vi.mock('ink', async () => {
});

describe('ModelSelectionStep', () => {
const mockDisableNavigation = vi.fn();
const mockEnableNavigation = vi.fn();

beforeEach(() => {
vi.clearAllMocks();
(useStepperInput as any).mockReturnValue({
disableNavigation: mockDisableNavigation,
enableNavigation: mockEnableNavigation,
});
});

it('renders title and models', () => {
Expand Down
9 changes: 1 addition & 8 deletions ink/configurationWizard/ModelSelectionStep.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Select } from '@inkjs/ui';
import { Box, Text, useInput } from 'ink';
import { useStepperInput } from 'ink-stepper';
import React, { useEffect, useMemo, useState } from 'react';
import React, { useMemo, useState } from 'react';
import { BlinkingTextInput } from '../components/BlinkingTextInput';
import { emitToListeners } from '../emitters/listener';

Expand All @@ -18,14 +17,8 @@ export function ModelSelectionStep({
onConfirm: (model: string) => void;
onBack: () => void;
}) {
const { disableNavigation, enableNavigation } = useStepperInput();
const [isCustom, setIsCustom] = useState(false);

useEffect(() => {
disableNavigation();
return () => enableNavigation();
}, [isCustom, disableNavigation, enableNavigation]);

useInput((input, key) => {
if (key.escape) {
if (isCustom) {
Expand Down
21 changes: 0 additions & 21 deletions ink/configurationWizard/ProviderStep.test.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
import { useStepperInput } from 'ink-stepper';
import { render } from 'ink-testing-library';
import React from 'react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { ProviderStep } from './ProviderStep';

vi.mock('ink-stepper', () => ({
useStepperInput: vi.fn(),
}));

describe('ProviderStep', () => {
const mockDisableNavigation = vi.fn();
const mockEnableNavigation = vi.fn();

beforeEach(() => {
vi.clearAllMocks();
(useStepperInput as any).mockReturnValue({
disableNavigation: mockDisableNavigation,
enableNavigation: mockEnableNavigation,
});
});

it('renders provider selection message', () => {
Expand All @@ -26,13 +14,4 @@ describe('ProviderStep', () => {

expect(lastFrame()).toContain('What model provider would you like to use today?');
});

it('disables stepper navigation on mount and enables on unmount', () => {
const onConfirm = vi.fn();
const { unmount } = render(<ProviderStep onConfirm={onConfirm} />);

expect(mockDisableNavigation).toHaveBeenCalled();
unmount();
expect(mockEnableNavigation).toHaveBeenCalled();
});
});
9 changes: 1 addition & 8 deletions ink/configurationWizard/ProviderStep.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Select } from '@inkjs/ui';
import { Box, Text, useInput } from 'ink';
import { useStepperInput } from 'ink-stepper';
import React, { useEffect, useMemo } from 'react';
import React, { useMemo } from 'react';
import type { ModelProvider } from '../models/config';
import { providers } from './providers';

Expand All @@ -12,7 +11,6 @@ export function ProviderStep(
onExit: () => void;
},
) {
const { disableNavigation, enableNavigation } = useStepperInput();
const sortedProviders = useMemo(
() =>
[...providers].sort((a, b) => {
Expand All @@ -23,11 +21,6 @@ export function ProviderStep(
[defaultValue],
);

useEffect(() => {
disableNavigation();
return () => enableNavigation();
}, [disableNavigation, enableNavigation]);

useInput((input, key) => {
if (key.escape) {
onExit();
Expand Down