Compare commits

...

6 Commits

Author SHA1 Message Date
azivner
2c5115003b release 0.5.4-beta 2018-02-03 13:25:29 -05:00
azivner
e8ed913374 small changes in the toolbar 2018-02-03 12:44:22 -05:00
azivner
5bffba4e2f add API to add plugin buttons, fixes 2018-02-03 10:37:57 -05:00
azivner
05575913db release 0.5.3-beta 2018-01-31 23:57:20 -05:00
azivner
31c32ff42c fixes when generating new DB 2018-01-31 23:36:39 -05:00
azivner
6a671a5c02 fix electron app icon 2018-01-31 22:39:30 -05:00
14 changed files with 154 additions and 141 deletions

View File

@@ -1,119 +1,121 @@
CREATE TABLE IF NOT EXISTS "options" ( CREATE TABLE IF NOT EXISTS "options" (
`opt_name` TEXT NOT NULL PRIMARY KEY, `name` TEXT NOT NULL PRIMARY KEY,
`opt_value` TEXT, `value` TEXT,
`date_modified` INT `dateModified` INT,
, is_synced INTEGER NOT NULL DEFAULT 0); isSynced INTEGER NOT NULL DEFAULT 0);
CREATE TABLE IF NOT EXISTS "sync" ( CREATE TABLE IF NOT EXISTS "sync" (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`entity_name` TEXT NOT NULL, `entityName` TEXT NOT NULL,
`entity_id` TEXT NOT NULL, `entityId` TEXT NOT NULL,
`source_id` TEXT NOT NULL, `sourceId` TEXT NOT NULL,
`sync_date` TEXT NOT NULL); `syncDate` TEXT NOT NULL);
CREATE UNIQUE INDEX `IDX_sync_entity_name_id` ON `sync` ( CREATE TABLE IF NOT EXISTS "source_ids" (
`entity_name`, `sourceId` TEXT NOT NULL,
`entity_id` `dateCreated` TEXT NOT NULL,
); PRIMARY KEY(`sourceId`)
CREATE INDEX `IDX_sync_sync_date` ON `sync` (
`sync_date`
);
CREATE TABLE `source_ids` (
`source_id` TEXT NOT NULL,
`date_created` TEXT NOT NULL,
PRIMARY KEY(`source_id`)
); );
CREATE TABLE IF NOT EXISTS "notes" ( CREATE TABLE IF NOT EXISTS "notes" (
`note_id` TEXT NOT NULL, `noteId` TEXT NOT NULL,
`note_title` TEXT, `title` TEXT,
`note_text` TEXT, `content` TEXT,
`is_protected` INT NOT NULL DEFAULT 0, `isProtected` INT NOT NULL DEFAULT 0,
`is_deleted` INT NOT NULL DEFAULT 0, `isDeleted` INT NOT NULL DEFAULT 0,
`date_created` TEXT NOT NULL, `dateCreated` TEXT NOT NULL,
`date_modified` TEXT NOT NULL, type TEXT NOT NULL DEFAULT 'text', mime TEXT NOT NULL DEFAULT 'text/html', `dateModified` TEXT NOT NULL,
PRIMARY KEY(`note_id`) type TEXT NOT NULL DEFAULT 'text',
mime TEXT NOT NULL DEFAULT 'text/html',
PRIMARY KEY(`noteId`)
); );
CREATE INDEX `IDX_notes_is_deleted` ON `notes` ( CREATE TABLE IF NOT EXISTS "event_log" (
`is_deleted` `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`noteId` TEXT,
`comment` TEXT,
`dateAdded` TEXT NOT NULL,
FOREIGN KEY(noteId) REFERENCES notes(noteId)
); );
CREATE TABLE `event_log` ( CREATE TABLE IF NOT EXISTS "note_tree" (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `noteTreeId` TEXT NOT NULL,
`note_id` TEXT, `noteId` TEXT NOT NULL,
`comment` TEXT, `parentNoteId` TEXT NOT NULL,
`date_added` TEXT NOT NULL, `notePosition` INTEGER NOT NULL,
FOREIGN KEY(note_id) REFERENCES notes(note_id)
);
CREATE TABLE IF NOT EXISTS "notes_tree" (
`note_tree_id` TEXT NOT NULL,
`note_id` TEXT NOT NULL,
`parent_note_id` TEXT NOT NULL,
`note_position` INTEGER NOT NULL,
`prefix` TEXT, `prefix` TEXT,
`is_expanded` BOOLEAN, `isExpanded` BOOLEAN,
`is_deleted` INTEGER NOT NULL DEFAULT 0, `isDeleted` INTEGER NOT NULL DEFAULT 0,
`date_modified` TEXT NOT NULL, `dateModified` TEXT NOT NULL,
PRIMARY KEY(`note_tree_id`) PRIMARY KEY(`noteTreeId`)
); );
CREATE INDEX `IDX_notes_tree_note_id` ON `notes_tree` ( CREATE TABLE IF NOT EXISTS "note_revisions" (
`note_id` `noteRevisionId` TEXT NOT NULL PRIMARY KEY,
`noteId` TEXT NOT NULL,
`title` TEXT,
`content` TEXT,
`isProtected` INT NOT NULL DEFAULT 0,
`dateModifiedFrom` TEXT NOT NULL,
`dateModifiedTo` TEXT NOT NULL
); );
CREATE TABLE IF NOT EXISTS "notes_history" ( CREATE TABLE IF NOT EXISTS "recent_notes" (
`note_history_id` TEXT NOT NULL PRIMARY KEY, `noteTreeId` TEXT NOT NULL PRIMARY KEY,
`note_id` TEXT NOT NULL, `notePath` TEXT NOT NULL,
`note_title` TEXT, `dateAccessed` TEXT NOT NULL,
`note_text` TEXT, isDeleted INT
`is_protected` INT NOT NULL DEFAULT 0,
`date_modified_from` TEXT NOT NULL,
`date_modified_to` TEXT NOT NULL
); );
CREATE INDEX `IDX_notes_history_note_id` ON `notes_history` ( CREATE TABLE IF NOT EXISTS "images"
`note_id`
);
CREATE INDEX `IDX_notes_history_note_date_modified_from` ON `notes_history` (
`date_modified_from`
);
CREATE INDEX `IDX_notes_history_note_date_modified_to` ON `notes_history` (
`date_modified_to`
);
CREATE TABLE `recent_notes` (
`note_tree_id` TEXT NOT NULL PRIMARY KEY,
`note_path` TEXT NOT NULL,
`date_accessed` TEXT NOT NULL,
is_deleted INT
);
CREATE INDEX `IDX_notes_tree_note_id_parent_note_id` ON `notes_tree` (
`note_id`,
`parent_note_id`
);
CREATE TABLE images
( (
image_id TEXT PRIMARY KEY NOT NULL, imageId TEXT PRIMARY KEY NOT NULL,
format TEXT NOT NULL, format TEXT NOT NULL,
checksum TEXT NOT NULL, checksum TEXT NOT NULL,
name TEXT NOT NULL, name TEXT NOT NULL,
data BLOB, data BLOB,
is_deleted INT NOT NULL DEFAULT 0, isDeleted INT NOT NULL DEFAULT 0,
date_modified TEXT NOT NULL, dateModified TEXT NOT NULL,
date_created TEXT NOT NULL dateCreated TEXT NOT NULL
); );
CREATE TABLE notes_image CREATE TABLE note_images
( (
note_image_id TEXT PRIMARY KEY NOT NULL, noteImageId TEXT PRIMARY KEY NOT NULL,
note_id TEXT NOT NULL, noteId TEXT NOT NULL,
image_id TEXT NOT NULL, imageId TEXT NOT NULL,
is_deleted INT NOT NULL DEFAULT 0, isDeleted INT NOT NULL DEFAULT 0,
date_modified TEXT NOT NULL, dateModified TEXT NOT NULL,
date_created TEXT NOT NULL dateCreated TEXT NOT NULL
); );
CREATE INDEX notes_image_note_id_index ON notes_image (note_id); CREATE TABLE IF NOT EXISTS "attributes"
CREATE INDEX notes_image_image_id_index ON notes_image (image_id);
CREATE INDEX notes_image_note_id_image_id_index ON notes_image (note_id, image_id);
CREATE TABLE attributes
( (
attribute_id TEXT PRIMARY KEY NOT NULL, attributeId TEXT PRIMARY KEY NOT NULL,
note_id TEXT NOT NULL, noteId TEXT NOT NULL,
name TEXT NOT NULL, name TEXT NOT NULL,
value TEXT, value TEXT,
date_created TEXT NOT NULL, dateCreated TEXT NOT NULL,
date_modified TEXT NOT NULL dateModified TEXT NOT NULL
); );
CREATE INDEX attributes_note_id_index ON attributes (note_id); CREATE UNIQUE INDEX `IDX_sync_entityName_entityId` ON `sync` (
CREATE UNIQUE INDEX attributes_note_id_name_index ON attributes (note_id, name); `entityName`,
`entityId`
);
CREATE INDEX `IDX_sync_syncDate` ON `sync` (
`syncDate`
);
CREATE INDEX `IDX_notes_isDeleted` ON `notes` (
`isDeleted`
);
CREATE INDEX `IDX_note_tree_noteId` ON `note_tree` (
`noteId`
);
CREATE INDEX `IDX_note_tree_noteId_parentNoteId` ON `note_tree` (
`noteId`,
`parentNoteId`
);
CREATE INDEX `IDX_note_revisions_noteId` ON `note_revisions` (
`noteId`
);
CREATE INDEX `IDX_note_revisions_dateModifiedFrom` ON `note_revisions` (
`dateModifiedFrom`
);
CREATE INDEX `IDX_note_revisions_dateModifiedTo` ON `note_revisions` (
`dateModifiedTo`
);
CREATE INDEX IDX_note_images_noteId ON note_images (noteId);
CREATE INDEX IDX_note_images_imageId ON note_images (imageId);
CREATE INDEX IDX_note_images_noteId_imageId ON note_images (noteId, imageId);
CREATE INDEX IDX_attributes_noteId ON attributes (noteId);
CREATE UNIQUE INDEX IDX_attributes_noteId_name ON attributes (noteId, name);

View File

@@ -24,7 +24,7 @@ function createMainWindow() {
width: 1200, width: 1200,
height: 900, height: 900,
title: 'Trilium Notes', title: 'Trilium Notes',
icon: path.join(__dirname, 'public/images/app-icons/png/256x256.png') icon: path.join(__dirname, 'src/public/images/app-icons/png/256x256.png')
}); });
const port = config['Network']['port'] || '3000'; const port = config['Network']['port'] || '3000';

View File

@@ -1,7 +1,7 @@
{ {
"name": "trilium", "name": "trilium",
"description": "Trilium Notes", "description": "Trilium Notes",
"version": "0.5.2-beta", "version": "0.5.4-beta",
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"main": "electron.js", "main": "electron.js",
"repository": { "repository": {
@@ -12,7 +12,7 @@
"start": "node ./bin/www", "start": "node ./bin/www",
"test-electron": "xo", "test-electron": "xo",
"rebuild-electron": "electron-rebuild", "rebuild-electron": "electron-rebuild",
"start-electron": "electron src/electron", "start-electron": "electron .",
"build-electron": "electron-packager . --out=dist --asar --overwrite --all", "build-electron": "electron-packager . --out=dist --asar --overwrite --all",
"start-forge": "electron-forge start", "start-forge": "electron-forge start",
"package-forge": "electron-forge package", "package-forge": "electron-forge package",

View File

@@ -0,0 +1,21 @@
const api = (function() {
const pluginButtonsEl = $("#plugin-buttons");
async function activateNote(notePath) {
await noteTree.activateNode(notePath);
}
function addButtonToToolbar(buttonId, button) {
$("#" + buttonId).remove();
button.attr('id', buttonId);
pluginButtonsEl.append(button);
}
return {
addButtonToToolbar,
activateNote
}
})();

View File

@@ -42,7 +42,7 @@ const attributesDialog = (function() {
dialogEl.dialog({ dialogEl.dialog({
modal: true, modal: true,
width: 800, width: 800,
height: 700 height: 500
}); });
attributesModel.loadAttributes(); attributesModel.loadAttributes();

View File

@@ -116,5 +116,6 @@ async function stopWatch(what, func) {
} }
function executeScript(script) { function executeScript(script) {
eval("(async function() {" + script + "})()"); // last \r\n is necessary if script contains line comment on its last line
eval("(async function() {" + script + "\r\n})()");
} }

View File

@@ -108,7 +108,7 @@ span.fancytree-active:not(.fancytree-focused) .fancytree-title {
} }
#header-title { #header-title {
padding: 5px 50px 5px 10px; padding: 5px 20px 5px 10px;
font-size: large; font-size: large;
font-weight: bold; font-weight: bold;
} }
@@ -190,11 +190,6 @@ div.ui-tooltip {
float: right; float: right;
} }
#note-id-display {
color: lightgrey;
margin-left: 10px;
}
#note-source { #note-source {
height: 98%; height: 98%;
width: 100%; width: 100%;
@@ -245,6 +240,7 @@ div.ui-tooltip {
right: 10px; right: 10px;
bottom: 5px; bottom: 5px;
z-index: 1000; z-index: 1000;
color: lightgrey;
} }
#note-type-dropdown { #note-type-dropdown {

View File

@@ -19,11 +19,12 @@ router.post('/exec', auth.checkApiAuth, wrap(async (req, res, next) => {
router.get('/startup', auth.checkApiAuth, wrap(async (req, res, next) => { router.get('/startup', auth.checkApiAuth, wrap(async (req, res, next) => {
const noteIds = await attributes.getNoteIdsWithAttribute("run_on_startup"); const noteIds = await attributes.getNoteIdsWithAttribute("run_on_startup");
const repository = new Repository(req);
const scripts = []; const scripts = [];
for (const noteId of noteIds) { for (const noteId of noteIds) {
scripts.push(await getNoteWithSubtreeScript(noteId, req)); scripts.push(await getNoteWithSubtreeScript(noteId, repository));
} }
res.send(scripts); res.send(scripts);
@@ -41,10 +42,10 @@ router.get('/subtree/:noteId', auth.checkApiAuth, wrap(async (req, res, next) =>
res.send(subTreeScripts + noteScript); res.send(subTreeScripts + noteScript);
})); }));
async function getNoteWithSubtreeScript(noteId, req) { async function getNoteWithSubtreeScript(noteId, repository) {
const noteScript = (await notes.getNoteById(noteId, req)).content; const noteScript = (await repository.getNote(noteId)).content;
const subTreeScripts = await getSubTreeScripts(noteId, [noteId], req); const subTreeScripts = await getSubTreeScripts(noteId, [noteId], repository);
return subTreeScripts + noteScript; return subTreeScripts + noteScript;
} }

11
src/scripts/today.js Normal file
View File

@@ -0,0 +1,11 @@
api.addButtonToToolbar('go-today', $('<button class="btn btn-xs" onclick="goToday();"><span class="ui-icon ui-icon-calendar"></span> Today</button>'));
window.goToday = async function() {
const todayDateStr = formatDateISO(new Date());
const todayNoteId = await server.exec([todayDateStr], async todayDateStr => {
return await this.getDateNoteId(todayDateStr);
});
api.activateNote(todayNoteId);
};

View File

@@ -65,6 +65,8 @@
}); });
} }
data.sort((a, b) => a.date < b.date ? -1 : +1);
return data; return data;
}); });

View File

@@ -5,32 +5,6 @@ const sync_table = require('./sync_table');
const attributes = require('./attributes'); const attributes = require('./attributes');
const protected_session = require('./protected_session'); const protected_session = require('./protected_session');
async function updateJsonNote(noteId, data) {
const ret = await createNewNote(noteId, {
title: name,
content: JSON.stringify(data),
target: 'into',
isProtected: false,
type: 'code',
mime: 'application/json'
});
return ret.noteId;
}
async function createNewJsonNote(parentNoteId, name, payload) {
const ret = await createNewNote(parentNoteId, {
title: name,
content: JSON.stringify(payload),
target: 'into',
isProtected: false,
type: 'code',
mime: 'application/json'
});
return ret.noteId;
}
async function createNewNote(parentNoteId, noteOpts, dataKey, sourceId) { async function createNewNote(parentNoteId, noteOpts, dataKey, sourceId) {
const noteId = utils.newNoteId(); const noteId = utils.newNoteId();
const noteTreeId = utils.newNoteTreeId(); const noteTreeId = utils.newNoteTreeId();

View File

@@ -17,15 +17,20 @@
<button class="btn btn-xs" onclick="jumpToNote.showDialog();" title="CTRL+J">Jump to note</button> <button class="btn btn-xs" onclick="jumpToNote.showDialog();" title="CTRL+J">Jump to note</button>
<button class="btn btn-xs" onclick="recentNotes.showDialog();" title="CTRL+E">Recent notes</button> <button class="btn btn-xs" onclick="recentNotes.showDialog();" title="CTRL+E">Recent notes</button>
<button class="btn btn-xs" onclick="recentChanges.showDialog();">Recent changes</button> <button class="btn btn-xs" onclick="recentChanges.showDialog();">Recent changes</button>
<button class="btn btn-xs" onclick="eventLog.showDialog();">Event log</button> </div>
<div id="plugin-buttons">
</div> </div>
<div> <div>
<button class="btn btn-xs" onclick="syncNow();" title="Number of outstanding changes to be pushed to server"> <button class="btn btn-xs" onclick="syncNow();" title="Number of outstanding changes to be pushed to server">
<span class="ui-icon ui-icon-refresh"></span>
Sync now (<span id="changes-to-push-count">0</span>) Sync now (<span id="changes-to-push-count">0</span>)
</button> </button>
<button class="btn btn-xs" onclick="settings.showDialog();">Settings</button> <button class="btn btn-xs" onclick="settings.showDialog();">
<span class="ui-icon ui-icon-gear"></span> Settings</button>
<form action="logout" id="logout-button" method="POST" style="display: inline;"> <form action="logout" id="logout-button" method="POST" style="display: inline;">
<input type="submit" class="btn btn-xs" value="Logout"> <input type="submit" class="btn btn-xs" value="Logout">
@@ -492,7 +497,7 @@
<script src="javascripts/link.js"></script> <script src="javascripts/link.js"></script>
<script src="javascripts/sync.js"></script> <script src="javascripts/sync.js"></script>
<script src="javascripts/messaging.js"></script> <script src="javascripts/messaging.js"></script>
<script src="javascripts/api.js"></script>
<script type="text/javascript"> <script type="text/javascript">
// we hide container initally because otherwise it is rendered first without CSS and then flickers into // we hide container initally because otherwise it is rendered first without CSS and then flickers into