mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	Merge branch 'stable' into next61
# Conflicts: # src/etapi/etapi.openapi.yaml # src/etapi/notes.js # src/public/app/widgets/type_widgets/editable_text.js # src/services/app_info.js
This commit is contained in:
		
							
								
								
									
										1
									
								
								db/migrations/0214__fix_root_children_ordering.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								db/migrations/0214__fix_root_children_ordering.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| UPDATE branches SET notePosition = notePosition - 999899999 WHERE parentNoteId = 'root' AND notePosition > 999999999; | ||||
| @@ -2,7 +2,7 @@ | ||||
|   "name": "trilium", | ||||
|   "productName": "Trilium Notes", | ||||
|   "description": "Trilium Notes", | ||||
|   "version": "0.60.2-beta", | ||||
|   "version": "0.60.4", | ||||
|   "license": "AGPL-3.0-only", | ||||
|   "main": "electron.js", | ||||
|   "bin": { | ||||
|   | ||||
| @@ -33,13 +33,7 @@ paths: | ||||
|           content: | ||||
|             application/json; charset=utf-8: | ||||
|               schema: | ||||
|                 properties: | ||||
|                   note: | ||||
|                     $ref: '#/components/schemas/Note' | ||||
|                     description: Created note | ||||
|                   branch: | ||||
|                     $ref: '#/components/schemas/Branch' | ||||
|                     description: Created branch | ||||
|                 $ref: '#/components/schemas/NoteWithBranch' | ||||
|         default: | ||||
|           description: unexpected error | ||||
|           content: | ||||
| @@ -291,6 +285,29 @@ paths: | ||||
|             application/json; charset=utf-8: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/Error' | ||||
|   /notes/{noteId}/import: | ||||
|     parameters: | ||||
|       - name: noteId | ||||
|         in: path | ||||
|         required: true | ||||
|         schema: | ||||
|           $ref: '#/components/schemas/EntityId' | ||||
|     post: | ||||
|       description: Imports ZIP file into a given note. | ||||
|       operationId: importZip | ||||
|       responses: | ||||
|         '201': | ||||
|           description: note created | ||||
|           content: | ||||
|             application/json; charset=utf-8: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/NoteWithBranch' | ||||
|         default: | ||||
|           description: unexpected error | ||||
|           content: | ||||
|             application/json; charset=utf-8: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/Error' | ||||
|   /notes/{noteId}/revision: | ||||
|     parameters: | ||||
|       - name: noteId | ||||
| @@ -855,6 +872,13 @@ components: | ||||
|         utcDateModified: | ||||
|           $ref: '#/components/schemas/UtcDateTime' | ||||
|           readOnly: true | ||||
|     NoteWithBranch: | ||||
|       type: object | ||||
|       properties: | ||||
|         note: | ||||
|           $ref: '#/components/schemas/Note' | ||||
|         branch: | ||||
|           $ref: '#/components/schemas/Branch' | ||||
|     Attribute: | ||||
|       type: object | ||||
|       description: Attribute (Label, Relation) is a key-value record attached to a note. | ||||
|   | ||||
| @@ -8,6 +8,7 @@ const v = require("./validators"); | ||||
| const searchService = require("../services/search/services/search"); | ||||
| const SearchContext = require("../services/search/search_context"); | ||||
| const zipExportService = require("../services/export/zip"); | ||||
| const zipImportService = require("../services/import/zip"); | ||||
|  | ||||
| function register(router) { | ||||
|     eu.route(router, 'get', '/etapi/notes', (req, res, next) => { | ||||
| @@ -151,6 +152,18 @@ function register(router) { | ||||
|         zipExportService.exportToZip(taskContext, branch, format, res); | ||||
|     }); | ||||
|  | ||||
|     eu.route(router, 'post' ,'/etapi/notes/:noteId/import', (req, res, next) => { | ||||
|         const note = eu.getAndCheckNote(req.params.noteId); | ||||
|         const taskContext = new TaskContext('no-progress-reporting'); | ||||
|  | ||||
|         zipImportService.importZip(taskContext, req.body, note).then(importedNote => { | ||||
|             res.status(201).json({ | ||||
|                 note: mappers.mapNoteToPojo(importedNote), | ||||
|                 branch: mappers.mapBranchToPojo(importedNote.getBranches()[0]), | ||||
|             }); | ||||
|         }); // we need better error handling here, async errors won't be properly processed. | ||||
|     }); | ||||
|  | ||||
|     eu.route(router, 'post' ,'/etapi/notes/:noteId/revision', (req, res, next) => { | ||||
|         const note = eu.getAndCheckNote(req.params.noteId); | ||||
|  | ||||
|   | ||||
| @@ -212,6 +212,15 @@ export default class NoteDetailWidget extends NoteContextAwareWidget { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async runActiveNoteCommand(params) { | ||||
|         if (this.isNoteContext(params.ntxId)) { | ||||
|             // make sure that script is saved before running it #4028 | ||||
|             await this.spacedUpdate.updateNowIfNecessary(); | ||||
|         } | ||||
|  | ||||
|         return await this.parent.triggerCommand('runActiveNote', params); | ||||
|     } | ||||
|  | ||||
|     async printActiveNoteEvent() { | ||||
|         if (!this.noteContext.isActive()) { | ||||
|             return; | ||||
|   | ||||
| @@ -93,11 +93,11 @@ export default class NoteIconWidget extends NoteContextAwareWidget { | ||||
|         }); | ||||
|  | ||||
|         this.$iconCategory = this.$widget.find("select[name='icon-category']"); | ||||
|         this.$iconCategory.on('change', () => this.renderFilteredDropdown()); | ||||
|         this.$iconCategory.on('change', () => this.renderDropdown()); | ||||
|         this.$iconCategory.on('click', e => e.stopPropagation()); | ||||
|  | ||||
|         this.$iconSearch = this.$widget.find("input[name='icon-search']"); | ||||
|         this.$iconSearch.on('input', () => this.renderFilteredDropdown()); | ||||
|         this.$iconSearch.on('input', () => this.renderDropdown()); | ||||
|  | ||||
|         this.$notePathList = this.$widget.find(".note-path-list"); | ||||
|         this.$widget.on('show.bs.dropdown', async () => { | ||||
| @@ -140,15 +140,9 @@ export default class NoteIconWidget extends NoteContextAwareWidget { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     renderFilteredDropdown() { | ||||
|         const categoryId = parseInt(this.$iconCategory.find('option:selected').val()); | ||||
|         const search = this.$iconSearch.val(); | ||||
|  | ||||
|         this.renderDropdown(categoryId, search); | ||||
|     } | ||||
|  | ||||
|     async renderDropdown(categoryId, search) { | ||||
|         const iconToCountPromise = this.getIconToCountMap(); | ||||
|     async renderDropdown() { | ||||
|         const iconToCount = await this.getIconToCountMap(); | ||||
|         const {icons} = (await import('./icon_list.js')).default; | ||||
|  | ||||
|         this.$iconList.empty(); | ||||
|  | ||||
| @@ -164,9 +158,8 @@ export default class NoteIconWidget extends NoteContextAwareWidget { | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         const {icons} = (await import('./icon_list.js')).default; | ||||
|  | ||||
|         search = search?.trim()?.toLowerCase(); | ||||
|         const categoryId = parseInt(this.$iconCategory.find('option:selected').val()); | ||||
|         const search = this.$iconSearch.val().trim().toLowerCase(); | ||||
|  | ||||
|         const filteredIcons = icons.filter(icon => { | ||||
|             if (categoryId && icon.category_id !== categoryId) { | ||||
| @@ -182,8 +175,6 @@ export default class NoteIconWidget extends NoteContextAwareWidget { | ||||
|             return true; | ||||
|         }); | ||||
|  | ||||
|         const iconToCount = await iconToCountPromise; | ||||
|  | ||||
|         filteredIcons.sort((a, b) => { | ||||
|             const countA = iconToCount[a.className] || 0; | ||||
|             const countB = iconToCount[b.className] || 0; | ||||
| @@ -199,9 +190,12 @@ export default class NoteIconWidget extends NoteContextAwareWidget { | ||||
|     } | ||||
|  | ||||
|     async getIconToCountMap() { | ||||
|         const {iconClassToCountMap} = await server.get('other/icon-usage'); | ||||
|         if (!this.iconToCountCache) { | ||||
|             this.iconToCountCache = server.get('other/icon-usage'); | ||||
|             setTimeout(() => this.iconToCountCache = null, 20000); // invalidate cache after 20 seconds | ||||
|         } | ||||
|  | ||||
|         return iconClassToCountMap; | ||||
|         return (await this.iconToCountCache).iconClassToCountMap; | ||||
|     } | ||||
|  | ||||
|     renderIcon(icon) { | ||||
|   | ||||
| @@ -185,14 +185,8 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { | ||||
|     async doRefresh(note) { | ||||
|         const blob = await note.getBlob(); | ||||
|  | ||||
|         await this.spacedUpdate.allowUpdateWithoutChange(() => { | ||||
|             // https://github.com/zadam/trilium/issues/3914 | ||||
|             // todo: quite hacky, but it works. remove it if ckeditor has fixed it. | ||||
|             this.$editor.trigger('focus'); | ||||
|             this.$editor.trigger('blur'); | ||||
|  | ||||
|             this.watchdog.editor.setData(blob.content || ""); | ||||
|         }); | ||||
|         await this.spacedUpdate.allowUpdateWithoutChange(() => | ||||
|             this.watchdog.editor.setData(blob.content || "")); | ||||
|     } | ||||
|  | ||||
|     getData() { | ||||
|   | ||||
| @@ -4,7 +4,7 @@ const build = require('./build'); | ||||
| const packageJson = require('../../package'); | ||||
| const {TRILIUM_DATA_DIR} = require('./data_dir'); | ||||
|  | ||||
| const APP_DB_VERSION = 221; | ||||
| const APP_DB_VERSION = 222; | ||||
| const SYNC_VERSION = 30; | ||||
| const CLIPPER_PROTOCOL_VERSION = "1.0"; | ||||
|  | ||||
|   | ||||
| @@ -1 +1 @@ | ||||
| module.exports = { buildDate:"2023-06-08T22:46:52+02:00", buildRevision: "6e69cafe5419e8efcc6f652647f9227dbcfa1e18" }; | ||||
| module.exports = { buildDate:"2023-06-19T23:26:50+02:00", buildRevision: "5905950c17791ce0eb278e010c2c8b3450fdb447" }; | ||||
|   | ||||
| @@ -27,11 +27,13 @@ const ws = require("./ws"); | ||||
| function getNewNotePosition(parentNote) { | ||||
|     if (parentNote.isLabelTruthy('newNotesOnTop')) { | ||||
|         const minNotePos = parentNote.getChildBranches() | ||||
|             .filter(branch => branch.noteId !== '_hidden') // has "always last" note position | ||||
|             .reduce((min, note) => Math.min(min, note.notePosition), 0); | ||||
|  | ||||
|         return minNotePos - 10; | ||||
|     } else { | ||||
|         const maxNotePos = parentNote.getChildBranches() | ||||
|             .filter(branch => branch.noteId !== '_hidden') // has "always last" note position | ||||
|             .reduce((max, note) => Math.max(max, note.notePosition), 0); | ||||
|  | ||||
|         return maxNotePos + 10; | ||||
|   | ||||
| @@ -6,7 +6,7 @@ const ws = require('./ws'); | ||||
| const taskContexts = {}; | ||||
|  | ||||
| class TaskContext { | ||||
|     constructor(taskId, taskType = null, data = null) { | ||||
|     constructor(taskId, taskType = null, data = {}) { | ||||
|         this.taskId = taskId; | ||||
|         this.taskType = taskType; | ||||
|         this.data = data; | ||||
|   | ||||
							
								
								
									
										12
									
								
								test-etapi/import-zip.http
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								test-etapi/import-zip.http
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| POST {{triliumHost}}/etapi/notes/root/import | ||||
| Authorization: {{authToken}} | ||||
| Content-Type: application/octet-stream | ||||
| Content-Transfer-Encoding: binary | ||||
|  | ||||
| < ../db/demo.zip | ||||
|  | ||||
| > {% | ||||
|     client.assert(response.status === 201); | ||||
|     client.assert(response.body.note.title == "Trilium Demo"); | ||||
|     client.assert(response.body.branch.parentNoteId == "root"); | ||||
| %} | ||||
		Reference in New Issue
	
	Block a user