mirror of
https://github.com/zadam/trilium.git
synced 2025-11-02 03:16:11 +01:00
Compare commits
24 Commits
v0.28.0-be
...
v0.28.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d42c3d802 | ||
|
|
c654172d33 | ||
|
|
e17b26c883 | ||
|
|
24d02d9cf5 | ||
|
|
7208a311ac | ||
|
|
ad7355372b | ||
|
|
f18b5babad | ||
|
|
9831ec0ca9 | ||
|
|
596544eca3 | ||
|
|
1f853024ee | ||
|
|
0308b13460 | ||
|
|
06b8a82f70 | ||
|
|
91ca07929d | ||
|
|
afabaa5fdb | ||
|
|
a6fd3fa77c | ||
|
|
58a2c08dcd | ||
|
|
299bbff2f4 | ||
|
|
19d8947123 | ||
|
|
35edce7523 | ||
|
|
bc4cec69a5 | ||
|
|
cce8c1b674 | ||
|
|
aa58788769 | ||
|
|
6c62ab7a52 | ||
|
|
d6ab638b30 |
@@ -17,4 +17,6 @@ rm -r $BUILD_DIR/swiftshader
|
||||
echo "Packaging linux x64 electron distribution..."
|
||||
VERSION=`jq -r ".version" package.json`
|
||||
|
||||
tar cJf $BUILD_DIR-${VERSION}.tar.xz $BUILD_DIR
|
||||
cd dist
|
||||
|
||||
tar cJf trilium-linux-x64-${VERSION}.tar.xz trilium-linux-x64
|
||||
|
||||
@@ -35,4 +35,4 @@ cd ..
|
||||
|
||||
VERSION=`jq -r ".version" ../package.json`
|
||||
|
||||
tar cJf trilium-linux-x64-server-${VERSION}.tar.gz trilium-linux-x64-server
|
||||
tar cJf trilium-linux-x64-server-${VERSION}.tar.xz trilium-linux-x64-server
|
||||
@@ -42,10 +42,10 @@ git push origin $TAG
|
||||
|
||||
bin/build.sh
|
||||
|
||||
LINUX_X64_BUILD=trilium-linux-x64-$VERSION.tar.gz
|
||||
LINUX_X64_BUILD=trilium-linux-x64-$VERSION.tar.xz
|
||||
WINDOWS_X64_BUILD=trilium-windows-x64-$VERSION.zip
|
||||
MAC_X64_BUILD=trilium-mac-x64-$VERSION.zip
|
||||
SERVER_BUILD=trilium-linux-x64-server-$VERSION.tar.gz
|
||||
SERVER_BUILD=trilium-linux-x64-server-$VERSION.tar.xz
|
||||
|
||||
echo "Creating release in GitHub"
|
||||
|
||||
|
||||
BIN
db/demo.tar
BIN
db/demo.tar
Binary file not shown.
@@ -81,7 +81,7 @@ app.on('ready', async () => {
|
||||
const dateNoteService = require('./src/services/date_notes');
|
||||
const dateUtils = require('./src/services/date_utils');
|
||||
|
||||
const parentNote = await dateNoteService.getDateNote(dateUtils.nowDate());
|
||||
const parentNote = await dateNoteService.getDateNote(dateUtils.nowLocalDate());
|
||||
|
||||
// window may be hidden / not in focus
|
||||
mainWindow.focus();
|
||||
|
||||
5
issue_template.md
Normal file
5
issue_template.md
Normal file
@@ -0,0 +1,5 @@
|
||||
For bug reports, please mention **version of the application** and include **log files** from following location:
|
||||
|
||||
* `/home/[user]/.local/share/trilium-data/log` for Linux
|
||||
* `C:\Users\[user]\AppData\Roaming\trilium-data\log` for Windows Vista and up
|
||||
* `/Users/[user]/Library/Application Support/trilium-data/log` for Mac OS
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "trilium",
|
||||
"productName": "Trilium Notes",
|
||||
"description": "Trilium Notes",
|
||||
"version": "0.28.0-beta",
|
||||
"version": "0.28.2",
|
||||
"license": "AGPL-3.0-only",
|
||||
"main": "electron.js",
|
||||
"bin": {
|
||||
|
||||
@@ -160,7 +160,7 @@ async function createPromotedAttributeRow(definitionAttr, valueAttr) {
|
||||
$input.autocomplete({
|
||||
appendTo: document.querySelector('body'),
|
||||
hint: false,
|
||||
autoselect: true,
|
||||
autoselect: false,
|
||||
openOnFocus: true,
|
||||
minLength: 0,
|
||||
tabAutocomplete: false
|
||||
|
||||
@@ -30,9 +30,13 @@ async function executeStartupBundles() {
|
||||
}
|
||||
|
||||
async function executeRelationBundles(note, relationName) {
|
||||
const bundlesToRun = await server.get("script/relation/" + note.noteId + "/" + relationName);
|
||||
note.bundleCache = note.bundleCache || {};
|
||||
|
||||
for (const bundle of bundlesToRun) {
|
||||
if (!note.bundleCache[relationName]) {
|
||||
note.bundleCache[relationName] = await server.get("script/relation/" + note.noteId + "/" + relationName);
|
||||
}
|
||||
|
||||
for (const bundle of note.bundleCache[relationName]) {
|
||||
await executeBundle(bundle, note);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,9 @@ async function saveNote() {
|
||||
}
|
||||
|
||||
$savedIndicator.fadeIn();
|
||||
|
||||
// run async
|
||||
bundleService.executeRelationBundles(getCurrentNote(), 'runOnNoteChange');
|
||||
}
|
||||
|
||||
async function saveNoteIfChanged() {
|
||||
|
||||
@@ -498,9 +498,11 @@ async function loadTree() {
|
||||
return await treeBuilder.prepareTree(resp.notes, resp.branches, resp.relations);
|
||||
}
|
||||
|
||||
function collapseTree(node = null) {
|
||||
async function collapseTree(node = null) {
|
||||
if (!node) {
|
||||
node = $tree.fancytree("getRootNode");
|
||||
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
node = getNodesByNoteId(hoistedNoteId)[0];
|
||||
}
|
||||
|
||||
node.setExpanded(false);
|
||||
@@ -541,9 +543,11 @@ async function setNoteTitle(noteId, title) {
|
||||
}
|
||||
|
||||
async function createNewTopLevelNote() {
|
||||
const rootNode = getNodesByNoteId('root')[0];
|
||||
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
await createNote(rootNode, "root", "into", false);
|
||||
const rootNode = getNodesByNoteId(hoistedNoteId)[0];
|
||||
|
||||
await createNote(rootNode, hoistedNoteId, "into", false);
|
||||
}
|
||||
|
||||
async function createNote(node, parentNoteId, target, isProtected, saveSelection = false) {
|
||||
|
||||
@@ -23,6 +23,7 @@ function formatTimeWithSeconds(date) {
|
||||
return padNum(date.getHours()) + ":" + padNum(date.getMinutes()) + ":" + padNum(date.getSeconds());
|
||||
}
|
||||
|
||||
// this is producing local time!
|
||||
function formatDate(date) {
|
||||
// return padNum(date.getDate()) + ". " + padNum(date.getMonth() + 1) + ". " + date.getFullYear();
|
||||
// instead of european format we'll just use ISO as that's pretty unambiguous
|
||||
@@ -30,6 +31,7 @@ function formatDate(date) {
|
||||
return formatDateISO(date);
|
||||
}
|
||||
|
||||
// this is producing local time!
|
||||
function formatDateISO(date) {
|
||||
return date.getFullYear() + "-" + padNum(date.getMonth() + 1) + "-" + padNum(date.getDate());
|
||||
}
|
||||
@@ -143,6 +145,7 @@ function bindShortcut(keyboardShortcut, handler) {
|
||||
}
|
||||
|
||||
$(document).bind('keydown', keyboardShortcut, e => {
|
||||
console.log(e);
|
||||
handler();
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
@@ -24,7 +24,6 @@ html, body {
|
||||
}
|
||||
|
||||
#tree {
|
||||
font-size: larger;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
@@ -45,7 +44,8 @@ html, body {
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
/* for some reason detail overflows a little bit so we subtract few pixels */
|
||||
height: calc(100% - 25px);
|
||||
/* large left padding is necessary for ckeditor gutter in detail-only (smartphone) layout */
|
||||
padding-left: 35px;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,11 @@ async function getRelationBundles(req) {
|
||||
|
||||
for (const noteId of uniqueNoteIds) {
|
||||
const note = await repository.getNote(noteId);
|
||||
|
||||
if (!note.isJavaScript() || note.getScriptEnv() !== 'frontend') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bundle = await scriptService.getScriptBundleForFrontend(note);
|
||||
|
||||
if (bundle) {
|
||||
|
||||
@@ -11,6 +11,7 @@ const repository = require('./repository');
|
||||
const axios = require('axios');
|
||||
const cloningService = require('./cloning');
|
||||
const messagingService = require('./messaging');
|
||||
const appInfo = require('./app_info');
|
||||
|
||||
/**
|
||||
* This is the main backend API interface for scripts. It's published in the local "api" object.
|
||||
@@ -234,6 +235,11 @@ function BackendScriptApi(startNote, currentNote, originEntity) {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
this.refreshTree = () => messagingService.sendMessageToAllClients({ type: 'refresh-tree' });
|
||||
|
||||
/**
|
||||
* @return {{syncVersion, appVersion, buildRevision, dbVersion, dataDirectory, buildDate}|*} - object representing basic info about running Trilium version
|
||||
*/
|
||||
this.getAppInfo = () => appInfo
|
||||
}
|
||||
|
||||
module.exports = BackendScriptApi;
|
||||
@@ -1 +1 @@
|
||||
module.exports = { buildDate:"2019-01-14T23:51:55+01:00", buildRevision: "e50f9cd0a354e29bb40c161cf7288e13b732e0d3" };
|
||||
module.exports = { buildDate:"2019-01-21T22:55:12+01:00", buildRevision: "c654172d33eed3773b5f76074a2c97479b522920" };
|
||||
|
||||
@@ -8,6 +8,10 @@ const repository = require('./repository');
|
||||
const Branch = require('../entities/branch');
|
||||
|
||||
async function cloneNoteToParent(noteId, parentNoteId, prefix) {
|
||||
if (await isNoteDeleted(noteId) || await isNoteDeleted(parentNoteId)) {
|
||||
return { success: false, message: 'Note is deleted.' };
|
||||
}
|
||||
|
||||
const validationResult = await treeService.validateParentChild(parentNoteId, noteId);
|
||||
|
||||
if (!validationResult.success) {
|
||||
@@ -27,6 +31,10 @@ async function cloneNoteToParent(noteId, parentNoteId, prefix) {
|
||||
}
|
||||
|
||||
async function ensureNoteIsPresentInParent(noteId, parentNoteId, prefix) {
|
||||
if (await isNoteDeleted(noteId) || await isNoteDeleted(parentNoteId)) {
|
||||
return { success: false, message: 'Note is deleted.' };
|
||||
}
|
||||
|
||||
const validationResult = await treeService.validateParentChild(parentNoteId, noteId);
|
||||
|
||||
if (!validationResult.success) {
|
||||
@@ -61,6 +69,10 @@ async function toggleNoteInParent(present, noteId, parentNoteId, prefix) {
|
||||
async function cloneNoteAfter(noteId, afterBranchId) {
|
||||
const afterNote = await treeService.getBranch(afterBranchId);
|
||||
|
||||
if (await isNoteDeleted(noteId) || await isNoteDeleted(afterNote.parentNoteId)) {
|
||||
return { success: false, message: 'Note is deleted.' };
|
||||
}
|
||||
|
||||
const validationResult = await treeService.validateParentChild(afterNote.parentNoteId, noteId);
|
||||
|
||||
if (!validationResult.result) {
|
||||
@@ -84,6 +96,12 @@ async function cloneNoteAfter(noteId, afterBranchId) {
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
async function isNoteDeleted(noteId) {
|
||||
const note = await repository.getNote(noteId);
|
||||
|
||||
return note.isDeleted;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
cloneNoteToParent,
|
||||
ensureNoteIsPresentInParent,
|
||||
|
||||
@@ -101,6 +101,26 @@ async function fixEmptyRelationTargets(errorList) {
|
||||
}
|
||||
}
|
||||
|
||||
async function fixUndeletedBranches() {
|
||||
const undeletedBranches = await sql.getRows(`
|
||||
SELECT
|
||||
branchId, noteId
|
||||
FROM
|
||||
branches
|
||||
JOIN notes USING(noteId)
|
||||
WHERE
|
||||
notes.isDeleted = 1
|
||||
AND branches.isDeleted = 0`);
|
||||
|
||||
for (const {branchId, noteId} of undeletedBranches) {
|
||||
const branch = await repository.getBranch(branchId);
|
||||
branch.isDeleted = true;
|
||||
await branch.save();
|
||||
|
||||
log.info(`Branch ${branchId} has been deleted since associated note ${noteId} is deleted.`);
|
||||
}
|
||||
}
|
||||
|
||||
async function runAllChecks() {
|
||||
const errorList = [];
|
||||
|
||||
@@ -125,16 +145,7 @@ async function runAllChecks() {
|
||||
notes.noteId IS NULL`,
|
||||
"Missing notes records for following branch ID > note ID", errorList);
|
||||
|
||||
await runCheck(`
|
||||
SELECT
|
||||
branchId
|
||||
FROM
|
||||
branches
|
||||
JOIN notes USING(noteId)
|
||||
WHERE
|
||||
notes.isDeleted = 1
|
||||
AND branches.isDeleted = 0`,
|
||||
"Branch is not deleted even though main note is deleted for following branch IDs", errorList);
|
||||
await fixUndeletedBranches();
|
||||
|
||||
await runCheck(`
|
||||
SELECT
|
||||
|
||||
@@ -47,8 +47,8 @@ async function getRootCalendarNote() {
|
||||
return rootNote;
|
||||
}
|
||||
|
||||
async function getYearNote(dateTimeStr, rootNote) {
|
||||
const yearStr = dateTimeStr.substr(0, 4);
|
||||
async function getYearNote(dateStr, rootNote) {
|
||||
const yearStr = dateStr.substr(0, 4);
|
||||
|
||||
let yearNote = await attributeService.getNoteWithLabel(YEAR_LABEL, yearStr);
|
||||
|
||||
@@ -66,19 +66,19 @@ async function getYearNote(dateTimeStr, rootNote) {
|
||||
return yearNote;
|
||||
}
|
||||
|
||||
async function getMonthNote(dateTimeStr, rootNote) {
|
||||
const monthStr = dateTimeStr.substr(0, 7);
|
||||
const monthNumber = dateTimeStr.substr(5, 2);
|
||||
async function getMonthNote(dateStr, rootNote) {
|
||||
const monthStr = dateStr.substr(0, 7);
|
||||
const monthNumber = dateStr.substr(5, 2);
|
||||
|
||||
let monthNote = await attributeService.getNoteWithLabel(MONTH_LABEL, monthStr);
|
||||
|
||||
if (!monthNote) {
|
||||
const yearNote = await getYearNote(dateTimeStr, rootNote);
|
||||
const yearNote = await getYearNote(dateStr, rootNote);
|
||||
|
||||
monthNote = await getNoteStartingWith(yearNote.noteId, monthNumber);
|
||||
|
||||
if (!monthNote) {
|
||||
const dateObj = dateUtils.parseDate(dateTimeStr);
|
||||
const dateObj = dateUtils.parseLocalDate(dateStr);
|
||||
|
||||
const noteTitle = monthNumber + " - " + MONTHS[dateObj.getMonth()];
|
||||
|
||||
@@ -92,21 +92,20 @@ async function getMonthNote(dateTimeStr, rootNote) {
|
||||
return monthNote;
|
||||
}
|
||||
|
||||
async function getDateNote(dateTimeStr) {
|
||||
async function getDateNote(dateStr) {
|
||||
const rootNote = await getRootCalendarNote();
|
||||
|
||||
const dateStr = dateTimeStr.substr(0, 10);
|
||||
const dayNumber = dateTimeStr.substr(8, 2);
|
||||
const dayNumber = dateStr.substr(8, 2);
|
||||
|
||||
let dateNote = await attributeService.getNoteWithLabel(DATE_LABEL, dateStr);
|
||||
|
||||
if (!dateNote) {
|
||||
const monthNote = await getMonthNote(dateTimeStr, rootNote);
|
||||
const monthNote = await getMonthNote(dateStr, rootNote);
|
||||
|
||||
dateNote = await getNoteStartingWith(monthNote.noteId, dayNumber);
|
||||
|
||||
if (!dateNote) {
|
||||
const dateObj = dateUtils.parseDate(dateTimeStr);
|
||||
const dateObj = dateUtils.parseLocalDate(dateStr);
|
||||
|
||||
const noteTitle = dayNumber + " - " + DAYS[dateObj.getDay()];
|
||||
|
||||
|
||||
@@ -2,6 +2,16 @@ function nowDate() {
|
||||
return dateStr(new Date());
|
||||
}
|
||||
|
||||
function nowLocalDate() {
|
||||
const date = new Date();
|
||||
|
||||
return date.getFullYear() + "-" + pad(date.getMonth() + 1) + "-" + pad(date.getDate());
|
||||
}
|
||||
|
||||
function pad(num) {
|
||||
return num <= 9 ? `0${num}` : `${num}`;
|
||||
}
|
||||
|
||||
function dateStr(date) {
|
||||
return date.toISOString();
|
||||
}
|
||||
@@ -25,14 +35,23 @@ function parseDate(str) {
|
||||
return parseDateTime(datePart + "T12:00:00.000Z");
|
||||
}
|
||||
|
||||
function parseLocalDate(str) {
|
||||
const datePart = str.substr(0, 10);
|
||||
|
||||
// not specifying the timezone and specifying the time means Date.parse() will use the local timezone
|
||||
return parseDateTime(datePart + " 12:00:00.000");
|
||||
}
|
||||
|
||||
function getDateTimeForFile() {
|
||||
return new Date().toISOString().substr(0, 19).replace(/:/g, '');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
nowDate,
|
||||
nowLocalDate,
|
||||
dateStr,
|
||||
parseDate,
|
||||
parseDateTime,
|
||||
parseLocalDate,
|
||||
getDateTimeForFile
|
||||
};
|
||||
@@ -6,7 +6,7 @@ const sourceIdService = require('./source_id');
|
||||
const log = require('./log');
|
||||
|
||||
async function executeNote(note, originEntity) {
|
||||
if (!note.isJavaScript() || !note.isContentAvailable) {
|
||||
if (!note.isJavaScript() || note.getScriptEnv() !== 'backend' || !note.isContentAvailable) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ async function execute(query, params = []) {
|
||||
|
||||
const milliseconds = Date.now() - startTimestamp;
|
||||
if (milliseconds >= 200) {
|
||||
log.info(`Slow query took ${milliseconds}ms: ${query}, params=${params}`);
|
||||
log.info(`Slow query took ${milliseconds}ms: ${query}`);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -155,6 +155,10 @@ async function dbInitialized() {
|
||||
await initDbConnection();
|
||||
}
|
||||
|
||||
dbReady.then(async () => {
|
||||
log.info("DB size: " + await sql.getValue("SELECT page_count * page_size / 1000 as size FROM pragma_page_count(), pragma_page_size()") + " KB");
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
dbReady,
|
||||
schemaExists,
|
||||
|
||||
@@ -111,6 +111,12 @@ async function sortNotesAlphabetically(parentNoteId) {
|
||||
}
|
||||
|
||||
async function setNoteToParent(noteId, prefix, parentNoteId) {
|
||||
const parentNote = await repository.getNote(parentNoteId);
|
||||
|
||||
if (parentNote && parentNote.isDeleted) {
|
||||
throw new Error(`Cannot move note to deleted parent note ${parentNoteId}`);
|
||||
}
|
||||
|
||||
// case where there might be more such branches is ignored. It's expected there should be just one
|
||||
const branch = await repository.getEntity("SELECT * FROM branches WHERE isDeleted = 0 AND noteId = ? AND prefix = ?", [noteId, prefix]);
|
||||
|
||||
@@ -126,6 +132,12 @@ async function setNoteToParent(noteId, prefix, parentNoteId) {
|
||||
await branch.save();
|
||||
}
|
||||
else if (parentNoteId) {
|
||||
const note = await repository.getNote(noteId);
|
||||
|
||||
if (note.isDeleted) {
|
||||
throw new Error(`Cannot create a branch for ${noteId} which is deleted.`);
|
||||
}
|
||||
|
||||
await new Branch({
|
||||
noteId: noteId,
|
||||
parentNoteId: parentNoteId,
|
||||
|
||||
@@ -128,6 +128,7 @@
|
||||
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
|
||||
|
||||
<script src="libraries/jquery.min.js"></script>
|
||||
<script src="libraries/jquery.hotkeys.js"></script>
|
||||
|
||||
<link href="libraries/bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="libraries/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
Reference in New Issue
Block a user