diff --git a/apps/extension/src/components/TaskDetails/useTaskDetails.ts b/apps/extension/src/components/TaskDetails/useTaskDetails.ts
index 71165ea9..9aaf49a4 100644
--- a/apps/extension/src/components/TaskDetails/useTaskDetails.ts
+++ b/apps/extension/src/components/TaskDetails/useTaskDetails.ts
@@ -47,47 +47,93 @@ export const useTaskDetails = ({
// Find the current task
useEffect(() => {
- console.log('🔍 TaskDetailsView: Looking for task:', taskId);
- console.log('🔍 TaskDetailsView: Available tasks:', tasks);
-
const { isSubtask: isSub, parentId, subtaskIndex } = parseTaskId(taskId);
if (isSub) {
const parent = tasks.find((t) => t.id === parentId);
if (parent && parent.subtasks && parent.subtasks[subtaskIndex]) {
const subtask = parent.subtasks[subtaskIndex];
- console.log('✅ TaskDetailsView: Found subtask:', subtask);
setCurrentTask(subtask);
setParentTask(parent);
- // Use subtask's own details and testStrategy
- setTaskFileData({
- details: subtask.details || '',
- testStrategy: subtask.testStrategy || ''
- });
} else {
- console.error('❌ TaskDetailsView: Subtask not found');
setCurrentTask(null);
setParentTask(null);
}
} else {
const task = tasks.find((t) => t.id === taskId);
if (task) {
- console.log('✅ TaskDetailsView: Found task:', task);
setCurrentTask(task);
setParentTask(null);
- // Use task's own details and testStrategy
- setTaskFileData({
- details: task.details || '',
- testStrategy: task.testStrategy || ''
- });
} else {
- console.error('❌ TaskDetailsView: Task not found');
setCurrentTask(null);
setParentTask(null);
}
}
}, [taskId, tasks]);
+ // Fetch full task details including details and testStrategy
+ useEffect(() => {
+ const fetchTaskDetails = async () => {
+ if (!currentTask) return;
+
+ try {
+ // Use the parent task ID for MCP call since get_task returns parent with subtasks
+ const taskIdToFetch =
+ isSubtask && parentTask ? parentTask.id : currentTask.id;
+
+ const result = await sendMessage({
+ type: 'mcpRequest',
+ tool: 'get_task',
+ params: {
+ id: taskIdToFetch
+ }
+ });
+
+ // Parse the MCP response - it comes as content[0].text JSON string
+ let fullTaskData = null;
+ if (result?.data?.content?.[0]?.text) {
+ try {
+ const parsed = JSON.parse(result.data.content[0].text);
+ fullTaskData = parsed.data;
+ } catch (e) {
+ console.error('Failed to parse MCP response:', e);
+ }
+ } else if (result?.data?.data) {
+ // Fallback if response structure is different
+ fullTaskData = result.data.data;
+ }
+
+ if (fullTaskData) {
+ if (isSubtask && fullTaskData.subtasks) {
+ // Find the specific subtask
+ const subtaskData = fullTaskData.subtasks.find(
+ (st: any) =>
+ st.id === currentTask.id ||
+ st.id === parseInt(currentTask.id as any)
+ );
+ if (subtaskData) {
+ setTaskFileData({
+ details: subtaskData.details || '',
+ testStrategy: subtaskData.testStrategy || ''
+ });
+ }
+ } else {
+ // Use the main task data
+ setTaskFileData({
+ details: fullTaskData.details || '',
+ testStrategy: fullTaskData.testStrategy || ''
+ });
+ }
+ }
+ } catch (error) {
+ console.error('❌ Failed to fetch task details:', error);
+ setTaskFileDataError('Failed to load task details');
+ }
+ };
+
+ fetchTaskDetails();
+ }, [currentTask, isSubtask, parentTask, sendMessage]);
+
// Fetch complexity score
const fetchComplexity = useCallback(async () => {
if (!currentTask) return;
diff --git a/apps/extension/src/components/TaskDetailsView.original.tsx b/apps/extension/src/components/TaskDetailsView.original.tsx
deleted file mode 100644
index bf84ce19..00000000
--- a/apps/extension/src/components/TaskDetailsView.original.tsx
+++ /dev/null
@@ -1,1304 +0,0 @@
-import { Badge } from '@/components/ui/badge';
-import {
- Breadcrumb,
- BreadcrumbItem,
- BreadcrumbLink,
- BreadcrumbList,
- BreadcrumbSeparator
-} from '@/components/ui/breadcrumb';
-import { Button } from '@/components/ui/button';
-import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
-import {
- Collapsible,
- CollapsibleContent,
- CollapsibleTrigger
-} from '@/components/ui/collapsible';
-import { Label } from '@/components/ui/label';
-import { Separator } from '@/components/ui/separator';
-import { Textarea } from '@/components/ui/textarea';
-import {
- ChevronDown,
- ChevronRight,
- Loader2,
- Plus,
- PlusCircle,
- Wand2
-} from 'lucide-react';
-import type React from 'react';
-import { useCallback, useContext, useEffect, useState } from 'react';
-import { VSCodeContext } from '../webview/contexts/VSCodeContext';
-import type { TaskMasterTask } from '../webview/types';
-
-interface TaskDetailsViewProps {
- taskId: string;
- onNavigateBack: () => void;
- onNavigateToTask: (taskId: string) => void;
-}
-
-// Markdown renderer component to handle code blocks
-const MarkdownRenderer: React.FC<{ content: string; className?: string }> = ({
- content,
- className = ''
-}) => {
- // Parse content to separate code blocks from regular text
- const parseMarkdown = (text: string) => {
- const parts = [];
- const lines = text.split('\n');
- let currentBlock = [];
- let inCodeBlock = false;
- let codeLanguage = '';
-
- for (let i = 0; i < lines.length; i++) {
- const line = lines[i];
-
- if (line.startsWith('```')) {
- if (inCodeBlock) {
- // End of code block
- if (currentBlock.length > 0) {
- parts.push({
- type: 'code',
- content: currentBlock.join('\n'),
- language: codeLanguage
- });
- currentBlock = [];
- }
- inCodeBlock = false;
- codeLanguage = '';
- } else {
- // Start of code block
- if (currentBlock.length > 0) {
- parts.push({
- type: 'text',
- content: currentBlock.join('\n')
- });
- currentBlock = [];
- }
- inCodeBlock = true;
- codeLanguage = line.substring(3).trim(); // Get language after ```
- }
- } else {
- currentBlock.push(line);
- }
- }
-
- // Handle remaining content
- if (currentBlock.length > 0) {
- parts.push({
- type: inCodeBlock ? 'code' : 'text',
- content: currentBlock.join('\n'),
- language: codeLanguage
- });
- }
-
- return parts;
- };
-
- const parts = parseMarkdown(content);
-
- return (
-
- {parts.map((part, index) => {
- if (part.type === 'code') {
- return (
-
- {part.content}
-
- );
- } else {
- // Handle inline code (single backticks) in text blocks
- const textWithInlineCode = part.content
- .split(/(`[^`]+`)/g)
- .map((segment, segIndex) => {
- if (segment.startsWith('`') && segment.endsWith('`')) {
- const codeContent = segment.slice(1, -1);
- return (
-
- {codeContent}
-
- );
- }
- return segment;
- });
-
- return (
-
- {textWithInlineCode}
-
- );
- }
- })}
-
- );
-};
-
-// Custom Priority Badge Component with theme-adaptive styling
-const PriorityBadge: React.FC<{ priority: TaskMasterTask['priority'] }> = ({
- priority
-}) => {
- const getPriorityColors = (priority: string) => {
- switch (priority) {
- case 'high':
- return {
- backgroundColor: 'rgba(239, 68, 68, 0.2)', // red-500 with opacity
- color: '#dc2626', // red-600 - works in both themes
- borderColor: 'rgba(239, 68, 68, 0.4)'
- };
- case 'medium':
- return {
- backgroundColor: 'rgba(245, 158, 11, 0.2)', // amber-500 with opacity
- color: '#d97706', // amber-600 - works in both themes
- borderColor: 'rgba(245, 158, 11, 0.4)'
- };
- case 'low':
- return {
- backgroundColor: 'rgba(34, 197, 94, 0.2)', // green-500 with opacity
- color: '#16a34a', // green-600 - works in both themes
- borderColor: 'rgba(34, 197, 94, 0.4)'
- };
- default:
- return {
- backgroundColor: 'rgba(156, 163, 175, 0.2)',
- color: 'var(--vscode-foreground)',
- borderColor: 'rgba(156, 163, 175, 0.4)'
- };
- }
- };
-
- const colors = getPriorityColors(priority);
-
- return (
-
- {priority}
-
- );
-};
-
-// Custom Status Badge Component with theme-adaptive styling
-const StatusBadge: React.FC<{ status: TaskMasterTask['status'] }> = ({
- status
-}) => {
- const getStatusColors = (status: string) => {
- // Use colors that work well in both light and dark themes
- switch (status) {
- case 'pending':
- return {
- backgroundColor: 'rgba(156, 163, 175, 0.2)', // gray-400 with opacity
- color: 'var(--vscode-foreground)',
- borderColor: 'rgba(156, 163, 175, 0.4)'
- };
- case 'in-progress':
- return {
- backgroundColor: 'rgba(245, 158, 11, 0.2)', // amber-500 with opacity
- color: '#d97706', // amber-600 - works in both themes
- borderColor: 'rgba(245, 158, 11, 0.4)'
- };
- case 'review':
- return {
- backgroundColor: 'rgba(59, 130, 246, 0.2)', // blue-500 with opacity
- color: '#2563eb', // blue-600 - works in both themes
- borderColor: 'rgba(59, 130, 246, 0.4)'
- };
- case 'done':
- return {
- backgroundColor: 'rgba(34, 197, 94, 0.2)', // green-500 with opacity
- color: '#16a34a', // green-600 - works in both themes
- borderColor: 'rgba(34, 197, 94, 0.4)'
- };
- case 'deferred':
- return {
- backgroundColor: 'rgba(239, 68, 68, 0.2)', // red-500 with opacity
- color: '#dc2626', // red-600 - works in both themes
- borderColor: 'rgba(239, 68, 68, 0.4)'
- };
- default:
- return {
- backgroundColor: 'rgba(156, 163, 175, 0.2)',
- color: 'var(--vscode-foreground)',
- borderColor: 'rgba(156, 163, 175, 0.4)'
- };
- }
- };
-
- const colors = getStatusColors(status);
-
- return (
-
- {status === 'pending' ? 'todo' : status}
-
- );
-};
-
-// Define the TaskFileData interface here since we're no longer importing it
-interface TaskFileData {
- details?: string;
- testStrategy?: string;
-}
-
-interface CombinedTaskData {
- details?: string;
- testStrategy?: string;
- complexityScore?: number; // Only from MCP API
-}
-
-export const TaskDetailsView: React.FC = ({
- taskId,
- onNavigateBack,
- onNavigateToTask
-}) => {
- const context = useContext(VSCodeContext);
- if (!context) {
- throw new Error('TaskDetailsView must be used within VSCodeContext');
- }
-
- const { state, sendMessage } = context;
- const { tasks } = state;
-
- const [currentTask, setCurrentTask] = useState(null);
- const [isSubtask, setIsSubtask] = useState(false);
- const [parentTask, setParentTask] = useState(null);
-
- // Collapsible section states
- const [isAiActionsExpanded, setIsAiActionsExpanded] = useState(true);
- const [isImplementationExpanded, setIsImplementationExpanded] =
- useState(false);
- const [isTestStrategyExpanded, setIsTestStrategyExpanded] = useState(false);
- const [isSubtasksExpanded, setIsSubtasksExpanded] = useState(true);
-
- // AI Actions states
- const [prompt, setPrompt] = useState('');
- const [isRegenerating, setIsRegenerating] = useState(false);
- const [isAppending, setIsAppending] = useState(false);
-
- // Add subtask states
- const [isAddingSubtask, setIsAddingSubtask] = useState(false);
- const [newSubtaskTitle, setNewSubtaskTitle] = useState('');
- const [newSubtaskDescription, setNewSubtaskDescription] = useState('');
- const [isSubmittingSubtask, setIsSubmittingSubtask] = useState(false);
-
- // Task file data states (for implementation details, test strategy, and complexity score)
- const [taskFileData, setTaskFileData] = useState({
- details: undefined,
- testStrategy: undefined,
- complexityScore: undefined
- });
- // Loading state removed as data comes directly from tasks
- const [taskFileDataError] = useState(null);
-
- // Get complexity score from main task data immediately (no flash)
- const currentComplexityScore = currentTask?.complexityScore;
-
- // State for complexity data from MCP (only used for updates)
- const [mcpComplexityScore, setMcpComplexityScore] = useState<
- number | undefined
- >(undefined);
- const [isLoadingComplexity, setIsLoadingComplexity] = useState(false);
-
- // Use MCP complexity if available, otherwise use main task data
- const displayComplexityScore =
- mcpComplexityScore !== undefined
- ? mcpComplexityScore
- : currentComplexityScore;
-
- // Fetch complexity from MCP when needed
- const fetchComplexityFromMCP = useCallback(
- async (force = false) => {
- if (!currentTask || (!force && currentComplexityScore !== undefined)) {
- return; // Don't fetch if we already have a score unless forced
- }
-
- setIsLoadingComplexity(true);
- try {
- const complexityResult = await sendMessage({
- type: 'mcpRequest',
- tool: 'complexity_report',
- params: {}
- });
-
- if (complexityResult?.data?.report?.complexityAnalysis) {
- const taskComplexity =
- complexityResult.data.report.complexityAnalysis.find(
- (analysis: any) => analysis.taskId === currentTask.id
- );
-
- if (taskComplexity?.complexityScore !== undefined) {
- setMcpComplexityScore(taskComplexity.complexityScore);
- }
- }
- } catch (error) {
- console.error('Failed to fetch complexity from MCP:', error);
- } finally {
- setIsLoadingComplexity(false);
- }
- },
- [currentTask, currentComplexityScore, sendMessage]
- );
-
- // Refresh complexity after AI operations or when task changes
- useEffect(() => {
- if (currentTask) {
- // Reset MCP complexity when task changes
- setMcpComplexityScore(undefined);
-
- // Fetch from MCP if no complexity score in main data
- if (currentComplexityScore === undefined) {
- fetchComplexityFromMCP();
- }
- }
- }, [currentTask?.id, currentComplexityScore, fetchComplexityFromMCP]);
-
- // Refresh complexity after AI operations
- const refreshComplexityAfterAI = useCallback(() => {
- // Force refresh complexity after AI operations
- setTimeout(() => {
- fetchComplexityFromMCP(true);
- }, 2000); // Wait for AI operation to complete
- }, [fetchComplexityFromMCP]);
-
- // Handle running complexity analysis for a task
- const handleRunComplexityAnalysis = useCallback(async () => {
- if (!currentTask) {
- return;
- }
-
- setIsLoadingComplexity(true);
- try {
- // Run complexity analysis on this specific task
- await sendMessage({
- type: 'mcpRequest',
- tool: 'analyze_project_complexity',
- params: {
- ids: currentTask.id.toString(),
- research: false
- }
- });
-
- // After analysis, fetch the updated complexity report
- setTimeout(() => {
- fetchComplexityFromMCP(true);
- }, 1000); // Wait for analysis to complete
- } catch (error) {
- console.error('Failed to run complexity analysis:', error);
- } finally {
- setIsLoadingComplexity(false);
- }
- }, [currentTask, sendMessage, fetchComplexityFromMCP]);
-
- // Parse task ID to determine if it's a subtask (e.g., "13.2")
- const parseTaskId = (id: string) => {
- const parts = id.split('.');
- if (parts.length === 2) {
- return {
- isSubtask: true,
- parentId: parts[0],
- subtaskIndex: parseInt(parts[1]) - 1 // Convert to 0-based index
- };
- }
- return {
- isSubtask: false,
- parentId: id,
- subtaskIndex: -1
- };
- };
-
- // Note: Task file data is now loaded directly from currentTask
- // The details, testStrategy, and complexityScore are already available in the task object
-
- // Find task or subtask by ID
- useEffect(() => {
- const {
- isSubtask: isSubtaskId,
- parentId,
- subtaskIndex
- } = parseTaskId(taskId);
- setIsSubtask(isSubtaskId);
-
- if (isSubtaskId) {
- // Find parent task
- const parent = tasks.find((task) => task.id === parentId);
- setParentTask(parent || null);
-
- // Find subtask
- if (
- parent &&
- parent.subtasks &&
- subtaskIndex >= 0 &&
- subtaskIndex < parent.subtasks.length
- ) {
- const subtask = parent.subtasks[subtaskIndex];
- setCurrentTask(subtask);
- // Set task file data from the subtask itself
- setTaskFileData({
- details: subtask.details || '',
- testStrategy: subtask.testStrategy || '',
- complexityScore: subtask.complexityScore
- });
- } else {
- setCurrentTask(null);
- }
- } else {
- // Find main task
- const task = tasks.find((task) => task.id === parentId);
- setCurrentTask(task || null);
- setParentTask(null);
- // Set task file data from the task itself
- if (task) {
- setTaskFileData({
- details: task.details || '',
- testStrategy: task.testStrategy || '',
- complexityScore: task.complexityScore
- });
- }
- }
- }, [taskId, tasks]);
-
- // Enhanced refresh logic for task file data when tasks are updated from polling
- useEffect(() => {
- if (currentTask) {
- // Update task file data from currentTask whenever it changes
- setTaskFileData({
- details: currentTask.details || '',
- testStrategy: currentTask.testStrategy || '',
- complexityScore: currentTask.complexityScore
- });
- }
- }, [currentTask, tasks, taskId]); // More comprehensive dependencies
-
- // Remove periodic refresh since we're using task data directly
- // The data will update when tasks update through the context
-
- // Handle AI Actions
- const handleRegenerate = async () => {
- if (!currentTask || !prompt.trim()) {
- return;
- }
-
- setIsRegenerating(true);
- try {
- if (isSubtask && parentTask) {
- await sendMessage({
- type: 'updateSubtask',
- data: {
- taskId: `${parentTask.id}.${currentTask.id}`,
- prompt: prompt,
- options: { research: false }
- }
- });
- } else {
- await sendMessage({
- type: 'updateTask',
- data: {
- taskId: currentTask.id,
- updates: { description: prompt },
- options: { append: false, research: false }
- }
- });
- }
-
- // Refresh both task file data and complexity after AI operation
- // Data will be refreshed automatically when tasks update
-
- // Refresh complexity after AI operation
- refreshComplexityAfterAI();
- } catch (error) {
- console.error('❌ TaskDetailsView: Failed to regenerate task:', error);
- } finally {
- setIsRegenerating(false);
- setPrompt('');
- }
- };
-
- const handleAppend = async () => {
- if (!currentTask || !prompt.trim()) {
- return;
- }
-
- setIsAppending(true);
- try {
- if (isSubtask && parentTask) {
- await sendMessage({
- type: 'updateSubtask',
- data: {
- taskId: `${parentTask.id}.${currentTask.id}`,
- prompt: prompt,
- options: { research: false }
- }
- });
- } else {
- await sendMessage({
- type: 'updateTask',
- data: {
- taskId: currentTask.id,
- updates: { description: prompt },
- options: { append: true, research: false }
- }
- });
- }
-
- // Refresh both task file data and complexity after AI operation
- // Data will be refreshed automatically when tasks update
-
- // Refresh complexity after AI operation
- refreshComplexityAfterAI();
- } catch (error) {
- console.error('❌ TaskDetailsView: Failed to append to task:', error);
- } finally {
- setIsAppending(false);
- setPrompt('');
- }
- };
-
- // Handle adding a new subtask
- const handleAddSubtask = async () => {
- if (!currentTask || !newSubtaskTitle.trim() || isSubtask) {
- return;
- }
-
- setIsSubmittingSubtask(true);
- try {
- await sendMessage({
- type: 'addSubtask',
- data: {
- parentTaskId: currentTask.id,
- subtaskData: {
- title: newSubtaskTitle.trim(),
- description: newSubtaskDescription.trim() || undefined,
- status: 'pending'
- }
- }
- });
-
- // Reset form and close
- setNewSubtaskTitle('');
- setNewSubtaskDescription('');
- setIsAddingSubtask(false);
-
- // Data will be refreshed automatically when tasks update
- } catch (error) {
- console.error('❌ TaskDetailsView: Failed to add subtask:', error);
- } finally {
- setIsSubmittingSubtask(false);
- }
- };
-
- const handleCancelAddSubtask = () => {
- setIsAddingSubtask(false);
- setNewSubtaskTitle('');
- setNewSubtaskDescription('');
- };
-
- // Handle dependency navigation
- const handleDependencyClick = (depId: string) => {
- onNavigateToTask(depId);
- };
-
- // Handle status change
- const handleStatusChange = async (newStatus: TaskMasterTask['status']) => {
- if (!currentTask) {
- return;
- }
-
- try {
- await sendMessage({
- type: 'updateTaskStatus',
- data: {
- taskId:
- isSubtask && parentTask
- ? `${parentTask.id}.${currentTask.id}`
- : currentTask.id,
- newStatus: newStatus
- }
- });
- } catch (error) {
- console.error('❌ TaskDetailsView: Failed to update task status:', error);
- }
- };
-
- if (!currentTask) {
- return (
-
-
-
- Task not found
-
-
-
-
- );
- }
-
- return (
-
- {/* Main content area with two-column layout */}
-
- {/* Left column - Main content (2/3 width) */}
-
- {/* Breadcrumb navigation */}
-
-
-
-
- Kanban Board
-
-
- {isSubtask && parentTask && (
- <>
-
-
- onNavigateToTask(parentTask.id)}
- className="cursor-pointer hover:text-vscode-foreground"
- >
- {parentTask.title}
-
-
- >
- )}
-
-
-
- {currentTask.title}
-
-
-
-
-
- {/* Task title */}
-
- {currentTask.title}
-
-
- {/* Description (non-editable) */}
-
-
- {currentTask.description || 'No description available.'}
-
-
-
- {/* AI Actions */}
-
-
-
-
-
- {isAiActionsExpanded && (
-
-
-
-
-
-
-
- {/* Show regenerate button only for main tasks, not subtasks */}
- {!isSubtask && (
-
- )}
-
-
-
-
-
- {isSubtask ? (
-
- Add Notes: Appends timestamped
- implementation notes, progress updates, or findings to
- this subtask's details
-
- ) : (
- <>
-
- Regenerate: Completely rewrites the
- task description and subtasks based on your prompt
-
-
- Append: Adds new content to the
- existing task description based on your prompt
-
- >
- )}
-
-
-
- )}
-
-
- {/* Implementation Details */}
-
-
-
-
-
- {isImplementationExpanded && (
-
-
- {taskFileDataError ? (
-
- Error loading details: {taskFileDataError}
-
- ) : taskFileData.details !== undefined &&
- taskFileData.details !== '' ? (
-
- ) : (
-
- No implementation details available
-
- )}
-
-
- )}
-
-
- {console.log(taskFileData)}
-
- {/* Test Strategy */}
-
-
-
-
-
- {isTestStrategyExpanded && (
-
-
- {taskFileDataError ? (
-
- Error loading strategy: {taskFileDataError}
-
- ) : taskFileData.testStrategy !== undefined &&
- taskFileData.testStrategy !== '' ? (
-
- ) : (
-
- No test strategy available
-
- )}
-
-
- )}
-
-
- {/* Subtasks section */}
- {((currentTask.subtasks && currentTask.subtasks.length > 0) ||
- !isSubtask) && (
-
-
-
- {currentTask.subtasks && currentTask.subtasks.length > 0 && (
-
- {
- currentTask.subtasks?.filter((st) => st.status === 'done')
- .length
- }
- /{currentTask.subtasks?.length}
-
- )}
- {/* Only show add button for main tasks, not subtasks */}
- {!isSubtask && (
-
- )}
-
-
- {isSubtasksExpanded && (
-
- {/* Add Subtask Form */}
- {isAddingSubtask && (
-
-
- Add New Subtask
-
-
-
-
- setNewSubtaskTitle(e.target.value)}
- className="w-full px-3 py-2 text-sm bg-vscode-input-background border border-vscode-input-border text-vscode-input-foreground placeholder-vscode-input-foreground/50 rounded focus:border-vscode-focusBorder focus:ring-1 focus:ring-vscode-focusBorder"
- disabled={isSubmittingSubtask}
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
- )}
-
- {currentTask.subtasks?.map((subtask, index) => {
- const subtaskId = `${currentTask.id}.${index + 1}`;
- const getStatusDotColor = (status: string) => {
- switch (status) {
- case 'pending':
- return '#9ca3af'; // gray-400
- case 'in-progress':
- return '#f59e0b'; // amber-500
- case 'review':
- return '#3b82f6'; // blue-500
- case 'done':
- return '#22c55e'; // green-500
- case 'deferred':
- return '#ef4444'; // red-500
- default:
- return '#9ca3af';
- }
- };
- const getSubtaskStatusColors = (status: string) => {
- switch (status) {
- case 'pending':
- return {
- backgroundColor: 'rgba(156, 163, 175, 0.2)',
- color: 'var(--vscode-foreground)',
- borderColor: 'rgba(156, 163, 175, 0.4)'
- };
- case 'in-progress':
- return {
- backgroundColor: 'rgba(245, 158, 11, 0.2)',
- color: '#d97706',
- borderColor: 'rgba(245, 158, 11, 0.4)'
- };
- case 'review':
- return {
- backgroundColor: 'rgba(59, 130, 246, 0.2)',
- color: '#2563eb',
- borderColor: 'rgba(59, 130, 246, 0.4)'
- };
- case 'done':
- return {
- backgroundColor: 'rgba(34, 197, 94, 0.2)',
- color: '#16a34a',
- borderColor: 'rgba(34, 197, 94, 0.4)'
- };
- case 'deferred':
- return {
- backgroundColor: 'rgba(239, 68, 68, 0.2)',
- color: '#dc2626',
- borderColor: 'rgba(239, 68, 68, 0.4)'
- };
- default:
- return {
- backgroundColor: 'rgba(156, 163, 175, 0.2)',
- color: 'var(--vscode-foreground)',
- borderColor: 'rgba(156, 163, 175, 0.4)'
- };
- }
- };
-
- return (
-
onNavigateToTask(subtaskId)}
- >
-
-
- {subtask.title}
-
-
- {subtask.status === 'pending'
- ? 'todo'
- : subtask.status}
-
-
- );
- })}
-
- )}
-
- )}
-
-
- {/* Right column - Properties sidebar (1/3 width) */}
-
-
-
-
-
- Properties
-
-
-
-
- {/* Status */}
-
-
- Status
-
-
-
-
- {/* Priority */}
-
-
- {/* Complexity Score */}
-
-
- {isLoadingComplexity ? (
-
-
-
- Loading...
-
-
- ) : displayComplexityScore !== undefined ? (
-
-
- {displayComplexityScore}/10
-
-
= 7
- ? 'bg-red-500/20'
- : displayComplexityScore >= 4
- ? 'bg-yellow-500/20'
- : 'bg-green-500/20'
- }`}
- >
-
= 7
- ? 'bg-red-500'
- : displayComplexityScore >= 4
- ? 'bg-yellow-500'
- : 'bg-green-500'
- }`}
- style={{
- width: `${(displayComplexityScore || 0) * 10}%`
- }}
- />
-
-
- ) : currentTask?.status === 'done' ||
- currentTask?.status === 'deferred' ||
- currentTask?.status === 'review' ? (
-
- N/A
-
- ) : (
- <>
-
- No complexity score available
-
-
-
-
- >
- )}
-
-
-
-
- {/* Dependencies */}
- {currentTask.dependencies &&
- currentTask.dependencies.length > 0 && (
-
-
- Dependencies
-
-
- {currentTask.dependencies.map((depId) => {
- const depTask = tasks.find((t) => t.id === depId);
- const fullTitle = `Task ${depId}: ${depTask?.title || 'Unknown Task'}`;
- const truncatedTitle =
- fullTitle.length > 40
- ? fullTitle.substring(0, 37) + '...'
- : fullTitle;
- return (
-
handleDependencyClick(depId)}
- title={fullTitle}
- >
- {truncatedTitle}
-
- );
- })}
-
-
- )}
-
- {/* Divider after Dependencies */}
- {currentTask.dependencies &&
- currentTask.dependencies.length > 0 && (
-
- )}
-
-
-
-
-
- );
-};
-
-export default TaskDetailsView;
diff --git a/apps/extension/src/components/TaskDetailsView.tsx b/apps/extension/src/components/TaskDetailsView.tsx
index c17a5b71..f5a1095a 100644
--- a/apps/extension/src/components/TaskDetailsView.tsx
+++ b/apps/extension/src/components/TaskDetailsView.tsx
@@ -151,11 +151,6 @@ export const TaskDetailsView: React.FC
= ({
defaultExpanded={false}
/>
- {(() => {
- console.log(taskFileData);
- return null;
- })()}
-
{/* Test Strategy */}
;
}>;
}