Automated Task Progress Monitor

Automated Task Progress Monitor

Add New Task

0%

Monitored Tasks

Task Summary

Understanding the Monitor

Actual Progress
This is the percentage of work you manually report as completed for the task.
Expected Progress
This is a calculated percentage based on the current date, task start date, and task end date. It represents how much of the task *should ideally* be completed if work is spread evenly over the task's duration.
Formula (simplified): (Days Passed Since Start / Total Task Duration Days) * 100%.
It's 0% if the task hasn't started and 100% if the end date has passed.
Status
Not Started: The current date is before the task's start date.
On Track: Actual progress is close to or greater than the expected progress (within a -5% tolerance).
Ahead: Actual progress is significantly greater (more than 10%) than expected progress.
Behind: Actual progress is less than the expected progress (by more than 5%).
Overdue: The current date is past the task's end date, and actual progress is less than 100%.
Completed: Actual progress is 100%.
Days Remaining / Overdue
Indicates the number of days left until the end date. If negative, it shows how many days the task is overdue (if not completed).
Progress Bar
The main colored bar shows your 'Actual Progress'. A thin vertical line/marker on the progress bar indicates the 'Expected Progress' point for quick visual comparison.
Refresh Calculations
Click this button on the "Task Monitor" tab if you've had the page open for a while, to ensure all calculations are based on the very latest time.

No tasks added yet. Use the form above to add your first task.

'; return; } atpmTasks.map(task => atpmCalculateTaskMetrics(task)).forEach(taskWithMetrics => { const taskEl = document.createElement('div'); taskEl.className = 'atpm-task-item'; let progressBarActualColor = 'var(--atpm-status-notstarted)'; if (taskWithMetrics.statusClass === 'atpm-status-completed') progressBarActualColor = 'var(--atpm-status-completed)'; else if (taskWithMetrics.statusClass === 'atpm-status-overdue') progressBarActualColor = 'var(--atpm-status-overdue)'; else if (taskWithMetrics.statusClass === 'atpm-status-behind') progressBarActualColor = 'var(--atpm-status-behind)'; else if (taskWithMetrics.statusClass === 'atpm-status-ahead') progressBarActualColor = 'var(--atpm-status-ahead)'; else if (taskWithMetrics.statusClass === 'atpm-status-ontrack') progressBarActualColor = 'var(--atpm-status-ontrack)'; taskEl.innerHTML = `

${taskWithMetrics.name}

${taskWithMetrics.assignee ? `

Assignee: ${taskWithMetrics.assignee}

` : ''}

Dates: ${taskWithMetrics.startDate} to ${taskWithMetrics.endDate}

Actual Progress: ${taskWithMetrics.actualProgress}%

${taskWithMetrics.actualProgress}%
${ taskWithMetrics.status !== "Completed" && taskWithMetrics.status !== "Not Started" ? `
` : ''}

Expected Progress: ${taskWithMetrics.expectedProgress}%

Status: ${taskWithMetrics.status}

Time: ${taskWithMetrics.daysRemaining}

