mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 15:30:13 +01:00
353 lines
11 KiB
JavaScript
353 lines
11 KiB
JavaScript
import { ReactiveCache } from '/imports/reactiveCache';
|
|
import { TAPi18n } from '/imports/i18n';
|
|
import Cards from '../../models/cards';
|
|
import SessionData from '../../models/usersessiondata';
|
|
import {QueryDebug} from "../../config/query-classes";
|
|
import {OPERATOR_DEBUG} from "../../config/search-const";
|
|
|
|
export class CardSearchPagedComponent extends BlazeComponent {
|
|
onCreated() {
|
|
this.searching = new ReactiveVar(false);
|
|
this.hasResults = new ReactiveVar(false);
|
|
this.hasQueryErrors = new ReactiveVar(false);
|
|
this.query = new ReactiveVar('');
|
|
this.resultsHeading = new ReactiveVar('');
|
|
this.searchLink = new ReactiveVar(null);
|
|
this.results = new ReactiveVar([]);
|
|
this.hasNextPage = new ReactiveVar(false);
|
|
this.hasPreviousPage = new ReactiveVar(false);
|
|
this.resultsCount = 0;
|
|
this.totalHits = 0;
|
|
this.queryErrors = null;
|
|
this.resultsPerPage = 25;
|
|
this.sessionId = SessionData.getSessionId();
|
|
this.subscriptionHandle = null;
|
|
this.serverError = new ReactiveVar(false);
|
|
this.sessionData = null;
|
|
this.debug = new ReactiveVar(new QueryDebug());
|
|
|
|
const that = this;
|
|
this.subscriptionCallbacks = {
|
|
onReady() {
|
|
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) {
|
|
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);
|
|
},
|
|
};
|
|
}
|
|
|
|
resetSearch() {
|
|
this.searching.set(false);
|
|
this.results.set([]);
|
|
this.hasResults.set(false);
|
|
this.hasQueryErrors.set(false);
|
|
this.resultsHeading.set('');
|
|
this.serverError.set(false);
|
|
this.resultsCount = 0;
|
|
this.totalHits = 0;
|
|
this.queryErrors = null;
|
|
this.debug.set(new QueryDebug());
|
|
}
|
|
|
|
getSessionData(sessionId) {
|
|
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() {
|
|
// eslint-disable-next-line no-console
|
|
// console.log('getting results');
|
|
this.sessionData = this.getSessionData();
|
|
// eslint-disable-next-line no-console
|
|
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 => {
|
|
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) {
|
|
// console.log('queryErrors:', this.queryErrorMessages());
|
|
this.hasQueryErrors.set(true);
|
|
// return null;
|
|
}
|
|
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 (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;
|
|
}
|
|
|
|
this.resultsCount = 0;
|
|
return null;
|
|
}
|
|
|
|
stopSubscription() {
|
|
if (this.subscriptionHandle) {
|
|
this.subscriptionHandle.stop();
|
|
}
|
|
}
|
|
|
|
getSubscription(queryParams) {
|
|
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) {
|
|
this.searching.set(true);
|
|
this.debug.set(new QueryDebug());
|
|
this.stopSubscription();
|
|
this.subscriptionHandle = this.getSubscription(queryParams);
|
|
}
|
|
|
|
queryErrorMessages() {
|
|
const messages = [];
|
|
|
|
this.queryErrors.forEach(err => {
|
|
let value = err.color ? TAPi18n.__(`color-${err.value}`) : err.value;
|
|
if (!value) {
|
|
value = err.value;
|
|
}
|
|
messages.push(TAPi18n.__(err.tag, value));
|
|
});
|
|
|
|
return messages;
|
|
}
|
|
|
|
nextPage() {
|
|
this.searching.set(true);
|
|
this.stopSubscription();
|
|
this.subscriptionHandle = Meteor.subscribe(
|
|
'nextPage',
|
|
this.sessionId,
|
|
this.subscriptionCallbacks,
|
|
);
|
|
}
|
|
|
|
previousPage() {
|
|
this.searching.set(true);
|
|
this.stopSubscription();
|
|
this.subscriptionHandle = Meteor.subscribe(
|
|
'previousPage',
|
|
this.sessionId,
|
|
this.subscriptionCallbacks,
|
|
);
|
|
}
|
|
|
|
getResultsHeading() {
|
|
if (this.resultsCount === 0) {
|
|
return TAPi18n.__('no-cards-found');
|
|
} else if (this.resultsCount === 1) {
|
|
return TAPi18n.__('one-card-found');
|
|
} else if (this.resultsCount === this.totalHits) {
|
|
return TAPi18n.__('n-cards-found', {sprintf: [this.resultsCount]});
|
|
}
|
|
|
|
return TAPi18n.__('n-n-of-n-cards-found', {
|
|
start: this.resultsStart,
|
|
end: this.resultsEnd,
|
|
total: this.totalHits,
|
|
});
|
|
}
|
|
|
|
getSearchHref() {
|
|
const baseUrl = window.location.href.replace(/([?#].*$|\s*$)/, '');
|
|
return `${baseUrl}?q=${encodeURIComponent(this.query.get())}`;
|
|
}
|
|
|
|
events() {
|
|
return [
|
|
{
|
|
'click .js-next-page'(evt) {
|
|
evt.preventDefault();
|
|
this.nextPage();
|
|
},
|
|
'click .js-previous-page'(evt) {
|
|
evt.preventDefault();
|
|
this.previousPage();
|
|
},
|
|
},
|
|
];
|
|
}
|
|
}
|