mirror of
https://github.com/zadam/trilium.git
synced 2024-09-22 08:36:10 +08:00
Merge branch 'master' into m43
This commit is contained in:
commit
768ac83e14
|
@ -5,7 +5,7 @@
|
|||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/../trilium-data/document.db</jdbc-url>
|
||||
<jdbc-url>jdbc:sqlite:$USER_HOME$/trilium-data/document.db</jdbc-url>
|
||||
</data-source>
|
||||
<data-source source="LOCAL" name="document" uuid="066dc5f4-4097-429e-8cf1-3adc0a9d648a">
|
||||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="JSUnfilteredForInLoop" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
|
|
34
package-lock.json
generated
34
package-lock.json
generated
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "trilium",
|
||||
"version": "0.41.6",
|
||||
"version": "0.42.0-beta",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -3345,9 +3345,9 @@
|
|||
}
|
||||
},
|
||||
"electron": {
|
||||
"version": "9.0.0-beta.21",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-9.0.0-beta.21.tgz",
|
||||
"integrity": "sha512-xFOD8I4RB9IkpVKnzoHwHvDNGvGl1IinpYTyQ7o7FAgSnkvP/upI1JtzE5Ff6PlAdyIGnbC+Rz1hJIfmAXxVuQ==",
|
||||
"version": "9.0.0-beta.22",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-9.0.0-beta.22.tgz",
|
||||
"integrity": "sha512-dfqAf+CXXTKcNDj7DU7mYsmx+oZQcXOvJnZ8ZsgAHjrE9Tv8zsYUgCP3JlO4Z8CIazgleKXYmgh6H2stdK7fEA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@electron/get": "^1.0.1",
|
||||
|
@ -3785,9 +3785,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"mime": {
|
||||
"version": "2.4.4",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
|
||||
"integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==",
|
||||
"version": "2.4.5",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz",
|
||||
"integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
|
@ -4448,9 +4448,9 @@
|
|||
}
|
||||
},
|
||||
"file-type": {
|
||||
"version": "14.2.0",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-14.2.0.tgz",
|
||||
"integrity": "sha512-CAkX5G5jq8LIgFu++dpM3giMZadYdU+QVQoPLajjNboo8IzaR4cKpBCVEuz+suhd/vHqoAJeSWhEubKjRPQHJg==",
|
||||
"version": "14.3.0",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-14.3.0.tgz",
|
||||
"integrity": "sha512-s71v6jMkbfwVdj87csLeNpL5K93mv4lN+lzgzifoICtPHhnXokDwBa3jrzfg+z6FK872iYJ0vS0i74v8XmoFDA==",
|
||||
"requires": {
|
||||
"readable-web-to-node-stream": "^2.0.0",
|
||||
"strtok3": "^6.0.0",
|
||||
|
@ -9725,7 +9725,6 @@
|
|||
"version": "2.88.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
|
||||
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"aws-sign2": "~0.7.0",
|
||||
"aws4": "^1.8.0",
|
||||
|
@ -9752,14 +9751,12 @@
|
|||
"qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
|
@ -10351,12 +10348,13 @@
|
|||
"integrity": "sha512-1bBO+me3gXRfqwRR3K9aNDoSbTkQ87o6fSjj/BE2gSHHsK3qIDR+LoFZHgZ6kSPdFBoLTsy5/w/+8PBBaK+lvg=="
|
||||
},
|
||||
"sqlite3": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.2.0.tgz",
|
||||
"integrity": "sha512-roEOz41hxui2Q7uYnWsjMOTry6TcNUNmp8audCx18gF10P2NknwdpF+E+HKvz/F2NvPKGGBF4NGc+ZPQ+AABwg==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.1.1.tgz",
|
||||
"integrity": "sha512-CvT5XY+MWnn0HkbwVKJAyWEMfzpAPwnTiB3TobA5Mri44SrTovmmh499NPQP+gatkeOipqPlBLel7rn4E/PCQg==",
|
||||
"requires": {
|
||||
"nan": "^2.12.1",
|
||||
"node-pre-gyp": "^0.11.0"
|
||||
"node-pre-gyp": "^0.11.0",
|
||||
"request": "^2.87.0"
|
||||
}
|
||||
},
|
||||
"squeak": {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "trilium",
|
||||
"productName": "Trilium Notes",
|
||||
"description": "Trilium Notes",
|
||||
"version": "0.41.6",
|
||||
"version": "0.42.0-beta",
|
||||
"license": "AGPL-3.0-only",
|
||||
"main": "electron.js",
|
||||
"bin": {
|
||||
|
@ -37,7 +37,7 @@
|
|||
"electron-window-state": "5.0.3",
|
||||
"express": "4.17.1",
|
||||
"express-session": "1.17.1",
|
||||
"file-type": "14.2.0",
|
||||
"file-type": "14.3.0",
|
||||
"fs-extra": "9.0.0",
|
||||
"helmet": "3.22.0",
|
||||
"html": "1.0.0",
|
||||
|
@ -67,7 +67,7 @@
|
|||
"session-file-store": "1.4.0",
|
||||
"simple-node-logger": "18.12.24",
|
||||
"sqlite": "4.0.7",
|
||||
"sqlite3": "4.2.0",
|
||||
"sqlite3": "4.1.1",
|
||||
"string-similarity": "4.0.1",
|
||||
"tar-stream": "2.1.2",
|
||||
"turndown": "6.0.0",
|
||||
|
@ -78,7 +78,7 @@
|
|||
"yazl": "^2.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "9.0.0-beta.21",
|
||||
"electron": "9.0.0-beta.22",
|
||||
"electron-builder": "22.6.0",
|
||||
"electron-packager": "14.2.1",
|
||||
"electron-rebuild": "1.10.1",
|
||||
|
|
|
@ -8,6 +8,8 @@ const RELATION = 'relation';
|
|||
const RELATION_DEFINITION = 'relation-definition';
|
||||
|
||||
/**
|
||||
* FIXME: since there's no "full note" anymore we can rename this to Note
|
||||
*
|
||||
* This note's representation is used in note tree and is kept in TreeCache.
|
||||
*/
|
||||
class NoteShort {
|
||||
|
|
|
@ -100,19 +100,6 @@ class AppContext extends Component {
|
|||
getComponentByEl(el) {
|
||||
return $(el).closest(".component").prop('component');
|
||||
}
|
||||
|
||||
async openInNewWindow(notePath) {
|
||||
if (utils.isElectron()) {
|
||||
const {ipcRenderer} = utils.dynamicRequire('electron');
|
||||
|
||||
ipcRenderer.send('create-extra-window', {notePath});
|
||||
}
|
||||
else {
|
||||
const url = window.location.protocol + '//' + window.location.host + window.location.pathname + '?extra=1#' + notePath;
|
||||
|
||||
window.open(url, '', 'width=1000,height=800');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const appContext = new AppContext(window.glob.isMainWindow);
|
||||
|
|
|
@ -182,4 +182,21 @@ export default class Entrypoints extends Component {
|
|||
}
|
||||
|
||||
createTopLevelNoteCommand() { noteCreateService.createNewTopLevelNote(); }
|
||||
|
||||
async openInWindowCommand({notePath}) {
|
||||
if (utils.isElectron()) {
|
||||
const {ipcRenderer} = utils.dynamicRequire('electron');
|
||||
|
||||
ipcRenderer.send('create-extra-window', {notePath});
|
||||
}
|
||||
else {
|
||||
const url = window.location.protocol + '//' + window.location.host + window.location.pathname + '?extra=1#' + notePath;
|
||||
|
||||
window.open(url, '', 'width=1000,height=800');
|
||||
}
|
||||
}
|
||||
|
||||
async openNewWindowCommand() {
|
||||
this.openInWindowCommand({notePath: ''});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ function newTabContextMenu(e) {
|
|||
y: e.pageY,
|
||||
items: [
|
||||
{title: "Open note in new tab", command: "openNoteInNewTab", uiIcon: "arrow-up-right"},
|
||||
{title: "Open note in new window", command: "openNoteInNewWindow", uiIcon: "arrow-up-right"}
|
||||
{title: "Open note in new window", command: "openNoteInNewWindow", uiIcon: "window-open"}
|
||||
],
|
||||
selectMenuItemHandler: ({command}) => {
|
||||
if (command === 'openNoteInNewTab') {
|
||||
|
|
|
@ -59,7 +59,7 @@ export default class MainTreeExecutors extends Component {
|
|||
target: 'after',
|
||||
targetBranchId: node.data.branchId,
|
||||
isProtected: isProtected,
|
||||
saveSelection: true
|
||||
saveSelection: false
|
||||
});
|
||||
|
||||
await ws.waitForMaxKnownSyncId();
|
||||
|
|
|
@ -31,6 +31,15 @@ function enterProtectedSession() {
|
|||
return dfd.promise();
|
||||
}
|
||||
|
||||
async function reloadData() {
|
||||
const allNoteIds = Object.keys(treeCache.notes);
|
||||
|
||||
await treeCache.loadInitialTree();
|
||||
|
||||
// make sure that all notes used in the application are loaded, including the ones not shown in the tree
|
||||
await treeCache.reloadNotes(allNoteIds, true);
|
||||
}
|
||||
|
||||
async function setupProtectedSession(password) {
|
||||
const response = await enterProtectedSessionOnServer(password);
|
||||
|
||||
|
@ -42,7 +51,7 @@ async function setupProtectedSession(password) {
|
|||
protectedSessionHolder.setProtectedSessionId(response.protectedSessionId);
|
||||
protectedSessionHolder.touchProtectedSession();
|
||||
|
||||
await treeCache.loadInitialTree();
|
||||
await reloadData();
|
||||
|
||||
await appContext.triggerEvent('treeCacheReloaded');
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ export default class TabManager extends Component {
|
|||
|
||||
if (filteredTabs.length === 0) {
|
||||
filteredTabs.push({
|
||||
notePath: 'root',
|
||||
notePath: this.isMainWindow ? 'root' : '',
|
||||
active: true
|
||||
});
|
||||
}
|
||||
|
@ -196,7 +196,9 @@ export default class TabManager extends Component {
|
|||
async openTabWithNote(notePath, activate, tabId = null) {
|
||||
const tabContext = await this.openEmptyTab(tabId);
|
||||
|
||||
if (notePath) {
|
||||
await tabContext.setNote(notePath, !activate); // if activate is false then send normal noteSwitched event
|
||||
}
|
||||
|
||||
if (activate) {
|
||||
this.activateTab(tabContext.tabId, false);
|
||||
|
@ -265,6 +267,9 @@ export default class TabManager extends Component {
|
|||
|
||||
this.children = this.children.filter(tc => tc.tabId !== tabId);
|
||||
|
||||
// remove dangling autocompletes after closing the tab
|
||||
$(".algolia-autocomplete").remove();
|
||||
|
||||
this.triggerEvent('tabRemoved', {tabId});
|
||||
|
||||
this.tabsUpdate.scheduleUpdate();
|
||||
|
@ -327,7 +332,7 @@ export default class TabManager extends Component {
|
|||
|
||||
this.removeTab(tabId);
|
||||
|
||||
appContext.openInNewWindow(notePath);
|
||||
this.triggerCommand('openInWindow', {notePath});
|
||||
}
|
||||
|
||||
async hoistedNoteChangedEvent({hoistedNoteId}) {
|
||||
|
|
|
@ -20,6 +20,8 @@ class TreeCache {
|
|||
async loadInitialTree() {
|
||||
const resp = await server.get('tree');
|
||||
|
||||
await this.loadParents(resp, false);
|
||||
|
||||
// clear the cache only directly before adding new content which is important for e.g. switching to protected session
|
||||
|
||||
/** @type {Object.<string, NoteShort>} */
|
||||
|
@ -34,22 +36,22 @@ class TreeCache {
|
|||
/** @type {Object.<string, Promise<NoteComplement>>} */
|
||||
this.noteComplementPromises = {};
|
||||
|
||||
await this.loadParents(resp);
|
||||
this.addResp(resp);
|
||||
}
|
||||
|
||||
async loadParents(resp) {
|
||||
async loadParents(resp, additiveLoad) {
|
||||
const noteIds = new Set(resp.notes.map(note => note.noteId));
|
||||
const missingNoteIds = [];
|
||||
const existingNotes = additiveLoad ? this.notes : {};
|
||||
|
||||
for (const branch of resp.branches) {
|
||||
if (!(branch.parentNoteId in this.notes) && !noteIds.has(branch.parentNoteId) && branch.parentNoteId !== 'none') {
|
||||
if (!(branch.parentNoteId in existingNotes) && !noteIds.has(branch.parentNoteId) && branch.parentNoteId !== 'none') {
|
||||
missingNoteIds.push(branch.parentNoteId);
|
||||
}
|
||||
}
|
||||
|
||||
for (const attr of resp.attributes) {
|
||||
if (attr.type === 'relation' && attr.name === 'template' && !(attr.value in this.notes) && !noteIds.has(attr.value)) {
|
||||
if (attr.type === 'relation' && attr.name === 'template' && !(attr.value in existingNotes) && !noteIds.has(attr.value)) {
|
||||
missingNoteIds.push(attr.value);
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +63,7 @@ class TreeCache {
|
|||
resp.branches = resp.branches.concat(newResp.branches);
|
||||
resp.attributes = resp.attributes.concat(newResp.attributes);
|
||||
|
||||
await this.loadParents(resp);
|
||||
await this.loadParents(resp, additiveLoad);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,7 +156,7 @@ class TreeCache {
|
|||
|
||||
const resp = await server.post('tree/load', { noteIds });
|
||||
|
||||
await this.loadParents(resp);
|
||||
await this.loadParents(resp, true);
|
||||
this.addResp(resp);
|
||||
|
||||
for (const note of resp.notes) {
|
||||
|
@ -231,7 +233,7 @@ class TreeCache {
|
|||
/** @return {Promise<NoteShort>} */
|
||||
async getNote(noteId, silentNotFoundError = false) {
|
||||
if (noteId === 'none') {
|
||||
console.log(`No 'none' note.`);
|
||||
console.trace(`No 'none' note.`);
|
||||
return null;
|
||||
}
|
||||
else if (!noteId) {
|
||||
|
@ -246,10 +248,10 @@ class TreeCache {
|
|||
return this.notes[noteId];
|
||||
}
|
||||
|
||||
getBranches(branchIds) {
|
||||
getBranches(branchIds, silentNotFoundError = false) {
|
||||
return branchIds
|
||||
.map(branchId => this.getBranch(branchId))
|
||||
.filter(b => b !== null);
|
||||
.map(branchId => this.getBranch(branchId, silentNotFoundError))
|
||||
.filter(b => !!b);
|
||||
}
|
||||
|
||||
/** @return {Branch} */
|
||||
|
|
|
@ -40,9 +40,9 @@ class TreeContextMenu {
|
|||
async getMenuItems() {
|
||||
const note = await treeCache.getNote(this.node.data.noteId);
|
||||
const branch = treeCache.getBranch(this.node.data.branchId);
|
||||
const parentNote = await treeCache.getNote(branch.parentNoteId);
|
||||
const isNotRoot = note.noteId !== 'root';
|
||||
const isHoisted = note.noteId === hoistedNoteService.getHoistedNoteId();
|
||||
const parentNote = isNotRoot ? await treeCache.getNote(branch.parentNoteId) : null;
|
||||
|
||||
// some actions don't support multi-note so they are disabled when notes are selected
|
||||
// the only exception is when the only selected note is the one that was right-clicked, then
|
||||
|
@ -57,7 +57,7 @@ class TreeContextMenu {
|
|||
|
||||
return [
|
||||
{ title: 'Open in a new tab <kbd>Ctrl+Click</kbd>', command: "openInTab", uiIcon: "empty", enabled: noSelectedNotes },
|
||||
{ title: 'Open in a new window', command: "openInWindow", uiIcon: "empty", enabled: noSelectedNotes },
|
||||
{ title: 'Open in a new window', command: "openInWindow", uiIcon: "window-open", enabled: noSelectedNotes },
|
||||
{ title: 'Insert note after <kbd data-command="createNoteAfter"></kbd>', command: "insertNoteAfter", uiIcon: "plus",
|
||||
items: insertNoteAfterEnabled ? this.getNoteTypeItems("insertNoteAfter") : null,
|
||||
enabled: insertNoteAfterEnabled && noSelectedNotes },
|
||||
|
@ -113,9 +113,6 @@ class TreeContextMenu {
|
|||
if (command === 'openInTab') {
|
||||
appContext.tabManager.openTabWithNote(notePath);
|
||||
}
|
||||
else if (command === 'openInWindow') {
|
||||
appContext.openInNewWindow(notePath);
|
||||
}
|
||||
else if (command === "insertNoteAfter") {
|
||||
const parentNoteId = this.node.data.parentNoteId;
|
||||
const isProtected = await treeService.getParentProtectedStatus(this.node);
|
||||
|
@ -134,7 +131,7 @@ class TreeContextMenu {
|
|||
});
|
||||
}
|
||||
else {
|
||||
this.treeWidget.triggerCommand(command, {node: this.node});
|
||||
this.treeWidget.triggerCommand(command, {node: this.node, notePath: notePath});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import BasicWidget from "./basic_widget.js";
|
||||
import keyboardActionService from "../services/keyboard_actions.js";
|
||||
import utils from "../services/utils.js";
|
||||
import syncService from "../services/sync.js";
|
||||
|
||||
|
@ -39,6 +38,12 @@ const TPL = `
|
|||
Sync (<span id="outstanding-syncs-count">0</span>)
|
||||
</a>
|
||||
|
||||
<a class="dropdown-item" data-trigger-command="openNewWindow">
|
||||
<span class="bx bx-window-open"></span>
|
||||
Open new window
|
||||
<kbd data-command="openNewWindow"></kbd>
|
||||
</a>
|
||||
|
||||
<a class="dropdown-item open-dev-tools-button" data-trigger-command="openDevTools">
|
||||
<span class="bx bx-terminal"></span>
|
||||
Open Dev Tools
|
||||
|
|
|
@ -57,6 +57,10 @@ export default class NoteTitleWidget extends TabAwareWidget {
|
|||
|
||||
this.$noteTitle.prop("readonly", note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable());
|
||||
|
||||
this.setProtectedStatus(note);
|
||||
}
|
||||
|
||||
setProtectedStatus(note) {
|
||||
this.$noteTitle.toggleClass("protected", !!note.isProtected);
|
||||
}
|
||||
|
||||
|
@ -88,7 +92,8 @@ export default class NoteTitleWidget extends TabAwareWidget {
|
|||
|
||||
entitiesReloadedEvent({loadResults}) {
|
||||
if (loadResults.isNoteReloaded(this.noteId)) {
|
||||
this.refresh();
|
||||
// not updating the title specifically since the synced title might be older than what the user is currently typing
|
||||
this.setProtectedStatus(this.note);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ const TPL = `
|
|||
position: absolute;
|
||||
top: 10px;
|
||||
right: 20px;
|
||||
z-index: 1000;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.tree-settings-popup {
|
||||
|
@ -362,9 +362,6 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||
},
|
||||
// this is done to automatically lazy load all expanded notes after tree load
|
||||
loadChildren: (event, data) => {
|
||||
// semaphore since the conflict when two processes are trying to load the same data
|
||||
// breaks the fancytree
|
||||
if (!this.tree || !this.tree.autoLoadingDisabled) {
|
||||
data.node.visit((subNode) => {
|
||||
// Load all lazy/unloaded child nodes
|
||||
// (which will trigger `loadChildren` recursively)
|
||||
|
@ -373,7 +370,6 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.$tree.on('contextmenu', '.fancytree-node', e => {
|
||||
|
@ -423,7 +419,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||
return labels.map(l => l.value).join(' ');
|
||||
}
|
||||
|
||||
getIcon(note) {
|
||||
getIcon(note, isFolder) {
|
||||
const hoistedNoteId = hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
const iconClass = this.getIconClass(note);
|
||||
|
@ -438,7 +434,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||
return "bx bxs-arrow-from-bottom";
|
||||
}
|
||||
else if (note.type === 'text') {
|
||||
if (note.hasChildren()) {
|
||||
if (isFolder) {
|
||||
return "bx bx-folder";
|
||||
}
|
||||
else {
|
||||
|
@ -460,6 +456,8 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||
const title = (branch.prefix ? (branch.prefix + " - ") : "") + note.title;
|
||||
const hoistedNoteId = hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
const isFolder = this.isFolder(note);
|
||||
|
||||
const node = {
|
||||
noteId: note.noteId,
|
||||
parentNoteId: branch.parentNoteId,
|
||||
|
@ -468,10 +466,10 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||
noteType: note.type,
|
||||
title: utils.escapeHtml(title),
|
||||
extraClasses: this.getExtraClasses(note),
|
||||
icon: this.getIcon(note),
|
||||
icon: this.getIcon(note, isFolder),
|
||||
refKey: note.noteId,
|
||||
lazy: true,
|
||||
folder: await this.isFolder(note),
|
||||
folder: isFolder,
|
||||
expanded: branch.isExpanded || hoistedNoteId === note.noteId,
|
||||
key: utils.randomString(12) // this should prevent some "duplicate key" errors
|
||||
};
|
||||
|
@ -483,12 +481,12 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||
return node;
|
||||
}
|
||||
|
||||
async isFolder(note) {
|
||||
isFolder(note) {
|
||||
if (note.type === 'search') {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
const childBranches = await this.getChildBranches(note);
|
||||
const childBranches = this.getChildBranches(note);
|
||||
|
||||
return childBranches.length > 0;
|
||||
}
|
||||
|
@ -499,7 +497,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||
|
||||
const noteList = [];
|
||||
|
||||
for (const branch of await this.getChildBranches(parentNote)) {
|
||||
for (const branch of this.getChildBranches(parentNote)) {
|
||||
const node = await this.prepareNode(branch);
|
||||
|
||||
noteList.push(node);
|
||||
|
@ -508,7 +506,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||
return noteList;
|
||||
}
|
||||
|
||||
async getChildBranches(parentNote) {
|
||||
getChildBranches(parentNote) {
|
||||
let childBranches = parentNote.getChildBranches();
|
||||
|
||||
if (!childBranches) {
|
||||
|
@ -523,20 +521,6 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||
childBranches = childBranches.filter(branch => !imageLinks.find(rel => rel.value === branch.noteId));
|
||||
}
|
||||
|
||||
if (this.hideArchivedNotes) {
|
||||
const filteredBranches = [];
|
||||
|
||||
for (const childBranch of childBranches) {
|
||||
const childNote = await childBranch.getNote();
|
||||
|
||||
if (!childNote.hasLabel('archived')) {
|
||||
filteredBranches.push(childBranch);
|
||||
}
|
||||
}
|
||||
|
||||
childBranches = filteredBranches;
|
||||
}
|
||||
|
||||
return childBranches;
|
||||
}
|
||||
|
||||
|
@ -596,39 +580,32 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||
return notes;
|
||||
}
|
||||
|
||||
async setExpandedStatusForSubtree(node, isExpanded) {
|
||||
if (!node) {
|
||||
const hoistedNoteId = hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
node = this.getNodesByNoteId(hoistedNoteId)[0];
|
||||
}
|
||||
|
||||
const {branchIds} = await server.put(`branches/${node.data.branchId}/expanded-subtree/${isExpanded ? 1 : 0}`);
|
||||
|
||||
treeCache.getBranches(branchIds, true).forEach(branch => branch.isExpanded = isExpanded);
|
||||
|
||||
await this.batchUpdate(async () => {
|
||||
await node.load(true);
|
||||
|
||||
if (node.data.noteId !== 'root') { // root is always expanded
|
||||
await node.setExpanded(isExpanded, {noEvents: true});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async expandTree(node = null) {
|
||||
if (!node) {
|
||||
const hoistedNoteId = hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
node = this.getNodesByNoteId(hoistedNoteId)[0];
|
||||
await this.setExpandedStatusForSubtree(node, true);
|
||||
}
|
||||
|
||||
this.batchUpdate(async () => {
|
||||
try {
|
||||
this.tree.autoLoadingDisabled = true;
|
||||
|
||||
// trick - first force load of the whole subtree and then visit and expand.
|
||||
// unfortunately the two steps can't be combined
|
||||
await node.visitAndLoad(_ => {}, true);
|
||||
|
||||
node.visit(node => node.setExpanded(true), true);
|
||||
}
|
||||
finally {
|
||||
this.tree.autoLoadingDisabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
collapseTree(node = null) {
|
||||
if (!node) {
|
||||
const hoistedNoteId = hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
node = this.getNodesByNoteId(hoistedNoteId)[0];
|
||||
}
|
||||
|
||||
this.batchUpdate(() => {
|
||||
node.visit(node => node.setExpanded(false), true);
|
||||
});
|
||||
async collapseTree(node = null) {
|
||||
await this.setExpandedStatusForSubtree(node, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -740,14 +717,16 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||
return this.getNodeFromPath(notePath, true, expandOpts);
|
||||
}
|
||||
|
||||
async updateNode(node) {
|
||||
updateNode(node) {
|
||||
const note = treeCache.getNoteFromCache(node.data.noteId);
|
||||
const branch = treeCache.getBranch(node.data.branchId);
|
||||
|
||||
const isFolder = this.isFolder(note);
|
||||
|
||||
node.data.isProtected = note.isProtected;
|
||||
node.data.noteType = note.type;
|
||||
node.folder = await this.isFolder(note);
|
||||
node.icon = this.getIcon(note);
|
||||
node.folder = isFolder;
|
||||
node.icon = this.getIcon(note, isFolder);
|
||||
node.extraClasses = this.getExtraClasses(note);
|
||||
node.title = (branch.prefix ? (branch.prefix + " - ") : "") + note.title;
|
||||
node.renderTitle();
|
||||
|
@ -898,18 +877,12 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||
noteIdsToUpdate.add(noteId);
|
||||
}
|
||||
|
||||
await this.batchUpdate(async () => {
|
||||
for (const noteId of noteIdsToReload) {
|
||||
for (const node of this.getNodesByNoteId(noteId)) {
|
||||
await node.load(true);
|
||||
|
||||
this.updateNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
await this.batchUpdate(async () => {
|
||||
for (const noteId of noteIdsToUpdate) {
|
||||
for (const node of this.getNodesByNoteId(noteId)) {
|
||||
this.updateNode(node);
|
||||
noteIdsToUpdate.add(noteId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -931,6 +904,13 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||
}
|
||||
});
|
||||
|
||||
// for some reason node update cannot be in the batchUpdate() block (node is not re-rendered)
|
||||
for (const noteId of noteIdsToUpdate) {
|
||||
for (const node of this.getNodesByNoteId(noteId)) {
|
||||
this.updateNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (activeNotePath) {
|
||||
let node = await this.expandToNote(activeNotePath);
|
||||
|
||||
|
|
|
@ -258,9 +258,9 @@ export default class TabRowWidget extends BasicWidget {
|
|||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
items: [
|
||||
{title: "Move this tab to a new window", command: "moveTabToNewWindow", uiIcon: "empty"},
|
||||
{title: "Close all tabs", command: "removeAllTabs", uiIcon: "empty"},
|
||||
{title: "Close all tabs except for this", command: "removeAllTabsExceptForThis", uiIcon: "empty"},
|
||||
{title: "Move this tab to a new window", command: "moveTabToNewWindow", uiIcon: "window-open"},
|
||||
{title: "Close all tabs", command: "removeAllTabs", uiIcon: "x"},
|
||||
{title: "Close all tabs except for this", command: "removeAllTabsExceptForThis", uiIcon: "x"},
|
||||
],
|
||||
selectMenuItemHandler: ({command}) => {
|
||||
this.triggerCommand(command, {tabId});
|
||||
|
|
|
@ -114,9 +114,35 @@ async function moveBranchAfterNote(req) {
|
|||
async function setExpanded(req) {
|
||||
const {branchId, expanded} = req.params;
|
||||
|
||||
if (branchId !== 'root') {
|
||||
await sql.execute("UPDATE branches SET isExpanded = ? WHERE branchId = ?", [expanded, branchId]);
|
||||
// we don't sync expanded label
|
||||
}
|
||||
}
|
||||
|
||||
async function setExpandedForSubtree(req) {
|
||||
const {branchId, expanded} = req.params;
|
||||
|
||||
let branchIds = await sql.getColumn(`
|
||||
WITH RECURSIVE
|
||||
tree(branchId, noteId) AS (
|
||||
SELECT branchId, noteId FROM branches WHERE branchId = ?
|
||||
UNION
|
||||
SELECT branches.branchId, branches.noteId FROM branches
|
||||
JOIN tree ON branches.parentNoteId = tree.noteId
|
||||
WHERE branches.isDeleted = 0
|
||||
)
|
||||
SELECT branchId FROM tree`, [branchId]);
|
||||
|
||||
// root is always expanded
|
||||
branchIds = branchIds.filter(branchId => branchId !== 'root');
|
||||
|
||||
await sql.executeMany(`UPDATE branches SET isExpanded = ${expanded} WHERE branchId IN (???)`, branchIds);
|
||||
|
||||
return {
|
||||
branchIds
|
||||
};
|
||||
}
|
||||
|
||||
async function deleteBranch(req) {
|
||||
const last = req.query.last === 'true';
|
||||
|
@ -149,6 +175,7 @@ module.exports = {
|
|||
moveBranchBeforeNote,
|
||||
moveBranchAfterNote,
|
||||
setExpanded,
|
||||
setExpandedForSubtree,
|
||||
deleteBranch,
|
||||
setPrefix
|
||||
};
|
|
@ -127,6 +127,7 @@ function register(app) {
|
|||
apiRoute(PUT, '/api/branches/:branchId/move-before/:beforeBranchId', branchesApiRoute.moveBranchBeforeNote);
|
||||
apiRoute(PUT, '/api/branches/:branchId/move-after/:afterBranchId', branchesApiRoute.moveBranchAfterNote);
|
||||
apiRoute(PUT, '/api/branches/:branchId/expanded/:expanded', branchesApiRoute.setExpanded);
|
||||
apiRoute(PUT, '/api/branches/:branchId/expanded-subtree/:expanded', branchesApiRoute.setExpandedForSubtree);
|
||||
apiRoute(DELETE, '/api/branches/:branchId', branchesApiRoute.deleteBranch);
|
||||
|
||||
apiRoute(GET, '/api/autocomplete', autocompleteApiRoute.getAutocomplete);
|
||||
|
|
|
@ -1 +1 @@
|
|||
module.exports = { buildDate:"2020-04-27T23:46:48+02:00", buildRevision: "0a9462241360e0baac71863af3ce7fb07cfd8c87" };
|
||||
module.exports = { buildDate:"2020-05-04T21:59:14+02:00", buildRevision: "cafcb67a8a3a1943acac829590b34ff729b57e09" };
|
||||
|
|
|
@ -12,9 +12,7 @@ const VIRTUAL_ATTRIBUTES = [
|
|||
"type",
|
||||
"mime",
|
||||
"text",
|
||||
"parentCount",
|
||||
"attributeName",
|
||||
"attributeValue"
|
||||
"parentCount"
|
||||
];
|
||||
|
||||
module.exports = function(filters, selectedColumns = 'notes.*') {
|
||||
|
@ -35,29 +33,11 @@ module.exports = function(filters, selectedColumns = 'notes.*') {
|
|||
|
||||
// forcing to use particular index since SQLite query planner would often choose something pretty bad
|
||||
joins[alias] = `LEFT JOIN attributes AS ${alias} INDEXED BY IDX_attributes_noteId_index `
|
||||
+ `ON ${alias}.noteId = notes.noteId AND ${alias}.isDeleted = 0 `
|
||||
+ `AND ${alias}.name = '${property}' `;
|
||||
+ `ON ${alias}.noteId = notes.noteId `
|
||||
+ `AND ${alias}.name = '${property}' AND ${alias}.isDeleted = 0`;
|
||||
|
||||
accessor = `${alias}.value`;
|
||||
}
|
||||
else if (['attributeType', 'attributeName', 'attributeValue'].includes(property)) {
|
||||
const alias = "attr_filter";
|
||||
|
||||
if (!(alias in joins)) {
|
||||
joins[alias] = `LEFT JOIN attributes AS ${alias} INDEXED BY IDX_attributes_noteId_index `
|
||||
+ `ON ${alias}.noteId = notes.noteId AND ${alias}.isDeleted = 0`;
|
||||
}
|
||||
|
||||
if (property === 'attributeType') {
|
||||
accessor = `${alias}.type`
|
||||
} else if (property === 'attributeName') {
|
||||
accessor = `${alias}.name`
|
||||
} else if (property === 'attributeValue') {
|
||||
accessor = `${alias}.value`
|
||||
} else {
|
||||
throw new Error(`Unrecognized property ${property}`);
|
||||
}
|
||||
}
|
||||
else if (property === 'content') {
|
||||
const alias = "note_contents";
|
||||
|
||||
|
@ -93,40 +73,33 @@ module.exports = function(filters, selectedColumns = 'notes.*') {
|
|||
});
|
||||
}
|
||||
|
||||
let where = '1';
|
||||
const params = [];
|
||||
|
||||
function parseWhereFilters(filters) {
|
||||
let whereStmt = '';
|
||||
|
||||
for (const filter of filters) {
|
||||
if (['isarchived', 'in', 'orderby', 'limit'].includes(filter.name.toLowerCase())) {
|
||||
continue; // these are not real filters
|
||||
}
|
||||
|
||||
if (whereStmt) {
|
||||
whereStmt += " " + filter.relation + " ";
|
||||
}
|
||||
|
||||
if (filter.children) {
|
||||
whereStmt += "(" + parseWhereFilters(filter.children) + ")";
|
||||
continue;
|
||||
}
|
||||
where += " " + filter.relation + " ";
|
||||
|
||||
const accessor = getAccessor(filter.name);
|
||||
|
||||
if (filter.operator === 'exists') {
|
||||
whereStmt += `${accessor} IS NOT NULL`;
|
||||
} else if (filter.operator === 'not-exists') {
|
||||
whereStmt += `${accessor} IS NULL`;
|
||||
} else if (filter.operator === '=' || filter.operator === '!=') {
|
||||
whereStmt += `${accessor} ${filter.operator} ?`;
|
||||
where += `${accessor} IS NOT NULL`;
|
||||
}
|
||||
else if (filter.operator === 'not-exists') {
|
||||
where += `${accessor} IS NULL`;
|
||||
}
|
||||
else if (filter.operator === '=' || filter.operator === '!=') {
|
||||
where += `${accessor} ${filter.operator} ?`;
|
||||
params.push(filter.value);
|
||||
} else if (filter.operator === '*=' || filter.operator === '!*=') {
|
||||
whereStmt += `${accessor}`
|
||||
where += `${accessor}`
|
||||
+ (filter.operator.includes('!') ? ' NOT' : '')
|
||||
+ ` LIKE ` + utils.prepareSqlForLike('%', filter.value, '');
|
||||
} else if (filter.operator === '=*' || filter.operator === '!=*') {
|
||||
whereStmt += `${accessor}`
|
||||
where += `${accessor}`
|
||||
+ (filter.operator.includes('!') ? ' NOT' : '')
|
||||
+ ` LIKE ` + utils.prepareSqlForLike('', filter.value, '%');
|
||||
} else if (filter.operator === '*=*' || filter.operator === '!*=*') {
|
||||
|
@ -145,8 +118,9 @@ module.exports = function(filters, selectedColumns = 'notes.*') {
|
|||
condition = `(${condition} AND notes.isProtected = 0)`;
|
||||
}
|
||||
|
||||
whereStmt += condition;
|
||||
} else if ([">", ">=", "<", "<="].includes(filter.operator)) {
|
||||
where += condition;
|
||||
}
|
||||
else if ([">", ">=", "<", "<="].includes(filter.operator)) {
|
||||
let floatParam;
|
||||
|
||||
// from https://stackoverflow.com/questions/12643009/regular-expression-for-floating-point-numbers
|
||||
|
@ -156,10 +130,10 @@ module.exports = function(filters, selectedColumns = 'notes.*') {
|
|||
|
||||
if (floatParam === undefined || isNaN(floatParam)) {
|
||||
// if the value can't be parsed as float then we assume that string comparison should be used instead of numeric
|
||||
whereStmt += `${accessor} ${filter.operator} ?`;
|
||||
where += `${accessor} ${filter.operator} ?`;
|
||||
params.push(filter.value);
|
||||
} else {
|
||||
whereStmt += `CAST(${accessor} AS DECIMAL) ${filter.operator} ?`;
|
||||
where += `CAST(${accessor} AS DECIMAL) ${filter.operator} ?`;
|
||||
params.push(floatParam);
|
||||
}
|
||||
} else {
|
||||
|
@ -167,11 +141,6 @@ module.exports = function(filters, selectedColumns = 'notes.*') {
|
|||
}
|
||||
}
|
||||
|
||||
return whereStmt;
|
||||
}
|
||||
|
||||
const where = parseWhereFilters(filters);
|
||||
|
||||
if (orderBy.length === 0) {
|
||||
// if no ordering is given then order at least by note title
|
||||
orderBy.push("notes.title");
|
||||
|
|
|
@ -617,6 +617,9 @@ class ConsistencyChecks {
|
|||
|
||||
await this.findSyncRowsIssues();
|
||||
|
||||
// root branch should always be expanded
|
||||
await sql.execute("UPDATE branches SET isExpanded = 1 WHERE branchId = 'root'");
|
||||
|
||||
if (this.unrecoveredConsistencyErrors) {
|
||||
// we run this only if basic checks passed since this assumes basic data consistency
|
||||
|
||||
|
|
|
@ -193,7 +193,7 @@ const DEFAULT_KEYBOARD_ACTIONS = [
|
|||
|
||||
|
||||
{
|
||||
separator: "Tabs"
|
||||
separator: "Tabs & Windows"
|
||||
},
|
||||
{
|
||||
actionName: "openNewTab",
|
||||
|
@ -219,6 +219,12 @@ const DEFAULT_KEYBOARD_ACTIONS = [
|
|||
description: "Activates tab on the left",
|
||||
scope: "window"
|
||||
},
|
||||
{
|
||||
actionName: "openNewWindow",
|
||||
defaultShortcuts: [],
|
||||
description: "Open new empty window",
|
||||
scope: "window"
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
|
|
|
@ -276,9 +276,9 @@ async function downloadImage(noteId, imageUrl) {
|
|||
const downloadImagePromises = {};
|
||||
|
||||
function replaceUrl(content, url, imageNote) {
|
||||
const quoted = url.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
const quoted = url.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');
|
||||
|
||||
return content.replace(new RegExp(`\s+src=[\"']${quoted}[\"']`, "g"), ` src="api/images/${imageNote.noteId}/${imageNote.title}"`);
|
||||
return content.replace(new RegExp(`\\s+src=[\"']${quoted}[\"']`, "g"), ` src="api/images/${imageNote.noteId}/${imageNote.title}"`);
|
||||
}
|
||||
|
||||
async function downloadImages(noteId, content) {
|
||||
|
@ -288,11 +288,11 @@ async function downloadImages(noteId, content) {
|
|||
const origContent = content;
|
||||
|
||||
while (match = re.exec(origContent)) {
|
||||
const url = match[1].toLowerCase();
|
||||
const url = match[1];
|
||||
|
||||
if (!url.startsWith('api/images/')
|
||||
if (!url.includes('api/images/')
|
||||
// this is and exception for the web clipper's "imageId"
|
||||
&& (url.length !== 20 || url.startsWith('http'))) {
|
||||
&& (url.length !== 20 || url.toLowerCase().startsWith('http'))) {
|
||||
if (url in downloadImagePromises) {
|
||||
// download is already in progress
|
||||
continue;
|
||||
|
@ -347,7 +347,7 @@ async function downloadImages(noteId, content) {
|
|||
for (const url in imageUrlToNoteIdMapping) {
|
||||
const imageNote = imageNotes.find(note => note.noteId === imageUrlToNoteIdMapping[url]);
|
||||
|
||||
if (imageNote) {
|
||||
if (imageNote && !imageNote.isDeleted) {
|
||||
updatedContent = replaceUrl(updatedContent, url, imageNote);
|
||||
}
|
||||
}
|
||||
|
@ -356,6 +356,8 @@ async function downloadImages(noteId, content) {
|
|||
if (updatedContent !== origContent) {
|
||||
await origNote.setContent(updatedContent);
|
||||
|
||||
await scanForLinks(origNote);
|
||||
|
||||
console.log(`Fixed the image links for note ${noteId} to the offline saved.`);
|
||||
}
|
||||
}, 5000);
|
||||
|
@ -376,11 +378,11 @@ async function saveLinks(note, content) {
|
|||
const foundLinks = [];
|
||||
|
||||
if (note.type === 'text') {
|
||||
content = await downloadImages(note.noteId, content);
|
||||
|
||||
content = findImageLinks(content, foundLinks);
|
||||
content = findInternalLinks(content, foundLinks);
|
||||
content = findIncludeNoteLinks(content, foundLinks);
|
||||
|
||||
content = await downloadImages(note.noteId, content);
|
||||
}
|
||||
else if (note.type === 'relation-map') {
|
||||
findRelationMapLinks(content, foundLinks);
|
||||
|
|
|
@ -83,8 +83,8 @@ const defaultOptions = [
|
|||
{ name: 'rightPaneVisible', value: 'true', isSynced: false },
|
||||
{ name: 'nativeTitleBarVisible', value: 'false', isSynced: false },
|
||||
{ name: 'eraseNotesAfterTimeInSeconds', value: '604800', isSynced: true }, // default is 7 days
|
||||
{ name: 'hideArchivedNotes_main', value: 'false', isSynced: false }, // default is 7 days
|
||||
{ name: 'hideIncludedImages_main', value: 'true', isSynced: false } // default is 7 days
|
||||
{ name: 'hideArchivedNotes_main', value: 'false', isSynced: false },
|
||||
{ name: 'hideIncludedImages_main', value: 'true', isSynced: false }
|
||||
];
|
||||
|
||||
async function initStartupOptions() {
|
||||
|
|
|
@ -60,20 +60,6 @@ module.exports = function (searchText) {
|
|||
operator: '*=*',
|
||||
value: searchText
|
||||
});
|
||||
|
||||
filters.push({
|
||||
relation: 'or',
|
||||
name: 'attributeName',
|
||||
operator: '*=*',
|
||||
value: searchText
|
||||
});
|
||||
|
||||
filters.push({
|
||||
relation: 'or',
|
||||
name: 'attributeValue',
|
||||
operator: '*=*',
|
||||
value: searchText
|
||||
});
|
||||
}
|
||||
else {
|
||||
const tokens = searchText.split(/\s+/);
|
||||
|
@ -81,27 +67,9 @@ module.exports = function (searchText) {
|
|||
for (const token of tokens) {
|
||||
filters.push({
|
||||
relation: 'and',
|
||||
name: 'sub',
|
||||
children: [
|
||||
{
|
||||
relation: 'or',
|
||||
name: 'text',
|
||||
operator: '*=*',
|
||||
value: token
|
||||
},
|
||||
{
|
||||
relation: 'or',
|
||||
name: 'attributeName',
|
||||
operator: '*=*',
|
||||
value: token
|
||||
},
|
||||
{
|
||||
relation: 'or',
|
||||
name: 'attributeValue',
|
||||
operator: '*=*',
|
||||
value: token
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -163,6 +163,10 @@ async function executeScript(query) {
|
|||
}
|
||||
|
||||
async function wrap(func, query) {
|
||||
if (!dbConnection) {
|
||||
throw new Error("DB connection not initialized yet");
|
||||
}
|
||||
|
||||
const thisError = new Error();
|
||||
|
||||
try {
|
||||
|
|
|
@ -13,16 +13,11 @@ const port = require('./port');
|
|||
const Option = require('../entities/option');
|
||||
const TaskContext = require('./task_context.js');
|
||||
|
||||
async function createConnection() {
|
||||
return await sqlite.open({
|
||||
const dbConnection = new Promise(async (resolve, reject) => {
|
||||
const db = await sqlite.open({
|
||||
filename: dataDir.DOCUMENT_PATH,
|
||||
driver: sqlite3.Database
|
||||
});
|
||||
}
|
||||
|
||||
const dbConnection = new Promise(async (resolve, reject) => {
|
||||
// no need to create new connection now since DB stays the same all the time
|
||||
const db = await createConnection();
|
||||
|
||||
db.run('PRAGMA journal_mode = WAL;');
|
||||
|
||||
|
|
Loading…
Reference in a new issue