Compare commits

...

15 Commits

Author SHA1 Message Date
zadam
deb67d6275 release 0.40.5 2020-03-08 21:05:52 +01:00
zadam
e4039ea5e1 fixed printing relation map 2020-03-08 09:24:03 +01:00
zadam
78a50be663 don't print control buttons 2020-03-07 22:18:12 +01:00
zadam
3d3ad3b99b include themes.css for printing to have default CSS variables available 2020-03-07 22:14:07 +01:00
zadam
0d9cdcac85 load appropriate styles for printing book notes, closes #899 2020-03-07 22:01:34 +01:00
zadam
350331e2ef fix 500px constant height of relation maps, closes #882 2020-02-28 15:20:54 +01:00
zadam
e8a9e49e9e release 0.40.4 2020-02-24 22:59:22 +01:00
zadam
fb55cdaea6 release 0.40.4 2020-02-24 22:58:18 +01:00
zadam
b9b2cc8364 make sure $rendered is always jquery object 2020-02-24 22:55:12 +01:00
zadam
8dfdd090f5 use note's css class also in book and included note, closes #879 2020-02-24 22:46:27 +01:00
zadam
fe7705524a fix include note in mobile frontend, closes #878 2020-02-24 22:37:45 +01:00
zadam
2b1b7774f8 make images in text notes rendered responsively in a book, fixes #871 2020-02-19 22:24:31 +01:00
zadam
2d58019d6e allow to setup web version as a sync client 2020-02-19 22:10:40 +01:00
zadam
fe31f08c0d show setup window if DB is not initialized 2020-02-19 22:09:49 +01:00
zadam
ad7a55d305 always autofix note_contents.content = NULL sync issue after note erasion 2020-02-19 19:51:36 +01:00
22 changed files with 176 additions and 167 deletions

3
.idea/dataSources.xml generated
View File

@@ -6,9 +6,6 @@
<synchronize>true</synchronize> <synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver> <jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/../trilium-data/document.db</jdbc-url> <jdbc-url>jdbc:sqlite:$PROJECT_DIR$/../trilium-data/document.db</jdbc-url>
<driver-properties>
<property name="enable_load_extension" value="true" />
</driver-properties>
</data-source> </data-source>
</component> </component>
</project> </project>

View File

