Merge branch 'beta'

This commit is contained in:
zadam 2023-06-13 23:24:09 +02:00
commit 6f16b4caec
10 changed files with 68 additions and 16 deletions

4
package-lock.json generated
View file

@ -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": {

View file

@ -2,7 +2,7 @@
"name": "trilium",
"productName": "Trilium Notes",
"description": "Trilium Notes",
"version": "0.60.1-beta",
"version": "0.60.2-beta",
"license": "AGPL-3.0-only",
"main": "electron.js",
"bin": {

14
src/etapi/backup.js Normal file
View 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
};

View file

@ -700,7 +700,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:
@ -880,6 +899,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:

View file

@ -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);
}

View file

@ -27,7 +27,8 @@ function getRecentChanges(req) {
for (const noteRevisionRow of noteRevisionRows) {
const note = becca.getNote(noteRevisionRow.noteId);
if (note?.hasAncestor(ancestorNoteId)) {
// for deleted notes, the becca note is null, and it's not possible to (easily) determine if it belongs to a subtree
if (ancestorNoteId === 'root' || note?.hasAncestor(ancestorNoteId)) {
recentChanges.push(noteRevisionRow);
}
}
@ -43,8 +44,8 @@ function getRecentChanges(req) {
notes.title AS current_title,
notes.isProtected AS current_isProtected,
notes.title,
notes.utcDateCreated AS utcDate,
notes.dateCreated AS date
notes.utcDateCreated AS utcDate, -- different from the second SELECT
notes.dateCreated AS date -- different from the second SELECT
FROM notes
UNION ALL
SELECT
@ -54,15 +55,16 @@ function getRecentChanges(req) {
notes.title AS current_title,
notes.isProtected AS current_isProtected,
notes.title,
notes.utcDateModified AS utcDate,
notes.dateModified AS date
notes.utcDateModified AS utcDate, -- different from the first SELECT
notes.dateModified AS date -- different from the first SELECT
FROM notes
WHERE notes.isDeleted = 1`);
for (const noteRow of noteRows) {
const note = becca.getNote(noteRow.noteId);
if (note?.hasAncestor(ancestorNoteId)) {
// for deleted notes, the becca note is null, and it's not possible to (easily) determine if it belongs to a subtree
if (ancestorNoteId === 'root' || note?.hasAncestor(ancestorNoteId)) {
recentChanges.push(noteRow);
}
}

View file

@ -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 {

View file

@ -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);
}

View file

@ -1 +1 @@
module.exports = { buildDate:"2023-05-26T23:11:53+02:00", buildRevision: "82efc924136c5b215e39f2108f00dd2bf075271c" };
module.exports = { buildDate:"2023-06-08T22:46:52+02:00", buildRevision: "6e69cafe5419e8efcc6f652647f9227dbcfa1e18" };

View file

@ -0,0 +1,4 @@
PUT {{triliumHost}}/etapi/backup/etapi_test
Authorization: {{authToken}}
> {% client.assert(response.status === 201); %}