mirror of
https://github.com/zadam/trilium.git
synced 2025-11-03 03:46:37 +01:00
Compare commits
8 Commits
v0.44.0-be
...
v0.44.1-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbdf089d5d | ||
|
|
a7505682ed | ||
|
|
b148f3d032 | ||
|
|
874972a3d3 | ||
|
|
6d095b7250 | ||
|
|
ceb762e56b | ||
|
|
0c72d29684 | ||
|
|
29efe3a492 |
@@ -2,7 +2,7 @@
|
||||
"name": "trilium",
|
||||
"productName": "Trilium Notes",
|
||||
"description": "Trilium Notes",
|
||||
"version": "0.44.0-beta",
|
||||
"version": "0.44.1-beta",
|
||||
"license": "AGPL-3.0-only",
|
||||
"main": "electron.js",
|
||||
"bin": {
|
||||
|
||||
@@ -481,6 +481,17 @@ class NoteShort {
|
||||
.map(attributeId => this.treeCache.attributes[attributeId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get relations which target this note
|
||||
*
|
||||
* @returns {NoteShort[]}
|
||||
*/
|
||||
async getTargetRelationSourceNotes() {
|
||||
const targetRelations = this.getTargetRelations();
|
||||
|
||||
return await this.treeCache.getNotes(targetRelations.map(tr => tr.noteId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return note complement which is most importantly note's content
|
||||
*
|
||||
|
||||
@@ -15,7 +15,6 @@ import AttributeListWidget from "../widgets/attribute_list.js";
|
||||
import RunScriptButtonsWidget from "../widgets/run_script_buttons.js";
|
||||
import NoteTypeWidget from "../widgets/note_type.js";
|
||||
import NoteActionsWidget from "../widgets/note_actions.js";
|
||||
import PromotedAttributesWidget from "../widgets/promoted_attributes.js";
|
||||
import NoteDetailWidget from "../widgets/note_detail.js";
|
||||
import NoteInfoWidget from "../widgets/collapsible_widgets/note_info.js";
|
||||
import CalendarWidget from "../widgets/collapsible_widgets/calendar.js";
|
||||
|
||||
@@ -11,19 +11,15 @@ function renderAttribute(attribute, $container, renderIsInheritable) {
|
||||
$container.append('=');
|
||||
$container.append(document.createTextNode(formatValue(attribute.value)));
|
||||
}
|
||||
|
||||
$container.append(" ");
|
||||
} else if (attribute.type === 'relation') {
|
||||
if (attribute.isAutoLink) {
|
||||
return;
|
||||
}
|
||||
|
||||
// when the relation has just been created then it might not have a value
|
||||
if (attribute.value) {
|
||||
$container.append(document.createTextNode('~' + attribute.name + isInheritable + "="));
|
||||
$container.append(createNoteLink(attribute.value));
|
||||
$container.append(" ");
|
||||
} else {
|
||||
ws.logError(`Relation ${attribute.attributeId} has empty target`);
|
||||
}
|
||||
} else {
|
||||
ws.logError("Unknown attr type: " + attribute.type);
|
||||
|
||||
@@ -219,4 +219,16 @@ export default class Entrypoints extends Component {
|
||||
|
||||
toastService.showMessage("Note executed");
|
||||
}
|
||||
|
||||
hideAllTooltips() {
|
||||
$(".tooltip").removeClass("show");
|
||||
}
|
||||
|
||||
tabNoteSwitchedEvent() {
|
||||
this.hideAllTooltips();
|
||||
}
|
||||
|
||||
activeTabChangedEvent() {
|
||||
this.hideAllTooltips();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import noteCreateService from "./note_create.js";
|
||||
import treeService from "./tree.js";
|
||||
import hoistedNoteService from "./hoisted_note.js";
|
||||
import Component from "../widgets/component.js";
|
||||
import ws from "./ws.js";
|
||||
|
||||
/**
|
||||
* This class contains command executors which logically belong to the NoteTree widget, but for better user experience
|
||||
|
||||
@@ -141,7 +141,7 @@ class TreeCache {
|
||||
|
||||
const note = this.notes[attributeRow.noteId];
|
||||
|
||||
if (!note.attributes.includes(attributeId)) {
|
||||
if (note && !note.attributes.includes(attributeId)) {
|
||||
note.attributes.push(attributeId);
|
||||
}
|
||||
|
||||
|
||||
@@ -230,6 +230,7 @@ function closeActiveDialog() {
|
||||
|
||||
let $lastFocusedElement = null;
|
||||
|
||||
// perhaps there should be saved focused element per tab?
|
||||
function saveFocusedElement() {
|
||||
$lastFocusedElement = $(":focus");
|
||||
}
|
||||
|
||||
@@ -156,7 +156,9 @@ async function consumeSyncData() {
|
||||
logError(`Encountered error ${e.message}: ${e.stack}, reloading frontend.`);
|
||||
|
||||
// if there's an error in updating the frontend then the easy option to recover is to reload the frontend completely
|
||||
utils.reloadApp();
|
||||
if (!glob.isDev) {
|
||||
utils.reloadApp();
|
||||
}
|
||||
}
|
||||
|
||||
for (const syncRow of nonProcessedSyncRows) {
|
||||
|
||||
@@ -215,7 +215,9 @@ const ATTR_HELP = {
|
||||
|
||||
export default class AttributeDetailWidget extends TabAwareWidget {
|
||||
async refresh() {
|
||||
// this widget is not activated in a standard way
|
||||
// switching note/tab should close the widget
|
||||
|
||||
this.hide();
|
||||
}
|
||||
|
||||
doRender() {
|
||||
@@ -327,46 +329,6 @@ export default class AttributeDetailWidget extends TabAwareWidget {
|
||||
});
|
||||
}
|
||||
|
||||
async saveAndClose() {
|
||||
await this.triggerCommand('saveAttributes');
|
||||
|
||||
this.hide();
|
||||
|
||||
this.triggerCommand('focusOnAttributes', {tabId: this.tabContext.tabId});
|
||||
}
|
||||
|
||||
async cancelAndClose() {
|
||||
await this.triggerCommand('reloadAttributes');
|
||||
|
||||
this.hide();
|
||||
|
||||
this.triggerCommand('focusOnAttributes', {tabId: this.tabContext.tabId});
|
||||
}
|
||||
|
||||
userEditedAttribute() {
|
||||
this.updateAttributeInEditor();
|
||||
this.updateHelp();
|
||||
this.relatedNotesSpacedUpdate.scheduleUpdate();
|
||||
}
|
||||
|
||||
updateHelp() {
|
||||
const attrName = this.$inputName.val();
|
||||
|
||||
if (this.attrType in ATTR_HELP && attrName in ATTR_HELP[this.attrType]) {
|
||||
this.$attrHelp
|
||||
.empty()
|
||||
.append($("<td colspan=2>")
|
||||
.append($("<strong>").text(attrName))
|
||||
.append(" - ")
|
||||
.append(ATTR_HELP[this.attrType][attrName])
|
||||
)
|
||||
.show();
|
||||
}
|
||||
else {
|
||||
this.$attrHelp.empty().hide();
|
||||
}
|
||||
}
|
||||
|
||||
async showAttributeDetail({allAttributes, attribute, isOwned, x, y, focus}) {
|
||||
if (!attribute) {
|
||||
this.hide();
|
||||
@@ -374,6 +336,8 @@ export default class AttributeDetailWidget extends TabAwareWidget {
|
||||
return;
|
||||
}
|
||||
|
||||
utils.saveFocusedElement();
|
||||
|
||||
this.attrType = this.getAttrType(attribute);
|
||||
|
||||
const attrName =
|
||||
@@ -444,12 +408,20 @@ export default class AttributeDetailWidget extends TabAwareWidget {
|
||||
.attr('readonly', () => !isOwned);
|
||||
}
|
||||
else if (attribute.type === 'relation') {
|
||||
const targetNote = await treeCache.getNote(attribute.value);
|
||||
|
||||
this.$inputTargetNote
|
||||
.attr('readonly', () => !isOwned)
|
||||
.val(targetNote ? targetNote.title : "")
|
||||
.setSelectedNotePath(attribute.value);
|
||||
.val("")
|
||||
.setSelectedNotePath("");
|
||||
|
||||
if (attribute.value) {
|
||||
const targetNote = await treeCache.getNote(attribute.value);
|
||||
|
||||
if (targetNote) {
|
||||
this.$inputTargetNote
|
||||
.val(targetNote ? targetNote.title : "")
|
||||
.setSelectedNotePath(attribute.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.$inputInheritable
|
||||
@@ -497,6 +469,46 @@ export default class AttributeDetailWidget extends TabAwareWidget {
|
||||
return {left, right};
|
||||
}
|
||||
|
||||
async saveAndClose() {
|
||||
await this.triggerCommand('saveAttributes');
|
||||
|
||||
this.hide();
|
||||
|
||||
utils.focusSavedElement();
|
||||
}
|
||||
|
||||
async cancelAndClose() {
|
||||
await this.triggerCommand('reloadAttributes');
|
||||
|
||||
this.hide();
|
||||
|
||||
utils.focusSavedElement();
|
||||
}
|
||||
|
||||
userEditedAttribute() {
|
||||
this.updateAttributeInEditor();
|
||||
this.updateHelp();
|
||||
this.relatedNotesSpacedUpdate.scheduleUpdate();
|
||||
}
|
||||
|
||||
updateHelp() {
|
||||
const attrName = this.$inputName.val();
|
||||
|
||||
if (this.attrType in ATTR_HELP && attrName in ATTR_HELP[this.attrType]) {
|
||||
this.$attrHelp
|
||||
.empty()
|
||||
.append($("<td colspan=2>")
|
||||
.append($("<strong>").text(attrName))
|
||||
.append(" - ")
|
||||
.append(ATTR_HELP[this.attrType][attrName])
|
||||
)
|
||||
.show();
|
||||
}
|
||||
else {
|
||||
this.$attrHelp.empty().hide();
|
||||
}
|
||||
}
|
||||
|
||||
async updateRelatedNotes() {
|
||||
let {results, count} = await server.post('search-related', this.attribute);
|
||||
|
||||
|
||||
@@ -232,13 +232,17 @@ export default class AttributeEditorWidget extends TabAwareWidget {
|
||||
}
|
||||
|
||||
// triggered from keyboard shortcut
|
||||
addNewLabelEvent() {
|
||||
this.handleAddNewAttributeCommand('addNewLabel');
|
||||
addNewLabelEvent({tabId}) {
|
||||
if (this.isTab(tabId)) {
|
||||
this.handleAddNewAttributeCommand('addNewLabel');
|
||||
}
|
||||
}
|
||||
|
||||
// triggered from keyboard shortcut
|
||||
addNewRelationEvent() {
|
||||
this.handleAddNewAttributeCommand('addNewRelation');
|
||||
addNewRelationEvent({tabId}) {
|
||||
if (this.isTab(tabId)) {
|
||||
this.handleAddNewAttributeCommand('addNewRelation');
|
||||
}
|
||||
}
|
||||
|
||||
async handleAddNewAttributeCommand(command) {
|
||||
@@ -459,11 +463,17 @@ export default class AttributeEditorWidget extends TabAwareWidget {
|
||||
}
|
||||
|
||||
async renderOwnedAttributes(ownedAttributes, saved) {
|
||||
ownedAttributes = ownedAttributes.filter(oa => !oa.isDeleted);
|
||||
|
||||
const $attributesContainer = $("<div>");
|
||||
|
||||
for (const attribute of ownedAttributes) {
|
||||
if (!attribute.isDeleted) {
|
||||
attributeRenderer.renderAttribute(attribute, $attributesContainer, true);
|
||||
for (let i = 0; i < ownedAttributes.length; i++) {
|
||||
const attribute = ownedAttributes[i];
|
||||
|
||||
attributeRenderer.renderAttribute(attribute, $attributesContainer, true);
|
||||
|
||||
if (i < ownedAttributes.length - 1) {
|
||||
$attributesContainer.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -220,9 +220,9 @@ export default class AttributeListWidget extends TabAwareWidget {
|
||||
y: e.pageY
|
||||
}));
|
||||
|
||||
$container.append($span);
|
||||
|
||||
attributeRenderer.renderAttribute(attribute, $span, false);
|
||||
|
||||
$container.append($span);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@ const TPL = `
|
||||
<table class="note-info-widget-table">
|
||||
<style>
|
||||
.note-info-widget-table {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.note-info-widget-table td, .note-info-widget-table th {
|
||||
@@ -22,16 +25,6 @@ const TPL = `
|
||||
<tr>
|
||||
<th>Note ID:</th>
|
||||
<td class="note-info-note-id"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Created:</th>
|
||||
<td class="note-info-date-created"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Modified:</th>
|
||||
<td class="note-info-date-modified"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Type:</th>
|
||||
<td>
|
||||
<span class="note-info-type"></span>
|
||||
@@ -39,6 +32,12 @@ const TPL = `
|
||||
<span class="note-info-mime"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Created:</th>
|
||||
<td class="note-info-date-created"></td>
|
||||
<th>Modified:</th>
|
||||
<td class="note-info-date-modified"></td>
|
||||
</tr>
|
||||
</table>
|
||||
`;
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ class NoteRevisionsWidget extends CollapsibleWidget {
|
||||
return;
|
||||
}
|
||||
|
||||
const groupedRevisionItems = this.getGroupedRevisionItems(revisionItems);
|
||||
|
||||
if (note.noteId !== this.noteId) {
|
||||
return;
|
||||
}
|
||||
@@ -54,23 +56,47 @@ class NoteRevisionsWidget extends CollapsibleWidget {
|
||||
|
||||
const $list = this.$body.find('.note-revision-list');
|
||||
|
||||
for (const item of revisionItems) {
|
||||
const $listItem = $('<li>').append($("<a>", {
|
||||
'data-action': 'note-revision',
|
||||
'data-note-path': note.noteId,
|
||||
'data-note-revision-id': item.noteRevisionId,
|
||||
title: 'This revision was last edited on ' + item.dateLastEdited,
|
||||
href: 'javascript:'
|
||||
}).text(item.dateLastEdited.substr(0, 16)));
|
||||
for (const [date, items] of groupedRevisionItems) {
|
||||
const $listItem = $('<li>').append($("<strong>").text(date + ": "));
|
||||
const revsWithinADay = [];
|
||||
|
||||
if (item.contentLength !== null) {
|
||||
$listItem.append($("<span>").text(` (${item.contentLength} bytes)`))
|
||||
for (const item of items) {
|
||||
const $rev = $("<span>");
|
||||
|
||||
|
||||
$rev.append($("<a>", {
|
||||
'data-action': 'note-revision',
|
||||
'data-note-path': note.noteId,
|
||||
'data-note-revision-id': item.noteRevisionId,
|
||||
title: 'This revision was last edited on ' + item.dateLastEdited,
|
||||
href: 'javascript:'
|
||||
})
|
||||
.text(item.dateLastEdited.substr(11, 5)));
|
||||
|
||||
revsWithinADay.push($rev.html());
|
||||
}
|
||||
|
||||
$listItem.append(revsWithinADay.join(", "));
|
||||
$list.append($listItem);
|
||||
}
|
||||
}
|
||||
|
||||
getGroupedRevisionItems(revisionItems) {
|
||||
const grouped = new Map(); // map preserves order of insertion
|
||||
|
||||
for (const item of revisionItems) {
|
||||
const [date] = item.dateLastEdited.substr(0, 16).split(" ");
|
||||
|
||||
if (!grouped.has(date)) {
|
||||
grouped.set(date, []);
|
||||
}
|
||||
|
||||
grouped.get(date).push(item);
|
||||
}
|
||||
|
||||
return grouped;
|
||||
}
|
||||
|
||||
entitiesReloadedEvent({loadResults}) {
|
||||
if (loadResults.hasNoteRevisionForNote(this.noteId)) {
|
||||
this.refresh();
|
||||
|
||||
@@ -66,4 +66,4 @@ export default class SimilarNotesWidget extends CollapsibleWidget {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,4 +53,4 @@ export default class WhatLinksHereWidget extends CollapsibleWidget {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ const TPL = `
|
||||
<style>
|
||||
.note-title-container {
|
||||
flex-grow: 100;
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
.note-title-container input.note-title {
|
||||
|
||||
@@ -905,6 +905,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
||||
|
||||
async refresh() {
|
||||
this.toggleInt(this.isEnabled());
|
||||
this.$treeSettingsPopup.hide();
|
||||
|
||||
this.activityDetected();
|
||||
|
||||
|
||||
@@ -122,7 +122,9 @@ export default class SearchBoxWidget extends BasicWidget {
|
||||
this.resetSearchEvent();
|
||||
}
|
||||
|
||||
showSearchEvent({searchText}) {
|
||||
showSearchEvent(data = {}) {
|
||||
const {searchText} = data;
|
||||
|
||||
utils.saveFocusedElement();
|
||||
|
||||
this.$searchBox.slideDown();
|
||||
|
||||
@@ -38,7 +38,8 @@ function getNotesAndBranchesAndAttributes(noteIds) {
|
||||
position,
|
||||
isInheritable
|
||||
FROM attributes
|
||||
WHERE isDeleted = 0 AND noteId IN (???)`, noteIds);
|
||||
WHERE isDeleted = 0
|
||||
AND (noteId IN (???) OR (type = 'relation' AND value IN (???)))`, noteIds);
|
||||
|
||||
// sorting in memory is faster
|
||||
attributes.sort((a, b) => a.position - b.position < 0 ? -1 : 1);
|
||||
|
||||
@@ -10,7 +10,6 @@ const repository = require('./repository');
|
||||
const axios = require('axios');
|
||||
const dayjs = require('dayjs');
|
||||
const cloningService = require('./cloning');
|
||||
const ws = require('./ws.js');
|
||||
const appInfo = require('./app_info');
|
||||
const searchService = require('./search/services/search.js');
|
||||
|
||||
@@ -88,7 +87,7 @@ function BackendScriptApi(currentNote, apiParams) {
|
||||
|
||||
/**
|
||||
* This is a powerful search method - you can search by attributes and their values, e.g.:
|
||||
* "@dateModified =* MONTH AND @log". See full documentation for all options at: https://github.com/zadam/trilium/wiki/Search
|
||||
* "#dateModified =* MONTH AND #log". See full documentation for all options at: https://github.com/zadam/trilium/wiki/Search
|
||||
*
|
||||
* @method
|
||||
* @param {string} searchString
|
||||
@@ -98,7 +97,7 @@ function BackendScriptApi(currentNote, apiParams) {
|
||||
|
||||
/**
|
||||
* This is a powerful search method - you can search by attributes and their values, e.g.:
|
||||
* "@dateModified =* MONTH AND @log". See full documentation for all options at: https://github.com/zadam/trilium/wiki/Search
|
||||
* "#dateModified =* MONTH AND #log". See full documentation for all options at: https://github.com/zadam/trilium/wiki/Search
|
||||
*
|
||||
* @method
|
||||
* @param {string} searchString
|
||||
|
||||
@@ -1 +1 @@
|
||||
module.exports = { buildDate:"2020-09-03T23:26:51+02:00", buildRevision: "11c63b7778011130b2a88b7896d52d0a476983d1" };
|
||||
module.exports = { buildDate:"2020-09-05T23:43:06+02:00", buildRevision: "a7505682eddb754f0ba951716f63f9e9ffe61131" };
|
||||
|
||||
Reference in New Issue
Block a user