mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-17 17:41:24 -07:00
feat(tracker): polish UI sorting and formatting (#22437)
This commit is contained in:
@@ -22,7 +22,6 @@ export const TASK_TYPE_LABELS: Record<TaskType, string> = {
|
||||
export enum TaskStatus {
|
||||
OPEN = 'open',
|
||||
IN_PROGRESS = 'in_progress',
|
||||
BLOCKED = 'blocked',
|
||||
CLOSED = 'closed',
|
||||
}
|
||||
export const TaskStatusSchema = z.nativeEnum(TaskStatus);
|
||||
|
||||
@@ -186,20 +186,55 @@ describe('Tracker Tools Integration', () => {
|
||||
|
||||
expect(display.todos).toEqual([
|
||||
{
|
||||
description: `[p1] [TASK] Parent`,
|
||||
description: `task: Parent (p1)`,
|
||||
status: 'in_progress',
|
||||
},
|
||||
{
|
||||
description: ` [c1] [EPIC] Child`,
|
||||
description: ` epic: Child (c1)`,
|
||||
status: 'pending',
|
||||
},
|
||||
{
|
||||
description: ` [leaf] [BUG] Closed Leaf`,
|
||||
description: ` bug: Closed Leaf (leaf)`,
|
||||
status: 'completed',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('sorts tasks by status', async () => {
|
||||
const t1 = {
|
||||
id: 't1',
|
||||
title: 'T1',
|
||||
type: TaskType.TASK,
|
||||
status: TaskStatus.CLOSED,
|
||||
dependencies: [],
|
||||
};
|
||||
const t2 = {
|
||||
id: 't2',
|
||||
title: 'T2',
|
||||
type: TaskType.TASK,
|
||||
status: TaskStatus.OPEN,
|
||||
dependencies: [],
|
||||
};
|
||||
const t3 = {
|
||||
id: 't3',
|
||||
title: 'T3',
|
||||
type: TaskType.TASK,
|
||||
status: TaskStatus.IN_PROGRESS,
|
||||
dependencies: [],
|
||||
};
|
||||
|
||||
const mockService = {
|
||||
listTasks: async () => [t1, t2, t3],
|
||||
} as unknown as TrackerService;
|
||||
const display = await buildTodosReturnDisplay(mockService);
|
||||
|
||||
expect(display.todos).toEqual([
|
||||
{ description: `task: T3 (t3)`, status: 'in_progress' },
|
||||
{ description: `task: T2 (t2)`, status: 'pending' },
|
||||
{ description: `task: T1 (t1)`, status: 'completed' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('detects cycles', async () => {
|
||||
// Since TrackerTask only has a single parentId, a true cycle is unreachable from roots.
|
||||
// We simulate a database corruption (two tasks with same ID, one root, one child)
|
||||
@@ -220,7 +255,7 @@ describe('Tracker Tools Integration', () => {
|
||||
|
||||
expect(display.todos).toEqual([
|
||||
{
|
||||
description: `[p1] [TASK] Parent`,
|
||||
description: `task: Parent (p1)`,
|
||||
status: 'pending',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
TRACKER_UPDATE_TASK_TOOL_NAME,
|
||||
TRACKER_VISUALIZE_TOOL_NAME,
|
||||
} from './tool-names.js';
|
||||
import type { ToolResult, TodoList } from './tools.js';
|
||||
import type { ToolResult, TodoList, TodoStatus } from './tools.js';
|
||||
import { BaseDeclarativeTool, BaseToolInvocation, Kind } from './tools.js';
|
||||
import { ToolErrorType } from './tool-error.js';
|
||||
import type { TrackerTask, TaskType } from '../services/trackerTypes.js';
|
||||
@@ -48,6 +48,21 @@ export async function buildTodosReturnDisplay(
|
||||
}
|
||||
}
|
||||
|
||||
const statusOrder = {
|
||||
[TaskStatus.IN_PROGRESS]: 0,
|
||||
[TaskStatus.OPEN]: 1,
|
||||
[TaskStatus.CLOSED]: 2,
|
||||
};
|
||||
|
||||
const sortTasks = (a: TrackerTask, b: TrackerTask) => {
|
||||
if (statusOrder[a.status] !== statusOrder[b.status]) {
|
||||
return statusOrder[a.status] - statusOrder[b.status];
|
||||
}
|
||||
return a.id.localeCompare(b.id);
|
||||
};
|
||||
|
||||
roots.sort(sortTasks);
|
||||
|
||||
const todos: TodoList['todos'] = [];
|
||||
|
||||
const addTask = (task: TrackerTask, depth: number, visited: Set<string>) => {
|
||||
@@ -60,8 +75,7 @@ export async function buildTodosReturnDisplay(
|
||||
}
|
||||
visited.add(task.id);
|
||||
|
||||
let status: 'pending' | 'in_progress' | 'completed' | 'cancelled' =
|
||||
'pending';
|
||||
let status: TodoStatus = 'pending';
|
||||
if (task.status === TaskStatus.IN_PROGRESS) {
|
||||
status = 'in_progress';
|
||||
} else if (task.status === TaskStatus.CLOSED) {
|
||||
@@ -69,11 +83,12 @@ export async function buildTodosReturnDisplay(
|
||||
}
|
||||
|
||||
const indent = ' '.repeat(depth);
|
||||
const description = `${indent}[${task.id}] ${TASK_TYPE_LABELS[task.type]} ${task.title}`;
|
||||
const description = `${indent}${task.type}: ${task.title} (${task.id})`;
|
||||
|
||||
todos.push({ description, status });
|
||||
|
||||
const children = childrenMap.get(task.id) ?? [];
|
||||
children.sort(sortTasks);
|
||||
for (const child of children) {
|
||||
addTask(child, depth + 1, visited);
|
||||
}
|
||||
@@ -570,7 +585,6 @@ class TrackerVisualizeInvocation extends BaseToolInvocation<
|
||||
const statusEmojis: Record<TaskStatus, string> = {
|
||||
open: '⭕',
|
||||
in_progress: '🚧',
|
||||
blocked: '🚫',
|
||||
closed: '✅',
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user