mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
improvements to notemap in relation to search
This commit is contained in:
parent
3d4776f577
commit
8b0c60a046
6
libraries/force-graph.min.js
vendored
6
libraries/force-graph.min.js
vendored
File diff suppressed because one or more lines are too long
@ -10,7 +10,7 @@ const AbstractEntity = require("./abstract_entity");
|
|||||||
const NoteRevision = require("./note_revision");
|
const NoteRevision = require("./note_revision");
|
||||||
const TaskContext = require("../../services/task_context");
|
const TaskContext = require("../../services/task_context");
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc');
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const LABEL = 'label';
|
const LABEL = 'label';
|
||||||
@ -839,30 +839,76 @@ class Note extends AbstractEntity {
|
|||||||
return Array.from(set);
|
return Array.from(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {Note[]} */
|
/**
|
||||||
getSubtreeNotes(includeArchived = true) {
|
* @returns {{notes: Note[], relationships: {parentNoteId, childNoteId}[]}}
|
||||||
|
*/
|
||||||
|
getSubtree({includeArchived = true, resolveSearch = false} = {}) {
|
||||||
const noteSet = new Set();
|
const noteSet = new Set();
|
||||||
|
const relationships = []; // list of tuples parentNoteId -> childNoteId
|
||||||
|
|
||||||
|
function resolveSearchNote(searchNote) {
|
||||||
|
try {
|
||||||
|
const searchService = require("../../services/search/services/search");
|
||||||
|
const becca = searchNote.becca;
|
||||||
|
const {searchResultNoteIds} = searchService.searchFromNote(searchNote);
|
||||||
|
|
||||||
|
for (const resultNoteId of searchResultNoteIds) {
|
||||||
|
const resultNote = becca.notes[resultNoteId];
|
||||||
|
|
||||||
|
if (resultNote) {
|
||||||
|
addSubtreeNotesInner(resultNote, searchNote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
log.error(`Could not resolve search note ${searchNote?.noteId}: ${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSubtreeNotesInner(note, parentNote = null) {
|
||||||
|
if (parentNote) {
|
||||||
|
// this needs to happen first before noteSet check to include all clone relationships
|
||||||
|
relationships.push({
|
||||||
|
parentNoteId: parentNote.noteId,
|
||||||
|
childNoteId: note.noteId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noteSet.has(note)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function addSubtreeNotesInner(note) {
|
|
||||||
if (!includeArchived && note.isArchived) {
|
if (!includeArchived && note.isArchived) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
noteSet.add(note);
|
noteSet.add(note);
|
||||||
|
|
||||||
|
if (note.type === 'search') {
|
||||||
|
if (resolveSearch) {
|
||||||
|
resolveSearchNote(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
for (const childNote of note.children) {
|
for (const childNote of note.children) {
|
||||||
addSubtreeNotesInner(childNote);
|
addSubtreeNotesInner(childNote, note);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addSubtreeNotesInner(this);
|
addSubtreeNotesInner(this);
|
||||||
|
|
||||||
return Array.from(noteSet);
|
return {
|
||||||
|
notes: Array.from(noteSet),
|
||||||
|
relationships
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {String[]} */
|
/** @returns {String[]} */
|
||||||
getSubtreeNoteIds(includeArchived = true) {
|
getSubtreeNoteIds({includeArchived = true, resolveSearch = false} = {}) {
|
||||||
return this.getSubtreeNotes(includeArchived).map(note => note.noteId);
|
return this.getSubtree({includeArchived, resolveSearch})
|
||||||
|
.notes
|
||||||
|
.map(note => note.noteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDescendantNoteIds() {
|
getDescendantNoteIds() {
|
||||||
|
@ -86,8 +86,6 @@ export default class NoteMapWidget extends NoteContextAwareWidget {
|
|||||||
|
|
||||||
this.mapType = this.note.getLabelValue("mapType") === "tree" ? "tree" : "link";
|
this.mapType = this.note.getLabelValue("mapType") === "tree" ? "tree" : "link";
|
||||||
|
|
||||||
this.setDimensions();
|
|
||||||
|
|
||||||
await libraryLoader.requireLibrary(libraryLoader.FORCE_GRAPH);
|
await libraryLoader.requireLibrary(libraryLoader.FORCE_GRAPH);
|
||||||
|
|
||||||
this.graph = ForceGraph()(this.$container[0])
|
this.graph = ForceGraph()(this.$container[0])
|
||||||
@ -121,7 +119,7 @@ export default class NoteMapWidget extends NoteContextAwareWidget {
|
|||||||
.linkCanvasObjectMode(() => "after");
|
.linkCanvasObjectMode(() => "after");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mapRootNoteId = this.getMapRootNoteId();
|
const mapRootNoteId = this.getMapRootNoteId();
|
||||||
const data = await this.loadNotesAndRelations(mapRootNoteId);
|
const data = await this.loadNotesAndRelations(mapRootNoteId);
|
||||||
|
|
||||||
const nodeLinkRatio = data.nodes.length / data.links.length;
|
const nodeLinkRatio = data.nodes.length / data.links.length;
|
||||||
@ -264,7 +262,7 @@ export default class NoteMapWidget extends NoteContextAwareWidget {
|
|||||||
return {
|
return {
|
||||||
nodes: this.nodes,
|
nodes: this.nodes,
|
||||||
links: links.map(link => ({
|
links: links.map(link => ({
|
||||||
id: link.id,
|
id: `${link.sourceNoteId}-${link.targetNoteId}`,
|
||||||
source: link.sourceNoteId,
|
source: link.sourceNoteId,
|
||||||
target: link.targetNoteId,
|
target: link.targetNoteId,
|
||||||
name: link.names.join(", ")
|
name: link.names.join(", ")
|
||||||
@ -333,6 +331,8 @@ export default class NoteMapWidget extends NoteContextAwareWidget {
|
|||||||
|
|
||||||
if (this.widgetMode === 'ribbon') {
|
if (this.widgetMode === 'ribbon') {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
this.setDimensions();
|
||||||
|
|
||||||
const subGraphNoteIds = this.getSubGraphConnectedToCurrentNote(data);
|
const subGraphNoteIds = this.getSubGraphConnectedToCurrentNote(data);
|
||||||
|
|
||||||
this.graph.zoomToFit(400, 50, node => subGraphNoteIds.has(node.id));
|
this.graph.zoomToFit(400, 50, node => subGraphNoteIds.has(node.id));
|
||||||
@ -345,6 +345,8 @@ export default class NoteMapWidget extends NoteContextAwareWidget {
|
|||||||
else if (this.widgetMode === 'type') {
|
else if (this.widgetMode === 'type') {
|
||||||
if (data.nodes.length > 1) {
|
if (data.nodes.length > 1) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
this.setDimensions();
|
||||||
|
|
||||||
this.graph.zoomToFit(400, 10);
|
this.graph.zoomToFit(400, 10);
|
||||||
|
|
||||||
if (data.nodes.length < 30) {
|
if (data.nodes.length < 30) {
|
||||||
@ -398,7 +400,12 @@ export default class NoteMapWidget extends NoteContextAwareWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
entitiesReloadedEvent({loadResults}) {
|
entitiesReloadedEvent({loadResults}) {
|
||||||
if (loadResults.getAttributes(this.componentId).find(attr => attr.name === 'mapType' && attributeService.isAffecting(attr, this.note))) {
|
if (loadResults.getAttributes(this.componentId).find(
|
||||||
|
attr =>
|
||||||
|
attr.type === 'label'
|
||||||
|
&& ['mapType', 'mapRootNoteId'].includes(attr.name)
|
||||||
|
&& attributeService.isAffecting(attr, this.note)
|
||||||
|
)) {
|
||||||
this.refresh();
|
this.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,12 +83,13 @@ function getNeighbors(note, depth) {
|
|||||||
|
|
||||||
function getLinkMap(req) {
|
function getLinkMap(req) {
|
||||||
const mapRootNote = becca.getNote(req.params.noteId);
|
const mapRootNote = becca.getNote(req.params.noteId);
|
||||||
// if the map root itself has ignore (journal typically) then there wouldn't be anything to display so
|
// if the map root itself has exclude attribute (journal typically) then there wouldn't be anything to display, so
|
||||||
// we'll just ignore it
|
// we'll just ignore it
|
||||||
const ignoreExcludeFromNoteMap = mapRootNote.hasLabel('excludeFromNoteMap');
|
const ignoreExcludeFromNoteMap = mapRootNote.hasLabel('excludeFromNoteMap');
|
||||||
|
const subtree = mapRootNote.getSubtree({includeArchived: false, resolveSearch: true});
|
||||||
|
|
||||||
const noteIds = new Set(
|
const noteIds = new Set(
|
||||||
mapRootNote.getSubtreeNotes(false)
|
subtree.notes
|
||||||
.filter(note => ignoreExcludeFromNoteMap || !note.hasLabel('excludeFromNoteMap'))
|
.filter(note => ignoreExcludeFromNoteMap || !note.hasLabel('excludeFromNoteMap'))
|
||||||
.map(note => note.noteId)
|
.map(note => note.noteId)
|
||||||
);
|
);
|
||||||
@ -142,8 +143,9 @@ function getTreeMap(req) {
|
|||||||
// if the map root itself has ignore (journal typically) then there wouldn't be anything to display so
|
// if the map root itself has ignore (journal typically) then there wouldn't be anything to display so
|
||||||
// we'll just ignore it
|
// we'll just ignore it
|
||||||
const ignoreExcludeFromNoteMap = mapRootNote.hasLabel('excludeFromNoteMap');
|
const ignoreExcludeFromNoteMap = mapRootNote.hasLabel('excludeFromNoteMap');
|
||||||
|
const subtree = mapRootNote.getSubtree({includeArchived: false, resolveSearch: true});
|
||||||
|
|
||||||
const notes = mapRootNote.getSubtreeNotes(false)
|
const notes = subtree.notes
|
||||||
.filter(note => ignoreExcludeFromNoteMap || !note.hasLabel('excludeFromNoteMap'))
|
.filter(note => ignoreExcludeFromNoteMap || !note.hasLabel('excludeFromNoteMap'))
|
||||||
.filter(note => {
|
.filter(note => {
|
||||||
if (note.type !== 'image' || note.getChildNotes().length > 0) {
|
if (note.type !== 'image' || note.getChildNotes().length > 0) {
|
||||||
@ -170,25 +172,40 @@ function getTreeMap(req) {
|
|||||||
|
|
||||||
const links = [];
|
const links = [];
|
||||||
|
|
||||||
for (const branch of Object.values(becca.branches)) {
|
for (const {parentNoteId, childNoteId} of subtree.relationships) {
|
||||||
if (!noteIds.has(branch.parentNoteId) || !noteIds.has(branch.noteId)) {
|
if (!noteIds.has(parentNoteId) || !noteIds.has(childNoteId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
links.push({
|
links.push({
|
||||||
id: branch.branchId,
|
sourceNoteId: parentNoteId,
|
||||||
sourceNoteId: branch.parentNoteId,
|
targetNoteId: childNoteId
|
||||||
targetNoteId: branch.noteId
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const noteIdToDescendantCountMap = buildDescendantCountMap();
|
||||||
|
|
||||||
|
updateDescendantCountMapForSearch(noteIdToDescendantCountMap, subtree.relationships);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
notes: notes,
|
notes: notes,
|
||||||
noteIdToDescendantCountMap: buildDescendantCountMap(),
|
noteIdToDescendantCountMap: noteIdToDescendantCountMap,
|
||||||
links: links
|
links: links
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateDescendantCountMapForSearch(noteIdToDescendantCountMap, relationships) {
|
||||||
|
for (const {parentNoteId, childNoteId} of relationships) {
|
||||||
|
const parentNote = becca.notes[parentNoteId];
|
||||||
|
if (!parentNote || parentNote.type !== 'search') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
noteIdToDescendantCountMap[parentNote.noteId] = noteIdToDescendantCountMap[parentNoteId] || 0;
|
||||||
|
noteIdToDescendantCountMap[parentNote.noteId] += noteIdToDescendantCountMap[childNoteId] || 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function removeImages(document) {
|
function removeImages(document) {
|
||||||
const images = document.getElementsByTagName('img');
|
const images = document.getElementsByTagName('img');
|
||||||
while (images.length > 0) {
|
while (images.length > 0) {
|
||||||
|
@ -2,49 +2,11 @@
|
|||||||
|
|
||||||
const becca = require('../../becca/becca');
|
const becca = require('../../becca/becca');
|
||||||
const SearchContext = require('../../services/search/search_context');
|
const SearchContext = require('../../services/search/search_context');
|
||||||
const log = require('../../services/log');
|
|
||||||
const scriptService = require('../../services/script');
|
|
||||||
const searchService = require('../../services/search/services/search');
|
const searchService = require('../../services/search/services/search');
|
||||||
const bulkActionService = require("../../services/bulk_actions");
|
const bulkActionService = require("../../services/bulk_actions");
|
||||||
const cls = require("../../services/cls");
|
const cls = require("../../services/cls");
|
||||||
const {formatAttrForSearch} = require("../../services/attribute_formatter");
|
const {formatAttrForSearch} = require("../../services/attribute_formatter");
|
||||||
|
|
||||||
function searchFromNoteInt(note) {
|
|
||||||
let searchResultNoteIds, highlightedTokens;
|
|
||||||
|
|
||||||
const searchScript = note.getRelationValue('searchScript');
|
|
||||||
const searchString = note.getLabelValue('searchString');
|
|
||||||
|
|
||||||
if (searchScript) {
|
|
||||||
searchResultNoteIds = searchFromRelation(note, 'searchScript');
|
|
||||||
highlightedTokens = [];
|
|
||||||
} else {
|
|
||||||
const searchContext = new SearchContext({
|
|
||||||
fastSearch: note.hasLabel('fastSearch'),
|
|
||||||
ancestorNoteId: note.getRelationValue('ancestor'),
|
|
||||||
ancestorDepth: note.getLabelValue('ancestorDepth'),
|
|
||||||
includeArchivedNotes: note.hasLabel('includeArchivedNotes'),
|
|
||||||
orderBy: note.getLabelValue('orderBy'),
|
|
||||||
orderDirection: note.getLabelValue('orderDirection'),
|
|
||||||
limit: note.getLabelValue('limit'),
|
|
||||||
debug: note.hasLabel('debug'),
|
|
||||||
fuzzyAttributeSearch: false
|
|
||||||
});
|
|
||||||
|
|
||||||
searchResultNoteIds = searchService.findResultsWithQuery(searchString, searchContext)
|
|
||||||
.map(sr => sr.noteId);
|
|
||||||
|
|
||||||
highlightedTokens = searchContext.highlightedTokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function searchFromNote(req) {
|
function searchFromNote(req) {
|
||||||
const note = becca.getNote(req.params.noteId);
|
const note = becca.getNote(req.params.noteId);
|
||||||
|
|
||||||
@ -61,7 +23,7 @@ function searchFromNote(req) {
|
|||||||
return [400, `Note ${req.params.noteId} is not a search note.`]
|
return [400, `Note ${req.params.noteId} is not a search note.`]
|
||||||
}
|
}
|
||||||
|
|
||||||
return searchFromNoteInt(note);
|
return searchService.searchFromNote(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchAndExecute(req) {
|
function searchAndExecute(req) {
|
||||||
@ -80,48 +42,11 @@ function searchAndExecute(req) {
|
|||||||
return [400, `Note ${req.params.noteId} is not a search note.`]
|
return [400, `Note ${req.params.noteId} is not a search note.`]
|
||||||
}
|
}
|
||||||
|
|
||||||
const {searchResultNoteIds} = searchFromNoteInt(note);
|
const {searchResultNoteIds} = searchService.searchFromNote(note);
|
||||||
|
|
||||||
bulkActionService.executeActions(note, searchResultNoteIds);
|
bulkActionService.executeActions(note, searchResultNoteIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchFromRelation(note, relationName) {
|
|
||||||
const scriptNote = note.getRelationTarget(relationName);
|
|
||||||
|
|
||||||
if (!scriptNote) {
|
|
||||||
log.info(`Search note's relation ${relationName} has not been found.`);
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!scriptNote.isJavaScript() || scriptNote.getScriptEnv() !== 'backend') {
|
|
||||||
log.info(`Note ${scriptNote.noteId} is not executable.`);
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!note.isContentAvailable()) {
|
|
||||||
log.info(`Note ${scriptNote.noteId} is not available outside of protected session.`);
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = scriptService.executeNote(scriptNote, { originEntity: note });
|
|
||||||
|
|
||||||
if (!Array.isArray(result)) {
|
|
||||||
log.info(`Result from ${scriptNote.noteId} is not an array.`);
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.length === 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// we expect either array of noteIds (strings) or notes, in that case we extract noteIds ourselves
|
|
||||||
return typeof result[0] === 'string' ? result : result.map(item => item.noteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
function quickSearch(req) {
|
function quickSearch(req) {
|
||||||
const {searchString} = req.params;
|
const {searchString} = req.params;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ function getSubtreeSize(req) {
|
|||||||
return [404, `Note ${noteId} was not found.`];
|
return [404, `Note ${noteId} was not found.`];
|
||||||
}
|
}
|
||||||
|
|
||||||
const subTreeNoteIds = note.getSubtreeNotes().map(note => note.noteId);
|
const subTreeNoteIds = note.getSubtreeNoteIds();
|
||||||
|
|
||||||
sql.fillParamList(subTreeNoteIds);
|
sql.fillParamList(subTreeNoteIds);
|
||||||
|
|
||||||
|
@ -23,7 +23,9 @@ class AncestorExp extends Expression {
|
|||||||
return new NoteSet([]);
|
return new NoteSet([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const subTreeNoteSet = new NoteSet(ancestorNote.getSubtreeNotes()).intersection(inputNoteSet);
|
const subtree = ancestorNote.getSubtree();
|
||||||
|
|
||||||
|
const subTreeNoteSet = new NoteSet(subtree.notes).intersection(inputNoteSet);
|
||||||
|
|
||||||
if (!this.ancestorDepthComparator) {
|
if (!this.ancestorDepthComparator) {
|
||||||
return subTreeNoteSet;
|
return subTreeNoteSet;
|
||||||
|
@ -18,7 +18,7 @@ class DescendantOfExp extends Expression {
|
|||||||
const subTreeNoteSet = new NoteSet();
|
const subTreeNoteSet = new NoteSet();
|
||||||
|
|
||||||
for (const note of subResNoteSet.notes) {
|
for (const note of subResNoteSet.notes) {
|
||||||
subTreeNoteSet.addAll(note.getSubtreeNotes());
|
subTreeNoteSet.addAll(note.getSubtree().notes);
|
||||||
}
|
}
|
||||||
|
|
||||||
return inputNoteSet.intersection(subTreeNoteSet);
|
return inputNoteSet.intersection(subTreeNoteSet);
|
||||||
|
@ -10,6 +10,80 @@ const becca = require('../../../becca/becca');
|
|||||||
const beccaService = require('../../../becca/becca_service');
|
const beccaService = require('../../../becca/becca_service');
|
||||||
const utils = require('../../utils');
|
const utils = require('../../utils');
|
||||||
const log = require('../../log');
|
const log = require('../../log');
|
||||||
|
const scriptService = require("../../script.js");
|
||||||
|
|
||||||
|
function searchFromNote(note) {
|
||||||
|
let searchResultNoteIds, highlightedTokens;
|
||||||
|
|
||||||
|
const searchScript = note.getRelationValue('searchScript');
|
||||||
|
const searchString = note.getLabelValue('searchString');
|
||||||
|
|
||||||
|
if (searchScript) {
|
||||||
|
searchResultNoteIds = searchFromRelation(note, 'searchScript');
|
||||||
|
highlightedTokens = [];
|
||||||
|
} else {
|
||||||
|
const searchContext = new SearchContext({
|
||||||
|
fastSearch: note.hasLabel('fastSearch'),
|
||||||
|
ancestorNoteId: note.getRelationValue('ancestor'),
|
||||||
|
ancestorDepth: note.getLabelValue('ancestorDepth'),
|
||||||
|
includeArchivedNotes: note.hasLabel('includeArchivedNotes'),
|
||||||
|
orderBy: note.getLabelValue('orderBy'),
|
||||||
|
orderDirection: note.getLabelValue('orderDirection'),
|
||||||
|
limit: note.getLabelValue('limit'),
|
||||||
|
debug: note.hasLabel('debug'),
|
||||||
|
fuzzyAttributeSearch: false
|
||||||
|
});
|
||||||
|
|
||||||
|
searchResultNoteIds = findResultsWithQuery(searchString, searchContext)
|
||||||
|
.map(sr => sr.noteId);
|
||||||
|
|
||||||
|
highlightedTokens = searchContext.highlightedTokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchFromRelation(note, relationName) {
|
||||||
|
const scriptNote = note.getRelationTarget(relationName);
|
||||||
|
|
||||||
|
if (!scriptNote) {
|
||||||
|
log.info(`Search note's relation ${relationName} has not been found.`);
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!scriptNote.isJavaScript() || scriptNote.getScriptEnv() !== 'backend') {
|
||||||
|
log.info(`Note ${scriptNote.noteId} is not executable.`);
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!note.isContentAvailable()) {
|
||||||
|
log.info(`Note ${scriptNote.noteId} is not available outside of protected session.`);
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = scriptService.executeNote(scriptNote, { originEntity: note });
|
||||||
|
|
||||||
|
if (!Array.isArray(result)) {
|
||||||
|
log.info(`Result from ${scriptNote.noteId} is not an array.`);
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// we expect either array of noteIds (strings) or notes, in that case we extract noteIds ourselves
|
||||||
|
return typeof result[0] === 'string' ? result : result.map(item => item.noteId);
|
||||||
|
}
|
||||||
|
|
||||||
function loadNeededInfoFromDatabase() {
|
function loadNeededInfoFromDatabase() {
|
||||||
const sql = require('../../sql');
|
const sql = require('../../sql');
|
||||||
@ -288,6 +362,7 @@ function formatAttribute(attr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
searchFromNote,
|
||||||
searchNotesForAutocomplete,
|
searchNotesForAutocomplete,
|
||||||
findResultsWithQuery,
|
findResultsWithQuery,
|
||||||
findFirstNoteWithQuery,
|
findFirstNoteWithQuery,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user