@@ -26,6 +26,9 @@ export interface ViewConfig {
2626export function buildTasknotesBaseViewFactory ( plugin : TaskNotesPlugin , config : ViewConfig ) {
2727 return function tasknotesBaseViewFactory ( basesContainer : BasesContainerLike ) {
2828 let currentRoot : HTMLElement | null = null ;
29+ let eventListener : any = null ;
30+ let updateDebounceTimer : number | null = null ;
31+ let currentTaskElements = new Map < string , HTMLElement > ( ) ;
2932
3033 const viewContainerEl = ( basesContainer as any ) ?. viewContainerEl as HTMLElement | undefined ;
3134 if ( ! viewContainerEl ) {
@@ -144,7 +147,9 @@ export function buildTasknotesBaseViewFactory(plugin: TaskNotesPlugin, config: V
144147 }
145148
146149 // Render tasks using existing helper
147- await renderTaskNotesInBasesView ( itemsContainer , taskNotes , plugin , basesContainer ) ;
150+ // Clear existing task elements tracking before re-render
151+ currentTaskElements . clear ( ) ;
152+ await renderTaskNotesInBasesView ( itemsContainer , taskNotes , plugin , basesContainer , currentTaskElements ) ;
148153 }
149154 } catch ( error : any ) {
150155 console . error ( `[TaskNotes][BasesPOC] Error rendering Bases ${ config . errorPrefix } :` , error ) ;
@@ -156,9 +161,88 @@ export function buildTasknotesBaseViewFactory(plugin: TaskNotesPlugin, config: V
156161 }
157162 } ;
158163
164+ // Setup selective update handling for real-time task changes
165+ const setupTaskUpdateListener = ( ) => {
166+ if ( ! eventListener ) {
167+ const { EVENT_TASK_UPDATED } = require ( '../types' ) ;
168+ eventListener = plugin . emitter . on ( EVENT_TASK_UPDATED , async ( eventData : any ) => {
169+ try {
170+ const updatedTask = eventData ?. task || eventData ?. taskInfo ;
171+ if ( ! updatedTask || ! updatedTask . path ) return ;
172+
173+ // Check if this task affects our current Bases view
174+ const currentTasks = extractDataItems ( ) ;
175+ const relevantTask = currentTasks . find ( item => item . path === updatedTask . path ) ;
176+
177+ if ( relevantTask ) {
178+ // Task is visible in this Bases view - perform selective update
179+ await selectiveUpdateTaskInBasesView ( updatedTask ) ;
180+ }
181+ } catch ( error ) {
182+ console . error ( '[TaskNotes][Bases] Error in selective task update:' , error ) ;
183+ // Fallback to full refresh
184+ debouncedFullRefresh ( ) ;
185+ }
186+ } ) ;
187+ }
188+ } ;
189+
190+ // Selective update for a single task within Bases view
191+ const selectiveUpdateTaskInBasesView = async ( updatedTask : any ) => {
192+ if ( ! currentRoot ) return ;
193+
194+ try {
195+ const taskElement = currentTaskElements . get ( updatedTask . path ) ;
196+ if ( taskElement ) {
197+ // Update existing task element
198+ const { updateTaskCard } = await import ( '../ui/TaskCard' ) ;
199+ const basesProperties = ( basesContainer as any ) ?. ctx ?. formulas ?
200+ Object . keys ( ( basesContainer as any ) . ctx . formulas ) : [ ] ;
201+
202+ updateTaskCard ( taskElement , updatedTask , plugin , basesProperties , {
203+ showDueDate : true ,
204+ showCheckbox : false ,
205+ showArchiveButton : false ,
206+ showTimeTracking : false ,
207+ showRecurringControls : true ,
208+ } ) ;
209+
210+ // Add update animation
211+ taskElement . classList . add ( 'task-card--updated' ) ;
212+ window . setTimeout ( ( ) => {
213+ taskElement . classList . remove ( 'task-card--updated' ) ;
214+ } , 1000 ) ;
215+
216+ console . log ( `[TaskNotes][Bases] Selectively updated task: ${ updatedTask . path } ` ) ;
217+ } else {
218+ // Task not currently visible, might need to be added - refresh to be safe
219+ debouncedFullRefresh ( ) ;
220+ }
221+ } catch ( error ) {
222+ console . error ( '[TaskNotes][Bases] Error in selective task update:' , error ) ;
223+ debouncedFullRefresh ( ) ;
224+ }
225+ } ;
226+
227+ // Debounced refresh to prevent multiple rapid refreshes
228+ const debouncedFullRefresh = ( ) => {
229+ if ( updateDebounceTimer ) {
230+ clearTimeout ( updateDebounceTimer ) ;
231+ }
232+
233+ updateDebounceTimer = window . setTimeout ( async ( ) => {
234+ console . log ( '[TaskNotes][Bases] Performing debounced full refresh' ) ;
235+ await render ( ) ;
236+ updateDebounceTimer = null ;
237+ } , 150 ) ;
238+ } ;
239+
159240 // Kick off initial async render
160241 void render ( ) ;
161242
243+ // Setup real-time updates
244+ setupTaskUpdateListener ( ) ;
245+
162246 // Create view object with proper listener management
163247 let queryListener : ( ( ) => void ) | null = null ;
164248
@@ -179,18 +263,36 @@ export function buildTasknotesBaseViewFactory(plugin: TaskNotesPlugin, config: V
179263 }
180264 } ,
181265 destroy : ( ) => {
266+ // Clean up task update listener
267+ if ( eventListener ) {
268+ plugin . emitter . offref ( eventListener ) ;
269+ eventListener = null ;
270+ }
271+
272+ // Clean up debounce timer
273+ if ( updateDebounceTimer ) {
274+ clearTimeout ( updateDebounceTimer ) ;
275+ updateDebounceTimer = null ;
276+ }
277+
278+ // Clean up query listener
182279 if ( queryListener && ( basesContainer as any ) ?. query ?. off ) {
183280 try {
184281 ( basesContainer as any ) . query . off ( 'change' , queryListener ) ;
185282 } catch ( e ) {
186283 // Query listener removal may fail if already disposed
187284 }
188285 }
286+
287+ // Clean up DOM and state
189288 if ( currentRoot ) {
190289 currentRoot . remove ( ) ;
191290 currentRoot = null ;
192291 }
292+ currentTaskElements . clear ( ) ;
193293 queryListener = null ;
294+
295+ console . log ( '[TaskNotes][Bases] Cleaned up view with real-time updates' ) ;
194296 } ,
195297 load : ( ) => {
196298 if ( ( basesContainer as any ) ?. query ?. on && ! queryListener ) {
0 commit comments