From 1aa2c5ec78f0a4ac09cc4f07fa7d72fed278fd88 Mon Sep 17 00:00:00 2001 From: Julien Capellari Date: Fri, 24 Nov 2023 17:16:48 +0100 Subject: [PATCH] fix: handle no raw mode --- src/ui/task-tree-full-spinner.tsx | 32 ++++++++++++ src/ui/task-tree-scrollable-spinner.tsx | 65 +++++++++++++++++++++++++ src/ui/task-tree-spinner.tsx | 54 ++++---------------- tests/commands/each.test.tsx | 4 +- 4 files changed, 109 insertions(+), 46 deletions(-) create mode 100644 src/ui/task-tree-full-spinner.tsx create mode 100644 src/ui/task-tree-scrollable-spinner.tsx diff --git a/src/ui/task-tree-full-spinner.tsx b/src/ui/task-tree-full-spinner.tsx new file mode 100644 index 000000000..67ae26c1e --- /dev/null +++ b/src/ui/task-tree-full-spinner.tsx @@ -0,0 +1,32 @@ +import { TaskManager } from '@jujulego/tasks'; +import { Box, Text } from 'ink'; + +import { useFlatTaskTree } from '@/src/ui/hooks/useFlatTaskTree.ts'; +import TaskSpinner from '@/src/ui/task-spinner.tsx'; +import TaskTreeStats from '@/src/ui/task-tree-stats.tsx'; + +// Types +export interface TaskTreeFullSpinnerProps { + readonly manager: TaskManager; +} + +// Component +export default function TaskTreeFullSpinner({ manager }: TaskTreeFullSpinnerProps) { + const flat = useFlatTaskTree(manager); + + // Render + return ( + <> + + { flat.map(({ task, level }) => ( + + + + )) } + + + + + + ); +} diff --git a/src/ui/task-tree-scrollable-spinner.tsx b/src/ui/task-tree-scrollable-spinner.tsx new file mode 100644 index 000000000..f7a9a3cc8 --- /dev/null +++ b/src/ui/task-tree-scrollable-spinner.tsx @@ -0,0 +1,65 @@ +import { TaskManager } from '@jujulego/tasks'; +import { Box, Text, useInput } from 'ink'; +import { useEffect, useMemo, useState } from 'react'; + +import { useStdoutDimensions } from '@/src/ui/hooks/useStdoutDimensions.ts'; +import { useFlatTaskTree } from '@/src/ui/hooks/useFlatTaskTree.ts'; +import TaskSpinner from '@/src/ui/task-spinner.tsx'; +import TaskTreeStats from '@/src/ui/task-tree-stats.tsx'; + +// Types +export interface TaskTreeScrollableSpinnerProps { + readonly manager: TaskManager; +} + +// Component +export default function TaskTreeScrollableSpinner({ manager }: TaskTreeScrollableSpinnerProps) { + const { rows: termHeight } = useStdoutDimensions(); + + // Extract all tasks + const flat = useFlatTaskTree(manager); + + const maxHeight = useMemo( + () => Math.min(termHeight - 4, flat.length), + [termHeight, flat] + ); + + // Manage scroll + const [start, setStart] = useState(0); + + const slice = useMemo( + () => flat.slice(start, start + maxHeight), + [flat, start, maxHeight] + ); + + useEffect(() => { + if (start + maxHeight > flat.length) { + setStart(Math.max(flat.length - maxHeight, 0)); + } + }, [start, flat, maxHeight]); + + useInput((_, key) => { + if (key.upArrow) { + setStart((old) => Math.max(0, old - 1)); + } else if (key.downArrow) { + setStart((old) => Math.min(flat.length - maxHeight, old + 1)); + } + }); + + // Render + return ( + <> + + { slice.map(({ task, level }) => ( + + + + )) } + + + + { (maxHeight < flat.length) && ( - use keyboard arrows to scroll) } + + + ); +} diff --git a/src/ui/task-tree-spinner.tsx b/src/ui/task-tree-spinner.tsx index 3597f4ca4..b6f0ab260 100644 --- a/src/ui/task-tree-spinner.tsx +++ b/src/ui/task-tree-spinner.tsx @@ -1,11 +1,8 @@ import { TaskManager } from '@jujulego/tasks'; -import { Box, Text, useInput } from 'ink'; -import { useEffect, useMemo, useState } from 'react'; +import { useStdin } from 'ink'; -import { useStdoutDimensions } from '@/src/ui/hooks/useStdoutDimensions.ts'; -import { useFlatTaskTree } from '@/src/ui/hooks/useFlatTaskTree.ts'; -import TaskSpinner from '@/src/ui/task-spinner.tsx'; -import TaskTreeStats from '@/src/ui/task-tree-stats.tsx'; +import TaskTreeScrollableSpinner from '@/src/ui/task-tree-scrollable-spinner.tsx'; +import TaskTreeFullSpinner from '@/src/ui/task-tree-full-spinner.tsx'; // Types export interface TaskTreeSpinnerProps { @@ -14,44 +11,11 @@ export interface TaskTreeSpinnerProps { // Component export default function TaskTreeSpinner({ manager }: TaskTreeSpinnerProps) { - // Extract all tasks - const flat = useFlatTaskTree(manager); + const stdin = useStdin(); - // Manage scroll - const [start, setStart] = useState(0); - - const { rows: termHeight } = useStdoutDimensions(); - const maxHeight = useMemo(() => Math.min(termHeight - 4, flat.length), [termHeight, flat]); - const slice = useMemo(() => flat.slice(start, start + maxHeight), [flat, start, maxHeight]); - - useEffect(() => { - if (start + maxHeight > flat.length) { - setStart(Math.max(flat.length - maxHeight, 0)); - } - }, [start, flat, maxHeight]); - - useInput((_, key) => { - if (key.upArrow) { - setStart((old) => Math.max(0, old - 1)); - } else if (key.downArrow) { - setStart((old) => Math.min(flat.length - maxHeight, old + 1)); - } - }); - - // Render - return ( - <> - - { slice.map(({ task, level }) => ( - - - - )) } - - - - { (maxHeight < flat.length) && ( - use keyboard arrows to scroll) } - - - ); + if (stdin.isRawModeSupported) { + return ; + } else { + return ; + } } diff --git a/tests/commands/each.test.tsx b/tests/commands/each.test.tsx index 0b9220e0c..a3d59a409 100644 --- a/tests/commands/each.test.tsx +++ b/tests/commands/each.test.tsx @@ -59,7 +59,7 @@ afterEach(() => { // Tests describe('jill each', () => { - it('should run script in all workspaces having that script', async () => { + it.only('should run script in all workspaces having that script', async () => { context.reset({}); // Setup workspaces @@ -94,6 +94,8 @@ describe('jill each', () => { expect(manager.add).toHaveBeenCalledWith(tasks[0]); expect(manager.add).toHaveBeenCalledWith(tasks[1]); + await flushPromises(); + // should print task spinners expect(app.lastFrame()).toMatchLines([ expect.ignoreColor(/^. Run cmd in wks-1$/),