mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-07 07:55:13 +02:00
fix notion setup picker exit
This commit is contained in:
parent
496cc3a767
commit
affbba54d8
6 changed files with 40 additions and 3 deletions
|
|
@ -378,7 +378,7 @@ describe('renderNotionPickerTui', () => {
|
|||
},
|
||||
),
|
||||
).resolves.toEqual({ kind: 'quit' });
|
||||
expect(stderr).toContain('Use --no-input --root-page-id <UUID> for scripted mode');
|
||||
expect(stderr).toContain('Use --no-input --notion-root-page-id <UUID> for scripted mode');
|
||||
expect(stderr).not.toContain('secret');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ export async function renderNotionPickerTui(
|
|||
return result;
|
||||
} catch (error) {
|
||||
io.stderr.write(
|
||||
`Notion picker requires a TTY. Use --no-input --root-page-id <UUID> for scripted mode. ${sanitizeNotionPickerTuiError(error)}\n`,
|
||||
`Notion picker requires a TTY. Use --no-input --notion-root-page-id <UUID> for scripted mode. ${sanitizeNotionPickerTuiError(error)}\n`,
|
||||
);
|
||||
return { kind: 'quit' };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,11 @@ function makeTracker(ctrlCValues: boolean[]): SetupInterruptTracker {
|
|||
|
||||
describe('setup interrupt confirmation', () => {
|
||||
const originalIsTTY = process.stdin.isTTY;
|
||||
const originalRef = process.stdin.ref;
|
||||
|
||||
afterEach(() => {
|
||||
Object.defineProperty(process.stdin, 'isTTY', { configurable: true, value: originalIsTTY });
|
||||
Object.defineProperty(process.stdin, 'ref', { configurable: true, value: originalRef });
|
||||
});
|
||||
|
||||
it('fails before opening a prompt when interactive setup has no tty', async () => {
|
||||
|
|
@ -33,6 +35,26 @@ describe('setup interrupt confirmation', () => {
|
|||
expect(prompt).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('refs stdin before opening a real interactive prompt', async () => {
|
||||
const calls: string[] = [];
|
||||
Object.defineProperty(process.stdin, 'isTTY', { configurable: true, value: true });
|
||||
Object.defineProperty(process.stdin, 'ref', {
|
||||
configurable: true,
|
||||
value: vi.fn(() => {
|
||||
calls.push('ref');
|
||||
return process.stdin;
|
||||
}),
|
||||
});
|
||||
const prompt = vi.fn(async () => {
|
||||
calls.push('prompt');
|
||||
return 'continued';
|
||||
});
|
||||
|
||||
await expect(withSetupInterruptConfirmation(prompt)).resolves.toBe('continued');
|
||||
|
||||
expect(calls).toEqual(['ref', 'prompt']);
|
||||
});
|
||||
|
||||
it('asks before exiting on Ctrl+C and reruns the active prompt when declined', async () => {
|
||||
const prompt = vi.fn(async () => (prompt.mock.calls.length === 1 ? CANCEL : 'continued'));
|
||||
const confirmExit = vi.fn(async () => false);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ interface SetupInterruptOptions {
|
|||
const NON_INTERACTIVE_SETUP_MESSAGE =
|
||||
'Interactive setup requires a terminal. Re-run this command in a TTY, or pass --no-input with the required options.';
|
||||
|
||||
function refSetupInput(input: NodeJS.ReadStream = stdin): void {
|
||||
input.ref?.();
|
||||
}
|
||||
|
||||
function createSetupInterruptTracker(input: NodeJS.ReadStream = stdin): SetupInterruptTracker {
|
||||
let ctrlCPressed = false;
|
||||
const onKeypress = (char: string | undefined, key: Key) => {
|
||||
|
|
@ -73,6 +77,9 @@ export async function withSetupInterruptConfirmation<T>(
|
|||
const confirmExit = options.confirmExit ?? defaultConfirmExit;
|
||||
|
||||
while (true) {
|
||||
if (!options.tracker) {
|
||||
refSetupInput();
|
||||
}
|
||||
const value = await tracker.track(prompt);
|
||||
if (!isCancel(value)) {
|
||||
return value;
|
||||
|
|
|
|||
|
|
@ -311,6 +311,14 @@ describe('setup sources step', () => {
|
|||
).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['notion-main'] });
|
||||
|
||||
expect(pickNotionRootPages).toHaveBeenCalledOnce();
|
||||
expect(testPrompts.select).toHaveBeenCalledWith({
|
||||
message: 'Which Notion pages should KTX ingest?',
|
||||
options: [
|
||||
{ value: 'selected_roots', label: 'Specific pages and their subpages (choose them in a picker)' },
|
||||
{ value: 'all_accessible', label: 'All pages the integration can access' },
|
||||
{ value: 'back', label: 'Back' },
|
||||
],
|
||||
});
|
||||
expect((await readConfig()).connections['notion-main']).toMatchObject({
|
||||
driver: 'notion',
|
||||
auth_token_ref: 'env:NOTION_TOKEN',
|
||||
|
|
|
|||
|
|
@ -1270,7 +1270,7 @@ async function promptForInteractiveSource(
|
|||
const crawlMode = await prompts.select({
|
||||
message: 'Which Notion pages should KTX ingest?',
|
||||
options: [
|
||||
{ value: 'selected_roots', label: 'Specific pages and their subpages (you\'ll paste page IDs)' },
|
||||
{ value: 'selected_roots', label: 'Specific pages and their subpages (choose them in a picker)' },
|
||||
{ value: 'all_accessible', label: 'All pages the integration can access' },
|
||||
{ value: 'back', label: 'Back' },
|
||||
],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue