Browse Source

Fix unable to see My Due Cards.

Thanks to xet7 !

Fixes #5948
Lauri Ojansivu 4 days ago
parent
commit
66b444e2b0

+ 3 - 3
client/components/cards/cardDate.js

@@ -160,9 +160,9 @@ class CardReceivedDate extends CardDate {
     const theDate = this.date.get();
     const theDate = this.date.get();
     // if dueAt, endAt and startAt exist & are > receivedAt, receivedAt doesn't need to be flagged
     // if dueAt, endAt and startAt exist & are > receivedAt, receivedAt doesn't need to be flagged
     if (
     if (
-      (startAt && theDate.isAfter(startAt)) ||
-      (endAt && theDate.isAfter(endAt)) ||
-      (dueAt && theDate.isAfter(dueAt))
+      (startAt && isAfter(theDate, startAt)) ||
+      (endAt && isAfter(theDate, endAt)) ||
+      (dueAt && isAfter(theDate, dueAt))
     )
     )
       classes += 'long-overdue';
       classes += 'long-overdue';
     else classes += 'current';
     else classes += 'current';

+ 57 - 8
client/components/main/dueCards.js

@@ -15,7 +15,7 @@ BlazeComponent.extendComponent({
   dueCardsView() {
   dueCardsView() {
     // eslint-disable-next-line no-console
     // eslint-disable-next-line no-console
     // console.log('sort:', Utils.dueCardsView());
     // console.log('sort:', Utils.dueCardsView());
-    return Utils.dueCardsView();
+    return Utils && Utils.dueCardsView ? Utils.dueCardsView() : 'me';
   },
   },
 
 
   events() {
   events() {
@@ -38,12 +38,16 @@ BlazeComponent.extendComponent({
     return [
     return [
       {
       {
         'click .js-due-cards-view-me'() {
         'click .js-due-cards-view-me'() {
-          Utils.setDueCardsView('me');
+          if (Utils && Utils.setDueCardsView) {
+            Utils.setDueCardsView('me');
+          }
           Popup.back();
           Popup.back();
         },
         },
 
 
         'click .js-due-cards-view-all'() {
         'click .js-due-cards-view-all'() {
-          Utils.setDueCardsView('all');
+          if (Utils && Utils.setDueCardsView) {
+            Utils.setDueCardsView('all');
+          }
           Popup.back();
           Popup.back();
         },
         },
       },
       },
@@ -54,7 +58,38 @@ BlazeComponent.extendComponent({
 class DueCardsComponent extends CardSearchPagedComponent {
 class DueCardsComponent extends CardSearchPagedComponent {
   onCreated() {
   onCreated() {
     super.onCreated();
     super.onCreated();
-
+    
+    // Add a small delay to ensure ReactiveCache is ready
+    this.searchRetryCount = 0;
+    this.maxRetries = 3;
+    
+    // Use a timeout to ensure the search runs after the component is fully initialized
+    Meteor.setTimeout(() => {
+      this.performSearch();
+    }, 100);
+  }
+  
+  performSearch() {
+    if (process.env.DEBUG === 'true') {
+      console.log('Performing due cards search, attempt:', this.searchRetryCount + 1);
+    }
+    
+    // Check if user is authenticated
+    const currentUser = ReactiveCache.getCurrentUser();
+    if (!currentUser) {
+      if (process.env.DEBUG === 'true') {
+        console.log('User not authenticated, waiting...');
+      }
+      Meteor.setTimeout(() => {
+        this.performSearch();
+      }, 1000);
+      return;
+    }
+    
+    if (process.env.DEBUG === 'true') {
+      console.log('User authenticated:', currentUser.username);
+    }
+    
     const queryParams = new QueryParams();
     const queryParams = new QueryParams();
     queryParams.addPredicate(OPERATOR_HAS, {
     queryParams.addPredicate(OPERATOR_HAS, {
       field: PREDICATE_DUE_AT,
       field: PREDICATE_DUE_AT,
@@ -66,17 +101,31 @@ class DueCardsComponent extends CardSearchPagedComponent {
       order: ORDER_ASCENDING,
       order: ORDER_ASCENDING,
     });
     });
 
 
-    if (Utils.dueCardsView() !== 'all') {
-      queryParams.addPredicate(OPERATOR_USER, ReactiveCache.getCurrentUser().username);
+    // Note: User filtering is handled server-side based on board membership
+    // The OPERATOR_USER filter is too restrictive as it only shows cards where
+    // the user is assigned or a member of the card, not the board
+    // if (Utils && Utils.dueCardsView && Utils.dueCardsView() !== 'all') {
+    //   const currentUser = ReactiveCache.getCurrentUser();
+    //   if (currentUser && currentUser.username) {
+    //     queryParams.addPredicate(OPERATOR_USER, currentUser.username);
+    //   }
+    // }
+
+    // Debug: Log the query parameters
+    if (process.env.DEBUG === 'true') {
+      console.log('Due cards query params:', queryParams.params);
+      console.log('Due cards query text:', queryParams.text);
+      console.log('Due cards has predicates:', queryParams.getPredicates('has'));
+      console.log('Due cards sort predicates:', queryParams.getPredicates('sort'));
     }
     }
-
+    
     this.runGlobalSearch(queryParams);
     this.runGlobalSearch(queryParams);
   }
   }
 
 
   dueCardsView() {
   dueCardsView() {
     // eslint-disable-next-line no-console
     // eslint-disable-next-line no-console
     //console.log('sort:', Utils.dueCardsView());
     //console.log('sort:', Utils.dueCardsView());
-    return Utils.dueCardsView();
+    return Utils && Utils.dueCardsView ? Utils.dueCardsView() : 'me';
   }
   }
 
 
   sortByBoard() {
   sortByBoard() {

+ 184 - 32
client/lib/cardSearch.js

@@ -29,21 +29,86 @@ export class CardSearchPagedComponent extends BlazeComponent {
     const that = this;
     const that = this;
     this.subscriptionCallbacks = {
     this.subscriptionCallbacks = {
       onReady() {
       onReady() {
-        that.getResults();
-        that.searching.set(false);
-        that.hasResults.set(true);
-        that.serverError.set(false);
+        if (process.env.DEBUG === 'true') {
+          console.log('Subscription ready, getting results...');
+          console.log('Subscription ready - sessionId:', that.sessionId);
+        }
+        
+        // Wait for session data to be available (with timeout)
+        let waitCount = 0;
+        const maxWaitCount = 50; // 10 seconds max wait
+        
+        const waitForSessionData = () => {
+          waitCount++;
+          const sessionData = that.getSessionData();
+          if (process.env.DEBUG === 'true') {
+            console.log('waitForSessionData - attempt', waitCount, 'session data:', sessionData);
+          }
+          
+          if (sessionData) {
+            const results = that.getResults();
+            if (process.env.DEBUG === 'true') {
+              console.log('Search results count:', results ? results.length : 0);
+            }
+            
+            // If no results and this is a due cards search, try to retry
+            if ((!results || results.length === 0) && that.searchRetryCount !== undefined && that.searchRetryCount < that.maxRetries) {
+              if (process.env.DEBUG === 'true') {
+                console.log('No results found, retrying search...');
+              }
+              that.searchRetryCount++;
+              Meteor.setTimeout(() => {
+                if (that.performSearch) {
+                  that.performSearch();
+                }
+              }, 500);
+              return;
+            }
+            
+            that.searching.set(false);
+            that.hasResults.set(true);
+            that.serverError.set(false);
+             } else if (waitCount < maxWaitCount) {
+               // Session data not available yet, wait a bit more
+               if (process.env.DEBUG === 'true') {
+                 console.log('Session data not available yet, waiting... (attempt', waitCount, 'of', maxWaitCount, ')');
+               }
+               Meteor.setTimeout(waitForSessionData, 200);
+             } else {
+               // Timeout reached, try fallback search
+               if (process.env.DEBUG === 'true') {
+                 console.log('Timeout reached waiting for session data, trying fallback search');
+               }
+               const results = that.getResults();
+               if (process.env.DEBUG === 'true') {
+                 console.log('Fallback search results count:', results ? results.length : 0);
+               }
+               
+               if (results && results.length > 0) {
+                 that.searching.set(false);
+                 that.hasResults.set(true);
+                 that.serverError.set(false);
+               } else {
+                 that.searching.set(false);
+                 that.hasResults.set(false);
+                 that.serverError.set(true);
+               }
+             }
+        };
+        
+        // Start waiting for session data
+        Meteor.setTimeout(waitForSessionData, 100);
       },
       },
       onError(error) {
       onError(error) {
+        if (process.env.DEBUG === 'true') {
+          console.log('Subscription error:', error);
+          console.log('Error.reason:', error.reason);
+          console.log('Error.message:', error.message);
+          console.log('Error.stack:', error.stack);
+        }
         that.searching.set(false);
         that.searching.set(false);
         that.hasResults.set(false);
         that.hasResults.set(false);
         that.serverError.set(true);
         that.serverError.set(true);
-        // eslint-disable-next-line no-console
-        //console.log('Error.reason:', error.reason);
-        // eslint-disable-next-line no-console
-        //console.log('Error.message:', error.message);
-        // eslint-disable-next-line no-console
-        //console.log('Error.stack:', error.stack);
       },
       },
     };
     };
   }
   }
@@ -62,9 +127,28 @@ export class CardSearchPagedComponent extends BlazeComponent {
   }
   }
 
 
   getSessionData(sessionId) {
   getSessionData(sessionId) {
-    return ReactiveCache.getSessionData({
-      sessionId: sessionId || SessionData.getSessionId(),
+    const sessionIdToUse = sessionId || SessionData.getSessionId();
+    if (process.env.DEBUG === 'true') {
+      console.log('getSessionData - looking for sessionId:', sessionIdToUse);
+    }
+    
+    // Try using the raw SessionData collection instead of ReactiveCache
+    const sessionData = SessionData.findOne({
+      sessionId: sessionIdToUse,
     });
     });
+    if (process.env.DEBUG === 'true') {
+      console.log('getSessionData - found session data (raw):', sessionData);
+    }
+    
+    // Also try ReactiveCache for comparison
+    const reactiveSessionData = ReactiveCache.getSessionData({
+      sessionId: sessionIdToUse,
+    });
+    if (process.env.DEBUG === 'true') {
+      console.log('getSessionData - found session data (reactive):', reactiveSessionData);
+    }
+    
+    return sessionData || reactiveSessionData;
   }
   }
 
 
   getResults() {
   getResults() {
@@ -72,33 +156,85 @@ export class CardSearchPagedComponent extends BlazeComponent {
     // console.log('getting results');
     // console.log('getting results');
     this.sessionData = this.getSessionData();
     this.sessionData = this.getSessionData();
     // eslint-disable-next-line no-console
     // eslint-disable-next-line no-console
-    console.log('session data:', this.sessionData);
+    if (process.env.DEBUG === 'true') {
+      console.log('getResults - sessionId:', this.sessionId);
+      console.log('getResults - session data:', this.sessionData);
+    }
     const cards = [];
     const cards = [];
-    this.sessionData.cards.forEach(cardId => {
-      cards.push(ReactiveCache.getCard(cardId));
-    });
-    this.queryErrors = this.sessionData.errors;
+    
+    if (this.sessionData && this.sessionData.cards) {
+      if (process.env.DEBUG === 'true') {
+        console.log('getResults - cards array length:', this.sessionData.cards.length);
+      }
+      this.sessionData.cards.forEach(cardId => {
+        const card = ReactiveCache.getCard(cardId);
+        if (process.env.DEBUG === 'true') {
+          console.log('getResults - card:', cardId, card);
+        }
+        cards.push(card);
+      });
+      this.queryErrors = this.sessionData.errors || [];
+    } else {
+      if (process.env.DEBUG === 'true') {
+        console.log('getResults - no sessionData or no cards array, trying direct card search');
+      }
+      // Fallback: try to get cards directly from the client-side collection
+      const selector = {
+        type: 'cardType-card',
+        dueAt: { $exists: true, $nin: [null, ''] }
+      };
+      const allCards = Cards.find(selector).fetch();
+      if (process.env.DEBUG === 'true') {
+        console.log('getResults - direct card search found:', allCards ? allCards.length : 0, 'cards');
+      }
+      
+      if (allCards && allCards.length > 0) {
+        allCards.forEach(card => {
+          if (card && card._id) {
+            if (process.env.DEBUG === 'true') {
+              console.log('getResults - direct card:', card._id, card.title);
+            }
+            cards.push(card);
+          }
+        });
+      }
+      
+      this.queryErrors = [];
+    }
     if (this.queryErrors.length) {
     if (this.queryErrors.length) {
       // console.log('queryErrors:', this.queryErrorMessages());
       // console.log('queryErrors:', this.queryErrorMessages());
       this.hasQueryErrors.set(true);
       this.hasQueryErrors.set(true);
       // return null;
       // return null;
     }
     }
-    this.debug.set(new QueryDebug(this.sessionData.debug));
-    console.log('debug:', this.debug.get().get());
-    console.log('debug.show():', this.debug.get().show());
-    console.log('debug.showSelector():', this.debug.get().showSelector());
+    this.debug.set(new QueryDebug(this.sessionData ? this.sessionData.debug : null));
+    if (process.env.DEBUG === 'true') {
+      console.log('debug:', this.debug.get().get());
+      console.log('debug.show():', this.debug.get().show());
+      console.log('debug.showSelector():', this.debug.get().showSelector());
+    }
 
 
     if (cards) {
     if (cards) {
-      this.totalHits = this.sessionData.totalHits;
-      this.resultsCount = cards.length;
-      this.resultsStart = this.sessionData.lastHit - this.resultsCount + 1;
-      this.resultsEnd = this.sessionData.lastHit;
-      this.resultsHeading.set(this.getResultsHeading());
-      this.results.set(cards);
-      this.hasNextPage.set(this.sessionData.lastHit < this.sessionData.totalHits);
-      this.hasPreviousPage.set(
-        this.sessionData.lastHit - this.sessionData.resultsCount > 0,
-      );
+      if (this.sessionData) {
+        this.totalHits = this.sessionData.totalHits || 0;
+        this.resultsCount = cards.length;
+        this.resultsStart = this.sessionData.lastHit - this.resultsCount + 1;
+        this.resultsEnd = this.sessionData.lastHit;
+        this.resultsHeading.set(this.getResultsHeading());
+        this.results.set(cards);
+        this.hasNextPage.set(this.sessionData.lastHit < this.sessionData.totalHits);
+        this.hasPreviousPage.set(
+          this.sessionData.lastHit - this.sessionData.resultsCount > 0,
+        );
+      } else {
+        this.totalHits = cards.length;
+        this.resultsCount = cards.length;
+        this.resultsStart = 1;
+        this.resultsEnd = cards.length;
+        this.resultsHeading.set(this.getResultsHeading());
+        this.results.set(cards);
+        this.hasNextPage.set(false);
+        this.hasPreviousPage.set(false);
+      }
       return cards;
       return cards;
     }
     }
 
 
@@ -113,13 +249,29 @@ export class CardSearchPagedComponent extends BlazeComponent {
   }
   }
 
 
   getSubscription(queryParams) {
   getSubscription(queryParams) {
-    return Meteor.subscribe(
+    if (process.env.DEBUG === 'true') {
+      console.log('Subscribing to globalSearch with:', {
+        sessionId: this.sessionId,
+        params: queryParams.params,
+        text: queryParams.text
+      });
+    }
+
+    // Subscribe to both globalSearch and sessionData
+    const globalSearchHandle = Meteor.subscribe(
       'globalSearch',
       'globalSearch',
       this.sessionId,
       this.sessionId,
       queryParams.params,
       queryParams.params,
       queryParams.text,
       queryParams.text,
       this.subscriptionCallbacks,
       this.subscriptionCallbacks,
     );
     );
+    
+    const sessionDataHandle = Meteor.subscribe('sessionData', this.sessionId);
+    if (process.env.DEBUG === 'true') {
+      console.log('Subscribed to sessionData with sessionId:', this.sessionId);
+    }
+
+    return globalSearchHandle;
   }
   }
 
 
   runGlobalSearch(queryParams) {
   runGlobalSearch(queryParams) {

+ 77 - 21
server/publications/cards.js

@@ -147,13 +147,31 @@ Meteor.publish('globalSearch', function(sessionId, params, text) {
   check(params, Object);
   check(params, Object);
   check(text, String);
   check(text, String);
 
 
-  // eslint-disable-next-line no-console
-  // console.log('queryParams:', params);
+  if (process.env.DEBUG === 'true') {
+    console.log('globalSearch publication called with:', { sessionId, params, text });
+  }
 
 
   const ret = findCards(sessionId, buildQuery(new QueryParams(params, text)));
   const ret = findCards(sessionId, buildQuery(new QueryParams(params, text)));
+  if (process.env.DEBUG === 'true') {
+    console.log('globalSearch publication returning:', ret);
+  }
   return ret;
   return ret;
 });
 });
 
 
+Meteor.publish('sessionData', function(sessionId) {
+  check(sessionId, String);
+  const userId = Meteor.userId();
+  if (process.env.DEBUG === 'true') {
+    console.log('sessionData publication called with:', { sessionId, userId });
+  }
+  
+  const cursor = SessionData.find({ userId, sessionId });
+  if (process.env.DEBUG === 'true') {
+    console.log('sessionData publication returning cursor with count:', cursor.count());
+  }
+  return cursor;
+});
+
 function buildSelector(queryParams) {
 function buildSelector(queryParams) {
   const userId = Meteor.userId();
   const userId = Meteor.userId();
 
 
@@ -261,8 +279,12 @@ function buildSelector(queryParams) {
         selector.archived = false;
         selector.archived = false;
       }
       }
     } else {
     } else {
+      const userBoardIds = Boards.userBoardIds(userId, null, boardsSelector);
+      if (process.env.DEBUG === 'true') {
+        console.log('buildSelector - userBoardIds:', userBoardIds);
+      }
       selector.boardId = {
       selector.boardId = {
-        $in: Boards.userBoardIds(userId, null, boardsSelector),
+        $in: userBoardIds,
       };
       };
     }
     }
     if (endAt !== null) {
     if (endAt !== null) {
@@ -537,8 +559,9 @@ function buildSelector(queryParams) {
     }
     }
   }
   }
 
 
-  // eslint-disable-next-line no-console
-  // console.log('cards selector:', JSON.stringify(selector, null, 2));
+  if (process.env.DEBUG === 'true') {
+    console.log('buildSelector - final selector:', JSON.stringify(selector, null, 2));
+  }
 
 
   const query = new Query();
   const query = new Query();
   query.selector = selector;
   query.selector = selector;
@@ -702,14 +725,17 @@ function findCards(sessionId, query) {
   const userId = Meteor.userId();
   const userId = Meteor.userId();
 
 
   // eslint-disable-next-line no-console
   // eslint-disable-next-line no-console
-  // console.log('selector:', query.selector);
-  // console.log('selector.$and:', query.selector.$and);
-  // eslint-disable-next-line no-console
-  // console.log('projection:', query.projection);
+  if (process.env.DEBUG === 'true') {
+    console.log('findCards - userId:', userId);
+    console.log('findCards - selector:', JSON.stringify(query.selector, null, 2));
+    console.log('findCards - selector.$and:', query.selector.$and);
+    console.log('findCards - projection:', query.projection);
+  }
 
 
   const cards = ReactiveCache.getCards(query.selector, query.projection, true);
   const cards = ReactiveCache.getCards(query.selector, query.projection, true);
-  // eslint-disable-next-line no-console
-  // console.log('count:', cards.count());
+  if (process.env.DEBUG === 'true') {
+    console.log('findCards - cards count:', cards ? cards.count() : 0);
+  }
 
 
   const update = {
   const update = {
     $set: {
     $set: {
@@ -720,7 +746,8 @@ function findCards(sessionId, query) {
       selector: SessionData.pickle(query.selector),
       selector: SessionData.pickle(query.selector),
       projection: SessionData.pickle(query.projection),
       projection: SessionData.pickle(query.projection),
       errors: query.errors(),
       errors: query.errors(),
-      debug: query.getQueryParams().getPredicate(OPERATOR_DEBUG)
+      debug: query.getQueryParams().getPredicate(OPERATOR_DEBUG),
+      modifiedAt: new Date()
     },
     },
   };
   };
 
 
@@ -736,13 +763,22 @@ function findCards(sessionId, query) {
     update.$set.resultsCount = update.$set.cards.length;
     update.$set.resultsCount = update.$set.cards.length;
   }
   }
 
 
-  // eslint-disable-next-line no-console
-  // console.log('sessionId:', sessionId);
-  // eslint-disable-next-line no-console
-  // console.log('userId:', userId);
-  // eslint-disable-next-line no-console
-  // console.log('update:', update);
-  SessionData.upsert({ userId, sessionId }, update);
+  if (process.env.DEBUG === 'true') {
+    console.log('findCards - sessionId:', sessionId);
+    console.log('findCards - userId:', userId);
+    console.log('findCards - update:', JSON.stringify(update, null, 2));
+  }
+  const upsertResult = SessionData.upsert({ userId, sessionId }, update);
+  if (process.env.DEBUG === 'true') {
+    console.log('findCards - upsertResult:', upsertResult);
+  }
+  
+  // Check if the session data was actually stored
+  const storedSessionData = SessionData.findOne({ userId, sessionId });
+  if (process.env.DEBUG === 'true') {
+    console.log('findCards - stored session data:', storedSessionData);
+    console.log('findCards - stored session data count:', storedSessionData ? 1 : 0);
+  }
 
 
   // remove old session data
   // remove old session data
   SessionData.remove({
   SessionData.remove({
@@ -793,6 +829,21 @@ function findCards(sessionId, query) {
       type: 1,
       type: 1,
     };
     };
 
 
+  // Add a small delay to ensure the session data is committed to the database
+  Meteor.setTimeout(() => {
+    const sessionDataCursor = SessionData.find({ userId, sessionId });
+    if (process.env.DEBUG === 'true') {
+      console.log('findCards - publishing session data cursor (after delay):', sessionDataCursor);
+      console.log('findCards - session data count (after delay):', sessionDataCursor.count());
+    }
+  }, 100);
+  
+  const sessionDataCursor = SessionData.find({ userId, sessionId });
+  if (process.env.DEBUG === 'true') {
+    console.log('findCards - publishing session data cursor:', sessionDataCursor);
+    console.log('findCards - session data count:', sessionDataCursor.count());
+  }
+
     return [
     return [
       cards,
       cards,
       ReactiveCache.getBoards(
       ReactiveCache.getBoards(
@@ -812,9 +863,14 @@ function findCards(sessionId, query) {
       ReactiveCache.getChecklistItems({ cardId: { $in: cards.map(c => c._id) } }, {}, true),
       ReactiveCache.getChecklistItems({ cardId: { $in: cards.map(c => c._id) } }, {}, true),
       ReactiveCache.getAttachments({ 'meta.cardId': { $in: cards.map(c => c._id) } }, {}, true).cursor,
       ReactiveCache.getAttachments({ 'meta.cardId': { $in: cards.map(c => c._id) } }, {}, true).cursor,
       ReactiveCache.getCardComments({ cardId: { $in: cards.map(c => c._id) } }, {}, true),
       ReactiveCache.getCardComments({ cardId: { $in: cards.map(c => c._id) } }, {}, true),
-      SessionData.find({ userId, sessionId }),
+      sessionDataCursor,
     ];
     ];
   }
   }
 
 
-  return [SessionData.find({ userId, sessionId })];
+  const sessionDataCursor = SessionData.find({ userId, sessionId });
+  if (process.env.DEBUG === 'true') {
+    console.log('findCards - publishing session data cursor (no cards):', sessionDataCursor);
+    console.log('findCards - session data count (no cards):', sessionDataCursor.count());
+  }
+  return [sessionDataCursor];
 }
 }