Compare commits

...

9 Commits

Author SHA1 Message Date
zadam
6e0a65b59c release 0.48.3 2021-10-22 21:31:44 +02:00
zadam
56e49cfc19 set iconClass also on whole page clipping #2250 2021-10-21 23:02:22 +02:00
zadam
af40d73cee fix saving images from web clipper, closes #2249 2021-10-21 22:58:52 +02:00
zadam
50b7063811 display properly relations in note map even if they are not in the subtree, closes #2251 2021-10-21 22:52:52 +02:00
zadam
ee1b377bc2 deactivate some buttons based on note type 2021-10-21 21:28:44 +02:00
zadam
51dfe8bb14 avoid double rendering of note paths 2021-10-21 21:10:55 +02:00
zadam
e426ee3e4f disallow changing note type of note-map 2021-10-21 21:02:37 +02:00
zadam
a434aa113d fix repeated invocation of actions in note actions dropdown, closes #2255 2021-10-21 20:53:35 +02:00
Sathyam M Vellal
3b551e3e4d Add week notes to frontend_script_api (#2253)
Note: getWeekNote can take `startOfTheWeek` as options but is not passed to the api route.
2021-10-21 12:16:51 +02:00
14 changed files with 134 additions and 39 deletions

14
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "trilium",
"version": "0.48.1-beta",
"version": "0.48.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -2850,9 +2850,9 @@
}
},
"electron": {
"version": "13.5.2",
"resolved": "https://registry.npmjs.org/electron/-/electron-13.5.2.tgz",
"integrity": "sha512-CPakwDpy5m8dL0383F5uJboQcVtn9bT/+6/wdDKo8LuTUO9aER1TF41v7feZgZW2c+UwoGPWa814ElSQ3qta2A==",
"version": "13.6.0",
"resolved": "https://registry.npmjs.org/electron/-/electron-13.6.0.tgz",
"integrity": "sha512-VDOUmRwa4eQ+5iXE+XHKXKX+2yk8Ey5uBe3nH9Hj6zNPUBY2S0EOClw7U90Ve2lLHXiQ6DnguNmDgOZKJLcHFQ==",
"dev": true,
"requires": {
"@electron/get": "^1.0.1",
@@ -2861,9 +2861,9 @@
},
"dependencies": {
"@types/node": {
"version": "14.17.21",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.21.tgz",
"integrity": "sha512-zv8ukKci1mrILYiQOwGSV4FpkZhyxQtuFWGya2GujWg+zVAeRQ4qbaMmWp9vb9889CFA8JECH7lkwCL6Ygg8kA==",
"version": "14.17.27",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.27.tgz",
"integrity": "sha512-94+Ahf9IcaDuJTle/2b+wzvjmutxXAEXU6O81JHblYXUg2BDG+dnBy7VxIPHKAyEEDHzCMQydTJuWvrE+Aanzw==",
"dev": true
}
}

View File

@@ -2,7 +2,7 @@
"name": "trilium",
"productName": "Trilium Notes",
"description": "Trilium Notes",
"version": "0.48.2",
"version": "0.48.3",
"license": "AGPL-3.0-only",
"main": "electron.js",
"bin": {
@@ -81,7 +81,7 @@
},
"devDependencies": {
"cross-env": "7.0.3",
"electron": "13.5.2",
"electron": "13.6.0",
"electron-builder": "22.13.1",
"electron-packager": "15.4.0",
"electron-rebuild": "3.2.3",

View File

@@ -764,8 +764,8 @@ class Note extends AbstractEntity {
}
/** @return {String[]} */
getSubtreeNoteIds() {
return this.getSubtreeNotes().map(note => note.noteId);
getSubtreeNoteIds(includeArchived = true) {
return this.getSubtreeNotes(includeArchived).map(note => note.noteId);
}
getDescendantNoteIds() {

View File

@@ -23,6 +23,15 @@ async function getDateNote(date) {
return await froca.getNote(note.noteId);
}
/** @return {NoteShort} */
async function getWeekNote(date) {
const note = await server.get('special-notes/week/' + date, "date-note");
await ws.waitForMaxKnownEntityChangeId();
return await froca.getNote(note.noteId);
}
/** @return {NoteShort} */
async function getMonthNote(month) {
const note = await server.get('special-notes/month/' + month, "date-note");
@@ -63,6 +72,7 @@ export default {
getInboxNote,
getTodayNote,
getDateNote,
getWeekNote,
getMonthNote,
getYearNote,
createSqlConsole,

View File

@@ -396,6 +396,15 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
*/
this.getDateNote = dateNotesService.getDateNote;
/**
* Returns date-note for the first date of the week of the given date. If it doesn't exist, it is automatically created.
*
* @method
* @param {string} date - e.g. "2019-04-29"
* @return {Promise<NoteShort>}
*/
this.getWeekNote = dateNotesService.getWeekNote;
/**
* Returns month-note. If it doesn't exist, it is automatically created.
*

View File

@@ -25,12 +25,12 @@ const TPL = `
<div class="dropdown-menu dropdown-menu-right">
<a data-trigger-command="renderActiveNote" class="dropdown-item render-note-button"><kbd data-command="renderActiveNote"></kbd> Re-render note</a>
<a data-trigger-command="findInText" class="dropdown-item">Search in note <kbd data-command="findInText"></a>
<a data-trigger-command="findInText" class="dropdown-item find-in-text-button">Search in note <kbd data-command="findInText"></a>
<a data-trigger-command="showNoteSource" class="dropdown-item show-source-button"><kbd data-command="showNoteSource"></kbd> Note source</a>
<a data-trigger-command="openNoteExternally" class="dropdown-item open-note-externally-button"><kbd data-command="openNoteExternally"></kbd> Open note externally</a>
<a class="dropdown-item import-files-button">Import files</a>
<a class="dropdown-item export-note-button">Export note</a>
<a data-trigger-command="printActiveNote" class="dropdown-item print-note-button"><kbd data-command="printActiveNote"></kbd> Print note</a>
<a data-trigger-command="printActiveNote" class="dropdown-item print-active-note-button"><kbd data-command="printActiveNote"></kbd> Print note</a>
</div>
</div>`;
@@ -42,6 +42,8 @@ export default class NoteActionsWidget extends NoteContextAwareWidget {
doRender() {
this.$widget = $(TPL);
this.$findInTextButton = this.$widget.find('.find-in-text-button');
this.$printActiveNoteButton = this.$widget.find('.print-active-note-button');
this.$showSourceButton = this.$widget.find('.show-source-button');
this.$renderNoteButton = this.$widget.find('.render-note-button');
@@ -57,14 +59,18 @@ export default class NoteActionsWidget extends NoteContextAwareWidget {
this.$importNoteButton = this.$widget.find('.import-files-button');
this.$importNoteButton.on("click", () => import('../../dialogs/import.js').then(d => d.showDialog(this.noteId)));
this.$widget.on('click', '.dropdown-item', () => this.$widget.find('.dropdown-menu').dropdown('toggle'));
this.$widget.on('click', '.dropdown-item', () => this.$widget.find("[data-toggle='dropdown']").dropdown('toggle'));
this.$openNoteExternallyButton = this.$widget.find(".open-note-externally-button");
}
refreshWithNote(note) {
this.toggleDisabled(this.$findInTextButton, ['text', 'code', 'book', 'search'].includes(note.type));
this.toggleDisabled(this.$showSourceButton, ['text', 'relation-map', 'search', 'code'].includes(note.type));
this.toggleDisabled(this.$printActiveNoteButton, ['text', 'code'].includes(note.type));
this.$renderNoteButton.toggle(note.type === 'render');
this.$openNoteExternallyButton.toggle(utils.isElectron());

View File

@@ -17,7 +17,7 @@ const TPL = `<div class="note-map-widget" style="position: relative;">
top: 10px;
right: 10px;
background-color: var(--accented-background-color);
z-index: 1000;
z-index: 10; /* should be below dropdown (note actions) */
}
.map-type-switcher .bx {
@@ -332,9 +332,9 @@ export default class NoteMapWidget extends NoteContextAwareWidget {
if (this.widgetMode === 'ribbon') {
setTimeout(() => {
const node = this.nodes.find(node => node.id === this.noteId);
const subGraphNoteIds = this.getSubGraphConnectedToCurrentNote(data);
this.graph.centerAt(node.x, node.y, 500);
this.graph.zoomToFit(400, 50, node => subGraphNoteIds.has(node.id));
}, 1000);
}
else if (this.widgetMode === 'type') {
@@ -344,6 +344,39 @@ export default class NoteMapWidget extends NoteContextAwareWidget {
}
}
getSubGraphConnectedToCurrentNote(data) {
function getGroupedLinksBySource(links) {
const map = {};
for (const link of links) {
const key = link.source.id;
map[key] = map[key] || [];
map[key].push(link);
}
return map;
}
const linksBySource = getGroupedLinksBySource(data.links);
const subGraphNoteIds = new Set();
function traverseGraph(noteId) {
if (subGraphNoteIds.has(noteId)) {
return;
}
subGraphNoteIds.add(noteId);
for (const link of linksBySource[noteId] || []) {
traverseGraph(link.target.id);
}
}
traverseGraph(this.noteId);
return subGraphNoteIds;
}
cleanup() {
this.$container.html('');
}

View File

@@ -5,7 +5,8 @@ import NoteContextAwareWidget from "./note_context_aware_widget.js";
const NOTE_TYPES = [
{ type: "file", title: "File", selectable: false },
{ type: "image", title: "Image", selectable: false },
{ type: "search", title: "Saved search", selectable: false },
{ type: "search", title: "Saved Search", selectable: false },
{ type: "note-map", mime: '', title: "Note Map", selectable: false },
{ type: "text", mime: "text/html", title: "Text", selectable: true },
{ type: "relation-map", mime: "application/json", title: "Relation Map", selectable: true },
@@ -15,6 +16,8 @@ const NOTE_TYPES = [
{ type: "code", mime: 'text/plain', title: "Code", selectable: true }
];
const NOT_SELECTABLE_NOTE_TYPES = NOTE_TYPES.filter(nt => !nt.selectable).map(nt => nt.type);
const TPL = `
<div class="dropdown note-type-widget">
<style>
@@ -48,7 +51,7 @@ export default class NoteTypeWidget extends NoteContextAwareWidget {
async refreshWithNote(note) {
this.$noteTypeButton.prop("disabled",
() => ["file", "image", "search"].includes(note.type));
() => NOT_SELECTABLE_NOTE_TYPES.includes(note.type));
this.$noteTypeDesc.text(await this.findTypeTitle(note.type, note.mime));

View File

@@ -69,7 +69,7 @@ export default class NotePathsWidget extends NoteContextAwareWidget {
this.$notePathList.empty();
if (this.noteId === 'root') {
await this.addPath('root');
await this.getRenderedPath('root');
return;
}
@@ -83,22 +83,18 @@ export default class NotePathsWidget extends NoteContextAwareWidget {
this.$notePathIntro.text("This note is not yet placed into the note tree.");
}
const printedNotePaths = new Set();
const renderedPaths = [];
for (const notePathRecord of sortedNotePaths) {
const notePath = notePathRecord.notePath.join('/');
if (printedNotePaths.has(notePath)) {
continue;
}
printedNotePaths.add(notePath);
await this.addPath(notePath, notePathRecord);
renderedPaths.push(await this.getRenderedPath(notePath, notePathRecord));
}
this.$notePathList.empty().append(...renderedPaths);
}
async addPath(notePath, notePathRecord) {
async getRenderedPath(notePath, notePathRecord) {
const title = await treeService.getNotePathTitle(notePath);
const $noteLink = await linkService.createNoteLink(notePath, {title});
@@ -136,7 +132,7 @@ export default class NotePathsWidget extends NoteContextAwareWidget {
$noteLink.append(` ${icons.join(' ')}`);
}
this.$notePathList.append($("<li>").append($noteLink));
return $("<li>").append($noteLink);
}
entitiesReloadedEvent({loadResults}) {

View File

@@ -15,7 +15,7 @@ const htmlSanitizer = require('../../services/html_sanitizer');
const {formatAttrForSearch} = require("../../services/attribute_formatter");
function findClippingNote(todayNote, pageUrl) {
const notes = todayNote.searchNoteInSubtree(
const notes = todayNote.searchNotesInSubtree(
formatAttrForSearch({
type: 'label',
name: "pageUrl",
@@ -93,6 +93,7 @@ function createNote(req) {
if (pageUrl) {
note.setLabel('pageUrl', pageUrl);
note.setLabel('iconClass', 'bx bx-globe');
}
const rewrittenContent = processContent(images, note, content);

View File

@@ -24,23 +24,54 @@ function buildDescendantCountMap() {
return noteIdToCountMap;
}
function getNeighbors(note, depth) {
if (depth === 0) {
return [];
}
const retNoteIds = [];
for (const relation of note.getRelations()) {
if (['relationMapLink', 'template', 'image'].includes(relation.name)) {
continue;
}
const targetNote = relation.getTargetNote();
retNoteIds.push(targetNote.noteId);
for (const noteId of getNeighbors(targetNote, depth - 1)) {
retNoteIds.push(noteId);
}
}
return retNoteIds;
}
function getLinkMap(req) {
const mapRootNote = becca.getNote(req.params.noteId);
// if the map root itself has ignore (journal typically) then there wouldn't be anything to display so
// we'll just ignore it
const ignoreExcludeFromNoteMap = mapRootNote.hasLabel('excludeFromNoteMap');
const noteIds = new Set();
const noteIds = new Set(
mapRootNote.getSubtreeNotes(false)
.filter(note => ignoreExcludeFromNoteMap || !note.hasLabel('excludeFromNoteMap'))
.map(note => note.noteId)
);
const notes = mapRootNote.getSubtreeNotes(false)
.filter(note => ignoreExcludeFromNoteMap || !note.hasLabel('excludeFromNoteMap'))
.map(note => [
for (const noteId of getNeighbors(mapRootNote, 3)) {
noteIds.add(noteId);
}
const notes = Array.from(noteIds).map(noteId => {
const note = becca.getNote(noteId);
return [
note.noteId,
note.isContentAvailable() ? note.title : '[protected]',
note.type
]);
notes.forEach(([noteId]) => noteIds.add(noteId));
];
});
const links = Object.values(becca.attributes).filter(rel => {
if (rel.type !== 'relation' || rel.name === 'relationMapLink' || rel.name === 'template') {

View File

@@ -14,6 +14,10 @@ function getDateNote(req) {
return dateNoteService.getDateNote(req.params.date);
}
function getWeekNote(req) {
return dateNoteService.getWeekNote(req.params.date);
}
function getMonthNote(req) {
return dateNoteService.getMonthNote(req.params.month);
}
@@ -65,6 +69,7 @@ function getHoistedNote() {
module.exports = {
getInboxNote,
getDateNote,
getWeekNote,
getMonthNote,
getYearNote,
getDateNotesForMonth,

View File

@@ -262,6 +262,7 @@ function register(app) {
apiRoute(GET, '/api/special-notes/inbox/:date', specialNotesRoute.getInboxNote);
apiRoute(GET, '/api/special-notes/date/:date', specialNotesRoute.getDateNote);
apiRoute(GET, '/api/special-notes/week/:date', specialNotesRoute.getWeekNote);
apiRoute(GET, '/api/special-notes/month/:month', specialNotesRoute.getMonthNote);
apiRoute(GET, '/api/special-notes/year/:year', specialNotesRoute.getYearNote);
apiRoute(GET, '/api/special-notes/notes-for-month/:month', specialNotesRoute.getDateNotesForMonth);

View File

@@ -1 +1 @@
module.exports = { buildDate:"2021-10-20T22:12:20+02:00", buildRevision: "a22e4d60b643542c72d0fd164b8096dfde026e18" };
module.exports = { buildDate:"2021-10-22T21:31:44+02:00", buildRevision: "56e49cfc19d7c142e70a0454c3dabf47cf845e3c" };