mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-03 20:06:08 +01:00 
			
		
		
		
	Compare commits
	
		
			9 Commits
		
	
	
		
			v0.60.2-be
			...
			v0.60.3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					e22f77eae7 | ||
| 
						 | 
					3223e76787 | ||
| 
						 | 
					74400dad97 | ||
| 
						 | 
					1b68adf3e4 | ||
| 
						 | 
					bea39f37ee | ||
| 
						 | 
					6548149107 | ||
| 
						 | 
					6015a067ec | ||
| 
						 | 
					4a1ecd906b | ||
| 
						 | 
					004cfe1965 | 
							
								
								
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -1,12 +1,12 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "trilium",
 | 
			
		||||
  "version": "0.60.1-beta",
 | 
			
		||||
  "version": "0.60.2-beta",
 | 
			
		||||
  "lockfileVersion": 2,
 | 
			
		||||
  "requires": true,
 | 
			
		||||
  "packages": {
 | 
			
		||||
    "": {
 | 
			
		||||
      "name": "trilium",
 | 
			
		||||
      "version": "0.60.1-beta",
 | 
			
		||||
      "version": "0.60.2-beta",
 | 
			
		||||
      "hasInstallScript": true,
 | 
			
		||||
      "license": "AGPL-3.0-only",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
  "name": "trilium",
 | 
			
		||||
  "productName": "Trilium Notes",
 | 
			
		||||
  "description": "Trilium Notes",
 | 
			
		||||
  "version": "0.60.2-beta",
 | 
			
		||||
  "version": "0.60.3",
 | 
			
		||||
  "license": "AGPL-3.0-only",
 | 
			
		||||
  "main": "electron.js",
 | 
			
		||||
  "bin": {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								src/etapi/backup.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/etapi/backup.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
const eu = require("./etapi_utils");
 | 
			
		||||
const backupService = require("../services/backup");
 | 
			
		||||
 | 
			
		||||
function register(router) {
 | 
			
		||||
    eu.route(router, 'put', '/etapi/backup/:backupName', async (req, res, next) => {
 | 
			
		||||
        await backupService.backupNow(req.params.backupName);
 | 
			
		||||
 | 
			
		||||
        res.sendStatus(204);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    register
 | 
			
		||||
};
 | 
			
		||||
@@ -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}/note-revision:
 | 
			
		||||
    parameters:
 | 
			
		||||
      - name: noteId
 | 
			
		||||
@@ -700,7 +717,26 @@ paths:
 | 
			
		||||
            application/json; charset=utf-8:
 | 
			
		||||
              schema:
 | 
			
		||||
                $ref: '#/components/schemas/Error'
 | 
			
		||||
 | 
			
		||||
  /backup/{backupName}:
 | 
			
		||||
    parameters:
 | 
			
		||||
      - name: backupName
 | 
			
		||||
        in: path
 | 
			
		||||
        required: true
 | 
			
		||||
        description: If the backupName is e.g. "now", then the backup will be written to "backup-now.db" file
 | 
			
		||||
        schema:
 | 
			
		||||
          $ref: '#/components/schemas/StringId'
 | 
			
		||||
    put:
 | 
			
		||||
      description: Create a database backup under a given name
 | 
			
		||||
      operationId: createBackup
 | 
			
		||||
      responses:
 | 
			
		||||
        '204':
 | 
			
		||||
          description: backup has been created
 | 
			
		||||
        default:
 | 
			
		||||
          description: unexpected error
 | 
			
		||||
          content:
 | 
			
		||||
            application/json; charset=utf-8:
 | 
			
		||||
              schema:
 | 
			
		||||
                $ref: '#/components/schemas/Error'
 | 
			
		||||
components:
 | 
			
		||||
  securitySchemes:
 | 
			
		||||
    EtapiTokenAuth:
 | 
			
		||||
@@ -833,6 +869,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.
 | 
			
		||||
@@ -880,6 +923,10 @@ components:
 | 
			
		||||
      type: string
 | 
			
		||||
      pattern: '[a-zA-Z0-9_]{4,32}'
 | 
			
		||||
      example: evnnmvHTCgIn
 | 
			
		||||
    StringId:
 | 
			
		||||
      type: string
 | 
			
		||||
      pattern: '[a-zA-Z0-9_]{1,32}'
 | 
			
		||||
      example: my_ID
 | 
			
		||||
    EntityIdList:
 | 
			
		||||
      type: array
 | 
			
		||||
      items:
 | 
			
		||||
 
 | 
			
		||||
@@ -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) => {
 | 
			
		||||
@@ -141,11 +142,21 @@ function register(router) {
 | 
			
		||||
        // (e.g. branchIds are not seen in UI), that we export "note export" instead.
 | 
			
		||||
        const branch = note.getParentBranches()[0];
 | 
			
		||||
 | 
			
		||||
        console.log(note.getParentBranches());
 | 
			
		||||
 | 
			
		||||
        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/note-revision', (req, res, next) => {
 | 
			
		||||
        const note = eu.getAndCheckNote(req.params.noteId);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -173,7 +173,7 @@ export default class Entrypoints extends Component {
 | 
			
		||||
            const resp = await server.post(`sql/execute/${note.noteId}`);
 | 
			
		||||
 | 
			
		||||
            if (!resp.success) {
 | 
			
		||||
                toastService.showError(`Error occurred while executing SQL query: ${resp.message}`);
 | 
			
		||||
                toastService.showError(`Error occurred while executing SQL query: ${resp.error}`);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await appContext.triggerEvent('sqlQueryResults', {ntxId: ntxId, results: resp.results});
 | 
			
		||||
 
 | 
			
		||||
@@ -230,6 +230,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;
 | 
			
		||||
 
 | 
			
		||||
@@ -148,6 +148,9 @@ const TPL = `
 | 
			
		||||
 | 
			
		||||
const MAX_SEARCH_RESULTS_IN_TREE = 100;
 | 
			
		||||
 | 
			
		||||
// this has to be hanged on the actual elements to effectively intercept and stop click event
 | 
			
		||||
const cancelClickPropagation = e => e.stopPropagation();
 | 
			
		||||
 | 
			
		||||
export default class NoteTreeWidget extends NoteContextAwareWidget {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super();
 | 
			
		||||
@@ -559,7 +562,8 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
 | 
			
		||||
                const isHoistedNote = activeNoteContext && activeNoteContext.hoistedNoteId === note.noteId && note.noteId !== 'root';
 | 
			
		||||
 | 
			
		||||
                if (isHoistedNote) {
 | 
			
		||||
                    const $unhoistButton = $('<span class="tree-item-button unhoist-button bx bx-door-open" title="Unhoist"></span>');
 | 
			
		||||
                    const $unhoistButton = $('<span class="tree-item-button unhoist-button bx bx-door-open" title="Unhoist"></span>')
 | 
			
		||||
                        .on("click", cancelClickPropagation);
 | 
			
		||||
 | 
			
		||||
                    // unhoist button is prepended since compared to other buttons this is not just convenience
 | 
			
		||||
                    // on the mobile interface - it's the only way to unhoist
 | 
			
		||||
@@ -567,19 +571,22 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (note.hasLabel('workspace') && !isHoistedNote) {
 | 
			
		||||
                    const $enterWorkspaceButton = $('<span class="tree-item-button enter-workspace-button bx bx-door-open" title="Hoist this note (workspace)"></span>');
 | 
			
		||||
                    const $enterWorkspaceButton = $('<span class="tree-item-button enter-workspace-button bx bx-door-open" title="Hoist this note (workspace)"></span>')
 | 
			
		||||
                        .on("click", cancelClickPropagation);
 | 
			
		||||
 | 
			
		||||
                    $span.append($enterWorkspaceButton);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (note.type === 'search') {
 | 
			
		||||
                    const $refreshSearchButton = $('<span class="tree-item-button refresh-search-button bx bx-refresh" title="Refresh saved search results"></span>');
 | 
			
		||||
                    const $refreshSearchButton = $('<span class="tree-item-button refresh-search-button bx bx-refresh" title="Refresh saved search results"></span>')
 | 
			
		||||
                        .on("click", cancelClickPropagation);
 | 
			
		||||
 | 
			
		||||
                    $span.append($refreshSearchButton);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!['search', 'launcher'].includes(note.type) && !note.isOptions() && !note.isLaunchBarConfig()) {
 | 
			
		||||
                    const $createChildNoteButton = $('<span class="tree-item-button add-note-button bx bx-plus" title="Create child note"></span>');
 | 
			
		||||
                    const $createChildNoteButton = $('<span class="tree-item-button add-note-button bx bx-plus" title="Create child note"></span>')
 | 
			
		||||
                        .on("click", cancelClickPropagation);
 | 
			
		||||
 | 
			
		||||
                    $span.append($createChildNoteButton);
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -285,6 +285,8 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        const content = {
 | 
			
		||||
            type: "excalidraw",
 | 
			
		||||
            version: 2,
 | 
			
		||||
            _meta: "This note has type `canvas`. It uses excalidraw and stores an exported svg alongside.",
 | 
			
		||||
            elements, // excalidraw
 | 
			
		||||
            appState, // excalidraw
 | 
			
		||||
 
 | 
			
		||||
@@ -110,6 +110,10 @@ export default class EtapiOptions extends OptionsWidget {
 | 
			
		||||
            defaultValue: oldName
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        if(tokenName === null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await server.patch(`etapi-tokens/${etapiTokenId}`, {name: tokenName});
 | 
			
		||||
 | 
			
		||||
        this.refreshTokens();
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,7 @@ function execute(req) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (query.toLowerCase().startsWith('select')) {
 | 
			
		||||
            if (query.toLowerCase().startsWith('select') || query.toLowerCase().startsWith('with')) {
 | 
			
		||||
                results.push(sql.getRows(query));
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
 
 | 
			
		||||
@@ -65,6 +65,7 @@ const etapiBranchRoutes = require('../etapi/branches');
 | 
			
		||||
const etapiNoteRoutes = require('../etapi/notes');
 | 
			
		||||
const etapiSpecialNoteRoutes = require('../etapi/special_notes');
 | 
			
		||||
const etapiSpecRoute = require('../etapi/spec');
 | 
			
		||||
const etapiBackupRoute = require('../etapi/backup');
 | 
			
		||||
 | 
			
		||||
const csrfMiddleware = csurf({
 | 
			
		||||
    cookie: true,
 | 
			
		||||
@@ -315,6 +316,7 @@ function register(app) {
 | 
			
		||||
    etapiNoteRoutes.register(router);
 | 
			
		||||
    etapiSpecialNoteRoutes.register(router);
 | 
			
		||||
    etapiSpecRoute.register(router);
 | 
			
		||||
    etapiBackupRoute.register(router);
 | 
			
		||||
 | 
			
		||||
    app.use('', router);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1 @@
 | 
			
		||||
module.exports = { buildDate:"2023-06-08T22:46:52+02:00", buildRevision: "6e69cafe5419e8efcc6f652647f9227dbcfa1e18" };
 | 
			
		||||
module.exports = { buildDate:"2023-06-15T23:23:37+02:00", buildRevision: "3223e767875e5379c99ff58a562cb9c1a2641bdf" };
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								test-etapi/create-backup.http
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test-etapi/create-backup.http
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
PUT {{triliumHost}}/etapi/backup/etapi_test
 | 
			
		||||
Authorization: {{authToken}}
 | 
			
		||||
 | 
			
		||||
> {% client.assert(response.status === 201); %}
 | 
			
		||||
							
								
								
									
										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