Hide collapsed Todo tray when they're all done. (#12242)

This commit is contained in:
Tommaso Sciortino
2025-10-29 13:41:20 -07:00
committed by GitHub
parent 3e9701861e
commit 121732dde6
3 changed files with 103 additions and 75 deletions

View File

@@ -30,36 +30,30 @@ const createTodoHistoryItem = (todos: Todo[]): HistoryItem =>
],
}) as unknown as HistoryItem;
describe('<TodoTray />', () => {
const renderWithUiState = (uiState: Partial<UIState>) =>
render(
<UIStateContext.Provider value={uiState as UIState}>
<TodoTray />
</UIStateContext.Provider>,
);
describe.each([true, false])(
'<TodoTray /> (showFullTodos: %s)',
(showFullTodos: boolean) => {
const renderWithUiState = (uiState: Partial<UIState>) =>
render(
<UIStateContext.Provider value={uiState as UIState}>
<TodoTray />
</UIStateContext.Provider>,
);
it.each([true, false])(
'renders null when no todos are in the history',
(showFullTodos) => {
it('renders null when no todos are in the history', () => {
const { lastFrame } = renderWithUiState({ history: [], showFullTodos });
expect(lastFrame()).toMatchSnapshot();
},
);
});
it.each([true, false])(
'renders null when todo list is empty',
(showFullTodos) => {
it('renders null when todo list is empty', () => {
const { lastFrame } = renderWithUiState({
history: [createTodoHistoryItem([])],
showFullTodos,
});
expect(lastFrame()).toMatchSnapshot();
},
);
});
it.each([true, false])(
'renders when todos exist but none are in progress',
(showFullTodos) => {
it('renders when todos exist but none are in progress', () => {
const { lastFrame } = renderWithUiState({
history: [
createTodoHistoryItem([
@@ -71,12 +65,9 @@ describe('<TodoTray />', () => {
showFullTodos,
});
expect(lastFrame()).toMatchSnapshot();
},
);
});
it.each([true, false])(
'renders when todos exist and one is in progress',
(showFullTodos) => {
it('renders when todos exist and one is in progress', () => {
const { lastFrame } = renderWithUiState({
history: [
createTodoHistoryItem([
@@ -89,12 +80,9 @@ describe('<TodoTray />', () => {
showFullTodos,
});
expect(lastFrame()).toMatchSnapshot();
},
);
});
it.each([true, false])(
'renders a todo list with long descriptions that wrap when full view is on',
(showFullTodos) => {
it('renders a todo list with long descriptions that wrap when full view is on', () => {
const { lastFrame } = render(
<Box width="50">
<UIStateContext.Provider
@@ -123,23 +111,36 @@ describe('<TodoTray />', () => {
</Box>,
);
expect(lastFrame()).toMatchSnapshot();
},
);
it('renders the most recent todo list when multiple write_todos calls are in history', () => {
const { lastFrame } = renderWithUiState({
history: [
createTodoHistoryItem([
{ description: 'Older Task 1', status: 'completed' },
{ description: 'Older Task 2', status: 'pending' },
]),
createTodoHistoryItem([
{ description: 'Newer Task 1', status: 'pending' },
{ description: 'Newer Task 2', status: 'in_progress' },
]),
],
showFullTodos: true,
});
expect(lastFrame()).toMatchSnapshot();
});
});
it('renders the most recent todo list when multiple write_todos calls are in history', () => {
const { lastFrame } = renderWithUiState({
history: [
createTodoHistoryItem([
{ description: 'Older Task 1', status: 'completed' },
{ description: 'Older Task 2', status: 'pending' },
]),
createTodoHistoryItem([
{ description: 'Newer Task 1', status: 'pending' },
{ description: 'Newer Task 2', status: 'in_progress' },
]),
],
showFullTodos,
});
expect(lastFrame()).toMatchSnapshot();
});
it('renders full list when all todos are inactive', () => {
const { lastFrame } = renderWithUiState({
history: [
createTodoHistoryItem([
{ description: 'Task 1', status: 'completed' },
{ description: 'Task 2', status: 'cancelled' },
]),
],
showFullTodos,
});
expect(lastFrame()).toMatchSnapshot();
});
},
);

View File

@@ -117,7 +117,19 @@ export const TodoTray: React.FC = () => {
return todos.todos.find((todo) => todo.status === 'in_progress') || null;
}, [todos]);
if (todos === null || !todos.todos || todos.todos.length === 0) {
const hasActiveTodos = useMemo(() => {
if (!todos || !todos.todos) return false;
return todos.todos.some(
(todo) => todo.status === 'pending' || todo.status === 'in_progress',
);
}, [todos]);
if (
todos === null ||
!todos.todos ||
todos.todos.length === 0 ||
(!uiState.showFullTodos && !hasActiveTodos)
) {
return null;
}
@@ -134,7 +146,7 @@ export const TodoTray: React.FC = () => {
{uiState.showFullTodos ? (
<Box flexDirection="column" rowGap={1}>
<TodoTitleDisplay todos={todos} />
<TodoListDisplay todos={todos!} />
<TodoListDisplay todos={todos} />
</Box>
) : (
<Box flexDirection="row" columnGap={1} height={1}>
@@ -143,7 +155,7 @@ export const TodoTray: React.FC = () => {
</Box>
{inProgress && (
<Box flexShrink={1} flexGrow={1}>
<TodoItemDisplay todo={inProgress!} wrap="truncate" />
<TodoItemDisplay todo={inProgress} wrap="truncate" />
</Box>
)}
</Box>

View File

@@ -1,6 +1,32 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`<TodoTray /> > renders a todo list with long descriptions that wrap when full view is on 1`] = `
exports[`<TodoTray /> (showFullTodos: false) > renders a todo list with long descriptions that wrap when full view is on 1`] = `
"──────────────────────────────────────────────────
Todo 1/2 (ctrl+t to toggle) » This is a very l…"
`;
exports[`<TodoTray /> (showFullTodos: false) > renders full list when all todos are inactive 1`] = `""`;
exports[`<TodoTray /> (showFullTodos: false) > renders null when no todos are in the history 1`] = `""`;
exports[`<TodoTray /> (showFullTodos: false) > renders null when todo list is empty 1`] = `""`;
exports[`<TodoTray /> (showFullTodos: false) > renders the most recent todo list when multiple write_todos calls are in history 1`] = `
"────────────────────────────────────────────────────────────────────────────────────────────────────
Todo 0/2 (ctrl+t to toggle) » Newer Task 2"
`;
exports[`<TodoTray /> (showFullTodos: false) > renders when todos exist and one is in progress 1`] = `
"────────────────────────────────────────────────────────────────────────────────────────────────────
Todo 1/3 (ctrl+t to toggle) » Task 2"
`;
exports[`<TodoTray /> (showFullTodos: false) > renders when todos exist but none are in progress 1`] = `
"────────────────────────────────────────────────────────────────────────────────────────────────────
Todo 1/2 (ctrl+t to toggle)"
`;
exports[`<TodoTray /> (showFullTodos: true) > renders a todo list with long descriptions that wrap when full view is on 1`] = `
"──────────────────────────────────────────────────
Todo 1/2 (ctrl+t to toggle)
@@ -11,20 +37,19 @@ exports[`<TodoTray /> > renders a todo list with long descriptions that wrap whe
description to test wrapping behavior."
`;
exports[`<TodoTray /> > renders a todo list with long descriptions that wrap when full view is on 2`] = `
"──────────────────────────────────────────────────
Todo 1/2 (ctrl+t to toggle) » This is a very l…"
exports[`<TodoTray /> (showFullTodos: true) > renders full list when all todos are inactive 1`] = `
"────────────────────────────────────────────────────────────────────────────────────────────────────
Todo 1/1 (ctrl+t to toggle)
✓ Task 1
✗ Task 2"
`;
exports[`<TodoTray /> > renders null when no todos are in the history 1`] = `""`;
exports[`<TodoTray /> (showFullTodos: true) > renders null when no todos are in the history 1`] = `""`;
exports[`<TodoTray /> > renders null when no todos are in the history 2`] = `""`;
exports[`<TodoTray /> (showFullTodos: true) > renders null when todo list is empty 1`] = `""`;
exports[`<TodoTray /> > renders null when todo list is empty 1`] = `""`;
exports[`<TodoTray /> > renders null when todo list is empty 2`] = `""`;
exports[`<TodoTray /> > renders the most recent todo list when multiple write_todos calls are in history 1`] = `
exports[`<TodoTray /> (showFullTodos: true) > renders the most recent todo list when multiple write_todos calls are in history 1`] = `
"────────────────────────────────────────────────────────────────────────────────────────────────────
Todo 0/2 (ctrl+t to toggle)
@@ -32,7 +57,7 @@ exports[`<TodoTray /> > renders the most recent todo list when multiple write_to
» Newer Task 2"
`;
exports[`<TodoTray /> > renders when todos exist and one is in progress 1`] = `
exports[`<TodoTray /> (showFullTodos: true) > renders when todos exist and one is in progress 1`] = `
"────────────────────────────────────────────────────────────────────────────────────────────────────
Todo 1/3 (ctrl+t to toggle)
@@ -42,12 +67,7 @@ exports[`<TodoTray /> > renders when todos exist and one is in progress 1`] = `
✓ Completed Task"
`;
exports[`<TodoTray /> > renders when todos exist and one is in progress 2`] = `
"────────────────────────────────────────────────────────────────────────────────────────────────────
Todo 1/3 (ctrl+t to toggle) » Task 2"
`;
exports[`<TodoTray /> > renders when todos exist but none are in progress 1`] = `
exports[`<TodoTray /> (showFullTodos: true) > renders when todos exist but none are in progress 1`] = `
"────────────────────────────────────────────────────────────────────────────────────────────────────
Todo 1/2 (ctrl+t to toggle)
@@ -55,8 +75,3 @@ exports[`<TodoTray /> > renders when todos exist but none are in progress 1`] =
✗ In Progress Task
✓ Completed Task"
`;
exports[`<TodoTray /> > renders when todos exist but none are in progress 2`] = `
"────────────────────────────────────────────────────────────────────────────────────────────────────
Todo 1/2 (ctrl+t to toggle)"
`;