Task Breakdown Assistant

Task Breakdown Assistant

Task Hierarchy

Breakdown Summary

Tips for Effective Task Breakdown

1. Start with the Main Goal
Clearly define the overall project or the largest task you want to accomplish.
2. Identify Major Phases or Deliverables
Break the main goal into high-level components or phases. These become your first level of tasks.
3. Decompose Further
For each major task, ask "What smaller steps are needed to complete this?" Continue breaking down tasks until they are manageable and actionable.
4. Aim for Manageable Chunks
A common rule of thumb is that a task should be small enough to be completed by one person (or a small team) in a reasonable timeframe (e.g., a few hours to a few days). If a task seems too big, break it down further.
5. Ensure Clarity
Each task should have a clear description so that anyone involved understands what needs to be done.
6. Define Outputs/Deliverables
For each task, know what the expected output or result is. This helps in determining when the task is truly "Completed".
7. The 100% Rule (WBS Principle)
The sum of all sub-tasks should represent the entirety of the work required for their parent task. Avoid gold-plating or missing scope.
8. Review and Refine
Once you have an initial breakdown, review it. Does it make sense? Are there any gaps? Is anything unclear? Get feedback if possible.
×

Add New Task

No tasks yet. Click "Add Root Task" to start breaking down your project.

'; } } function tbaCreateTaskElement(task, level) { const li = document.createElement('li'); li.setAttribute('data-task-id', task.id); li.style.marginLeft = (level * 0) + 'px'; // CSS will handle actual indentation via ul padding-left const taskContent = document.createElement('div'); taskContent.className = 'tba-task-content'; const taskInfo = document.createElement('div'); taskInfo.className = 'tba-task-info'; const toggle = document.createElement('span'); toggle.className = 'tba-tree-toggle'; if (task.children && task.children.length > 0) { toggle.innerHTML = task.isCollapsed ? '►' : '▼'; // Right or Down arrow toggle.onclick = (e) => { e.stopPropagation(); tbaToggleCollapse(task.id); }; } else { toggle.innerHTML = ' '; // Non-breaking space for alignment toggle.classList.add('empty'); } const taskNameEl = document.createElement('span'); taskNameEl.className = 'tba-task-name'; taskNameEl.textContent = task.name; const taskDetailsEl = document.createElement('div'); taskDetailsEl.className = 'tba-task-details'; let detailsHTML = ''; if(task.effort) detailsHTML += `Effort: ${task.effort}`; if(task.assignee) detailsHTML += `Assignee: ${task.assignee}`; if(task.status) detailsHTML += `Status: ${task.status}`; taskDetailsEl.innerHTML = detailsHTML || 'No details'; taskInfo.appendChild(toggle); taskInfo.appendChild(taskNameEl); taskInfo.appendChild(taskDetailsEl); const taskActions = document.createElement('div'); taskActions.className = 'tba-task-actions'; taskActions.innerHTML = ` `; taskContent.appendChild(taskInfo); taskContent.appendChild(taskActions); li.appendChild(taskContent); if (task.children && task.children.length > 0 && !task.isCollapsed) { const childrenUl = document.createElement('ul'); task.children.forEach(childTask => { childrenUl.appendChild(tbaCreateTaskElement(childTask, level + 1)); }); li.appendChild(childrenUl); } return li; } function tbaFindTaskById(taskId, tasksArray = tbaProjectData.tasks) { for (const task of tasksArray) { if (task.id === taskId) return task; if (task.children && task.children.length > 0) { const found = tbaFindTaskById(taskId, task.children); if (found) return found; } } return null; } window.tbaToggleCollapse = function(taskId) { const task = tbaFindTaskById(taskId); if (task) { task.isCollapsed = !task.isCollapsed; tbaSaveData(); // Save collapse state tbaRenderTaskTree(); } }; window.tbaExpandAll = function() { function setCollapseState(tasks, isCollapsed) { for (const task of tasks) { if (task.children && task.children.length > 0) { task.isCollapsed = isCollapsed; setCollapseState(task.children, isCollapsed); } } } setCollapseState(tbaProjectData.tasks, false); tbaSaveData(); tbaRenderTaskTree(); }; window.tbaCollapseAll = function() { function setCollapseState(tasks, isCollapsed) { for (const task of tasks) { if (task.children && task.children.length > 0) { task.isCollapsed = isCollapsed; // Don't recursively collapse children of already collapsed parents in this specific function // Only top-level expandable items or those whose parents are expanded. // For a true "collapse all", simply set isCollapsed=true for all expandable. setCollapseState(task.children, isCollapsed); } } } setCollapseState(tbaProjectData.tasks, true); tbaSaveData(); tbaRenderTaskTree(); }; // --- Modal & Task CRUD --- window.tbaOpenTaskModal = function(taskIdToEdit = null, parentId = null) { tbaTaskForm.reset(); tbaTaskIdInput.value = ''; tbaParentIdInput.value = parentId || ''; // parentId can be null for root tasks if (taskIdToEdit) { // Editing existing task const task = tbaFindTaskById(taskIdToEdit); if (task) { tbaModalTitleEl.textContent = 'Edit Task'; tbaTaskIdInput.value = task.id; tbaTaskNameInput.value = task.name; tbaTaskEffortInput.value = task.effort || ''; tbaTaskAssigneeInput.value = task.assignee || ''; tbaTaskStatusInput.value = task.status || 'To Do'; // Parent ID is not changed during edit via this flow } } else { // Adding new task (could be root or sub-task) tbaModalTitleEl.textContent = parentId ? 'Add Sub-task' : 'Add Root Task'; // Parent ID is already set in tbaParentIdInput } tbaTaskModalEl.style.display = 'block'; } window.tbaCloseModal = function(modalId) { const modal = document.getElementById(modalId); if (modal) modal.style.display = 'none'; } if(tbaTaskForm) { tbaTaskForm.addEventListener('submit', function(e) { e.preventDefault(); const taskId = tbaTaskIdInput.value; const parentId = tbaParentIdInput.value; const taskData = { name: tbaTaskNameInput.value.trim(), effort: tbaTaskEffortInput.value.trim(), assignee: tbaTaskAssigneeInput.value.trim(), status: tbaTaskStatusInput.value }; if (!taskData.name) { alert("Task name cannot be empty."); return; } if (taskId) { // Editing const task = tbaFindTaskById(taskId); if (task) { task.name = taskData.name; task.effort = taskData.effort; task.assignee = taskData.assignee; task.status = taskData.status; } } else { // Adding new const newTask = { id: 'tba-task-' + Date.now(), ...taskData, children: [], isCollapsed: false }; if (parentId) { const parentTask = tbaFindTaskById(parentId); if (parentTask) { if (!parentTask.children) parentTask.children = []; parentTask.children.push(newTask); parentTask.isCollapsed = false; // Expand parent when adding sub-task } else { // Fallback to root if parent somehow not found tbaProjectData.tasks.push(newTask); } } else { // Adding root task tbaProjectData.tasks.push(newTask); } } tbaSaveData(); tbaRenderTaskTree(); tbaCloseModal('tbaTaskModal'); }); } window.tbaDeleteTask = function(taskId) { if (confirm('Are you sure you want to delete this task and all its sub-tasks?')) { function removeTask(tasksArray, idToRemove) { for (let i = 0; i < tasksArray.length; i++) { if (tasksArray[i].id === idToRemove) { tasksArray.splice(i, 1); return true; // Task found and removed } if (tasksArray[i].children && tasksArray[i].children.length > 0) { if (removeTask(tasksArray[i].children, idToRemove)) { return true; // Task found and removed in children } } } return false; // Task not found } removeTask(tbaProjectData.tasks, taskId); tbaSaveData(); tbaRenderTaskTree(); } } // --- Summary --- function tbaRenderSummary() { if (!tbaSummaryOutputEl) return; let totalTasks = 0; let statusCounts = { "To Do": 0, "In Progress": 0, "Completed": 0 }; function countTasks(tasksArray) { for (const task of tasksArray) { totalTasks++; statusCounts[task.status] = (statusCounts[task.status] || 0) + 1; if (task.children && task.children.length > 0) { countTasks(task.children); } } } countTasks(tbaProjectData.tasks); tbaSummaryOutputEl.innerHTML = `
${totalTasks}Total Tasks
${statusCounts["To Do"]}To Do
${statusCounts["In Progress"]}In Progress
${statusCounts["Completed"]}Completed
`; } // --- PDF Export --- function tbaAddTasksToPdf(doc, tasks, level, currentY, lineheight, startX) { let y = currentY; const indentSpace = " "; // 4 spaces for indentation per level tasks.forEach(task => { if (y > 270) { // Check for page break doc.addPage(); y = 20; // Reset Y for new page } let taskText = `${indentSpace.repeat(level)}${level > 0 ? '\u2022 ' : ''}${task.name}`; doc.text(taskText, startX, y); y += (lineheight * 0.7); // Smaller line for details let detailsText = ""; if (task.effort) detailsText += `Effort: ${task.effort} | `; if (task.assignee) detailsText += `Assignee: ${task.assignee} | `; if (task.status) detailsText += `Status: ${task.status}`; if(detailsText.endsWith(" | ")) detailsText = detailsText.slice(0, -3); if (detailsText) { if (y > 275) { doc.addPage(); y = 20; } doc.setFontSize(8); doc.setTextColor(80); // Lighter text for details doc.text(`${indentSpace.repeat(level + 1)}${detailsText}`, startX, y); doc.setFontSize(10); // Reset font size doc.setTextColor(40); // Reset text color y += lineheight * 0.8; } y += lineheight * 0.4; // Spacing after task item if (task.children && task.children.length > 0) { y = tbaAddTasksToPdf(doc, task.children, level + 1, y, lineheight, startX); } }); return y; } if(tbaDownloadPdfBtn) { tbaDownloadPdfBtn.addEventListener('click', function() { const { jsPDF } = window.jspdf; // Ensure jsPDF is from the global scope const doc = new jsPDF(); const projectName = tbaProjectData.projectName || "Task Breakdown"; const reportDate = new Date().toLocaleDateString(); const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--tba-primary-color').trim(); doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text(projectName, 14, 22); doc.setFontSize(10); doc.setTextColor(100); doc.text(`Report Date: ${reportDate}`, 14, 30); doc.setFontSize(10); doc.setTextColor(40); // Default text color for tasks tbaAddTasksToPdf(doc, tbaProjectData.tasks, 0, 40, 7, 14); // startY, lineheight, startX doc.save(`${projectName.replace(/\s+/g, '_')}_Breakdown_${reportDate.replace(/\//g, '-')}.pdf`); }); } // --- Initialization --- document.addEventListener('DOMContentLoaded', () => { tbaLoadData(); const firstTabButton = document.querySelector('#taskBreakdownAssistantTool .tba-tab-button'); if (firstTabButton) { firstTabButton.click(); } // Close modal if clicked outside window.addEventListener('click', function(event) { const modal = document.getElementById('tbaTaskModal'); if (modal && event.target == modal) { tbaCloseModal('tbaTaskModal'); } }); });
Scroll to Top