From 2d5c117d5fa74870d2011cf8a1d9386c52d53be9 Mon Sep 17 00:00:00 2001 From: Quorafind Date: Tue, 16 Sep 2025 16:32:44 +0800 Subject: [PATCH] fix(view): prevent rendering when container not visible - Add visibility checks before task list rendering to avoid DOM errors - Implement retry mechanism with timeout for deferred rendering - Queue refresh requests instead of skipping when render in progress - Fix cache ready event to properly trigger view refresh - Prevent concurrent renders while allowing force refresh override --- src/components/features/task/view/content.ts | 61 +++++- src/pages/TaskSpecificView.ts | 210 ++++++++++--------- src/pages/TaskView.ts | 4 +- 3 files changed, 171 insertions(+), 104 deletions(-) diff --git a/src/components/features/task/view/content.ts b/src/components/features/task/view/content.ts index 1f5db248..a38459ca 100644 --- a/src/components/features/task/view/content.ts +++ b/src/components/features/task/view/content.ts @@ -55,7 +55,8 @@ export class ContentComponent extends Component { private isTreeView: boolean = false; private isRendering: boolean = false; // Guard against concurrent renders private pendingForceRefresh: boolean = false; // Track if a force refresh is pending - + private pendingVisibilityRetry: boolean = false; // Queue a retry when container becomes visible + private visibilityRetryCount: number = 0; // Limit visibility retry loop constructor( private parentEl: HTMLElement, private app: App, @@ -350,18 +351,58 @@ export class ContentComponent extends Component { this.taskListEl.empty(); } + private isContainerVisible(): boolean { + if (!this.containerEl) return false; + const inDom = document.body.contains(this.containerEl); + if (!inDom) return false; + const style = window.getComputedStyle(this.containerEl); + if (style.display === "none" || style.visibility === "hidden") + return false; + const rect = this.containerEl.getBoundingClientRect(); + return rect.width > 0 && rect.height > 0; + } + private refreshTaskList() { - // Allow force refresh to override concurrent rendering - if (this.pendingForceRefresh) { - console.log("ContentComponent: Processing pending force refresh"); - this.isRendering = false; // Cancel any ongoing render + // Defer rendering if container is not visible yet (e.g., view hidden during init) + if (!this.isContainerVisible()) { + console.warn( + "ContentComponent: Cannot render: Container not visible. Queuing refresh..." + ); + this.pendingForceRefresh = true; + if (!this.pendingVisibilityRetry) { + this.pendingVisibilityRetry = true; + const tryAgain = () => { + if (this.isContainerVisible()) { + this.pendingVisibilityRetry = false; + this.visibilityRetryCount = 0; + if (this.pendingForceRefresh && !this.isRendering) { + this.pendingForceRefresh = false; + this.refreshTaskList(); + } + return; + } + if (this.visibilityRetryCount < 30) { + this.visibilityRetryCount++; + setTimeout(tryAgain, 100); + } else { + this.pendingVisibilityRetry = false; + this.visibilityRetryCount = 0; + console.warn( + "ContentComponent: Container still not visible after retries; will wait for next trigger." + ); + } + }; + tryAgain(); + } + return; } - // Prevent concurrent renders (unless force refresh) + // If a render is already in progress, queue a refresh instead of skipping if (this.isRendering) { console.log( - "ContentComponent: Already rendering, skipping refresh" + "ContentComponent: Already rendering, queueing a refresh" ); + this.pendingForceRefresh = true; return; } @@ -453,7 +494,11 @@ export class ContentComponent extends Component { // Reset rendering flag after completion setTimeout(() => { this.isRendering = false; - this.pendingForceRefresh = false; // Reset force refresh flag + // If a refresh was queued during rendering, process it now + if (this.pendingForceRefresh) { + this.pendingForceRefresh = false; + this.refreshTaskList(); + } }, 50); // Small delay to prevent immediate re-entry } } diff --git a/src/pages/TaskSpecificView.ts b/src/pages/TaskSpecificView.ts index a83cd9ad..42565815 100644 --- a/src/pages/TaskSpecificView.ts +++ b/src/pages/TaskSpecificView.ts @@ -33,7 +33,10 @@ import { TwoColumnSpecificConfig, } from "../common/setting-definition"; import { filterTasks } from "../utils/task/task-filter-utils"; -import { CalendarComponent, CalendarEvent } from "../components/features/calendar"; +import { + CalendarComponent, + CalendarEvent, +} from "../components/features/calendar"; import { KanbanComponent } from "../components/features/kanban/kanban"; import { GanttComponent } from "../components/features/gantt/gantt"; import { TaskPropertyTwoColumnView } from "../components/features/task/view/TaskPropertyTwoColumnView"; @@ -95,10 +98,7 @@ export class TaskSpecificView extends ItemView { // Data management tasks: Task[] = []; - constructor( - leaf: WorkspaceLeaf, - private plugin: TaskProgressBarPlugin, - ) { + constructor(leaf: WorkspaceLeaf, private plugin: TaskProgressBarPlugin) { super(leaf); // 使用预加载的任务进行快速初始显示 @@ -141,7 +141,7 @@ export class TaskSpecificView extends ItemView { if (this.currentViewId) { this.switchView( this.currentViewId, - this.currentProject, + this.currentProject ); } }); @@ -158,7 +158,7 @@ export class TaskSpecificView extends ItemView { getDisplayText(): string { const currentViewConfig = getViewSettingOrDefault( this.plugin, - this.currentViewId, + this.currentViewId ); // Potentially add project name if relevant for 'projects' view? return currentViewConfig.name; @@ -167,7 +167,7 @@ export class TaskSpecificView extends ItemView { getIcon(): string { const currentViewConfig = getViewSettingOrDefault( this.plugin, - this.currentViewId, + this.currentViewId ); return currentViewConfig.icon; } @@ -194,20 +194,20 @@ export class TaskSpecificView extends ItemView { const { on, Events } = await import("../dataflow/events/Events"); this.registerEvent( on(this.app, Events.CACHE_READY, async () => { - // 冷启动就绪,从快照加载 - await this.loadTasksFast(true); - }), + // 冷启动就绪,从快照加载,并刷新视图 + await this.loadTasksFast(false); + }) ); this.registerEvent( - on(this.app, Events.TASK_CACHE_UPDATED, debouncedViewUpdate), + on(this.app, Events.TASK_CACHE_UPDATED, debouncedViewUpdate) ); } else { // Legacy: 兼容旧事件 this.registerEvent( this.app.workspace.on( "task-genius:task-cache-updated", - debouncedViewUpdate, - ), + debouncedViewUpdate + ) ); } @@ -219,7 +219,7 @@ export class TaskSpecificView extends ItemView { "TaskSpecificView 过滤器实时变更:", filterState, "leafId:", - leafId, + leafId ); // 只处理来自当前视图的过滤器变更 @@ -231,8 +231,8 @@ export class TaskSpecificView extends ItemView { this.debouncedApplyFilter(); } // 忽略来自其他leafId的变更,包括基础过滤器(view-config-开头) - }, - ), + } + ) ); // 2. 初始化组件(但先不传入数据) @@ -249,8 +249,8 @@ export class TaskSpecificView extends ItemView { // 4. 先使用预加载的数据快速显示 this.switchView(this.currentViewId, this.currentProject); - // 5. 快速加载缓存数据以立即显示 UI - await this.loadTasksFast(true); // 跳过视图更新,避免双重渲染 + // 5. 快速加载缓存数据以立即显示 UI 并刷新视图 + await this.loadTasksFast(false); // 6. 后台同步最新数据(非阻塞) this.loadTasksWithSyncInBackground(); @@ -262,7 +262,7 @@ export class TaskSpecificView extends ItemView { (this.leaf.tabHeaderStatusContainerEl as HTMLElement)?.empty(); (this.leaf.tabHeaderEl as HTMLElement)?.toggleClass( "task-genius-tab-header", - true, + true ); this.tabActionButton = ( this.leaf.tabHeaderStatusContainerEl as HTMLElement @@ -280,11 +280,11 @@ export class TaskSpecificView extends ItemView { this.plugin.app, this.plugin, {}, - true, + true ); modal.open(); }); - }, + } ); if (this.tabActionButton) { this.register(() => { @@ -317,7 +317,7 @@ export class TaskSpecificView extends ItemView { onTaskContextMenu: (event: MouseEvent, task: Task) => { this.handleTaskContextMenu(event, task); }, - }, + } ); this.addChild(this.contentComponent); this.contentComponent.load(); @@ -339,7 +339,7 @@ export class TaskSpecificView extends ItemView { onTaskContextMenu: (event: MouseEvent, task: Task) => { this.handleTaskContextMenu(event, task); }, - }, + } ); this.addChild(this.forecastComponent); this.forecastComponent.load(); @@ -359,7 +359,7 @@ export class TaskSpecificView extends ItemView { onTaskContextMenu: (event: MouseEvent, task: Task) => { this.handleTaskContextMenu(event, task); }, - }, + } ); this.addChild(this.tagsComponent); this.tagsComponent.load(); @@ -379,7 +379,7 @@ export class TaskSpecificView extends ItemView { onTaskContextMenu: (event: MouseEvent, task: Task) => { this.handleTaskContextMenu(event, task); }, - }, + } ); this.addChild(this.projectsComponent); this.projectsComponent.load(); @@ -399,7 +399,7 @@ export class TaskSpecificView extends ItemView { onTaskContextMenu: (event: MouseEvent, task: Task) => { this.handleTaskContextMenu(event, task); }, - }, + } ); this.addChild(this.reviewComponent); this.reviewComponent.load(); @@ -420,7 +420,7 @@ export class TaskSpecificView extends ItemView { onEventContextMenu: (ev: MouseEvent, event: CalendarEvent) => { this.handleTaskContextMenu(ev, event); }, - }, + } ); this.addChild(this.calendarComponent); this.calendarComponent.load(); @@ -438,7 +438,7 @@ export class TaskSpecificView extends ItemView { onTaskSelected: this.handleTaskSelection.bind(this), onTaskCompleted: this.toggleTaskCompletion.bind(this), onTaskContextMenu: this.handleTaskContextMenu.bind(this), - }, + } ); this.addChild(this.kanbanComponent); this.kanbanComponent.containerEl.hide(); @@ -450,21 +450,21 @@ export class TaskSpecificView extends ItemView { onTaskSelected: this.handleTaskSelection.bind(this), onTaskCompleted: this.toggleTaskCompletion.bind(this), onTaskContextMenu: this.handleTaskContextMenu.bind(this), - }, + } ); this.addChild(this.ganttComponent); this.ganttComponent.containerEl.hide(); this.habitsComponent = new HabitsComponent( this.plugin, - this.rootContainerEl, + this.rootContainerEl ); this.addChild(this.habitsComponent); this.habitsComponent.containerEl.hide(); this.detailsComponent = new TaskDetailsComponent( this.rootContainerEl, this.app, - this.plugin, + this.plugin ); this.addChild(this.detailsComponent); this.detailsComponent.load(); @@ -482,7 +482,7 @@ export class TaskSpecificView extends ItemView { onTaskStatusUpdate: this.handleKanbanTaskStatusUpdate.bind(this), onEventContextMenu: this.handleTaskContextMenu.bind(this), - }, + } ); this.addChild(this.viewComponentManager); @@ -498,7 +498,7 @@ export class TaskSpecificView extends ItemView { t("Details"), () => { this.toggleDetailsVisibility(!this.isDetailsVisible); - }, + } ); this.detailsToggleBtn.toggleClass("panel-toggle-btn", true); @@ -510,7 +510,7 @@ export class TaskSpecificView extends ItemView { this.plugin.app, this.plugin, {}, - true, + true ); modal.open(); }); @@ -520,7 +520,7 @@ export class TaskSpecificView extends ItemView { const popover = new ViewTaskFilterPopover( this.plugin.app, this.leaf.id, - this.plugin, + this.plugin ); // 设置关闭回调 - 现在主要用于处理取消操作 @@ -540,7 +540,7 @@ export class TaskSpecificView extends ItemView { const filterState = this .liveFilterState as RootFilterState; popover.taskFilterComponent.loadFilterState( - filterState, + filterState ); } }, 100); @@ -551,7 +551,7 @@ export class TaskSpecificView extends ItemView { const modal = new ViewTaskFilterModal( this.plugin.app, this.leaf.id, - this.plugin, + this.plugin ); // 设置关闭回调 - 现在主要用于处理取消操作 @@ -617,7 +617,7 @@ export class TaskSpecificView extends ItemView { this.detailsToggleBtn.toggleClass("is-active", visible); this.detailsToggleBtn.setAttribute( "aria-label", - visible ? t("Hide Details") : t("Show Details"), + visible ? t("Hide Details") : t("Show Details") ); } @@ -635,7 +635,7 @@ export class TaskSpecificView extends ItemView { this.detailsComponent.onTaskEdit = (task: Task) => this.editTask(task); this.detailsComponent.onTaskUpdate = async ( originalTask: Task, - updatedTask: Task, + updatedTask: Task ) => { await this.updateTask(originalTask, updatedTask); }; @@ -649,7 +649,7 @@ export class TaskSpecificView extends ItemView { private switchView( viewId: ViewMode, project?: string | null, - forceRefresh: boolean = false, + forceRefresh: boolean = false ) { this.currentViewId = viewId; this.currentProject = project; @@ -690,7 +690,7 @@ export class TaskSpecificView extends ItemView { this.app, this.plugin, twoColumnConfig, - viewId, + viewId ); this.addChild(twoColumnComponent); @@ -752,7 +752,7 @@ export class TaskSpecificView extends ItemView { if (targetComponent) { console.log( `Activating component for view ${viewId}`, - targetComponent.constructor.name, + targetComponent.constructor.name ); targetComponent.containerEl.show(); if (typeof targetComponent.setTasks === "function") { @@ -774,20 +774,20 @@ export class TaskSpecificView extends ItemView { this.tasks, viewId, this.plugin, - filterOptions, + filterOptions ); // Filter out badge tasks for forecast view - they should only appear in event view if (viewId === "forecast") { filteredTasks = filteredTasks.filter( - (task) => !(task as any).badge, + (task) => !(task as any).badge ); } targetComponent.setTasks( filteredTasks, this.tasks, - forceRefresh, + forceRefresh ); } @@ -807,13 +807,13 @@ export class TaskSpecificView extends ItemView { } targetComponent.updateTasks( - filterTasks(this.tasks, viewId, this.plugin, filterOptions), + filterTasks(this.tasks, viewId, this.plugin, filterOptions) ); } if (typeof targetComponent.setViewMode === "function") { console.log( - `Setting view mode for ${viewId} to ${modeForComponent} with project ${project}`, + `Setting view mode for ${viewId} to ${modeForComponent} with project ${project}` ); targetComponent.setViewMode(modeForComponent, project); } @@ -840,13 +840,13 @@ export class TaskSpecificView extends ItemView { this.tasks, component.getViewId(), this.plugin, - filterOptions, + filterOptions ); // Filter out badge tasks for forecast view - they should only appear in event view if (component.getViewId() === "forecast") { filteredTasks = filteredTasks.filter( - (task) => !(task as any).badge, + (task) => !(task as any).badge ); } @@ -876,7 +876,7 @@ export class TaskSpecificView extends ItemView { // Check for special view types first const viewConfig = getViewSettingOrDefault( this.plugin, - this.currentViewId, + this.currentViewId ); // Handle TwoColumn views @@ -963,7 +963,7 @@ export class TaskSpecificView extends ItemView { }, (el) => { createTaskCheckbox(mark, task, el); - }, + } ); item.titleEl.createEl("span", { cls: "status-option", @@ -1035,28 +1035,28 @@ export class TaskSpecificView extends ItemView { private async loadTasks( forceSync: boolean = false, - skipViewUpdate: boolean = false, + skipViewUpdate: boolean = false ) { // Only use dataflow - TaskManager is deprecated if (!this.plugin.dataflowOrchestrator) { console.warn( - "[TaskSpecificView] Dataflow orchestrator not available, waiting for initialization...", + "[TaskSpecificView] Dataflow orchestrator not available, waiting for initialization..." ); this.tasks = []; } else { try { console.log( - "[TaskSpecificView] Loading tasks from dataflow orchestrator...", + "[TaskSpecificView] Loading tasks from dataflow orchestrator..." ); const queryAPI = this.plugin.dataflowOrchestrator.getQueryAPI(); this.tasks = await queryAPI.getAllTasks(); console.log( - `[TaskSpecificView] Loaded ${this.tasks.length} tasks from dataflow`, + `[TaskSpecificView] Loaded ${this.tasks.length} tasks from dataflow` ); } catch (error) { console.error( "[TaskSpecificView] Error loading tasks from dataflow:", - error, + error ); this.tasks = []; } @@ -1065,7 +1065,7 @@ export class TaskSpecificView extends ItemView { if (!skipViewUpdate) { // 直接切换到当前视图 if (this.currentViewId) { - this.switchView(this.currentViewId, this.currentProject); + this.switchView(this.currentViewId, this.currentProject, true); } // 更新操作按钮 @@ -1080,24 +1080,24 @@ export class TaskSpecificView extends ItemView { // Only use dataflow if (!this.plugin.dataflowOrchestrator) { console.warn( - "[TaskSpecificView] Dataflow orchestrator not available for fast load", + "[TaskSpecificView] Dataflow orchestrator not available for fast load" ); this.tasks = []; } else { try { console.log( - "[TaskSpecificView] Loading tasks fast from dataflow orchestrator...", + "[TaskSpecificView] Loading tasks fast from dataflow orchestrator..." ); const queryAPI = this.plugin.dataflowOrchestrator.getQueryAPI(); // For fast loading, use regular getAllTasks (it should be cached) this.tasks = await queryAPI.getAllTasks(); console.log( - `[TaskSpecificView] Loaded ${this.tasks.length} tasks (fast from dataflow)`, + `[TaskSpecificView] Loaded ${this.tasks.length} tasks (fast from dataflow)` ); } catch (error) { console.error( "[TaskSpecificView] Error loading tasks fast from dataflow:", - error, + error ); this.tasks = []; } @@ -1106,7 +1106,7 @@ export class TaskSpecificView extends ItemView { if (!skipViewUpdate) { // 直接切换到当前视图 if (this.currentViewId) { - this.switchView(this.currentViewId, this.currentProject); + this.switchView(this.currentViewId, this.currentProject, true); } // 更新操作按钮 @@ -1129,7 +1129,7 @@ export class TaskSpecificView extends ItemView { if (tasks.length !== this.tasks.length || tasks.length === 0) { this.tasks = tasks; console.log( - `TaskSpecificView updated with ${this.tasks.length} tasks (dataflow sync)`, + `TaskSpecificView updated with ${this.tasks.length} tasks (dataflow sync)` ); // Don't trigger view update here as it will be handled by events } @@ -1143,7 +1143,7 @@ export class TaskSpecificView extends ItemView { console.log( "应用 TaskSpecificView 当前过滤状态:", this.liveFilterState ? "有实时筛选器" : "无实时筛选器", - this.currentFilterState ? "有过滤器" : "无过滤器", + this.currentFilterState ? "有过滤器" : "无过滤器" ); // 通过 loadTasks 重新加载任务 this.loadTasks(); @@ -1157,7 +1157,7 @@ export class TaskSpecificView extends ItemView { this.updateActionButtons(); } else { console.warn( - "TaskSpecificView: Cannot trigger update, currentViewId is not set.", + "TaskSpecificView: Cannot trigger update, currentViewId is not set." ); } } @@ -1165,7 +1165,7 @@ export class TaskSpecificView extends ItemView { private updateActionButtons() { // 移除过滤器重置按钮(如果存在) const resetButton = this.leaf.view.containerEl.querySelector( - ".view-action.task-filter-reset", + ".view-action.task-filter-reset" ); if (resetButton) { resetButton.remove(); @@ -1229,9 +1229,12 @@ export class TaskSpecificView extends ItemView { /** * Extract only the fields that have changed between two tasks */ - private extractChangedFields(originalTask: Task, updatedTask: Task): Partial { + private extractChangedFields( + originalTask: Task, + updatedTask: Task + ): Partial { const changes: Partial = {}; - + // Check top-level fields if (originalTask.content !== updatedTask.content) { changes.content = updatedTask.content; @@ -1242,22 +1245,35 @@ export class TaskSpecificView extends ItemView { if (originalTask.status !== updatedTask.status) { changes.status = updatedTask.status; } - + // Check metadata fields const metadataChanges: Partial = {}; let hasMetadataChanges = false; - + // Compare each metadata field - const metadataFields = ['priority', 'project', 'tags', 'context', 'dueDate', 'startDate', 'scheduledDate', 'completedDate', 'recurrence']; + const metadataFields = [ + "priority", + "project", + "tags", + "context", + "dueDate", + "startDate", + "scheduledDate", + "completedDate", + "recurrence", + ]; for (const field of metadataFields) { const originalValue = (originalTask.metadata as any)?.[field]; const updatedValue = (updatedTask.metadata as any)?.[field]; - + // Handle arrays specially (tags) - if (field === 'tags') { + if (field === "tags") { const origTags = originalValue || []; const updTags = updatedValue || []; - if (origTags.length !== updTags.length || !origTags.every((t: string, i: number) => t === updTags[i])) { + if ( + origTags.length !== updTags.length || + !origTags.every((t: string, i: number) => t === updTags[i]) + ) { metadataChanges.tags = updTags; hasMetadataChanges = true; } @@ -1266,12 +1282,12 @@ export class TaskSpecificView extends ItemView { hasMetadataChanges = true; } } - + // Only include metadata if there are changes if (hasMetadataChanges) { changes.metadata = metadataChanges as any; } - + return changes; } @@ -1288,13 +1304,16 @@ export class TaskSpecificView extends ItemView { originalTask.id, updatedTask.id, updatedTask, - originalTask, + originalTask ); try { // Extract only the changed fields - const updates = this.extractChangedFields(originalTask, updatedTask); - + const updates = this.extractChangedFields( + originalTask, + updatedTask + ); + // Always use WriteAPI with only the changed fields // Use originalTask.id to ensure we're updating the correct task const writeResult = await this.plugin.writeAPI.updateTask({ @@ -1310,7 +1329,7 @@ export class TaskSpecificView extends ItemView { } console.log( - `Task ${updatedTask.id} updated successfully via handleTaskUpdate.`, + `Task ${updatedTask.id} updated successfully via handleTaskUpdate.` ); // Update local task list immediately @@ -1321,7 +1340,7 @@ export class TaskSpecificView extends ItemView { this.tasks[index] = updatedTask; } else { console.warn( - "Updated task not found in local list, might reload.", + "Updated task not found in local list, might reload." ); } @@ -1348,7 +1367,7 @@ export class TaskSpecificView extends ItemView { private async updateTask( originalTask: Task, - updatedTask: Task, + updatedTask: Task ): Promise { if (!this.plugin.writeAPI) { console.error("WriteAPI not available for updateTask"); @@ -1356,8 +1375,11 @@ export class TaskSpecificView extends ItemView { } try { // Extract only the changed fields - const updates = this.extractChangedFields(originalTask, updatedTask); - + const updates = this.extractChangedFields( + originalTask, + updatedTask + ); + // Always use WriteAPI with only the changed fields // Use originalTask.id to ensure we're updating the correct task const writeResult = await this.plugin.writeAPI.updateTask({ @@ -1380,7 +1402,7 @@ export class TaskSpecificView extends ItemView { this.tasks[index] = updatedTask; } else { console.warn( - "Updated task not found in local list, might reload.", + "Updated task not found in local list, might reload." ); } @@ -1413,7 +1435,7 @@ export class TaskSpecificView extends ItemView { const existingLeaf = this.app.workspace .getLeavesOfType("markdown") .find( - (leaf) => (leaf.view as any).file === file, // Type assertion needed here + (leaf) => (leaf.view as any).file === file // Type assertion needed here ); const leafToUse = existingLeaf || this.app.workspace.getLeaf("tab"); // Open in new tab if not open @@ -1457,10 +1479,10 @@ export class TaskSpecificView extends ItemView { // Method to handle status updates originating from Kanban drag-and-drop private handleKanbanTaskStatusUpdate = async ( taskId: string, - newStatusMark: string, + newStatusMark: string ) => { console.log( - `TaskSpecificView handling Kanban status update request for ${taskId} to mark ${newStatusMark}`, + `TaskSpecificView handling Kanban status update request for ${taskId} to mark ${newStatusMark}` ); const taskToUpdate = this.tasks.find((t) => t.id === taskId); @@ -1492,22 +1514,22 @@ export class TaskSpecificView extends ItemView { // Use updateTask to ensure consistency and UI updates await this.updateTask(taskToUpdate, updatedTaskData); console.log( - `Task ${taskId} status update processed by TaskSpecificView.`, + `Task ${taskId} status update processed by TaskSpecificView.` ); } catch (error) { console.error( `TaskSpecificView failed to update task status from Kanban callback for task ${taskId}:`, - error, + error ); } } else { console.log( - `Task ${taskId} status (${newStatusMark}) already matches, no update needed.`, + `Task ${taskId} status (${newStatusMark}) already matches, no update needed.` ); } } else { console.warn( - `TaskSpecificView could not find task with ID ${taskId} for Kanban status update.`, + `TaskSpecificView could not find task with ID ${taskId} for Kanban status update.` ); } }; @@ -1519,7 +1541,7 @@ export class TaskSpecificView extends ItemView { this.currentFilterState = null; this.app.saveLocalStorage( `task-genius-view-filter-${this.leaf.id}`, - null, + null ); this.applyCurrentFilter(); this.updateActionButtons(); diff --git a/src/pages/TaskView.ts b/src/pages/TaskView.ts index c242584c..d442f8d5 100644 --- a/src/pages/TaskView.ts +++ b/src/pages/TaskView.ts @@ -158,8 +158,8 @@ export class TaskView extends ItemView { const { on, Events } = await import("../dataflow/events/Events"); this.registerEvent( on(this.app, Events.CACHE_READY, async () => { - // 冷启动就绪,从快照加载 - await this.loadTasksFast(true); + // 冷启动就绪,从快照加载,并更新视图 + await this.loadTasksFast(false); }) ); this.registerEvent(