`; atpmTaskListEl.appendChild(taskEl); }); } // --- Add Task --- if(atpmAddTaskForm) { atpmAddTaskForm.addEventListener('submit', function(e) { e.preventDefault(); const taskName = document.getElementById('atpmTaskName').value; const startDate = document.getElementById('atpmStartDate').value; const endDate = document.getElementById('atpmEndDate').value; const actualProgress = parseInt(document.getElementById('atpmActualProgress').value); const assignee = document.getElementById('atpmTaskAssignee').value; if (parseDateAsLocalMidnight(endDate) < parseDateAsLocalMidnight(startDate)) { alert("End Date cannot be before Start Date."); return; } const newTask = { id: 'atpm-task-' + Date.now(), name: taskName, startDate: startDate, endDate: endDate, actualProgress: actualProgress, assignee: assignee || '' }; atpmTasks.push(newTask); atpmSaveTasks(); atpmRenderTasks(); atpmAddTaskForm.reset(); document.getElementById('atpmActualProgressValue').textContent = '0%'; // Reset slider display }); } // --- Edit Task --- window.atpmOpenEditModal = function(taskId) { const task = atpmTasks.find(t => t.id === taskId); if (task && atpmEditTaskModalEl && atpmEditTaskForm) { document.getElementById('atpmEditTaskId').value = task.id; document.getElementById('atpmEditTaskName').value = task.name; document.getElementById('atpmEditTaskAssignee').value = task.assignee; document.getElementById('atpmEditStartDate').value = task.startDate; document.getElementById('atpmEditEndDate').value = task.endDate; document.getElementById('atpmEditActualProgress').value = task.actualProgress; document.getElementById('atpmEditActualProgressValue').textContent = task.actualProgress + '%'; atpmEditTaskModalEl.style.display = 'block'; } } if(atpmEditTaskForm) { atpmEditTaskForm.addEventListener('submit', function(e) { e.preventDefault(); const taskId = document.getElementById('atpmEditTaskId').value; const updatedTask = { id: taskId, name: document.getElementById('atpmEditTaskName').value, assignee: document.getElementById('atpmEditTaskAssignee').value, startDate: document.getElementById('atpmEditStartDate').value, endDate: document.getElementById('atpmEditEndDate').value, actualProgress: parseInt(document.getElementById('atpmEditActualProgress').value) }; if (parseDateAsLocalMidnight(updatedTask.endDate) < parseDateAsLocalMidnight(updatedTask.startDate)) { alert("End Date cannot be before Start Date."); return; } const taskIndex = atpmTasks.findIndex(t => t.id === taskId); if (taskIndex > -1) { atpmTasks[taskIndex] = updatedTask; atpmSaveTasks(); atpmRenderTasks(); if(atpmEditTaskModalEl) atpmEditTaskModalEl.style.display = 'none'; } }); } // --- Delete Task --- window.atpmDeleteTask = function(taskId) { if (confirm('Are you sure you want to delete this task?')) { atpmTasks = atpmTasks.filter(t => t.id !== taskId); atpmSaveTasks(); atpmRenderTasks(); } } // --- Refresh Calculations --- window.atpmRefreshCalculations = function() { atpmRenderTasks(); if(document.getElementById('Summary').classList.contains('active')) { // if summary tab is active atpmRenderSummary(); } alert("Task calculations have been refreshed based on the current time."); } // --- Summary --- function atpmRenderSummary() { if (!atpmSummaryOutputEl) return; let summary = { total: atpmTasks.length, notStarted: 0, onTrack: 0, ahead: 0, behind: 0, overdue: 0, completed: 0 }; atpmTasks.map(task => atpmCalculateTaskMetrics(task)).forEach(taskWithMetrics => { if (taskWithMetrics.status === "Not Started") summary.notStarted++; else if (taskWithMetrics.status === "On Track") summary.onTrack++; else if (taskWithMetrics.status === "Ahead") summary.ahead++; else if (taskWithMetrics.status === "Behind") summary.behind++; else if (taskWithMetrics.status === "Overdue") summary.overdue++; else if (taskWithMetrics.status === "Completed") summary.completed++; }); atpmSummaryOutputEl.innerHTML = `
${summary.total}Total Tasks
${summary.completed}Completed
${summary.onTrack}On Track
${summary.ahead}Ahead
${summary.behind}Behind
${summary.overdue}Overdue
${summary.notStarted}Not Started
`; } // --- PDF Export --- if(atpmDownloadPdfBtn) { atpmDownloadPdfBtn.addEventListener('click', function() { const doc = new jsPDF(); const reportDate = new Date().toLocaleDateString(); const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--atpm-primary-color').trim(); const secondaryColor = getComputedStyle(document.documentElement).getPropertyValue('--atpm-secondary-color').trim(); doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text("Automated Task Progress Report", 14, 22); doc.setFontSize(11); doc.setTextColor(100); doc.text(`Report Date: ${reportDate}`, 14, 30); const tableColumn = ["Task Name", "Assignee", "Start", "End", "Actual %", "Expected %", "Status", "Time Details"]; const tableRows = []; atpmTasks.map(task => atpmCalculateTaskMetrics(task)).forEach(task => { const taskData = [ task.name || "N/A", task.assignee || "N/A", task.startDate || "N/A", task.endDate || "N/A", `${task.actualProgress}%`, `${task.expectedProgress}%`, task.status || "N/A", task.daysRemaining || "N/A" ]; tableRows.push(taskData); }); if (tableRows.length > 0) { doc.autoTable({ head: [tableColumn], body: tableRows, startY: 40, theme: 'grid', headStyles: { fillColor: secondaryColor, textColor: '#ffffff' }, styles: { font: 'Arial', fontSize: 9, cellPadding: 2, overflow: 'linebreak' }, columnStyles: { 0: { cellWidth: 40 }, // Task Name 6: { cellWidth: 25 }, // Status 7: { cellWidth: 30 } // Time Details } }); } else { doc.setFontSize(12); doc.setTextColor(100); doc.text("No tasks to report.", 14, 45); } doc.save(`Task_Progress_Report_${reportDate.replace(/\//g, '-')}.pdf`); }); } // --- Initialization --- document.addEventListener('DOMContentLoaded', () => { atpmLoadTasks(); const firstTabButton = document.querySelector('#automatedTaskProgressMonitorTool .atpm-tab-button'); if (firstTabButton) { firstTabButton.click(); } // Close modal if clicked outside (generic for any modal with this structure) window.addEventListener('click', function(event) { if (event.target.classList.contains('atpm-modal')) { event.target.style.display = 'none'; } }); });
Scroll to Top