@@ -57,7 +57,6 @@
<index id="24" parent="6" name="sqlite_autoindex_api_tokens_1"> <index id="24" parent="6" name="sqlite_autoindex_api_tokens_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>apiTokenId</ColNames> <ColNames>apiTokenId</ColNames>
<ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<key id="25" parent="6"> <key id="25" parent="6">
@@ -131,21 +130,17 @@
<index id="38" parent="7" name="sqlite_autoindex_attributes_1"> <index id="38" parent="7" name="sqlite_autoindex_attributes_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>attributeId</ColNames> <ColNames>attributeId</ColNames>
<ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<index id="39" parent="7" name="IDX_attributes_noteId_index"> <index id="39" parent="7" name="IDX_attributes_noteId_index">
<ColNames>noteId</ColNames> <ColNames>noteId</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<index id="40" parent="7" name="IDX_attributes_name_value"> <index id="40" parent="7" name="IDX_attributes_name_value">
<ColNames>name <ColNames>name
value</ColNames> value</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<index id="41" parent="7" name="IDX_attributes_value_index"> <index id="41" parent="7" name="IDX_attributes_value_index">
<ColNames>value</ColNames> <ColNames>value</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<key id="42" parent="7"> <key id="42" parent="7">
<ColNames>attributeId</ColNames> <ColNames>attributeId</ColNames>
@@ -212,17 +207,14 @@ value</ColNames>
<index id="54" parent="8" name="sqlite_autoindex_branches_1"> <index id="54" parent="8" name="sqlite_autoindex_branches_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>branchId</ColNames> <ColNames>branchId</ColNames>
<ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<index id="55" parent="8" name="IDX_branches_noteId_parentNoteId"> <index id="55" parent="8" name="IDX_branches_noteId_parentNoteId">
<ColNames>noteId <ColNames>noteId
parentNoteId</ColNames> parentNoteId</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<index id="56" parent="8" name="IDX_branches_parentNoteId"> <index id="56" parent="8" name="IDX_branches_parentNoteId">
<ColNames>parentNoteId</ColNames> <ColNames>parentNoteId</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<key id="57" parent="8"> <key id="57" parent="8">
<ColNames>branchId</ColNames> <ColNames>branchId</ColNames>
@@ -253,7 +245,6 @@ parentNoteId</ColNames>
<index id="62" parent="9" name="sqlite_autoindex_note_contents_1"> <index id="62" parent="9" name="sqlite_autoindex_note_contents_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>noteId</ColNames> <ColNames>noteId</ColNames>
<ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<key id="63" parent="9"> <key id="63" parent="9">
@@ -284,7 +275,6 @@ parentNoteId</ColNames>
<index id="68" parent="10" name="sqlite_autoindex_note_revision_contents_1"> <index id="68" parent="10" name="sqlite_autoindex_note_revision_contents_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>noteRevisionId</ColNames> <ColNames>noteRevisionId</ColNames>
<ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<key id="69" parent="10"> <key id="69" parent="10">
@@ -369,28 +359,22 @@ parentNoteId</ColNames>
<index id="84" parent="11" name="sqlite_autoindex_note_revisions_1"> <index id="84" parent="11" name="sqlite_autoindex_note_revisions_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>noteRevisionId</ColNames> <ColNames>noteRevisionId</ColNames>
<ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<index id="85" parent="11" name="IDX_note_revisions_noteId"> <index id="85" parent="11" name="IDX_note_revisions_noteId">
<ColNames>noteId</ColNames> <ColNames>noteId</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<index id="86" parent="11" name="IDX_note_revisions_utcDateLastEdited"> <index id="86" parent="11" name="IDX_note_revisions_utcDateLastEdited">
<ColNames>utcDateLastEdited</ColNames> <ColNames>utcDateLastEdited</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<index id="87" parent="11" name="IDX_note_revisions_utcDateCreated"> <index id="87" parent="11" name="IDX_note_revisions_utcDateCreated">
<ColNames>utcDateCreated</ColNames> <ColNames>utcDateCreated</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<index id="88" parent="11" name="IDX_note_revisions_dateLastEdited"> <index id="88" parent="11" name="IDX_note_revisions_dateLastEdited">
<ColNames>dateLastEdited</ColNames> <ColNames>dateLastEdited</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<index id="89" parent="11" name="IDX_note_revisions_dateCreated"> <index id="89" parent="11" name="IDX_note_revisions_dateCreated">
<ColNames>dateCreated</ColNames> <ColNames>dateCreated</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<key id="90" parent="11"> <key id="90" parent="11">
<ColNames>noteRevisionId</ColNames> <ColNames>noteRevisionId</ColNames>
@@ -477,36 +461,28 @@ parentNoteId</ColNames>
<index id="105" parent="12" name="sqlite_autoindex_notes_1"> <index id="105" parent="12" name="sqlite_autoindex_notes_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>noteId</ColNames> <ColNames>noteId</ColNames>
<ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<index id="106" parent="12" name="IDX_notes_title"> <index id="106" parent="12" name="IDX_notes_title">
<ColNames>title</ColNames> <ColNames>title</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<index id="107" parent="12" name="IDX_notes_type"> <index id="107" parent="12" name="IDX_notes_type">
<ColNames>type</ColNames> <ColNames>type</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<index id="108" parent="12" name="IDX_notes_isDeleted"> <index id="108" parent="12" name="IDX_notes_isDeleted">
<ColNames>isDeleted</ColNames> <ColNames>isDeleted</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<index id="109" parent="12" name="IDX_notes_dateCreated"> <index id="109" parent="12" name="IDX_notes_dateCreated">
<ColNames>dateCreated</ColNames> <ColNames>dateCreated</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<index id="110" parent="12" name="IDX_notes_dateModified"> <index id="110" parent="12" name="IDX_notes_dateModified">
<ColNames>dateModified</ColNames> <ColNames>dateModified</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<index id="111" parent="12" name="IDX_notes_utcDateCreated"> <index id="111" parent="12" name="IDX_notes_utcDateCreated">
<ColNames>utcDateCreated</ColNames> <ColNames>utcDateCreated</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<index id="112" parent="12" name="IDX_notes_utcDateModified"> <index id="112" parent="12" name="IDX_notes_utcDateModified">
<ColNames>utcDateModified</ColNames> <ColNames>utcDateModified</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<key id="113" parent="12"> <key id="113" parent="12">
<ColNames>noteId</ColNames> <ColNames>noteId</ColNames>
@@ -547,7 +523,6 @@ parentNoteId</ColNames>
<index id="120" parent="13" name="sqlite_autoindex_options_1"> <index id="120" parent="13" name="sqlite_autoindex_options_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>name</ColNames> <ColNames>name</ColNames>
<ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<key id="121" parent="13"> <key id="121" parent="13">
@@ -583,7 +558,6 @@ parentNoteId</ColNames>
<index id="127" parent="14" name="sqlite_autoindex_recent_notes_1"> <index id="127" parent="14" name="sqlite_autoindex_recent_notes_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>noteId</ColNames> <ColNames>noteId</ColNames>
<ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<key id="128" parent="14"> <key id="128" parent="14">
@@ -604,12 +578,10 @@ parentNoteId</ColNames>
<index id="131" parent="15" name="sqlite_autoindex_source_ids_1"> <index id="131" parent="15" name="sqlite_autoindex_source_ids_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>sourceId</ColNames> <ColNames>sourceId</ColNames>
<ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<index id="132" parent="15" name="IDX_source_ids_utcDateCreated"> <index id="132" parent="15" name="IDX_source_ids_utcDateCreated">
<ColNames>utcDateCreated</ColNames> <ColNames>utcDateCreated</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<key id="133" parent="15"> <key id="133" parent="15">
<ColNames>sourceId</ColNames> <ColNames>sourceId</ColNames>
@@ -671,12 +643,10 @@ parentNoteId</ColNames>
<index id="146" parent="18" name="IDX_sync_entityName_entityId"> <index id="146" parent="18" name="IDX_sync_entityName_entityId">
<ColNames>entityName <ColNames>entityName
entityId</ColNames> entityId</ColNames>
<ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<index id="147" parent="18" name="IDX_sync_utcSyncDate"> <index id="147" parent="18" name="IDX_sync_utcSyncDate">
<ColNames>utcSyncDate</ColNames> <ColNames>utcSyncDate</ColNames>
<ColumnCollations></ColumnCollations>
</index> </index>
<key id="148" parent="18"> <key id="148" parent="18">
<ColNames>id</ColNames> <ColNames>id</ColNames>

