mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 15:30:13 +01:00
parent
23860b1ee8
commit
66b444e2b0
4 changed files with 321 additions and 64 deletions
|
|
@ -160,9 +160,9 @@ class CardReceivedDate extends CardDate {
|
|||
const theDate = this.date.get();
|
||||
// if dueAt, endAt and startAt exist & are > receivedAt, receivedAt doesn't need to be flagged
|
||||
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';
|
||||
else classes += 'current';
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ BlazeComponent.extendComponent({
|
|||
dueCardsView() {
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('sort:', Utils.dueCardsView());
|
||||
return Utils.dueCardsView();
|
||||
return Utils && Utils.dueCardsView ? Utils.dueCardsView() : 'me';
|
||||
},
|
||||
|
||||
events() {
|
||||
|
|
@ -38,12 +38,16 @@ BlazeComponent.extendComponent({
|
|||
return [
|
||||
{
|
||||
'click .js-due-cards-view-me'() {
|
||||
if (Utils && Utils.setDueCardsView) {
|
||||
Utils.setDueCardsView('me');
|
||||
}
|
||||
Popup.back();
|
||||
},
|
||||
|
||||
'click .js-due-cards-view-all'() {
|
||||
if (Utils && Utils.setDueCardsView) {
|
||||
Utils.setDueCardsView('all');
|
||||
}
|
||||
Popup.back();
|
||||
},
|
||||
},
|
||||
|
|
@ -55,6 +59,37 @@ class DueCardsComponent extends CardSearchPagedComponent {
|
|||
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();
|
||||
queryParams.addPredicate(OPERATOR_HAS, {
|
||||
field: PREDICATE_DUE_AT,
|
||||
|
|
@ -66,8 +101,22 @@ class DueCardsComponent extends CardSearchPagedComponent {
|
|||
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);
|
||||
|
|
@ -76,7 +125,7 @@ class DueCardsComponent extends CardSearchPagedComponent {
|
|||
dueCardsView() {
|
||||
// eslint-disable-next-line no-console
|
||||
//console.log('sort:', Utils.dueCardsView());
|
||||
return Utils.dueCardsView();
|
||||
return Utils && Utils.dueCardsView ? Utils.dueCardsView() : 'me';
|
||||
}
|
||||
|
||||
sortByBoard() {
|
||||
|
|
|
|||
|
|
@ -29,21 +29,86 @@ export class CardSearchPagedComponent extends BlazeComponent {
|
|||
const that = this;
|
||||
this.subscriptionCallbacks = {
|
||||
onReady() {
|
||||
that.getResults();
|
||||
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);
|
||||
},
|
||||
onError(error) {
|
||||
} 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) {
|
||||
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.hasResults.set(false);
|
||||
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) {
|
||||
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() {
|
||||
|
|
@ -72,24 +156,66 @@ export class CardSearchPagedComponent extends BlazeComponent {
|
|||
// console.log('getting results');
|
||||
this.sessionData = this.getSessionData();
|
||||
// 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 = [];
|
||||
|
||||
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 => {
|
||||
cards.push(ReactiveCache.getCard(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;
|
||||
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) {
|
||||
// console.log('queryErrors:', this.queryErrorMessages());
|
||||
this.hasQueryErrors.set(true);
|
||||
// return null;
|
||||
}
|
||||
this.debug.set(new QueryDebug(this.sessionData.debug));
|
||||
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) {
|
||||
this.totalHits = this.sessionData.totalHits;
|
||||
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;
|
||||
|
|
@ -99,6 +225,16 @@ export class CardSearchPagedComponent extends BlazeComponent {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
@ -113,13 +249,29 @@ export class CardSearchPagedComponent extends BlazeComponent {
|
|||
}
|
||||
|
||||
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',
|
||||
this.sessionId,
|
||||
queryParams.params,
|
||||
queryParams.text,
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -147,13 +147,31 @@ Meteor.publish('globalSearch', function(sessionId, params, text) {
|
|||
check(params, Object);
|
||||
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)));
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log('globalSearch publication returning:', 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) {
|
||||
const userId = Meteor.userId();
|
||||
|
||||
|
|
@ -261,8 +279,12 @@ function buildSelector(queryParams) {
|
|||
selector.archived = false;
|
||||
}
|
||||
} else {
|
||||
const userBoardIds = Boards.userBoardIds(userId, null, boardsSelector);
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log('buildSelector - userBoardIds:', userBoardIds);
|
||||
}
|
||||
selector.boardId = {
|
||||
$in: Boards.userBoardIds(userId, null, boardsSelector),
|
||||
$in: userBoardIds,
|
||||
};
|
||||
}
|
||||
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();
|
||||
query.selector = selector;
|
||||
|
|
@ -702,14 +725,17 @@ function findCards(sessionId, query) {
|
|||
const userId = Meteor.userId();
|
||||
|
||||
// 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);
|
||||
// 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 = {
|
||||
$set: {
|
||||
|
|
@ -720,7 +746,8 @@ function findCards(sessionId, query) {
|
|||
selector: SessionData.pickle(query.selector),
|
||||
projection: SessionData.pickle(query.projection),
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
SessionData.remove({
|
||||
|
|
@ -793,6 +829,21 @@ function findCards(sessionId, query) {
|
|||
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 [
|
||||
cards,
|
||||
ReactiveCache.getBoards(
|
||||
|
|
@ -812,9 +863,14 @@ function findCards(sessionId, query) {
|
|||
ReactiveCache.getChecklistItems({ cardId: { $in: cards.map(c => c._id) } }, {}, true),
|
||||
ReactiveCache.getAttachments({ 'meta.cardId': { $in: cards.map(c => c._id) } }, {}, true).cursor,
|
||||
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];
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue