mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-30 18:05:55 +01:00 
			
		
		
		
	added "save search to note" button
This commit is contained in:
		
							
								
								
									
										3
									
								
								TODO
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								TODO
									
									
									
									
									
								
							| @@ -2,3 +2,6 @@ | |||||||
| - all ribbon tabs should have assignable shortcut | - all ribbon tabs should have assignable shortcut | ||||||
| - new icon | - new icon | ||||||
| - green theme | - green theme | ||||||
|  | - polish becca entities API | ||||||
|  | - separate private and public APIs in becca entities | ||||||
|  | - handle FIXMEs | ||||||
|   | |||||||
| @@ -1008,6 +1008,24 @@ class Note extends AbstractEntity { | |||||||
|      */ |      */ | ||||||
|     removeRelation(name, value) { return this.removeAttribute(RELATION, name, value); } |     removeRelation(name, value) { return this.removeAttribute(RELATION, name, value); } | ||||||
|  |  | ||||||
|  |     searchNotesInSubtree(searchString) { | ||||||
|  |         const searchService = require("../../services/search/services/search"); | ||||||
|  |  | ||||||
|  |         return searchService.searchNotes(searchString); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     searchNoteInSubtree(searchString) { | ||||||
|  |         return this.searchNotesInSubtree(searchString)[0]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     cloneTo(parentNoteId) { | ||||||
|  |         const cloningService = require("../../services/cloning"); | ||||||
|  |  | ||||||
|  |         const branch = this.becca.getNote(parentNoteId).getParentBranches()[0]; | ||||||
|  |  | ||||||
|  |         return cloningService.cloneNoteToParent(this.noteId, branch.branchId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     decrypt() { |     decrypt() { | ||||||
|         if (this.isProtected && !this.isDecrypted && protectedSessionService.isProtectedSessionAvailable()) { |         if (this.isProtected && !this.isDecrypted && protectedSessionService.isProtectedSessionAvailable()) { | ||||||
|             try { |             try { | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ import NoteContextAwareWidget from "../note_context_aware_widget.js"; | |||||||
| import froca from "../../services/froca.js"; | import froca from "../../services/froca.js"; | ||||||
| import ws from "../../services/ws.js"; | import ws from "../../services/ws.js"; | ||||||
| import toastService from "../../services/toast.js"; | import toastService from "../../services/toast.js"; | ||||||
|  | import treeService from "../../services/tree.js"; | ||||||
|  |  | ||||||
| import DeleteNoteSearchAction from "../search_actions/delete_note.js"; | import DeleteNoteSearchAction from "../search_actions/delete_note.js"; | ||||||
| import DeleteLabelSearchAction from "../search_actions/delete_label.js"; | import DeleteLabelSearchAction from "../search_actions/delete_label.js"; | ||||||
| @@ -21,6 +22,8 @@ import SearchScript from "../search_options/search_script.js"; | |||||||
| import Limit from "../search_options/limit.js"; | import Limit from "../search_options/limit.js"; | ||||||
| import DeleteNoteRevisionsSearchAction from "../search_actions/delete_note_revisions.js"; | import DeleteNoteRevisionsSearchAction from "../search_actions/delete_note_revisions.js"; | ||||||
| import Debug from "../search_options/debug.js"; | import Debug from "../search_options/debug.js"; | ||||||
|  | import appContext from "../../services/app_context.js"; | ||||||
|  | import toast from "../../services/toast.js"; | ||||||
|  |  | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="search-definition-widget"> | <div class="search-definition-widget"> | ||||||
| @@ -164,6 +167,11 @@ const TPL = ` | |||||||
|                                 <span class="bx bxs-zap"></span> |                                 <span class="bx bxs-zap"></span> | ||||||
|                                 Search & Execute actions |                                 Search & Execute actions | ||||||
|                             </button> |                             </button> | ||||||
|  |                              | ||||||
|  |                             <button type="button" class="btn btn-sm save-to-note-button"> | ||||||
|  |                                 <span class="bx bx-save"></span> | ||||||
|  |                                 Save to note | ||||||
|  |                             </button> | ||||||
|                         </div> |                         </div> | ||||||
|                     </td> |                     </td> | ||||||
|                 </tr> |                 </tr> | ||||||
| @@ -258,6 +266,19 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget { | |||||||
|  |  | ||||||
|         this.$searchAndExecuteButton = this.$widget.find('.search-and-execute-button'); |         this.$searchAndExecuteButton = this.$widget.find('.search-and-execute-button'); | ||||||
|         this.$searchAndExecuteButton.on('click', () => this.searchAndExecute()); |         this.$searchAndExecuteButton.on('click', () => this.searchAndExecute()); | ||||||
|  |  | ||||||
|  |         this.$saveToNoteButton = this.$widget.find('.save-to-note-button'); | ||||||
|  |         this.$saveToNoteButton.on('click', async () => { | ||||||
|  |             const {notePath} = await server.post("save-search-note", {searchNoteId: this.noteId}); | ||||||
|  |  | ||||||
|  |             await ws.waitForMaxKnownEntityChangeId(); | ||||||
|  |  | ||||||
|  |             await appContext.tabManager.getActiveContext().setNote(notePath); | ||||||
|  |  | ||||||
|  |             console.log("notePath", notePath); | ||||||
|  |  | ||||||
|  |             toastService.showMessage("Search note has been saved into " + await treeService.getNotePathTitle(notePath)); | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async refreshResultsCommand() { |     async refreshResultsCommand() { | ||||||
| @@ -278,6 +299,8 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget { | |||||||
|     async refreshWithNote(note) { |     async refreshWithNote(note) { | ||||||
|         this.$component.show(); |         this.$component.show(); | ||||||
|  |  | ||||||
|  |         this.$saveToNoteButton.toggle(!note.getAllNotePaths().find(notePathArr => !notePathArr.includes("hidden"))); | ||||||
|  |  | ||||||
|         this.$searchOptions.empty(); |         this.$searchOptions.empty(); | ||||||
|  |  | ||||||
|         for (const OptionClass of OPTION_CLASSES) { |         for (const OptionClass of OPTION_CLASSES) { | ||||||
|   | |||||||
| @@ -12,9 +12,16 @@ const utils = require('../../services/utils'); | |||||||
| const path = require('path'); | const path = require('path'); | ||||||
| const Attribute = require('../../becca/entities/attribute.js'); | const Attribute = require('../../becca/entities/attribute.js'); | ||||||
| const htmlSanitizer = require('../../services/html_sanitizer'); | const htmlSanitizer = require('../../services/html_sanitizer'); | ||||||
|  | const {formatAttrForSearch} = require("../../services/attribute_formatter.js"); | ||||||
|  |  | ||||||
| function findClippingNote(todayNote, pageUrl) { | function findClippingNote(todayNote, pageUrl) { | ||||||
|     const notes = todayNote.getDescendantNotesWithLabel('pageUrl', pageUrl); |     const notes = todayNote.searchNoteInSubtree( | ||||||
|  |         formatAttrForSearch({ | ||||||
|  |             type: 'label', | ||||||
|  |             name: "pageUrl", | ||||||
|  |             value: pageUrl | ||||||
|  |         }, true) | ||||||
|  |     ); | ||||||
|  |  | ||||||
|     for (const note of notes) { |     for (const note of notes) { | ||||||
|         if (note.getOwnedLabelValue('clipType') === 'clippings') { |         if (note.getOwnedLabelValue('clipType') === 'clippings') { | ||||||
|   | |||||||
| @@ -13,11 +13,11 @@ function getInboxNote(req) { | |||||||
|  |  | ||||||
|     let inbox; |     let inbox; | ||||||
|  |  | ||||||
|     if (hoistedNote) { |     if (!hoistedNote.isRoot()) { | ||||||
|         ([inbox] = hoistedNote.getDescendantNotesWithLabel('hoistedInbox')); |         inbox = hoistedNote.searchNoteInSubtree('#hoistedInbox'); | ||||||
|  |  | ||||||
|         if (!inbox) { |         if (!inbox) { | ||||||
|             ([inbox] = hoistedNote.getDescendantNotesWithLabel('inbox')); |             inbox = hoistedNote.searchNoteInSubtree('#inbox'); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (!inbox) { |         if (!inbox) { | ||||||
| @@ -114,39 +114,35 @@ function getSearchRoot() { | |||||||
|     return searchRoot; |     return searchRoot; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function saveSearchNote(req) { | ||||||
|  |     const searchNote = becca.getNote(req.body.searchNoteId); | ||||||
|  |  | ||||||
|  |     const hoistedNote = getHoistedNote(); | ||||||
|  |     let searchHome; | ||||||
|  |  | ||||||
|  |     if (!hoistedNote.isRoot()) { | ||||||
|  |         searchHome = hoistedNote.searchNoteInSubtree('#hoistedSearchHome') | ||||||
|  |             || hoistedNote.searchNoteInSubtree('#searchHome') | ||||||
|  |             || hoistedNote; | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         const today = dateUtils.localNowDate(); | ||||||
|  |  | ||||||
|  |         searchHome = hoistedNote.searchNoteInSubtree('#searchHome') | ||||||
|  |             || dateNoteService.getDateNote(today); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return searchNote.cloneTo(searchHome.noteId); | ||||||
|  | } | ||||||
|  |  | ||||||
| function createSearchNote(req) { | function createSearchNote(req) { | ||||||
|     const params = req.body; |     const params = req.body; | ||||||
|     const searchString = params.searchString || ""; |     const searchString = params.searchString || ""; | ||||||
|     let ancestorNoteId = params.ancestorNoteId; |  | ||||||
|  |  | ||||||
|     const hoistedNote = getHoistedNote(); |     const hoistedNote = getHoistedNote(); | ||||||
|  |     const ancestorNoteId = params.ancestorNoteId || hoistedNote.noteId; | ||||||
|     let searchHome = getSearchRoot(); |  | ||||||
|  |  | ||||||
|     // if (hoistedNote) { |  | ||||||
|     //     ([searchHome] = hoistedNote.getDescendantNotesWithLabel('hoistedSearchHome')); |  | ||||||
|     // |  | ||||||
|     //     if (!searchHome) { |  | ||||||
|     //         ([searchHome] = hoistedNote.getDescendantNotesWithLabel('searchHome')); |  | ||||||
|     //     } |  | ||||||
|     // |  | ||||||
|     //     if (!searchHome) { |  | ||||||
|     //         searchHome = hoistedNote; |  | ||||||
|     //     } |  | ||||||
|     // |  | ||||||
|     //     if (!ancestorNoteId) { |  | ||||||
|     //         ancestorNoteId = hoistedNote.noteId; |  | ||||||
|     //     } |  | ||||||
|     // } |  | ||||||
|     // else { |  | ||||||
|     //     const today = dateUtils.localNowDate(); |  | ||||||
|     // |  | ||||||
|     //     searchHome = attributeService.getNoteWithLabel('searchHome') |  | ||||||
|     //               || dateNoteService.getDateNote(today); |  | ||||||
|     // } |  | ||||||
|  |  | ||||||
|     const {note} = noteService.createNewNote({ |     const {note} = noteService.createNewNote({ | ||||||
|         parentNoteId: searchHome.noteId, |         parentNoteId: getSearchRoot().noteId, | ||||||
|         title: 'Search: ' + searchString, |         title: 'Search: ' + searchString, | ||||||
|         content: "", |         content: "", | ||||||
|         type: 'search', |         type: 'search', | ||||||
| @@ -163,9 +159,7 @@ function createSearchNote(req) { | |||||||
| } | } | ||||||
|  |  | ||||||
| function getHoistedNote() { | function getHoistedNote() { | ||||||
|     return cls.getHoistedNoteId() && cls.getHoistedNoteId() !== 'root' |     return becca.getNote(cls.getHoistedNoteId()); | ||||||
|         ? becca.getNote(cls.getHoistedNoteId()) |  | ||||||
|         : null; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
| @@ -175,5 +169,6 @@ module.exports = { | |||||||
|     getYearNote, |     getYearNote, | ||||||
|     getDateNotesForMonth, |     getDateNotesForMonth, | ||||||
|     createSqlConsole, |     createSqlConsole, | ||||||
|     createSearchNote |     createSearchNote, | ||||||
|  |     saveSearchNote | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -92,7 +92,7 @@ function update(name, value) { | |||||||
| } | } | ||||||
|  |  | ||||||
| function getUserThemes() { | function getUserThemes() { | ||||||
|     const notes = searchService.findNotes("#appTheme"); |     const notes = searchService.searchNotes("#appTheme"); | ||||||
|     const ret = []; |     const ret = []; | ||||||
|  |  | ||||||
|     for (const note of notes) { |     for (const note of notes) { | ||||||
|   | |||||||
| @@ -212,6 +212,7 @@ function register(app) { | |||||||
|     apiRoute(GET, '/api/date-notes/notes-for-month/:month', dateNotesRoute.getDateNotesForMonth); |     apiRoute(GET, '/api/date-notes/notes-for-month/:month', dateNotesRoute.getDateNotesForMonth); | ||||||
|     apiRoute(POST, '/api/sql-console', dateNotesRoute.createSqlConsole); |     apiRoute(POST, '/api/sql-console', dateNotesRoute.createSqlConsole); | ||||||
|     apiRoute(POST, '/api/search-note', dateNotesRoute.createSearchNote); |     apiRoute(POST, '/api/search-note', dateNotesRoute.createSearchNote); | ||||||
|  |     apiRoute(POST, '/api/save-search-note', dateNotesRoute.saveSearchNote); | ||||||
|  |  | ||||||
|     route(GET, '/api/images/:noteId/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnImage); |     route(GET, '/api/images/:noteId/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnImage); | ||||||
|     route(POST, '/api/images', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware], imageRoute.uploadImage, apiResultHandler); |     route(POST, '/api/images', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware], imageRoute.uploadImage, apiResultHandler); | ||||||
|   | |||||||
| @@ -60,7 +60,7 @@ const BUILTIN_ATTRIBUTES = [ | |||||||
| ]; | ]; | ||||||
|  |  | ||||||
| function getNotesWithLabel(name, value) { | function getNotesWithLabel(name, value) { | ||||||
|     return searchService.findNotes(formatAttrForSearch({type: 'label', name, value}, true)); |     return searchService.searchNotes(formatAttrForSearch({type: 'label', name, value}, true)); | ||||||
| } | } | ||||||
|  |  | ||||||
| function getNoteIdsWithLabels(names) { | function getNoteIdsWithLabels(names) { | ||||||
| @@ -75,6 +75,7 @@ function getNoteIdsWithLabels(names) { | |||||||
|     return Array.from(noteIds); |     return Array.from(noteIds); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // TODO: should be in search service | ||||||
| function getNoteWithLabel(name, value) { | function getNoteWithLabel(name, value) { | ||||||
|     const notes = getNotesWithLabel(name, value); |     const notes = getNotesWithLabel(name, value); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ const Branch = require('../becca/entities/branch.js'); | |||||||
| const TaskContext = require("./task_context.js"); | const TaskContext = require("./task_context.js"); | ||||||
| const utils = require('./utils'); | const utils = require('./utils'); | ||||||
| const becca = require("../becca/becca.js"); | const becca = require("../becca/becca.js"); | ||||||
|  | const beccaService = require("../becca/becca_service"); | ||||||
|  |  | ||||||
| function cloneNoteToParent(noteId, parentBranchId, prefix) { | function cloneNoteToParent(noteId, parentBranchId, prefix) { | ||||||
|     const parentBranch = becca.getBranch(parentBranchId); |     const parentBranch = becca.getBranch(parentBranchId); | ||||||
| @@ -32,7 +33,11 @@ function cloneNoteToParent(noteId, parentBranchId, prefix) { | |||||||
|     parentBranch.isExpanded = true; // the new target should be expanded so it immediately shows up to the user |     parentBranch.isExpanded = true; // the new target should be expanded so it immediately shows up to the user | ||||||
|     parentBranch.save(); |     parentBranch.save(); | ||||||
|  |  | ||||||
|     return { success: true, branchId: branch.branchId }; |     return { | ||||||
|  |         success: true, | ||||||
|  |         branchId: branch.branchId, | ||||||
|  |         notePath: beccaService.getNotePath(parentBranch.noteId).path + "/" + noteId | ||||||
|  |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
| function ensureNoteIsPresentInParent(noteId, parentNoteId, prefix) { | function ensureNoteIsPresentInParent(noteId, parentNoteId, prefix) { | ||||||
|   | |||||||
| @@ -136,7 +136,7 @@ function parseQueryToExpression(query, searchContext) { | |||||||
|  * @param {string} query |  * @param {string} query | ||||||
|  * @return {Note[]} |  * @return {Note[]} | ||||||
|  */ |  */ | ||||||
| function findNotes(query) { | function searchNotes(query) { | ||||||
|     const searchResults = findResultsWithQuery(query, new SearchContext()); |     const searchResults = findResultsWithQuery(query, new SearchContext()); | ||||||
|  |  | ||||||
|     return searchResults.map(sr => becca.notes[sr.noteId]); |     return searchResults.map(sr => becca.notes[sr.noteId]); | ||||||
| @@ -263,5 +263,5 @@ module.exports = { | |||||||
|     searchTrimmedNotes, |     searchTrimmedNotes, | ||||||
|     searchNotesForAutocomplete, |     searchNotesForAutocomplete, | ||||||
|     findResultsWithQuery, |     findResultsWithQuery, | ||||||
|     findNotes |     searchNotes | ||||||
| }; | }; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user