View File

@@ -26,9 +26,9 @@ app.on('ready', async () => {
await sqlInit.dbConnection; await sqlInit.dbConnection;
// if schema doesn't exist -> setup process // if db is not initialized -> setup process
// if schema exists, then we need to wait until the migration process is finished // if db is initialized, then we need to wait until the migration process is finished
if (await sqlInit.schemaExists()) { if (await sqlInit.isDbInitialized()) {
await sqlInit.dbReady; await sqlInit.dbReady;
await windowService.createMainWindow(); await windowService.createMainWindow();

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "trilium", "name": "trilium",
"version": "0.40.2", "version": "0.40.4",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

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

View File

@@ -161,7 +161,13 @@ async function printActiveNote() {
importCSS: false, importCSS: false,
loadCSS: [ loadCSS: [
"libraries/codemirror/codemirror.css", "libraries/codemirror/codemirror.css",
"libraries/ckeditor/ckeditor-content.css" "libraries/ckeditor/ckeditor-content.css",
"libraries/ckeditor/ckeditor-content.css",
"libraries/bootstrap/css/bootstrap.min.css",
"stylesheets/print.css",
"stylesheets/relation_map.css",
"stylesheets/themes.css",
"stylesheets/detail.css"
], ],
debug: true debug: true
}); });

View File

@@ -7,9 +7,26 @@ import contextMenuWidget from "./services/context_menu.js";
import treeChangesService from "./services/branches.js"; import treeChangesService from "./services/branches.js";
import utils from "./services/utils.js"; import utils from "./services/utils.js";
import treeUtils from "./services/tree_utils.js"; import treeUtils from "./services/tree_utils.js";
import linkService from "./services/link.js";
import noteContentRenderer from "./services/note_content_renderer.js";
window.glob.isDesktop = utils.isDesktop; window.glob.isDesktop = utils.isDesktop;
window.glob.isMobile = utils.isMobile; window.glob.isMobile = utils.isMobile;
window.glob.showAddLinkDialog = () => import('./dialogs/add_link.js').then(d => d.showDialog());
window.glob.showIncludeNoteDialog = cb => import('./dialogs/include_note.js').then(d => d.showDialog(cb));
window.glob.loadIncludedNote = async (noteId, el) => {
const note = await treeCache.getNote(noteId);
if (note) {
$(el).empty().append($("<h3>").append(await linkService.createNoteLink(note.noteId, {
showTooltip: false
})));
const {renderedContent} = await noteContentRenderer.getRenderedContent(note);
$(el).append(renderedContent);
}
};
const $leftPane = $("#left-pane"); const $leftPane = $("#left-pane");
const $tree = $("#tree"); const $tree = $("#tree");

View File

@@ -7,31 +7,20 @@ import protectedSessionHolder from "./protected_session_holder.js";
async function getRenderedContent(note) { async function getRenderedContent(note) {
const type = getRenderingType(note); const type = getRenderingType(note);
let rendered; let $rendered;
if (type === 'text') { if (type === 'text') {
const fullNote = await server.get('notes/' + note.noteId); const fullNote = await server.get('notes/' + note.noteId);
const $content = $("<div>").html(fullNote.content); $rendered = $("<div>").html(fullNote.content);
if (utils.isHtmlEmpty(fullNote.content)) {
rendered = "";
}
else {
rendered = $content;
}
} }
else if (type === 'code') { else if (type === 'code') {
const fullNote = await server.get('notes/' + note.noteId); const fullNote = await server.get('notes/' + note.noteId);
if (fullNote.content.trim() === "") { $rendered = $("<pre>").text(fullNote.content);
rendered = "";
}
rendered = $("<pre>").text(fullNote.content);
} }
else if (type === 'image') { else if (type === 'image') {
rendered = $("<img>").attr("src", `api/images/${note.noteId}/${note.title}`); $rendered = $("<img>").attr("src", `api/images/${note.noteId}/${note.title}`);
} }
else if (type === 'file') { else if (type === 'file') {
function getFileUrl() { function getFileUrl() {
@@ -56,33 +45,35 @@ async function getRenderedContent(note) {
// open doesn't work for protected notes since it works through browser which isn't in protected session // open doesn't work for protected notes since it works through browser which isn't in protected session
$openButton.toggle(!note.isProtected); $openButton.toggle(!note.isProtected);
rendered = $('<div>') $rendered = $('<div>')
.append($downloadButton) .append($downloadButton)
.append(' &nbsp; ') .append(' &nbsp; ')
.append($openButton); .append($openButton);
} }
else if (type === 'render') { else if (type === 'render') {
const $el = $('<div>'); $rendered = $('<div>');
await renderService.render(note, $el, this.ctx); await renderService.render(note, $rendered, this.ctx);
rendered = $el;
} }
else if (type === 'protected-session') { else if (type === 'protected-session') {
const $button = $(`<button class="btn btn-sm"><span class="bx bx-log-in"></span> Enter protected session</button>`) const $button = $(`<button class="btn btn-sm"><span class="bx bx-log-in"></span> Enter protected session</button>`)
.on('click', protectedSessionService.enterProtectedSession); .on('click', protectedSessionService.enterProtectedSession);
rendered = $("<div>") $rendered = $("<div>")
.append("<div>This note is protected and to access it you need to enter password.</div>") .append("<div>This note is protected and to access it you need to enter password.</div>")
.append("<br/>") .append("<br/>")
.append($button); .append($button);
} }
else { else {
rendered = "<em>Content of this note cannot be displayed in the book format</em>"; $rendered = $("<em>Content of this note cannot be displayed in the book format</em>");
}
if (note.cssClass) {
$rendered.addClass(note.cssClass);
} }
return { return {
renderedContent: rendered, renderedContent: $rendered,
type type
}; };
} }

View File

@@ -148,8 +148,8 @@ class NoteDetailBook {
const label = `${childCount} child${childCount > 1 ? 'ren' : ''}`; const label = `${childCount} child${childCount > 1 ? 'ren' : ''}`;
$card.append($('<div class="note-book-children">') $card.append($('<div class="note-book-children">')
.append($(`<a class="note-book-open-children-button" href="javascript:">+ Show ${label}</a>`)) .append($(`<a class="note-book-open-children-button no-print" href="javascript:">+ Show ${label}</a>`))
.append($(`<a class="note-book-hide-children-button" href="javascript:">- Hide ${label}</a>`).hide()) .append($(`<a class="note-book-hide-children-button no-print" href="javascript:">- Hide ${label}</a>`).hide())
.append($('<div class="note-book-children-content">')) .append($('<div class="note-book-children-content">'))
); );
} }

View File

@@ -43,6 +43,7 @@ body {
min-height: 0; min-height: 0;
padding-left: 10px; padding-left: 10px;
width: 100%; width: 100%;
height: 100%;
} }
#search-box { #search-box {

View File

@@ -0,0 +1,69 @@
.note-detail-book {
height: 100%;
}
.note-detail-book-content {
display: flex;
flex-wrap: wrap;
overflow: auto;
height: 100%;
align-content: start;
}
.note-book-card {
border-radius: 10px;
background-color: var(--accented-background-color);
padding: 15px;
padding-bottom: 5px;
margin: 5px;
margin-left: 0;
overflow: hidden;
display: flex;
flex-direction: column;
flex-shrink: 0;
}
.note-book-card .note-book-card {
border: 1px solid var(--main-border-color);
}
.note-book-content {
overflow: hidden;
}
.note-book-card.type-image .note-book-content, .note-book-card.type-file .note-book-content, .note-book-card.type-protected-session .note-book-content {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.note-book-card.type-image .note-book-content img, .note-book-card.type-text .note-book-content img {
max-width: 100%;
max-height: 100%;
}
.note-book-title {
flex-grow: 0;
}
.note-book-content {
flex-grow: 1;
}
.note-book-auto-message {
background-color: var(--accented-background-color);
text-align: center;
width: 100%;
border-radius: 10px;
padding: 5px;
margin-top: 5px;
}
.note-detail-image {
text-align: center;
}
.note-detail-image-view {
max-width: 100%;
}

View File

@@ -0,0 +1,11 @@
@media print
{
.no-print, .no-print *
{
display: none !important;
}
.relation-map-wrapper {
height: 100vh !important;
}
}

View File

@@ -518,14 +518,6 @@ button.icon-button {
padding: 5px; padding: 5px;
} }
.note-detail-image {
text-align: center;
}
.note-detail-image-view {
max-width: 100%;
}
pre:not(.CodeMirror-line) { pre:not(.CodeMirror-line) {
color: var(--main-text-color) !important; color: var(--main-text-color) !important;
white-space: pre-wrap; white-space: pre-wrap;
@@ -857,68 +849,6 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
z-index: 100; z-index: 100;
} }
.note-detail-book {
height: 100%;
}
.note-detail-book-content {
display: flex;
flex-wrap: wrap;
overflow: auto;
height: 100%;
align-content: start;
}
.note-book-card {
border-radius: 10px;
background-color: var(--accented-background-color);
padding: 15px;
padding-bottom: 5px;
margin: 5px;
margin-left: 0;
overflow: hidden;
display: flex;
flex-direction: column;
flex-shrink: 0;
}
.note-book-card .note-book-card {
border: 1px solid var(--main-border-color);
}
.note-book-content {
overflow: hidden;
}
.note-book-card.type-image .note-book-content, .note-book-card.type-file .note-book-content, .note-book-card.type-protected-session .note-book-content {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.note-book-card.type-image .note-book-content img {
max-width: 100%;
max-height: 100%;
}
.note-book-title {
flex-grow: 0;
}
.note-book-content {
flex-grow: 1;
}
.note-book-auto-message {
background-color: var(--accented-background-color);
text-align: center;
width: 100%;
border-radius: 10px;
padding: 5px;
margin-top: 5px;
}
#toast-container { #toast-container {
position: absolute; position: absolute;
width: 100%; width: 100%;

View File

@@ -1 +1 @@
module.exports = { buildDate:"2020-02-09T10:48:23+01:00", buildRevision: "88bd65c6798609a39206722305fab4f8d91d618b" }; module.exports = { buildDate:"2020-03-08T21:05:52+01:00", buildRevision: "e4039ea5e1c6ac87e0947bc77b6bdcbb29a23092" };

View File

@@ -323,14 +323,25 @@ class ConsistencyChecks {
WHERE isErased = 1 WHERE isErased = 1
AND content IS NOT NULL`, AND content IS NOT NULL`,
async ({noteId}) => { async ({noteId}) => {
if (this.autoFix) {
await sql.execute(`UPDATE note_contents SET content = NULL WHERE noteId = ?`, [noteId]);
logFix(`Note ${noteId} content has been set to null since the note is erased`); // we always fix this issue because there does not seem to be a good way to prevent it.
} // Scenario in which this can happen:
else { // 1. user on instance A deletes the note (sync for notes is created, but not for note_contents) and is later erased
logError(`Note ${noteId} content is not null even though the note is erased`); // 2. instance B gets synced from instance A, note is updated because of sync row for notes,
} // but note_contents is not because erasion does not create sync rows
// 3. therefore note.isErased = true, but note_contents.content remains not updated and not erased.
//
// Considered solutions:
// - don't sync erased notes - this might prevent syncing also of the isDeleted flag and note would continue
// to exist on the other instance
// - create sync rows for erased event - this would be a problem for undeletion since erasion might happen
// on one instance after undelete and thus would win even though there's no user action behind it
//
// So instead we just fix such cases afterwards here.
await sql.execute(`UPDATE note_contents SET content = NULL WHERE noteId = ?`, [noteId]);
logFix(`Note ${noteId} content has been set to null since the note is erased`);
}); });
await this.findAndFixIssues(` await this.findAndFixIssues(`
@@ -547,23 +558,23 @@ class ConsistencyChecks {
}); });
await this.findAndFixIssues(` await this.findAndFixIssues(`
SELECT SELECT
id, entityId id, entityId
FROM FROM
sync sync
LEFT JOIN ${entityName} ON entityId = ${key} LEFT JOIN ${entityName} ON entityId = ${key}
WHERE WHERE
sync.entityName = '${entityName}' sync.entityName = '${entityName}'
AND ${key} IS NULL`, AND ${key} IS NULL`,
async ({id, entityId}) => { async ({id, entityId}) => {
if (this.autoFix) { if (this.autoFix) {
await sql.execute("DELETE FROM sync WHERE entityName = ? AND entityId = ?", [entityName, entityId]); await sql.execute("DELETE FROM sync WHERE entityName = ? AND entityId = ?", [entityName, entityId]);
logFix(`Deleted extra sync record id=${id}, entityName=${entityName}, entityId=${entityId}`); logFix(`Deleted extra sync record id=${id}, entityName=${entityName}, entityId=${entityId}`);
} else { } else {
logError(`Unrecognized sync record id=${id}, entityName=${entityName}, entityId=${entityId}`); logError(`Unrecognized sync record id=${id}, entityName=${entityName}, entityId=${entityId}`);
} }
}); });
} }
async findSyncRowsIssues() { async findSyncRowsIssues() {

View File

@@ -599,6 +599,7 @@ async function eraseDeletedNotes() {
UPDATE notes UPDATE notes
SET title = '[deleted]', SET title = '[deleted]',
contentLength = 0, contentLength = 0,
isProtected = 0,
isErased = 1 isErased = 1
WHERE noteId IN (???)`, noteIdsToErase); WHERE noteId IN (???)`, noteIdsToErase);

View File

@@ -228,9 +228,10 @@ async function syncFinished(syncContext) {
async function checkContentHash(syncContext) { async function checkContentHash(syncContext) {
const resp = await syncRequest(syncContext, 'GET', '/api/sync/check'); const resp = await syncRequest(syncContext, 'GET', '/api/sync/check');
const lastSyncedPullId = await getLastSyncedPull();
if (await getLastSyncedPull() < resp.maxSyncId) { if (lastSyncedPullId < resp.maxSyncId) {
log.info("There are some outstanding pulls, skipping content check."); log.info(`There are some outstanding pulls (${lastSyncedPullId} vs. ${resp.maxSyncId}), skipping content check.`);
return true; return true;
} }

View File

@@ -250,6 +250,7 @@
<link href="stylesheets/themes.css" rel="stylesheet"> <link href="stylesheets/themes.css" rel="stylesheet">
<link href="stylesheets/style.css" rel="stylesheet"> <link href="stylesheets/style.css" rel="stylesheet">
<link href="stylesheets/detail.css" rel="stylesheet">
<link href="stylesheets/desktop.css" rel="stylesheet"> <link href="stylesheets/desktop.css" rel="stylesheet">
<script src="javascripts/desktop.js" crossorigin type="module"></script> <script src="javascripts/desktop.js" crossorigin type="module"></script>

View File

@@ -1,5 +1,5 @@
<div class="note-detail-image note-detail-component"> <div class="note-detail-image note-detail-component">
<div style="display: flex; justify-content: space-evenly; margin: 10px;"> <div class="no-print" style="display: flex; justify-content: space-evenly; margin: 10px;">
<button class="image-download btn btn-sm btn-primary" type="button">Download</button> <button class="image-download btn btn-sm btn-primary" type="button">Download</button>
<button class="image-copy-to-clipboard btn btn-sm btn-primary" type="button">Copy to clipboard</button> <button class="image-copy-to-clipboard btn btn-sm btn-primary" type="button">Copy to clipboard</button>

View File

@@ -1,5 +1,5 @@
<div class="note-detail-relation-map note-detail-component"> <div class="note-detail-relation-map note-detail-component">
<button class="relation-map-create-child-note btn btn-sm floating-button" type="button" <button class="relation-map-create-child-note btn btn-sm floating-button no-print" type="button"
title="Create new child note and add it into this relation map"> title="Create new child note and add it into this relation map">
<span class="bx bx-folder-plus"></span> <span class="bx bx-folder-plus"></span>
@@ -7,11 +7,11 @@
</button> </button>
<button type="button" <button type="button"
class="relation-map-reset-pan-zoom btn icon-button floating-button bx bx-crop" class="relation-map-reset-pan-zoom btn icon-button floating-button bx bx-crop no-print"
title="Reset pan & zoom to initial coordinates and magnification" title="Reset pan & zoom to initial coordinates and magnification"
style="right: 70px;"></button> style="right: 70px;"></button>
<div class="btn-group floating-button" style="right: 10px;"> <div class="btn-group floating-button no-print" style="right: 10px;">
<button type="button" <button type="button"
class="relation-map-zoom-in btn icon-button bx bx-zoom-in" class="relation-map-zoom-in btn icon-button bx bx-zoom-in"
title="Zoom In"></button> title="Zoom In"></button>

View File

@@ -73,6 +73,8 @@
<% include details/relation_map.ejs %> <% include details/relation_map.ejs %>
<% include details/protected_session_password.ejs %> <% include details/protected_session_password.ejs %>
<% include details/book.ejs %>
</div> </div>
</div> </div>
</div> </div>
@@ -116,6 +118,7 @@
<link href="stylesheets/themes.css" rel="stylesheet"> <link href="stylesheets/themes.css" rel="stylesheet">
<link href="stylesheets/style.css" rel="stylesheet"> <link href="stylesheets/style.css" rel="stylesheet">
<link href="stylesheets/detail.css" rel="stylesheet">
<link href="stylesheets/mobile.css" rel="stylesheet"> <link href="stylesheets/mobile.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="libraries/boxicons/css/boxicons.min.css"> <link rel="stylesheet" type="text/css" href="libraries/boxicons/css/boxicons.min.css">

View File

@@ -19,13 +19,13 @@
<label><input type="radio" name="setup-type" value="new-document" data-bind="checked: setupType"> <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> I'm a new user and I want to create new Trilium document for my notes</label>
</div> </div>
<div class="radio" data-bind="if: instanceType == 'server'" style="margin-bottom: 15px;"> <div class="radio" style="margin-bottom: 15px;">
<label><input type="radio" name="setup-type" value="sync-from-desktop" data-bind="checked: setupType"> <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> I have desktop instance already and I want to setup sync with it</label>
</div> </div>
<div class="radio" data-bind="if: instanceType == 'desktop'" style="margin-bottom: 15px;"> <div class="radio" style="margin-bottom: 15px;">
<label><input type="radio" name="setup-type" value="sync-from-server" data-bind="checked: setupType"> <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> I have server instance already and I want to setup sync with it</label>
</div> </div>
<button type="button" data-bind="disable: !setupTypeSelected(), click: selectSetupType" class="btn btn-primary">Next</button> <button type="button" data-bind="disable: !setupTypeSelected(), click: selectSetupType" class="btn btn-primary">Next</button>