Skip to content

Commit 797ac5c

Browse files
hangtime79claude
andcommitted
fix(v0.9.8): Filter tasks via re-render instead of DOM hiding (#51)
Refactored task filtering to properly resize the chart: - Store allTasks separately from filtered currentTasks - filterTasksByStatus() filters task array before render - applyTaskFilters() triggers full re-render with filtered tasks - Chart container now properly resizes when filtering 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 8f3159d commit 797ac5c

1 file changed

Lines changed: 51 additions & 29 deletions

File tree

webapps/gantt-chart/app.js

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@
6060
let configDebounceTimer = null; // Debounce timer for config updates
6161
let renderInProgress = false; // Prevent overlapping renders
6262
const CONFIG_DEBOUNCE_MS = 300; // 300ms debounce delay
63-
let currentTasks = []; // Store tasks for expected progress markers
63+
let allTasks = []; // Store ALL tasks from backend (unfiltered)
64+
let currentTasks = []; // Store filtered tasks for current display
65+
let lastGanttConfig = null; // Store last config for filter re-renders (#51)
6466
let activeFilters = ['all']; // Track active filter buttons (#51)
6567

6668
// Zoom State
@@ -864,12 +866,29 @@
864866

865867
// ===== GANTT RENDERING =====
866868

867-
function renderGantt(tasks, config) {
868-
console.log(`Rendering Gantt with ${tasks.length} tasks`);
869-
// console.log('Gantt config:', JSON.stringify(config, null, 2));
869+
function renderGantt(tasks, config, isFilterRerender = false) {
870+
// Store all tasks on initial load (not filter re-renders)
871+
if (!isFilterRerender) {
872+
allTasks = tasks;
873+
lastGanttConfig = config;
874+
}
875+
876+
// Apply status filters to get visible tasks (#51)
877+
const filteredTasks = filterTasksByStatus(tasks);
878+
console.log(`Rendering Gantt with ${filteredTasks.length}/${tasks.length} tasks (filtered)`);
879+
880+
// Store filtered tasks for expected progress markers
881+
currentTasks = filteredTasks;
870882

871-
// Store tasks for expected progress markers
872-
currentTasks = tasks;
883+
// Handle empty filtered result
884+
if (filteredTasks.length === 0) {
885+
const container = document.getElementById('gantt-container');
886+
container.innerHTML = '';
887+
ganttInstance = null;
888+
updateFilterEmptyState(0);
889+
return;
890+
}
891+
updateFilterEmptyState(filteredTasks.length);
873892

874893
const container = document.getElementById('gantt-container');
875894

@@ -966,7 +985,6 @@
966985
ensureStackingOrder(); // Ensure today line and markers on top (#57)
967986
ensureEdgeToEdgeContent(); // Check edge-to-edge, zoom if needed (#21)
968987
updateZoomIndicator(); // Update indicator for new view's zoom
969-
applyTaskFilters(); // Re-apply task filters after view change (#51)
970988
});
971989
}
972990
};
@@ -984,8 +1002,8 @@
9841002

9851003
// Initialize Frappe Gantt
9861004
try {
987-
ganttInstance = new Gantt('#gantt-svg', tasks, ganttOptions);
988-
console.log(`Gantt chart created successfully with ${tasks.length} tasks`);
1005+
ganttInstance = new Gantt('#gantt-svg', filteredTasks, ganttOptions);
1006+
console.log(`Gantt chart created successfully with ${filteredTasks.length} tasks`);
9891007

9901008
// Debug: Log gantt instance date boundaries
9911009
console.log('Gantt date debug:', {
@@ -1213,7 +1231,6 @@
12131231
addCompletionIndicators(); // Add checkmarks to 100% tasks (#31)
12141232
ensureStackingOrder(); // Ensure today line and markers on top (#57)
12151233
ensureEdgeToEdgeContent(); // Zoom if needed to fill viewport (#21)
1216-
applyTaskFilters(); // Apply task filters after render (#51)
12171234

12181235
// Restore view state if we have saved state from config update
12191236
if (window._ganttRestoreState) {
@@ -2318,30 +2335,35 @@
23182335
}
23192336

23202337
/**
2321-
* Apply active filters to hide/show task bars in DOM.
2322-
* Uses display:none on bar-wrapper elements.
2338+
* Filter tasks array based on active status filters.
2339+
* @param {Array} tasks - Array of task objects
2340+
* @returns {Array} Filtered tasks matching active filters
23232341
*/
2324-
function applyTaskFilters() {
2325-
const barWrappers = document.querySelectorAll('.gantt .bar-wrapper');
2326-
let visibleCount = 0;
2327-
2328-
barWrappers.forEach(wrapper => {
2329-
const taskId = wrapper.getAttribute('data-id');
2330-
const task = currentTasks.find(t => t.id === taskId);
2331-
if (!task) return;
2342+
function filterTasksByStatus(tasks) {
2343+
// If 'all' is active, return all tasks
2344+
if (activeFilters.includes('all')) {
2345+
return tasks;
2346+
}
23322347

2348+
return tasks.filter(task => {
23332349
const taskStatuses = getTaskStatuses(task);
2334-
2335-
// Show if 'all' is active OR any of task's statuses match active filters
2336-
const shouldShow = activeFilters.includes('all') ||
2337-
taskStatuses.some(status => activeFilters.includes(status));
2338-
2339-
wrapper.style.display = shouldShow ? '' : 'none';
2340-
if (shouldShow) visibleCount++;
2350+
// Show if any of task's statuses match active filters (OR logic)
2351+
return taskStatuses.some(status => activeFilters.includes(status));
23412352
});
2353+
}
2354+
2355+
/**
2356+
* Apply active filters by re-rendering the Gantt chart.
2357+
* This properly resizes the chart container.
2358+
*/
2359+
function applyTaskFilters() {
2360+
if (!allTasks.length || !lastGanttConfig) {
2361+
console.log('No tasks or config available for filter re-render');
2362+
return;
2363+
}
23422364

2343-
// Update empty state if needed
2344-
updateFilterEmptyState(visibleCount);
2365+
// Re-render with filtered tasks
2366+
renderGantt(allTasks, lastGanttConfig, true);
23452367
}
23462368

23472369
/**

0 commit comments

Comments
 (0)