mirror of
https://github.com/zadam/trilium.git
synced 2025-06-05 01:18:44 +02:00
full search shows search errors, closes #3221
This commit is contained in:
parent
c496519095
commit
c28383de4f
@ -176,7 +176,7 @@ class Froca {
|
||||
return;
|
||||
}
|
||||
|
||||
const {searchResultNoteIds, highlightedTokens} = await server.get('search-note/' + note.noteId);
|
||||
const {searchResultNoteIds, highlightedTokens, error} = await server.get('search-note/' + note.noteId);
|
||||
|
||||
if (!Array.isArray(searchResultNoteIds)) {
|
||||
throw new Error(`Search note '${note.noteId}' failed: ${searchResultNoteIds}`);
|
||||
@ -208,6 +208,8 @@ class Froca {
|
||||
|
||||
froca.notes[note.noteId].searchResultsLoaded = true;
|
||||
froca.notes[note.noteId].highlightedTokens = highlightedTokens;
|
||||
|
||||
return {error};
|
||||
}
|
||||
|
||||
/** @returns {NoteShort[]} */
|
||||
|
@ -250,7 +250,11 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget {
|
||||
|
||||
async refreshResultsCommand() {
|
||||
try {
|
||||
await froca.loadSearchNote(this.noteId);
|
||||
const {error} = await froca.loadSearchNote(this.noteId);
|
||||
|
||||
if (error) {
|
||||
this.handleEvent('showSearchError', { error });
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
toastService.showError(e.message);
|
||||
|
@ -71,6 +71,18 @@ export default class SearchString extends AbstractSearchOption {
|
||||
return $option;
|
||||
}
|
||||
|
||||
showSearchErrorEvent({error}) {
|
||||
this.$searchString.tooltip({
|
||||
trigger: 'manual',
|
||||
title: "Search error: " + error,
|
||||
placement: 'bottom'
|
||||
});
|
||||
|
||||
this.$searchString.tooltip("show");
|
||||
|
||||
setTimeout(() => this.$searchString.tooltip("dispose"), 4000);
|
||||
}
|
||||
|
||||
focusOnSearchDefinitionEvent() {
|
||||
this.$searchString.focus();
|
||||
}
|
||||
|
@ -385,9 +385,10 @@ table.promoted-attributes-in-tooltip td, table.promoted-attributes-in-tooltip th
|
||||
font-size: var(--main-font-size) !important;
|
||||
}
|
||||
|
||||
.tooltip .arrow::before {
|
||||
border-right-color: var(--main-border-color) !important;
|
||||
}
|
||||
.bs-tooltip-bottom .arrow::before { border-bottom-color: var(--main-border-color) !important; }
|
||||
.bs-tooltip-top .arrow::before { border-top-color: var(--main-border-color) !important; }
|
||||
.bs-tooltip-left .arrow::before { border-left-color: var(--main-border-color) !important; }
|
||||
.bs-tooltip-right .arrow::before { border-right-color: var(--main-border-color) !important; }
|
||||
|
||||
.note-tooltip.tooltip .arrow {
|
||||
display: none;
|
||||
|
@ -21,9 +21,9 @@ class AndExp extends Expression {
|
||||
this.subExpressions = subExpressions;
|
||||
}
|
||||
|
||||
execute(inputNoteSet, executionContext) {
|
||||
execute(inputNoteSet, executionContext, searchContext) {
|
||||
for (const subExpression of this.subExpressions) {
|
||||
inputNoteSet = subExpression.execute(inputNoteSet, executionContext);
|
||||
inputNoteSet = subExpression.execute(inputNoteSet, executionContext, searchContext);
|
||||
}
|
||||
|
||||
return inputNoteSet;
|
||||
|
@ -10,14 +10,14 @@ class ChildOfExp extends Expression {
|
||||
this.subExpression = subExpression;
|
||||
}
|
||||
|
||||
execute(inputNoteSet, executionContext) {
|
||||
execute(inputNoteSet, executionContext, searchContext) {
|
||||
const subInputNoteSet = new NoteSet();
|
||||
|
||||
for (const note of inputNoteSet.notes) {
|
||||
subInputNoteSet.addAll(note.parents);
|
||||
}
|
||||
|
||||
const subResNoteSet = this.subExpression.execute(subInputNoteSet, executionContext);
|
||||
const subResNoteSet = this.subExpression.execute(subInputNoteSet, executionContext, searchContext);
|
||||
|
||||
const resNoteSet = new NoteSet();
|
||||
|
||||
|
@ -11,9 +11,9 @@ class DescendantOfExp extends Expression {
|
||||
this.subExpression = subExpression;
|
||||
}
|
||||
|
||||
execute(inputNoteSet, executionContext) {
|
||||
execute(inputNoteSet, executionContext, searchContext) {
|
||||
const subInputNoteSet = new NoteSet(Object.values(becca.notes));
|
||||
const subResNoteSet = this.subExpression.execute(subInputNoteSet, executionContext);
|
||||
const subResNoteSet = this.subExpression.execute(subInputNoteSet, executionContext, searchContext);
|
||||
|
||||
const subTreeNoteSet = new NoteSet();
|
||||
|
||||
|
@ -8,9 +8,10 @@ class Expression {
|
||||
/**
|
||||
* @param {NoteSet} inputNoteSet
|
||||
* @param {object} executionContext
|
||||
* @param {SearchContext} searchContext
|
||||
* @return {NoteSet}
|
||||
*/
|
||||
execute(inputNoteSet, executionContext) {}
|
||||
execute(inputNoteSet, executionContext, searchContext) {}
|
||||
}
|
||||
|
||||
module.exports = Expression;
|
||||
|
@ -9,8 +9,8 @@ class NotExp extends Expression {
|
||||
this.subExpression = subExpression;
|
||||
}
|
||||
|
||||
execute(inputNoteSet, executionContext) {
|
||||
const subNoteSet = this.subExpression.execute(inputNoteSet, executionContext);
|
||||
execute(inputNoteSet, executionContext, searchContext) {
|
||||
const subNoteSet = this.subExpression.execute(inputNoteSet, executionContext, searchContext);
|
||||
|
||||
return inputNoteSet.minus(subNoteSet);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ const protectedSessionService = require('../../protected_session');
|
||||
const striptags = require('striptags');
|
||||
const utils = require("../../utils");
|
||||
|
||||
const ALLOWED_OPERATORS = ['*=*', '=', '*=', '=*', '%='];
|
||||
const ALLOWED_OPERATORS = ['=', '!=', '*=*', '*=', '=*', '%='];
|
||||
|
||||
const cachedRegexes = {};
|
||||
|
||||
@ -24,17 +24,19 @@ class NoteContentFulltextExp extends Expression {
|
||||
constructor(operator, {tokens, raw, flatText}) {
|
||||
super();
|
||||
|
||||
if (!ALLOWED_OPERATORS.includes(operator)) {
|
||||
throw new Error(`Note content can be searched only with operators: ` + ALLOWED_OPERATORS.join(", ") + `, operator ${operator} given.`);
|
||||
}
|
||||
|
||||
this.operator = operator;
|
||||
this.tokens = tokens;
|
||||
this.raw = !!raw;
|
||||
this.flatText = !!flatText;
|
||||
}
|
||||
|
||||
execute(inputNoteSet) {
|
||||
execute(inputNoteSet, executionContext, searchContext) {
|
||||
if (!ALLOWED_OPERATORS.includes(this.operator)) {
|
||||
searchContext.addError(`Note content can be searched only with operators: ` + ALLOWED_OPERATORS.join(", ") + `, operator ${this.operator} given.`);
|
||||
|
||||
return inputNoteSet;
|
||||
}
|
||||
|
||||
const resultNoteSet = new NoteSet();
|
||||
const sql = require('../../sql');
|
||||
|
||||
@ -66,6 +68,7 @@ class NoteContentFulltextExp extends Expression {
|
||||
const [token] = this.tokens;
|
||||
|
||||
if ((this.operator === '=' && token === content)
|
||||
|| (this.operator === '!=' && token !== content)
|
||||
|| (this.operator === '*=' && content.endsWith(token))
|
||||
|| (this.operator === '=*' && content.startsWith(token))
|
||||
|| (this.operator === '*=*' && content.includes(token))
|
||||
|
@ -20,8 +20,8 @@ class OrderByAndLimitExp extends Expression {
|
||||
this.subExpression = null; // it's expected to be set after construction
|
||||
}
|
||||
|
||||
execute(inputNoteSet, executionContext) {
|
||||
let {notes} = this.subExpression.execute(inputNoteSet, executionContext);
|
||||
execute(inputNoteSet, executionContext, searchContext) {
|
||||
let {notes} = this.subExpression.execute(inputNoteSet, executionContext, searchContext);
|
||||
|
||||
notes.sort((a, b) => {
|
||||
for (const {valueExtractor, smaller, larger} of this.orderDefinitions) {
|
||||
|
@ -10,14 +10,14 @@ class ParentOfExp extends Expression {
|
||||
this.subExpression = subExpression;
|
||||
}
|
||||
|
||||
execute(inputNoteSet, executionContext) {
|
||||
execute(inputNoteSet, executionContext, searchContext) {
|
||||
const subInputNoteSet = new NoteSet();
|
||||
|
||||
for (const note of inputNoteSet.notes) {
|
||||
subInputNoteSet.addAll(note.children);
|
||||
}
|
||||
|
||||
const subResNoteSet = this.subExpression.execute(subInputNoteSet, executionContext);
|
||||
const subResNoteSet = this.subExpression.execute(subInputNoteSet, executionContext, searchContext);
|
||||
|
||||
const resNoteSet = new NoteSet();
|
||||
|
||||
|
@ -12,7 +12,7 @@ class RelationWhereExp extends Expression {
|
||||
this.subExpression = subExpression;
|
||||
}
|
||||
|
||||
execute(inputNoteSet, executionContext) {
|
||||
execute(inputNoteSet, executionContext, searchContext) {
|
||||
const candidateNoteSet = new NoteSet();
|
||||
|
||||
for (const attr of becca.findAttributes('relation', this.relationName)) {
|
||||
@ -20,7 +20,7 @@ class RelationWhereExp extends Expression {
|
||||
|
||||
if (inputNoteSet.hasNoteId(note.noteId) && attr.targetNote) {
|
||||
const subInputNoteSet = new NoteSet([attr.targetNote]);
|
||||
const subResNoteSet = this.subExpression.execute(subInputNoteSet, executionContext);
|
||||
const subResNoteSet = this.subExpression.execute(subInputNoteSet, executionContext, searchContext);
|
||||
|
||||
if (subResNoteSet.hasNote(attr.targetNote)) {
|
||||
if (attr.isInheritable) {
|
||||
|
@ -18,6 +18,7 @@ const AncestorExp = require("../expressions/ancestor");
|
||||
const buildComparator = require('./build_comparator');
|
||||
const ValueExtractor = require('../value_extractor');
|
||||
const utils = require("../../utils");
|
||||
const TrueExp = require("../expressions/true.js");
|
||||
|
||||
function getFulltext(tokens, searchContext) {
|
||||
tokens = tokens.map(t => utils.removeDiacritic(t.token));
|
||||
@ -417,11 +418,22 @@ function getExpression(tokens, searchContext, level = 0) {
|
||||
}
|
||||
|
||||
function parse({fulltextTokens, expressionTokens, searchContext}) {
|
||||
let expression;
|
||||
|
||||
try {
|
||||
expression = getExpression(expressionTokens, searchContext);
|
||||
}
|
||||
catch (e) {
|
||||
searchContext.addError(e.message);
|
||||
|
||||
expression = new TrueExp();
|
||||
}
|
||||
|
||||
let exp = AndExp.of([
|
||||
searchContext.includeArchivedNotes ? null : new PropertyComparisonExp(searchContext, "isarchived", "=", "false"),
|
||||
(searchContext.ancestorNoteId && searchContext.ancestorNoteId !== 'root') ? new AncestorExp(searchContext.ancestorNoteId, searchContext.ancestorDepth) : null,
|
||||
getFulltext(fulltextTokens, searchContext),
|
||||
getExpression(expressionTokens, searchContext)
|
||||
expression
|
||||
]);
|
||||
|
||||
if (searchContext.orderBy && searchContext.orderBy !== 'relevancy') {
|
||||
|
@ -17,6 +17,7 @@ function searchFromNote(note) {
|
||||
|
||||
const searchScript = note.getRelationValue('searchScript');
|
||||
const searchString = note.getLabelValue('searchString');
|
||||
let error = null;
|
||||
|
||||
if (searchScript) {
|
||||
searchResultNoteIds = searchFromRelation(note, 'searchScript');
|
||||
@ -38,13 +39,15 @@ function searchFromNote(note) {
|
||||
.map(sr => sr.noteId);
|
||||
|
||||
highlightedTokens = searchContext.highlightedTokens;
|
||||
error = searchContext.getError();
|
||||
}
|
||||
|
||||
// we won't return search note's own noteId
|
||||
// also don't allow root since that would force infinite cycle
|
||||
return {
|
||||
searchResultNoteIds: searchResultNoteIds.filter(resultNoteId => !['root', note.noteId].includes(resultNoteId)),
|
||||
highlightedTokens
|
||||
highlightedTokens,
|
||||
error: error
|
||||
};
|
||||
}
|
||||
|
||||
@ -148,7 +151,7 @@ function findResultsWithExpression(expression, searchContext) {
|
||||
noteIdToNotePath: {}
|
||||
};
|
||||
|
||||
const noteSet = expression.execute(allNoteSet, executionContext);
|
||||
const noteSet = expression.execute(allNoteSet, executionContext, searchContext);
|
||||
|
||||
const searchResults = noteSet.notes
|
||||
.map(note => {
|
||||
@ -197,7 +200,15 @@ function findResultsWithExpression(expression, searchContext) {
|
||||
|
||||
function parseQueryToExpression(query, searchContext) {
|
||||
const {fulltextTokens, expressionTokens} = lex(query);
|
||||
const structuredExpressionTokens = handleParens(expressionTokens);
|
||||
let structuredExpressionTokens;
|
||||
|
||||
try {
|
||||
structuredExpressionTokens = handleParens(expressionTokens);
|
||||
}
|
||||
catch (e) {
|
||||
structuredExpressionTokens = [];
|
||||
searchContext.addError(e.message);
|
||||
}
|
||||
|
||||
const expression = parse({
|
||||
fulltextTokens,
|
||||
|
Loading…
x
Reference in New Issue
Block a user