mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 13:01:31 +08:00 
			
		
		
		
	use standard search to find notes with same attrs
This commit is contained in:
		
							parent
							
								
									a87e59cecb
								
							
						
					
					
						commit
						f700e6e12b
					
				| @ -93,12 +93,18 @@ const TPL = ` | |||||||
|     max-height: 500px; |     max-height: 500px; | ||||||
|     overflow: auto; |     overflow: auto; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .attr-extras-list { | ||||||
|  |     padding-left: 20px; | ||||||
|  |     margin-top: 10px; | ||||||
|  |     margin-bottom: 10px; | ||||||
|  | } | ||||||
| </style> | </style> | ||||||
| 
 | 
 | ||||||
| <div class="attr-extras" style="display: none;"> | <div class="attr-extras" style="display: none;"> | ||||||
|     <div class="attr-extras-title"></div> |     <div class="attr-extras-title"></div> | ||||||
|      |      | ||||||
|     <div class="attr-extras-list"></div> |     <ul class="attr-extras-list"></ul> | ||||||
|      |      | ||||||
|     <div class="attr-extras-more-notes"></div> |     <div class="attr-extras-more-notes"></div> | ||||||
| </div> | </div> | ||||||
| @ -117,6 +123,8 @@ export default class NoteAttributesWidget extends TabAwareWidget { | |||||||
|             const content = this.textEditor.getData(); |             const content = this.textEditor.getData(); | ||||||
| 
 | 
 | ||||||
|             this.parse(content); |             this.parse(content); | ||||||
|  | 
 | ||||||
|  |             this.$attrExtras.hide(); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -129,16 +137,19 @@ export default class NoteAttributesWidget extends TabAwareWidget { | |||||||
|         this.$attrExtrasMoreNotes = this.$widget.find('.attr-extras-more-notes'); |         this.$attrExtrasMoreNotes = this.$widget.find('.attr-extras-more-notes'); | ||||||
|         this.initialized = this.initEditor(); |         this.initialized = this.initEditor(); | ||||||
| 
 | 
 | ||||||
|         this.$editor.keypress(async e => { |         this.$editor.on('keydown', async e => { | ||||||
|             const keycode = (e.keyCode ? e.keyCode : e.which); |             const keycode = (e.keyCode ? e.keyCode : e.which); | ||||||
|  | 
 | ||||||
|             if (keycode === 13) { |             if (keycode === 13) { | ||||||
|                 const attributes = attributesParser.lexAndParse(this.textEditor.getData()); |                 const attributes = attributesParser.lexAndParse(this.textEditor.getData()); | ||||||
| 
 | 
 | ||||||
|                 await server.put(`notes/${this.noteId}/attributes2`, attributes, this.componentId); |                 await server.put(`notes/${this.noteId}/attributes2`, attributes, this.componentId); | ||||||
| 
 |  | ||||||
|                 console.log("Saved!"); |  | ||||||
|             } |             } | ||||||
|         }) | 
 | ||||||
|  |             this.$attrExtras.hide(); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         this.$editor.on('blur', () => this.$attrExtras.hide()); | ||||||
| 
 | 
 | ||||||
|         return this.$widget; |         return this.$widget; | ||||||
|     } |     } | ||||||
| @ -178,20 +189,26 @@ export default class NoteAttributesWidget extends TabAwareWidget { | |||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (!matchedAttr) { |                 if (!matchedAttr) { | ||||||
|                     console.log(`Not found attribute for index ${clickIndex}, attr: ${JSON.stringify(parsedAttrs)}, text: ${attrText}`); |                     this.$attrExtras.hide(); | ||||||
| 
 | 
 | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 let noteIds = await server.post('attributes/notes-with-attribute', { |                 const searchString = this.formatAttrForSearch(matchedAttr); | ||||||
|  | 
 | ||||||
|  |                 let {count, results} = await server.get('search/' + encodeURIComponent(searchString), { | ||||||
|                     type: matchedAttr.type, |                     type: matchedAttr.type, | ||||||
|                     name: matchedAttr.name, |                     name: matchedAttr.name, | ||||||
|                     value: matchedPart === 'value' ? matchedAttr.value : undefined |                     value: matchedPart === 'value' ? matchedAttr.value : undefined | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|                 noteIds = noteIds.filter(noteId => noteId !== this.noteId); |                 for (const res of results) { | ||||||
|  |                     res.noteId = res.notePathArray[res.notePathArray.length - 1]; | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|                 if (noteIds.length === 0) { |                 results = results.filter(({noteId}) => noteId !== this.noteId); | ||||||
|  | 
 | ||||||
|  |                 if (results.length === 0) { | ||||||
|                     this.$attrExtrasTitle.text( |                     this.$attrExtrasTitle.text( | ||||||
|                         `There are no other notes with ${matchedAttr.type} name "${matchedAttr.name}"` |                         `There are no other notes with ${matchedAttr.type} name "${matchedAttr.name}"` | ||||||
|                         // not displaying value since it can be long
 |                         // not displaying value since it can be long
 | ||||||
| @ -208,9 +225,9 @@ export default class NoteAttributesWidget extends TabAwareWidget { | |||||||
| 
 | 
 | ||||||
|                 this.$attrExtrasList.empty(); |                 this.$attrExtrasList.empty(); | ||||||
| 
 | 
 | ||||||
|                 const displayedNoteIds = noteIds.length <= DISPLAYED_NOTES ? noteIds : noteIds.slice(0, DISPLAYED_NOTES); |                 const displayedResults = results.length <= DISPLAYED_NOTES ? results : results.slice(0, DISPLAYED_NOTES); | ||||||
|                 const displayedNotes = await treeCache.getNotes(displayedNoteIds); |                 const displayedNotes = await treeCache.getNotes(displayedResults.map(res => res.noteId)); | ||||||
| console.log(displayedNoteIds, displayedNotes); | 
 | ||||||
|                 for (const note of displayedNotes) { |                 for (const note of displayedNotes) { | ||||||
|                     const notePath = treeService.getSomeNotePath(note); |                     const notePath = treeService.getSomeNotePath(note); | ||||||
|                     const $noteLink = await linkService.createNoteLink(notePath, {showNotePath: true}); |                     const $noteLink = await linkService.createNoteLink(notePath, {showNotePath: true}); | ||||||
| @ -220,15 +237,15 @@ console.log(displayedNoteIds, displayedNotes); | |||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (noteIds.length > DISPLAYED_NOTES) { |                 if (results.length > DISPLAYED_NOTES) { | ||||||
|                     this.$attrExtrasMoreNotes.show().text(`... and ${noteIds.length - DISPLAYED_NOTES} more.`); |                     this.$attrExtrasMoreNotes.show().text(`... and ${count - DISPLAYED_NOTES} more.`); | ||||||
|                 } |                 } | ||||||
|                 else { |                 else { | ||||||
|                     this.$attrExtrasMoreNotes.hide(); |                     this.$attrExtrasMoreNotes.hide(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 this.$attrExtras.css("left", e.pageX - this.$attrExtras.width() / 2); |                 this.$attrExtras.css("left", e.pageX - this.$attrExtras.width() / 2); | ||||||
|                 this.$attrExtras.css("top", e.pageY + 20); |                 this.$attrExtras.css("top", e.pageY + 30); | ||||||
|                 this.$attrExtras.show(); |                 this.$attrExtras.show(); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
| @ -315,7 +332,7 @@ console.log(displayedNoteIds, displayedNotes); | |||||||
|         const $attributesContainer = $("<div>"); |         const $attributesContainer = $("<div>"); | ||||||
| 
 | 
 | ||||||
|         await this.renderAttributes(ownedAttributes, $attributesContainer); |         await this.renderAttributes(ownedAttributes, $attributesContainer); | ||||||
| console.log($attributesContainer.html()); | 
 | ||||||
|         this.textEditor.setData($attributesContainer.html()); |         this.textEditor.setData($attributesContainer.html()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -330,14 +347,20 @@ console.log($attributesContainer.html()); | |||||||
|     async renderAttributes(attributes, $container) { |     async renderAttributes(attributes, $container) { | ||||||
|         for (const attribute of attributes) { |         for (const attribute of attributes) { | ||||||
|             if (attribute.type === 'label') { |             if (attribute.type === 'label') { | ||||||
|                 $container.append(utils.formatLabel(attribute) + " "); |                 $container.append(document.createTextNode('#' + attribute.name)); | ||||||
|  | 
 | ||||||
|  |                 if (attribute.value) { | ||||||
|  |                     $container.append('='); | ||||||
|  |                     $container.append(document.createTextNode(this.formatValue(attribute.value))); | ||||||
|  |                     $container.append(' '); | ||||||
|  |                 } | ||||||
|             } else if (attribute.type === 'relation') { |             } else if (attribute.type === 'relation') { | ||||||
|                 if (attribute.isAutoLink) { |                 if (attribute.isAutoLink) { | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (attribute.value) { |                 if (attribute.value) { | ||||||
|                     $container.append('~' + attribute.name + "="); |                     $container.append(document.createTextNode('~' + attribute.name + "=")); | ||||||
|                     $container.append(this.createNoteLink(attribute.value)); |                     $container.append(this.createNoteLink(attribute.value)); | ||||||
|                     $container.append(" "); |                     $container.append(" "); | ||||||
|                 } else { |                 } else { | ||||||
| @ -349,6 +372,47 @@ console.log($attributesContainer.html()); | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     formatValue(val) { | ||||||
|  |         if (!/[^\w_-]/.test(val)) { | ||||||
|  |             return val; | ||||||
|  |         } | ||||||
|  |         else if (!val.includes('"')) { | ||||||
|  |             return '"' + val + '"'; | ||||||
|  |         } | ||||||
|  |         else if (!val.includes("'")) { | ||||||
|  |             return "'" + val + "'"; | ||||||
|  |         } | ||||||
|  |         else if (!val.includes("`")) { | ||||||
|  |             return "`" + val + "`"; | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             return '"' + val.replace(/"/g, '\\"') + '"'; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     formatAttrForSearch(attr) { | ||||||
|  |         let searchStr = ''; | ||||||
|  | 
 | ||||||
|  |         if (attr.type === 'label') { | ||||||
|  |             searchStr += '#'; | ||||||
|  |         } | ||||||
|  |         else if (attr.type === 'relation') { | ||||||
|  |             searchStr += '~'; | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             throw new Error(`Unrecognized attribute type ${JSON.stringify(attr)}`); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         searchStr += attr.name; | ||||||
|  | 
 | ||||||
|  |         if (attr.value) { | ||||||
|  |             searchStr += '='; | ||||||
|  |             searchStr += this.formatValue(attr.value); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return searchStr; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     parse(content) { |     parse(content) { | ||||||
|         if (content.startsWith('<p>')) { |         if (content.startsWith('<p>')) { | ||||||
|             content = content.substr(3); |             content = content.substr(3); | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ export default class NoteTitleWidget extends TabAwareWidget { | |||||||
|         this.$noteTitle.on('input', () => this.spacedUpdate.scheduleUpdate()); |         this.$noteTitle.on('input', () => this.spacedUpdate.scheduleUpdate()); | ||||||
| 
 | 
 | ||||||
|         utils.bindElShortcut(this.$noteTitle, 'return', () => { |         utils.bindElShortcut(this.$noteTitle, 'return', () => { | ||||||
|             this.triggerCommand('focusOnDetail', {tabId: this.tabContext.tabId}); |             this.triggerCommand('focusOnAttributes', {tabId: this.tabContext.tabId}); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         return this.$widget; |         return this.$widget; | ||||||
|  | |||||||
| @ -258,14 +258,6 @@ async function deleteRelation(req) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function getNotesWithAttribute(req) { |  | ||||||
|     const {type, name, value} = req.body; |  | ||||||
| 
 |  | ||||||
|     const notes = await attributeService.getNotesWithAttribute(type, name, value); |  | ||||||
| 
 |  | ||||||
|     return notes.map(note => note.noteId); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     updateNoteAttributes, |     updateNoteAttributes, | ||||||
|     updateNoteAttributes2, |     updateNoteAttributes2, | ||||||
| @ -275,6 +267,5 @@ module.exports = { | |||||||
|     getValuesForAttribute, |     getValuesForAttribute, | ||||||
|     getEffectiveNoteAttributes, |     getEffectiveNoteAttributes, | ||||||
|     createRelation, |     createRelation, | ||||||
|     deleteRelation, |     deleteRelation | ||||||
|     getNotesWithAttribute |  | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -7,12 +7,13 @@ const scriptService = require('../../services/script'); | |||||||
| const searchService = require('../../services/search/search'); | const searchService = require('../../services/search/search'); | ||||||
| 
 | 
 | ||||||
| async function searchNotes(req) { | async function searchNotes(req) { | ||||||
|     const notePaths = await searchService.searchNotes(req.params.searchString); |     const {count, results} = await searchService.searchNotes(req.params.searchString); | ||||||
| 
 | 
 | ||||||
|     try { |     try { | ||||||
|         return { |         return { | ||||||
|             success: true, |             success: true, | ||||||
|             results: notePaths |             count, | ||||||
|  |             results | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     catch { |     catch { | ||||||
|  | |||||||
| @ -177,7 +177,6 @@ function register(app) { | |||||||
|     apiRoute(DELETE, '/api/notes/:noteId/attributes/:attributeId', attributesRoute.deleteNoteAttribute); |     apiRoute(DELETE, '/api/notes/:noteId/attributes/:attributeId', attributesRoute.deleteNoteAttribute); | ||||||
|     apiRoute(GET, '/api/attributes/names', attributesRoute.getAttributeNames); |     apiRoute(GET, '/api/attributes/names', attributesRoute.getAttributeNames); | ||||||
|     apiRoute(GET, '/api/attributes/values/:attributeName', attributesRoute.getValuesForAttribute); |     apiRoute(GET, '/api/attributes/values/:attributeName', attributesRoute.getValuesForAttribute); | ||||||
|     apiRoute(POST, '/api/attributes/notes-with-attribute', attributesRoute.getNotesWithAttribute); |  | ||||||
| 
 | 
 | ||||||
|     apiRoute(POST, '/api/notes/:noteId/link-map', linkMapRoute.getLinkMap); |     apiRoute(POST, '/api/notes/:noteId/link-map', linkMapRoute.getLinkMap); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -41,27 +41,6 @@ const BUILTIN_ATTRIBUTES = [ | |||||||
|     { type: 'relation', name: 'renderNote', isDangerous: true } |     { type: 'relation', name: 'renderNote', isDangerous: true } | ||||||
| ]; | ]; | ||||||
| 
 | 
 | ||||||
| async function getNotesWithAttribute(type, name, value) { |  | ||||||
|     let valueCondition = ""; |  | ||||||
|     let params = [type, name]; |  | ||||||
| 
 |  | ||||||
|     if (value !== undefined) { |  | ||||||
|         valueCondition = " AND attributes.value = ?"; |  | ||||||
|         params.push(value); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return await repository.getEntities(` |  | ||||||
|         SELECT notes.*  |  | ||||||
|         FROM notes  |  | ||||||
|         JOIN attributes USING (noteId)  |  | ||||||
|         WHERE notes.isDeleted = 0  |  | ||||||
|           AND attributes.isDeleted = 0  |  | ||||||
|           AND attributes.type = ?  |  | ||||||
|           AND attributes.name = ?  |  | ||||||
|           ${valueCondition}  |  | ||||||
|         ORDER BY position`, params);
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| async function getNotesWithLabel(name, value) { | async function getNotesWithLabel(name, value) { | ||||||
|     let valueCondition = ""; |     let valueCondition = ""; | ||||||
|     let params = [name]; |     let params = [name]; | ||||||
| @ -155,7 +134,6 @@ function getBuiltinAttributeNames() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module.exports = { | module.exports = { | ||||||
|     getNotesWithAttribute, |  | ||||||
|     getNotesWithLabel, |     getNotesWithLabel, | ||||||
|     getNotesWithLabels, |     getNotesWithLabels, | ||||||
|     getNoteWithLabel, |     getNoteWithLabel, | ||||||
|  | |||||||
| @ -87,11 +87,13 @@ async function searchNotes(query) { | |||||||
|         fuzzyAttributeSearch: false |         fuzzyAttributeSearch: false | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     let searchResults = await findNotesWithQuery(query, parsingContext); |     const allSearchResults = await findNotesWithQuery(query, parsingContext); | ||||||
|  |     const trimmedSearchResults = allSearchResults.slice(0, 200); | ||||||
| 
 | 
 | ||||||
|     searchResults = searchResults.slice(0, 200); |     return { | ||||||
| 
 |         count: allSearchResults.length, | ||||||
|     return searchResults; |         results: trimmedSearchResults | ||||||
|  |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function searchNotesForAutocomplete(query) { | async function searchNotesForAutocomplete(query) { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 zadam
						zadam