mirror of
https://github.com/zadam/trilium.git
synced 2025-10-30 18:05:55 +01:00
Compare commits
22 Commits
v0.27.1-be
...
v0.27.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b8d7b8fba | ||
|
|
9fca7f09a5 | ||
|
|
fd39d6b3a9 | ||
|
|
a103886ea5 | ||
|
|
373408e401 | ||
|
|
db44c1d8e6 | ||
|
|
95a34c9e2d | ||
|
|
6ce401f260 | ||
|
|
5d74dcd256 | ||
|
|
5a9fc1697b | ||
|
|
927415838c | ||
|
|
d72fcefdc7 | ||
|
|
0be173a8f7 | ||
|
|
c3913a8735 | ||
|
|
e2dfe1b6de | ||
|
|
fec3e47eb8 | ||
|
|
d72efd2450 | ||
|
|
ef1c840aa7 | ||
|
|
1581464d8c | ||
|
|
9de29584a4 | ||
|
|
9e2e6fb50c | ||
|
|
c85979b66b |
@@ -18,6 +18,7 @@ Trilium Notes is a hierarchical note taking application with focus on building l
|
||||
* [Relation maps](https://github.com/zadam/trilium/wiki/Relation-map) for visualizing notes and their relations
|
||||
* [Scripting](https://github.com/zadam/trilium/wiki/Scripts) - see [Advanced showcases](https://github.com/zadam/trilium/wiki/Advanced-showcases)
|
||||
* Scales well in both usability and performance upwards of 100 000 notes
|
||||
* Touch optimized [mobile frontend](https://github.com/zadam/trilium/wiki/Mobile-frontend) for smartphones and tablets
|
||||
* [Night theme](https://github.com/zadam/trilium/wiki/Themes)
|
||||
* [Evernote](https://github.com/zadam/trilium/wiki/Evernote-import) and [Markdown import & export](https://github.com/zadam/trilium/wiki/Markdown)
|
||||
|
||||
|
||||
16
package-lock.json
generated
16
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "trilium",
|
||||
"version": "0.27.0-beta",
|
||||
"version": "0.27.2-beta",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -399,9 +399,9 @@
|
||||
"integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "8.10.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.39.tgz",
|
||||
"integrity": "sha512-rE7fktr02J8ybFf6eysife+WF+L4sAHWzw09DgdCebEu+qDwMvv4zl6Bc+825ttGZP73kCKxa3dhJOoGJ8+5mA==",
|
||||
"version": "10.12.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz",
|
||||
"integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==",
|
||||
"dev": true
|
||||
},
|
||||
"abab": {
|
||||
@@ -2375,12 +2375,12 @@
|
||||
"integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ=="
|
||||
},
|
||||
"electron": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-4.0.0.tgz",
|
||||
"integrity": "sha512-3XPG/3IXlvnT1oe1K6zEushoD0SKbP8xwdrL10EWGe6k2iOV4hSHqJ8vWnR8yZ7VbSXmBRfomEFDNAo/q/cwKw==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-4.0.1.tgz",
|
||||
"integrity": "sha512-kBWDLn1Vq8Tm6+/HpQc8gkjX7wJyQI8v/lf2kAirfi0Q4cXh6vBjozFvV1U/9gGCbyKnIDM+m8/wpyJIjg4w7g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "^8.0.24",
|
||||
"@types/node": "^10.12.18",
|
||||
"electron-download": "^4.1.0",
|
||||
"extract-zip": "^1.0.3"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "trilium",
|
||||
"productName": "Trilium Notes",
|
||||
"description": "Trilium Notes",
|
||||
"version": "0.27.1-beta",
|
||||
"version": "0.27.3",
|
||||
"license": "AGPL-3.0-only",
|
||||
"main": "electron.js",
|
||||
"bin": {
|
||||
@@ -66,7 +66,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"devtron": "1.4.0",
|
||||
"electron": "4.0.0",
|
||||
"electron": "4.0.1",
|
||||
"electron-compile": "6.4.3",
|
||||
"electron-packager": "13.0.1",
|
||||
"electron-rebuild": "1.8.2",
|
||||
|
||||
@@ -15,7 +15,8 @@ const ENTITY_NAME_TO_ENTITY = {
|
||||
"note_revisions": NoteRevision,
|
||||
"recent_notes": RecentNote,
|
||||
"options": Option,
|
||||
"api_tokens": ApiToken
|
||||
"api_tokens": ApiToken,
|
||||
"links": Link
|
||||
};
|
||||
|
||||
function getEntityFromEntityName(entityName) {
|
||||
|
||||
@@ -198,15 +198,17 @@ addTabHandler((async function () {
|
||||
const $syncVersion = $("#sync-version");
|
||||
const $buildDate = $("#build-date");
|
||||
const $buildRevision = $("#build-revision");
|
||||
const $dataDirectory = $("#data-directory");
|
||||
|
||||
const appInfo = await server.get('app-info');
|
||||
|
||||
$appVersion.html(appInfo.appVersion);
|
||||
$dbVersion.html(appInfo.dbVersion);
|
||||
$syncVersion.html(appInfo.syncVersion);
|
||||
$buildDate.html(appInfo.buildDate);
|
||||
$buildRevision.html(appInfo.buildRevision);
|
||||
$appVersion.text(appInfo.appVersion);
|
||||
$dbVersion.text(appInfo.dbVersion);
|
||||
$syncVersion.text(appInfo.syncVersion);
|
||||
$buildDate.text(appInfo.buildDate);
|
||||
$buildRevision.text(appInfo.buildRevision);
|
||||
$buildRevision.attr('href', 'https://github.com/zadam/trilium/commit/' + appInfo.buildRevision);
|
||||
$dataDirectory.text(appInfo.dataDirectory);
|
||||
|
||||
return {};
|
||||
})());
|
||||
|
||||
@@ -426,13 +426,17 @@ function initFancyTree(tree) {
|
||||
clones: {
|
||||
highlightActiveClones: true
|
||||
},
|
||||
renderNode: async function (event, data) {
|
||||
enhanceTitle: async function (event, data) {
|
||||
const node = data.node;
|
||||
const $span = $(node.span);
|
||||
|
||||
if (node.data.noteId !== 'root'
|
||||
&& node.data.noteId === await hoistedNoteService.getHoistedNoteId()
|
||||
&& $span.find('.unhoist-button').length === 0) {
|
||||
|
||||
if (node.data.noteId !== 'root' && node.data.noteId === await hoistedNoteService.getHoistedNoteId()) {
|
||||
const unhoistButton = $('<span> (<a class="unhoist-button">unhoist</a>)</span>');
|
||||
|
||||
$(node.span).append(unhoistButton);
|
||||
$span.append(unhoistButton);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -649,11 +653,15 @@ messagingService.subscribeToSyncMessages(syncData => {
|
||||
}
|
||||
});
|
||||
|
||||
utils.bindShortcut('ctrl+o', () => {
|
||||
utils.bindShortcut('ctrl+o', async () => {
|
||||
const node = getCurrentNode();
|
||||
const parentNoteId = node.data.parentNoteId;
|
||||
const isProtected = treeUtils.getParentProtectedStatus(node);
|
||||
|
||||
if (node.data.noteId === 'root' || node.data.noteId === await hoistedNoteService.getHoistedNoteId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
createNote(node, parentNoteId, 'after', isProtected, true);
|
||||
});
|
||||
|
||||
|
||||
@@ -158,7 +158,11 @@ class TreeCache {
|
||||
return;
|
||||
}
|
||||
|
||||
treeCache.childParentToBranch[childNoteId + '-' + newParentNoteId] = treeCache.childParentToBranch[childNoteId + '-' + oldParentNoteId];
|
||||
const branchId = treeCache.childParentToBranch[childNoteId + '-' + oldParentNoteId];
|
||||
const branch = await this.getBranch(branchId);
|
||||
branch.parentNoteId = newParentNoteId;
|
||||
|
||||
treeCache.childParentToBranch[childNoteId + '-' + newParentNoteId] = branchId;
|
||||
delete treeCache.childParentToBranch[childNoteId + '-' + oldParentNoteId]; // this is correct because we know that oldParentId isn't same as newParentId
|
||||
|
||||
// remove old associations
|
||||
|
||||
@@ -13,8 +13,6 @@ import syncService from "./sync.js";
|
||||
import hoistedNoteService from './hoisted_note.js';
|
||||
import ContextMenuItemsContainer from './context_menu_items_container.js';
|
||||
|
||||
const $tree = $("#tree");
|
||||
|
||||
let clipboardIds = [];
|
||||
let clipboardMode = null;
|
||||
|
||||
@@ -110,11 +108,12 @@ async function getContextMenuItems(event) {
|
||||
const note = await treeCache.getNote(node.data.noteId);
|
||||
const parentNote = await treeCache.getNote(branch.parentNoteId);
|
||||
const isNotRoot = note.noteId !== 'root';
|
||||
const isHoisted = note.noteId === await hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
const itemsContainer = new ContextMenuItemsContainer(contextMenuItems);
|
||||
|
||||
// Modify menu entries depending on node status
|
||||
itemsContainer.enableItem("insertNoteAfter", isNotRoot && parentNote.type !== 'search');
|
||||
itemsContainer.enableItem("insertNoteAfter", isNotRoot && !isHoisted && parentNote.type !== 'search');
|
||||
itemsContainer.enableItem("insertChildNote", note.type !== 'search');
|
||||
itemsContainer.enableItem("delete", isNotRoot && parentNote.type !== 'search');
|
||||
itemsContainer.enableItem("copy", isNotRoot);
|
||||
@@ -125,10 +124,8 @@ async function getContextMenuItems(event) {
|
||||
itemsContainer.enableItem("export", note.type !== 'search');
|
||||
itemsContainer.enableItem("editBranchPrefix", isNotRoot && parentNote.type !== 'search');
|
||||
|
||||
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
itemsContainer.hideItem("hoist", note.noteId === hoistedNoteId);
|
||||
itemsContainer.hideItem("unhoist", note.noteId !== hoistedNoteId || !isNotRoot);
|
||||
itemsContainer.hideItem("hoist", isHoisted);
|
||||
itemsContainer.hideItem("unhoist", !isHoisted || !isNotRoot);
|
||||
|
||||
// Activate node on right-click
|
||||
node.setActive();
|
||||
|
||||
@@ -25,26 +25,20 @@ function SetupModel() {
|
||||
|
||||
this.instanceType = utils.isElectron() ? "desktop" : "server";
|
||||
|
||||
this.setupTypeSelected = this.getSetupType = () =>
|
||||
this.setupNewDocument()
|
||||
|| this.setupSyncFromDesktop()
|
||||
|| this.setupSyncFromServer();
|
||||
this.setupTypeSelected = () => !!this.setupType();
|
||||
|
||||
this.selectSetupType = () => {
|
||||
this.step(this.getSetupType());
|
||||
this.setupType(this.getSetupType());
|
||||
this.step(this.setupType());
|
||||
};
|
||||
|
||||
this.back = () => {
|
||||
this.step("setup-type");
|
||||
|
||||
this.setupNewDocument(false);
|
||||
this.setupSyncFromServer(false);
|
||||
this.setupSyncFromDesktop(false);
|
||||
this.setupType("");
|
||||
};
|
||||
|
||||
this.finish = async () => {
|
||||
if (this.setupNewDocument()) {
|
||||
if (this.setupType() === 'new-document') {
|
||||
const username = this.username();
|
||||
const password1 = this.password1();
|
||||
const password2 = this.password2();
|
||||
@@ -72,7 +66,7 @@ function SetupModel() {
|
||||
window.location.replace("/");
|
||||
});
|
||||
}
|
||||
else if (this.setupSyncFromServer()) {
|
||||
else if (this.setupType() === 'sync-from-server') {
|
||||
const syncServerHost = this.syncServerHost();
|
||||
const syncProxy = this.syncProxy();
|
||||
const username = this.username();
|
||||
|
||||
@@ -45,14 +45,23 @@
|
||||
#header button {
|
||||
padding: 1px 5px 1px 5px;
|
||||
font-size: small;
|
||||
margin-bottom: 2px;
|
||||
margin-top: 2px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
#history-navigation {
|
||||
margin: 0 15px 0 5px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
#global-buttons {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 10px 0 10px 0;
|
||||
margin: 0 10px 0 16px;
|
||||
border: 1px solid #ccc;
|
||||
margin: 0 20px 0 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
|
||||
@@ -155,17 +155,6 @@ span.fancytree-active:not(.fancytree-focused) .fancytree-title {
|
||||
color: #337ab7 !important;
|
||||
}
|
||||
|
||||
#header-title {
|
||||
padding: 5px 20px 5px 10px;
|
||||
font-size: large;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#header .btn-sm {
|
||||
margin-bottom: 2px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
div.ui-tooltip {
|
||||
max-width: 600px;
|
||||
max-height: 600px;
|
||||
@@ -377,13 +366,8 @@ div.ui-tooltip {
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
#history-navigation {
|
||||
margin: 0 20px 0 5px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.btn:not(.btn-primary):not(.btn-danger) {
|
||||
border-color: #bbb;
|
||||
border-color: #ddd;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
@@ -446,7 +430,7 @@ html.theme-dark body {
|
||||
display: block;
|
||||
flex-basis: content;
|
||||
flex-shrink: 1;
|
||||
flex-grow: 100;
|
||||
flex-grow: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@@ -544,7 +528,8 @@ table.promoted-attributes-in-tooltip td, table.promoted-attributes-in-tooltip th
|
||||
max-height: 300px;
|
||||
overflow: hidden;
|
||||
color: black;
|
||||
border: 1px solid #aaa;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ const appInfo = require('../../services/app_info');
|
||||
const eventService = require('../../services/events');
|
||||
const cls = require('../../services/cls');
|
||||
const sqlInit = require('../../services/sql_init');
|
||||
const sql = require('../../services/sql');
|
||||
|
||||
async function loginSync(req) {
|
||||
if (!await sqlInit.schemaExists()) {
|
||||
@@ -44,7 +45,8 @@ async function loginSync(req) {
|
||||
req.session.loggedIn = true;
|
||||
|
||||
return {
|
||||
sourceId: sourceIdService.getCurrentSourceId()
|
||||
sourceId: sourceIdService.getCurrentSourceId(),
|
||||
maxSyncId: await sql.getValue("SELECT MAX(id) FROM sync")
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
|
||||
const build = require('./build');
|
||||
const packageJson = require('../../package');
|
||||
const {TRILIUM_DATA_DIR} = require('./data_dir');
|
||||
|
||||
const APP_DB_VERSION = 121;
|
||||
const SYNC_VERSION = 2;
|
||||
const SYNC_VERSION = 3;
|
||||
|
||||
module.exports = {
|
||||
appVersion: packageJson.version,
|
||||
dbVersion: APP_DB_VERSION,
|
||||
syncVersion: SYNC_VERSION,
|
||||
buildDate: build.buildDate,
|
||||
buildRevision: build.buildRevision
|
||||
buildRevision: build.buildRevision,
|
||||
dataDirectory: TRILIUM_DATA_DIR
|
||||
};
|
||||
@@ -1 +1 @@
|
||||
module.exports = { buildDate:"2019-01-01T20:54:23+01:00", buildRevision: "1771ddb78783352970ef64906af8c8fe117183d0" };
|
||||
module.exports = { buildDate:"2019-01-05T22:48:11+01:00", buildRevision: "9fca7f09a564c719c834d38d76c3b595c8579b2a" };
|
||||
|
||||
@@ -12,6 +12,7 @@ const Attribute = require('../entities/attribute');
|
||||
const NoteRevision = require('../entities/note_revision');
|
||||
const RecentNote = require('../entities/recent_note');
|
||||
const Option = require('../entities/option');
|
||||
const Link = require('../entities/link');
|
||||
|
||||
async function getHash(entityConstructor, whereBranch) {
|
||||
// subselect is necessary to have correct ordering in GROUP_CONCAT
|
||||
@@ -37,7 +38,8 @@ async function getHashes() {
|
||||
recent_notes: await getHash(RecentNote),
|
||||
options: await getHash(Option, "isSynced = 1"),
|
||||
attributes: await getHash(Attribute),
|
||||
api_tokens: await getHash(ApiToken)
|
||||
api_tokens: await getHash(ApiToken),
|
||||
links: await getHash(Link)
|
||||
};
|
||||
|
||||
const elapseTimeMs = new Date().getTime() - startTime.getTime();
|
||||
|
||||
@@ -55,10 +55,6 @@ function getTriliumDataDir() {
|
||||
}
|
||||
|
||||
const TRILIUM_DATA_DIR = getTriliumDataDir();
|
||||
|
||||
// not necessary to log this since if we have logs we already know where data dir is.
|
||||
console.log("Using data dir:", TRILIUM_DATA_DIR);
|
||||
|
||||
const DOCUMENT_PATH = TRILIUM_DATA_DIR + "/document.db";
|
||||
const BACKUP_DIR = TRILIUM_DATA_DIR + "/backup";
|
||||
const LOG_DIR = TRILIUM_DATA_DIR + "/log";
|
||||
|
||||
@@ -5,14 +5,25 @@ const ENTER_PROTECTED_SESSION = "ENTER_PROTECTED_SESSION";
|
||||
const ENTITY_CREATED = "ENTITY_CREATED";
|
||||
const ENTITY_CHANGED = "ENTITY_CHANGED";
|
||||
const ENTITY_DELETED = "ENTITY_DELETED";
|
||||
const ENTITY_SYNCED = "ENTITY_SYNCED";
|
||||
const CHILD_NOTE_CREATED = "CHILD_NOTE_CREATED";
|
||||
|
||||
const eventListeners = {};
|
||||
|
||||
function subscribe(eventType, listener) {
|
||||
/**
|
||||
* @param eventTypes - can be either single event or an array of events
|
||||
* @param listener
|
||||
*/
|
||||
function subscribe(eventTypes, listener) {
|
||||
if (!Array.isArray(eventTypes)) {
|
||||
eventTypes = [ eventTypes ];
|
||||
}
|
||||
|
||||
for (const eventType of eventTypes) {
|
||||
eventListeners[eventType] = eventListeners[eventType] || [];
|
||||
eventListeners[eventType].push(listener);
|
||||
}
|
||||
}
|
||||
|
||||
async function emit(eventType, data) {
|
||||
const listeners = eventListeners[eventType];
|
||||
@@ -39,5 +50,6 @@ module.exports = {
|
||||
ENTITY_CREATED,
|
||||
ENTITY_CHANGED,
|
||||
ENTITY_DELETED,
|
||||
ENTITY_SYNCED,
|
||||
CHILD_NOTE_CREATED
|
||||
};
|
||||
@@ -45,8 +45,6 @@ function request(req) {
|
||||
logger.info(req.method + " " + req.url);
|
||||
}
|
||||
|
||||
info("Using data dir: " + dataDir.TRILIUM_DATA_DIR);
|
||||
|
||||
module.exports = {
|
||||
info,
|
||||
error,
|
||||
|
||||
@@ -52,6 +52,7 @@ async function sendMessage(client, message) {
|
||||
async function sendMessageToAllClients(message) {
|
||||
const jsonStr = JSON.stringify(message);
|
||||
|
||||
if (webSocketServer) {
|
||||
log.info("Sending message to all clients: " + jsonStr);
|
||||
|
||||
webSocketServer.clients.forEach(function each(client) {
|
||||
@@ -60,6 +61,7 @@ async function sendMessageToAllClients(message) {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function sendPing(client, lastSentSyncId) {
|
||||
const syncData = await sql.getRows("SELECT * FROM sync WHERE id > ?", [lastSentSyncId]);
|
||||
|
||||
@@ -299,7 +299,9 @@ function getNotePath(noteId) {
|
||||
}
|
||||
}
|
||||
|
||||
eventService.subscribe(eventService.ENTITY_CHANGED, async ({entityName, entity}) => {
|
||||
eventService.subscribe([eventService.ENTITY_CHANGED, eventService.ENTITY_DELETED, eventService.ENTITY_SYNCED], async ({entityName, entity}) => {
|
||||
// note that entity can also be just POJO without methods if coming from sync
|
||||
|
||||
if (!loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const sql = require('./sql');
|
||||
const sqlInit = require('./sql_init');
|
||||
const optionService = require('./options');
|
||||
const dateUtils = require('./date_utils');
|
||||
const syncTableService = require('./sync_table');
|
||||
@@ -364,6 +365,8 @@ async function deleteNote(branch) {
|
||||
// content with non-existent protected session key
|
||||
// we don't reset content here, that's postponed and done later to give the user a chance to correct a mistake
|
||||
await sql.execute("UPDATE notes SET isDeleted = 1 WHERE noteId = ?", [note.noteId]);
|
||||
// need to manually trigger sync since it's not taken care of by note save
|
||||
await syncTableService.addNoteSync(note.noteId);
|
||||
|
||||
for (const noteRevision of await note.getRevisions()) {
|
||||
await noteRevision.save();
|
||||
@@ -406,10 +409,12 @@ async function cleanupDeletedNotes() {
|
||||
await sql.execute("UPDATE note_revisions SET content = NULL WHERE note_revisions.content IS NOT NULL AND noteId IN (SELECT noteId FROM notes WHERE isDeleted = 1 AND notes.dateModified <= ?)", [dateUtils.dateStr(cutoffDate)]);
|
||||
}
|
||||
|
||||
sqlInit.dbReady.then(() => {
|
||||
// first cleanup kickoff 5 minutes after startup
|
||||
setTimeout(cls.wrap(cleanupDeletedNotes), 5 * 60 * 1000);
|
||||
|
||||
setInterval(cls.wrap(cleanupDeletedNotes), 4 * 3600 * 1000);
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
createNewNote,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
const url = require('url');
|
||||
const log = require('./log');
|
||||
const sql = require('./sql');
|
||||
const sqlInit = require('./sql_init');
|
||||
@@ -99,6 +98,16 @@ async function doLogin() {
|
||||
|
||||
syncContext.sourceId = resp.sourceId;
|
||||
|
||||
const lastSyncedPull = await getLastSyncedPull();
|
||||
|
||||
// this is important in a scenario where we setup the sync by manually copying the document
|
||||
// lastSyncedPull then could be pretty off for the newly cloned client
|
||||
if (lastSyncedPull > resp.maxSyncId) {
|
||||
log.info(`Lowering last synced pull from ${lastSyncedPull} to ${resp.maxSyncId}`);
|
||||
|
||||
await setLastSyncedPull(resp.maxSyncId);
|
||||
}
|
||||
|
||||
return syncContext;
|
||||
}
|
||||
|
||||
@@ -256,7 +265,7 @@ async function getEntityRow(entityName, entityId) {
|
||||
&& entity.content !== null
|
||||
&& (entity.type === 'file' || entity.type === 'image')) {
|
||||
|
||||
entity.content = entity.content.toString("binary");
|
||||
entity.content = entity.content.toString("base64");
|
||||
}
|
||||
|
||||
return entity;
|
||||
|
||||
@@ -2,6 +2,7 @@ const sql = require('./sql');
|
||||
const log = require('./log');
|
||||
const eventLogService = require('./event_log');
|
||||
const syncTableService = require('./sync_table');
|
||||
const eventService = require('./events');
|
||||
|
||||
async function updateEntity(sync, entity, sourceId) {
|
||||
const {entityName} = sync;
|
||||
@@ -36,11 +37,20 @@ async function updateEntity(sync, entity, sourceId) {
|
||||
else {
|
||||
throw new Error(`Unrecognized entity type ${entityName}`);
|
||||
}
|
||||
|
||||
// currently making exception for protected notes and note revisions because here
|
||||
// the title and content are not available decrypted as listeners would expect
|
||||
if ((entityName !== 'notes' && entityName !== 'note_revisions') || !entity.isProtected) {
|
||||
await eventService.emit(eventService.ENTITY_SYNCED, {
|
||||
entityName,
|
||||
entity
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function deserializeNoteContentBuffer(note) {
|
||||
if (note.content !== null && (note.type === 'file' || note.type === 'image')) {
|
||||
note.content = new Buffer(note.content, 'binary');
|
||||
note.content = Buffer.from(note.content, 'base64');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div id="history-navigation" style="display: none;">
|
||||
<a id="history-back-button" title="Go to previous note." class="icon-action jam jam-arrow-square-left"></a>
|
||||
|
||||
|
||||
|
||||
|
||||
<a id="history-forward-button" title="Go to next note." class="icon-action jam jam-arrow-square-right"></a>
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<div id="confirm-dialog-custom"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-default btn-sm" id="confirm-dialog-cancel-button">Cancel</button>
|
||||
<button class="btn btn-secondary btn-sm" id="confirm-dialog-cancel-button">Cancel</button>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
|
||||
<button class="btn btn-default" type="button" data-help-page="Protected-notes">Help</button>
|
||||
<button class="btn btn-secondary" type="button" data-help-page="Protected-notes">Help</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -125,7 +125,7 @@
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
|
||||
<button class="btn btn-default" type="button" data-help-page="Note-revisions">Help</button>
|
||||
<button class="btn btn-secondary" type="button" data-help-page="Note-revisions">Help</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -154,7 +154,7 @@
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
|
||||
<button class="btn btn-default" type="button" data-help-page="Synchronization">Help</button>
|
||||
<button class="btn btn-secondary" type="button" data-help-page="Synchronization">Help</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -164,24 +164,24 @@
|
||||
|
||||
<p>This will test connection and handshake to the sync server. If sync server isn't initialized, this will set it up to sync with local document.</p>
|
||||
|
||||
<button id="test-sync-button" class="btn btn-default">Test sync</button>
|
||||
<button id="test-sync-button" class="btn btn-secondary">Test sync</button>
|
||||
</div>
|
||||
|
||||
<div id="advanced" class="tab-pane">
|
||||
<h4 style="margin-top: 0px;">Sync</h4>
|
||||
<button id="force-full-sync-button" class="btn btn-default">Force full sync</button>
|
||||
<button id="force-full-sync-button" class="btn btn-secondary">Force full sync</button>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="fill-sync-rows-button" class="btn btn-default">Fill sync rows</button>
|
||||
<button id="fill-sync-rows-button" class="btn btn-secondary">Fill sync rows</button>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<h4>Debugging</h4>
|
||||
|
||||
<button id="anonymize-button" class="btn btn-default">Save anonymized database</button><br/><br/>
|
||||
<button id="anonymize-button" class="btn btn-secondary">Save anonymized database</button><br/><br/>
|
||||
|
||||
<p>This action will create a new copy of the database and anonymise it (remove all note content and leave only structure and metadata)
|
||||
for sharing online for debugging purposes without fear of leaking your personal data.</p>
|
||||
@@ -190,7 +190,7 @@
|
||||
|
||||
<p>This will rebuild database which will typically result in smaller database file. No data will be actually changed.</p>
|
||||
|
||||
<button id="vacuum-database-button" class="btn btn-default">Vacuum database</button>
|
||||
<button id="vacuum-database-button" class="btn btn-secondary">Vacuum database</button>
|
||||
</div>
|
||||
|
||||
<div id="about" class="tab-pane">
|
||||
@@ -216,6 +216,11 @@
|
||||
<th>Build revision:</th>
|
||||
<td><a href="" target="_blank" id="build-revision"></a></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>Data directory:</th>
|
||||
<td id="data-directory"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="col-md-5 offset-md-3" style="padding-top: 25px;">
|
||||
<div class="col-xs-12 col-sm-10 col-md-6 col-lg-4 col-xl-4 mx-auto" style="padding-top: 25px;">
|
||||
<h1>Trilium login</h1>
|
||||
|
||||
<% if (failedAuth) { %>
|
||||
@@ -60,6 +60,8 @@
|
||||
device = /Mobi/.test(navigator.userAgent) ? "mobile" : "desktop";
|
||||
}
|
||||
|
||||
console.log("Setting device cookie to:", device);
|
||||
|
||||
setCookie("trilium-device", device);
|
||||
|
||||
function setCookie(name, value) {
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>Setup</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="setup-dialog" style="width: 700px; margin: auto; padding-top: 50px; display:none; font-size: larger;">
|
||||
<div class="container">
|
||||
<div id="setup-dialog" class="col-md-12 col-lg-8 col-xl-6 mx-auto" style="padding-top: 25px;">
|
||||
<h1>Trilium Notes setup</h1>
|
||||
|
||||
<div class="alert alert-warning" id="alert" style="display: none;">
|
||||
@@ -13,15 +15,15 @@
|
||||
|
||||
<div id="setup-type" data-bind="visible: step() == 'setup-type'" style="margin-top: 20px;">
|
||||
<div class="radio" style="margin-bottom: 15px;">
|
||||
<label><input type="radio" name="setup-type" value="new-document" data-bind="checked: setupNewDocument">
|
||||
<label><input type="radio" name="setup-type" value="new-document" data-bind="checked: setupType">
|
||||
I'm a new user and I want to create new Trilium document for my notes</label>
|
||||
</div>
|
||||
<div class="radio" data-bind="if: instanceType == 'server'" style="margin-bottom: 15px;">
|
||||
<label><input type="radio" name="setup-type" value="sync-from-desktop" data-bind="checked: setupSyncFromDesktop">
|
||||
<label><input type="radio" name="setup-type" value="sync-from-desktop" data-bind="checked: setupType">
|
||||
I have desktop instance already and I want to setup sync with it</label>
|
||||
</div>
|
||||
<div class="radio" data-bind="if: instanceType == 'desktop'" style="margin-bottom: 15px;">
|
||||
<label><input type="radio" name="setup-type" value="sync-from-server" data-bind="checked: setupSyncFromServer">
|
||||
<label><input type="radio" name="setup-type" value="sync-from-server" data-bind="checked: setupType">
|
||||
I have server instance up and I want to setup sync with it</label>
|
||||
</div>
|
||||
|
||||
@@ -47,7 +49,7 @@
|
||||
<input type="password" class="form-control" data-bind="value: password2" placeholder="Password">
|
||||
</div>
|
||||
|
||||
<button type="button" data-bind="click: back" class="btn btn-default">Back</button>
|
||||
<button type="button" data-bind="click: back" class="btn btn-secondary">Back</button>
|
||||
|
||||
|
||||
|
||||
@@ -68,7 +70,7 @@
|
||||
<li>once you've done all this, click <a href="/">here</a></li>
|
||||
</ol>
|
||||
|
||||
<button type="button" data-bind="click: back" class="btn btn-default">Back</button>
|
||||
<button type="button" data-bind="click: back" class="btn btn-secondary">Back</button>
|
||||
</div>
|
||||
|
||||
<div data-bind="visible: step() == 'sync-from-server'">
|
||||
@@ -95,7 +97,7 @@
|
||||
<input type="password" id="password1" class="form-control" data-bind="value: password1" placeholder="Password">
|
||||
</div>
|
||||
|
||||
<button type="button" data-bind="click: back" class="btn btn-default">Back</button>
|
||||
<button type="button" data-bind="click: back" class="btn btn-secondary">Back</button>
|
||||
|
||||
|
||||
|
||||
@@ -112,6 +114,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
const baseApiUrl = 'api/';
|
||||
|
||||
Reference in New Issue
Block a user