fix: correct log order sorting and add configurable log order setting (#1720)
* feat: add configurable log order setting for task detail view
Add a new "Log Order" setting in Display Settings that allows users to
choose how logs are displayed in the task detail view:
- Chronological (oldest first): Oldest logs appear at top, auto-scroll to bottom
- Reverse-chronological (newest first): Newest logs appear at top, auto-scroll to top
Changes:
- Add logOrder property to AppSettings type ('chronological' | 'reverse-chronological')
- Set default value to 'chronological' to maintain current behavior
- Add English and French i18n translations
- Add Select component in DisplaySettings UI
- Update TaskLogs component to apply log order
- Update scroll behavior in useTaskDetail hook based on log order
* fix: increase log order dropdown width to prevent text truncation
* fix: address PR review comments - reactive settings and memoized entries
- Add reactive settings access at top of useTaskDetail hook
- Update auto-scroll useEffect to include settings.logOrder in dependency array
- Update handleLogsScroll to use reactive settings for consistency
- Add useMemo to PhaseLogSection to avoid re-calculating sorted entries on every render
Fixes review comments from PR #1720
* refactor: use focused selectors for logOrder to avoid unnecessary re-renders
- Replace wide subscription to settings object with focused selector for logOrder
- In useTaskDetail: use logOrder selector instead of full settings object
- In TaskLogs PhaseLogSection: subscribe only to logOrder instead of entire settings
- This ensures components only re-render when logOrder specifically changes
* fix: correct log order sorting and improve timestamp display
This commit fixes inverted log order logic and improves UX for task logs.
Bug Fixes:
- Fix inverted log order sorting: chronological now correctly shows oldest
entries first (entries are naturally chronological from append() in backend)
- Fix auto-scroll not triggering when new logs arrive by adding phaseLogs
to useEffect dependency array
UX Improvements:
- Add max-height and internal scrolling to log order dropdown to prevent
viewport expansion
- Change timestamp format to use system locale (toLocaleString) which
displays date and time according to user's OS settings, making it more
readable for European users who prefer 24-hour format
Files changed:
- TaskLogs.tsx: fix sorting logic, update timestamp formatting
- useTaskDetail.ts: add phaseLogs to auto-scroll dependency array
- DisplaySettings.tsx: add max-height to SelectContent
* fix: preserve log entry state when toggling log order
Use stable timestamp as React key instead of timestamp+index to prevent
component remounting when log order changes. This preserves the isExpanded
state for log detail views when users toggle between chronological and
reverse-chronological order.
Previously, the key included the array index which changed on reorder,
causing React to unmount and remount all LogEntry components, losing
any expanded detail view state.
---------
Co-authored-by: Andy <[email protected]>
This commit is contained in:
committed by
StillKnotKnown
co-authored by
Andy
parent
ab0cd7b54b
commit
085afc9907
@@ -1,5 +1,6 @@
|
||||
import { useState, useRef, useEffect, useCallback } from 'react';
|
||||
import { useProjectStore } from '../../../stores/project-store';
|
||||
import { useSettingsStore } from '../../../stores/settings-store';
|
||||
import { checkTaskRunning, isIncompleteHumanReview, getTaskProgress, useTaskStore, loadTasks, hasRecentActivity } from '../../../stores/task-store';
|
||||
import type { Task, TaskLogs, TaskLogPhase, WorktreeStatus, WorktreeDiff, MergeConflict, MergeStats, GitConflictInfo, ImageAttachment } from '../../../../shared/types';
|
||||
|
||||
@@ -93,6 +94,7 @@ export function useTaskDetail({ task }: UseTaskDetailOptions) {
|
||||
const [isCreatingPR, setIsCreatingPR] = useState(false);
|
||||
|
||||
const selectedProject = useProjectStore((state) => state.getSelectedProject());
|
||||
const logOrder = useSettingsStore(s => s.settings.logOrder);
|
||||
const isRunning = task.status === 'in_progress';
|
||||
// isActiveTask includes ai_review for stuck detection (CHANGELOG documents this feature)
|
||||
const isActiveTask = task.status === 'in_progress' || task.status === 'ai_review';
|
||||
@@ -131,19 +133,31 @@ export function useTaskDetail({ task }: UseTaskDetailOptions) {
|
||||
return () => clearInterval(intervalId);
|
||||
}, [task.id, isActiveTask]);
|
||||
|
||||
// Handle scroll events in logs to detect if user scrolled up
|
||||
// Handle scroll events in logs to detect if user scrolled away from anchor
|
||||
const handleLogsScroll = (e: React.UIEvent<HTMLDivElement>) => {
|
||||
const target = e.target as HTMLDivElement;
|
||||
const isNearBottom = target.scrollHeight - target.scrollTop - target.clientHeight < 100;
|
||||
setIsUserScrolledUp(!isNearBottom);
|
||||
const isReverseOrder = logOrder === 'reverse-chronological';
|
||||
|
||||
// Check distance from top for reverse order, bottom for chronological
|
||||
const isAtAnchor = isReverseOrder
|
||||
? target.scrollTop < 100
|
||||
: target.scrollHeight - target.scrollTop - target.clientHeight < 100;
|
||||
|
||||
setIsUserScrolledUp(!isAtAnchor);
|
||||
};
|
||||
|
||||
// Auto-scroll logs to bottom only if user hasn't scrolled up
|
||||
// Auto-scroll logs to anchor (top for reverse, bottom for chronological) only if user hasn't scrolled away
|
||||
useEffect(() => {
|
||||
if (activeTab === 'logs' && logsEndRef.current && !isUserScrolledUp) {
|
||||
logsEndRef.current.scrollIntoView({ behavior: 'smooth' });
|
||||
const isReverseOrder = logOrder === 'reverse-chronological';
|
||||
|
||||
if (activeTab === 'logs' && !isUserScrolledUp) {
|
||||
if (isReverseOrder && logsContainerRef.current) {
|
||||
logsContainerRef.current.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
} else if (!isReverseOrder && logsEndRef.current) {
|
||||
logsEndRef.current.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
}
|
||||
}, [activeTab, isUserScrolledUp]);
|
||||
}, [activeTab, isUserScrolledUp, logOrder, phaseLogs]);
|
||||
|
||||
// Reset scroll state when switching to logs tab
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user