mirror of
https://github.com/zadam/trilium.git
synced 2025-11-05 04:45:47 +01:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9a2cacb5b | ||
|
|
17085e5578 | ||
|
|
fc7da015fe | ||
|
|
adf222b5e8 | ||
|
|
ade22ea825 | ||
|
|
2c8fb90ecb | ||
|
|
c67644a2e3 | ||
|
|
346f6edd7e | ||
|
|
92f586486f | ||
|
|
e7c6d912a4 | ||
|
|
290f7e2101 | ||
|
|
5e0fbea3b3 | ||
|
|
7b2c3afe4c | ||
|
|
2e181d0fb1 | ||
|
|
68a03211ce | ||
|
|
f2a19c56b1 | ||
|
|
a98fd509c6 | ||
|
|
a3149aecf4 | ||
|
|
ef825371cf | ||
|
|
b567775129 |
BIN
db/demo.zip
BIN
db/demo.zip
Binary file not shown.
@@ -7,6 +7,6 @@ module.exports = () => {
|
|||||||
beccaLoader.load();
|
beccaLoader.load();
|
||||||
// make sure the hidden subtree exists since the subsequent migrations we will move some existing notes into it (share...)
|
// make sure the hidden subtree exists since the subsequent migrations we will move some existing notes into it (share...)
|
||||||
// in previous releases hidden subtree was created lazily
|
// in previous releases hidden subtree was created lazily
|
||||||
hiddenSubtreeService.checkHiddenSubtree();
|
hiddenSubtreeService.checkHiddenSubtree(true);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
5
package-lock.json
generated
5
package-lock.json
generated
@@ -1,12 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "trilium",
|
"name": "trilium",
|
||||||
"version": "0.58.5",
|
"version": "0.58.7",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "trilium",
|
"version": "0.58.7",
|
||||||
"version": "0.58.5",
|
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "trilium",
|
"name": "trilium",
|
||||||
"productName": "Trilium Notes",
|
"productName": "Trilium Notes",
|
||||||
"description": "Trilium Notes",
|
"description": "Trilium Notes",
|
||||||
"version": "0.58.6",
|
"version": "0.58.8",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"main": "electron.js",
|
"main": "electron.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@@ -152,6 +152,10 @@ class Becca {
|
|||||||
.replace('_', '')
|
.replace('_', '')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!(camelCaseEntityName in this)) {
|
||||||
|
throw new Error(`Unknown entity name '${camelCaseEntityName}' (original argument '${entityName}')`);
|
||||||
|
}
|
||||||
|
|
||||||
return this[camelCaseEntityName][entityId];
|
return this[camelCaseEntityName][entityId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,10 +83,8 @@ function getNoteTitleArrayForPath(notePathArray) {
|
|||||||
throw new Error(`${notePathArray} is not an array.`);
|
throw new Error(`${notePathArray} is not an array.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hoistedNoteId = cls.getHoistedNoteId();
|
if (notePathArray.length === 1) {
|
||||||
|
return [getNoteTitle(notePathArray[0])];
|
||||||
if (notePathArray.length === 1 && notePathArray[0] === hoistedNoteId) {
|
|
||||||
return [getNoteTitle(hoistedNoteId)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const titles = [];
|
const titles = [];
|
||||||
@@ -95,6 +93,7 @@ function getNoteTitleArrayForPath(notePathArray) {
|
|||||||
let hoistedNotePassed = false;
|
let hoistedNotePassed = false;
|
||||||
|
|
||||||
// this is a notePath from outside of hoisted subtree so full title path needs to be returned
|
// this is a notePath from outside of hoisted subtree so full title path needs to be returned
|
||||||
|
const hoistedNoteId = cls.getHoistedNoteId();
|
||||||
const outsideOfHoistedSubtree = !notePathArray.includes(hoistedNoteId);
|
const outsideOfHoistedSubtree = !notePathArray.includes(hoistedNoteId);
|
||||||
|
|
||||||
for (const noteId of notePathArray) {
|
for (const noteId of notePathArray) {
|
||||||
|
|||||||
@@ -80,14 +80,14 @@ class AbstractEntity {
|
|||||||
*
|
*
|
||||||
* @returns {this}
|
* @returns {this}
|
||||||
*/
|
*/
|
||||||
save() {
|
save(opts = {}) {
|
||||||
const entityName = this.constructor.entityName;
|
const entityName = this.constructor.entityName;
|
||||||
const primaryKeyName = this.constructor.primaryKeyName;
|
const primaryKeyName = this.constructor.primaryKeyName;
|
||||||
|
|
||||||
const isNewEntity = !this[primaryKeyName];
|
const isNewEntity = !this[primaryKeyName];
|
||||||
|
|
||||||
if (this.beforeSaving) {
|
if (this.beforeSaving) {
|
||||||
this.beforeSaving();
|
this.beforeSaving(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pojo = this.getPojoToSave();
|
const pojo = this.getPojoToSave();
|
||||||
|
|||||||
@@ -176,8 +176,10 @@ class Attribute extends AbstractEntity {
|
|||||||
return !(this.attributeId in this.becca.attributes);
|
return !(this.attributeId in this.becca.attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeSaving() {
|
beforeSaving(opts = {}) {
|
||||||
|
if (!opts.skipValidation) {
|
||||||
this.validate();
|
this.validate();
|
||||||
|
}
|
||||||
|
|
||||||
this.name = sanitizeAttributeName(this.name);
|
this.name = sanitizeAttributeName(this.name);
|
||||||
|
|
||||||
|
|||||||
@@ -79,11 +79,12 @@ export default class TabManager extends Component {
|
|||||||
filteredTabs = filteredTabs.filter(tab => tab.active);
|
filteredTabs = filteredTabs.filter(tab => tab.active);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filteredTabs.length === 0) {
|
// resolve before opened tabs can change this
|
||||||
const [notePath] = treeService.getHashValueFromAddress();
|
const [notePathInUrl, ntxIdInUrl] = treeService.getHashValueFromAddress();
|
||||||
|
|
||||||
|
if (filteredTabs.length === 0) {
|
||||||
filteredTabs.push({
|
filteredTabs.push({
|
||||||
notePath: notePath || 'root',
|
notePath: notePathInUrl || 'root',
|
||||||
active: true,
|
active: true,
|
||||||
hoistedNoteId: glob.extraHoistedNoteId || 'root'
|
hoistedNoteId: glob.extraHoistedNoteId || 'root'
|
||||||
});
|
});
|
||||||
@@ -95,17 +96,14 @@ export default class TabManager extends Component {
|
|||||||
|
|
||||||
await this.tabsUpdate.allowUpdateWithoutChange(async () => {
|
await this.tabsUpdate.allowUpdateWithoutChange(async () => {
|
||||||
for (const tab of filteredTabs) {
|
for (const tab of filteredTabs) {
|
||||||
|
|
||||||
await this.openContextWithNote(tab.notePath, tab.active, tab.ntxId, tab.hoistedNoteId, tab.mainNtxId);
|
await this.openContextWithNote(tab.notePath, tab.active, tab.ntxId, tab.hoistedNoteId, tab.mainNtxId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// if there's notePath in the URL, make sure it's open and active
|
// if there's notePath in the URL, make sure it's open and active
|
||||||
// (useful, for e.g. opening clipped notes from clipper or opening link in an extra window)
|
// (useful, for e.g. opening clipped notes from clipper or opening link in an extra window)
|
||||||
if (treeService.isNotePathInAddress()) {
|
if (notePathInUrl) {
|
||||||
const [notePath, ntxId] = treeService.getHashValueFromAddress();
|
await appContext.tabManager.switchToNoteContext(ntxIdInUrl, notePathInUrl);
|
||||||
|
|
||||||
await appContext.tabManager.switchToNoteContext(ntxId, notePath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
|
|||||||
@@ -688,7 +688,7 @@ class NoteShort {
|
|||||||
return promotedAttrs;
|
return promotedAttrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasAncestor(ancestorNoteId, visitedNoteIds = null) {
|
hasAncestor(ancestorNoteId, followTemplates = false, visitedNoteIds = null) {
|
||||||
if (this.noteId === ancestorNoteId) {
|
if (this.noteId === ancestorNoteId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -702,14 +702,16 @@ class NoteShort {
|
|||||||
|
|
||||||
visitedNoteIds.add(this.noteId);
|
visitedNoteIds.add(this.noteId);
|
||||||
|
|
||||||
|
if (followTemplates) {
|
||||||
for (const templateNote of this.getTemplateNotes()) {
|
for (const templateNote of this.getTemplateNotes()) {
|
||||||
if (templateNote.hasAncestor(ancestorNoteId, visitedNoteIds)) {
|
if (templateNote.hasAncestor(ancestorNoteId, followTemplates, visitedNoteIds)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const parentNote of this.getParentNotes()) {
|
for (const parentNote of this.getParentNotes()) {
|
||||||
if (parentNote.hasAncestor(ancestorNoteId, visitedNoteIds)) {
|
if (parentNote.hasAncestor(ancestorNoteId, followTemplates, visitedNoteIds)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ function isAffecting(attrRow, affectedNote) {
|
|||||||
|
|
||||||
if (this.isInheritable) {
|
if (this.isInheritable) {
|
||||||
for (const owningNote of owningNotes) {
|
for (const owningNote of owningNotes) {
|
||||||
if (owningNote.hasAncestor(attrNote.noteId)) {
|
if (owningNote.hasAncestor(attrNote.noteId, true)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -242,6 +242,7 @@ const ATTR_HELP = {
|
|||||||
"keepCurrentHoisting": "Opening this link won't change hoisting even if the note is not displayable in the current hoisted subtree.",
|
"keepCurrentHoisting": "Opening this link won't change hoisting even if the note is not displayable in the current hoisted subtree.",
|
||||||
"executeButton": "Title of the button which will execute the current code note",
|
"executeButton": "Title of the button which will execute the current code note",
|
||||||
"executeDescription": "Longer description of the current code note displayed together with the execute button",
|
"executeDescription": "Longer description of the current code note displayed together with the execute button",
|
||||||
|
"excludeFromNoteMap": "Notes with this label will be hidden from the Note Map"
|
||||||
},
|
},
|
||||||
"relation": {
|
"relation": {
|
||||||
"runOnNoteCreation": "executes when note is created on backend. Use this relation if you want to run the script for all notes created under a specific subtree. In that case, create it on the subtree root note and make it inheritable. A new note created within the subtree (any depth) will trigger the script.",
|
"runOnNoteCreation": "executes when note is created on backend. Use this relation if you want to run the script for all notes created under a specific subtree. In that case, create it on the subtree root note and make it inheritable. A new note created within the subtree (any depth) will trigger the script.",
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ export default class GlobalMenuWidget extends BasicWidget {
|
|||||||
const resp = await fetch(RELEASES_API_URL);
|
const resp = await fetch(RELEASES_API_URL);
|
||||||
const data = await resp.json();
|
const data = await resp.json();
|
||||||
|
|
||||||
return data.tag_name.substring(1);
|
return data?.tag_name?.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadLatestVersionCommand() {
|
downloadLatestVersionCommand() {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ const TPL = `
|
|||||||
<div class="dropdown right-dropdown-widget dropright">
|
<div class="dropdown right-dropdown-widget dropright">
|
||||||
<style>
|
<style>
|
||||||
.right-dropdown-widget {
|
.right-dropdown-widget {
|
||||||
width: 53px;
|
|
||||||
height: 53px;
|
height: 53px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import options from "../../services/options.js";
|
import options from "../../services/options.js";
|
||||||
import FlexContainer from "./flex_container.js";
|
import FlexContainer from "./flex_container.js";
|
||||||
|
import appContext from "../../components/app_context.js";
|
||||||
|
|
||||||
export default class LeftPaneContainer extends FlexContainer {
|
export default class LeftPaneContainer extends FlexContainer {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -16,7 +17,15 @@ export default class LeftPaneContainer extends FlexContainer {
|
|||||||
|
|
||||||
entitiesReloadedEvent({loadResults}) {
|
entitiesReloadedEvent({loadResults}) {
|
||||||
if (loadResults.isOptionReloaded("leftPaneVisible")) {
|
if (loadResults.isOptionReloaded("leftPaneVisible")) {
|
||||||
this.toggleInt(this.isEnabled());
|
const visible = this.isEnabled();
|
||||||
|
this.toggleInt(visible);
|
||||||
|
|
||||||
|
if (visible) {
|
||||||
|
this.triggerEvent('focusTree');
|
||||||
|
} else {
|
||||||
|
const activeNoteContext = appContext.tabManager.getActiveContext();
|
||||||
|
this.triggerEvent('focusOnDetail', {ntxId: activeNoteContext.ntxId});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -832,6 +832,8 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await this.filterHoistedBranch();
|
||||||
|
|
||||||
const activeNode = await this.getNodeFromPath(appContext.tabManager.getActiveContextNotePath());
|
const activeNode = await this.getNodeFromPath(appContext.tabManager.getActiveContextNotePath());
|
||||||
|
|
||||||
if (activeNode) {
|
if (activeNode) {
|
||||||
@@ -887,6 +889,11 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async focusTreeEvent() {
|
||||||
|
this.tree.$container.focus();
|
||||||
|
this.tree.setFocus(true);
|
||||||
|
}
|
||||||
|
|
||||||
/** @returns {FancytreeNode} */
|
/** @returns {FancytreeNode} */
|
||||||
async getNodeFromPath(notePath, expand = false, logErrors = true) {
|
async getNodeFromPath(notePath, expand = false, logErrors = true) {
|
||||||
utils.assertArguments(notePath);
|
utils.assertArguments(notePath);
|
||||||
@@ -1074,6 +1081,8 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
|
this.filterHoistedBranch();
|
||||||
}, 600 * 1000);
|
}, 600 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class ImageTypeWidget extends TypeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async doRefresh(note) {
|
async doRefresh(note) {
|
||||||
this.$imageView.prop("src", `api/images/${note.noteId}/${note.title}`);
|
this.$imageView.prop("src", `api/images/${note.noteId}/${encodeURIComponent(note.title)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
copyImageReferenceToClipboardEvent({ntxId}) {
|
copyImageReferenceToClipboardEvent({ntxId}) {
|
||||||
|
|||||||
@@ -871,12 +871,11 @@ body {
|
|||||||
#launcher-pane .launcher-button {
|
#launcher-pane .launcher-button {
|
||||||
font-size: 150%;
|
font-size: 150%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 15px 15px;
|
padding: 13px 13px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: none;
|
border: none;
|
||||||
color: var(--launcher-pane-text-color);
|
color: var(--launcher-pane-text-color);
|
||||||
background-color: var(--launcher-pane-background-color);
|
background-color: var(--launcher-pane-background-color);
|
||||||
width: 53px;
|
|
||||||
height: 53px;
|
height: 53px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
module.exports = { buildDate:"2023-01-16T22:39:28+01:00", buildRevision: "9fd0b85ff2be264be35ec2052c956b654f0dac9e" };
|
module.exports = { buildDate:"2023-02-13T21:50:54+01:00", buildRevision: "17085e5578d2a20a77a6ade058f74e6d5b798ecc" };
|
||||||
|
|||||||
@@ -148,13 +148,28 @@ class ConsistencyChecks {
|
|||||||
AND notes.noteId IS NULL`,
|
AND notes.noteId IS NULL`,
|
||||||
({branchId, parentNoteId}) => {
|
({branchId, parentNoteId}) => {
|
||||||
if (this.autoFix) {
|
if (this.autoFix) {
|
||||||
const branch = becca.getBranch(branchId);
|
// Delete the old branch and recreate it with root as parent.
|
||||||
branch.parentNoteId = 'root';
|
const oldBranch = becca.getBranch(branchId);
|
||||||
branch.save();
|
const noteId = oldBranch.noteId;
|
||||||
|
oldBranch.markAsDeleted("missing-parent");
|
||||||
|
|
||||||
|
let message = `Branch '${branchId}' was was missing parent note '${parentNoteId}', so it was deleted. `;
|
||||||
|
|
||||||
|
if (becca.getNote(noteId).getParentBranches().length === 0) {
|
||||||
|
const newBranch = new Branch({
|
||||||
|
parentNoteId: 'root',
|
||||||
|
noteId: noteId,
|
||||||
|
prefix: 'recovered'
|
||||||
|
}).save();
|
||||||
|
|
||||||
|
message += `${newBranch.branchId} was created in the root instead.`;
|
||||||
|
} else {
|
||||||
|
message += `There is one or more valid branches, so no new one will be created as a replacement.`;
|
||||||
|
}
|
||||||
|
|
||||||
this.reloadNeeded = true;
|
this.reloadNeeded = true;
|
||||||
|
|
||||||
logFix(`Branch '${branchId}' was set to root parent since it was referencing missing parent note '${parentNoteId}'`);
|
logFix(message);
|
||||||
} else {
|
} else {
|
||||||
logError(`Branch '${branchId}' references missing parent note '${parentNoteId}'`);
|
logError(`Branch '${branchId}' references missing parent note '${parentNoteId}'`);
|
||||||
}
|
}
|
||||||
@@ -428,10 +443,17 @@ class ConsistencyChecks {
|
|||||||
const branches = branchIds.map(branchId => becca.getBranch(branchId));
|
const branches = branchIds.map(branchId => becca.getBranch(branchId));
|
||||||
|
|
||||||
for (const branch of branches) {
|
for (const branch of branches) {
|
||||||
branch.parentNoteId = 'root';
|
// delete the old wrong branch
|
||||||
branch.save();
|
branch.markAsDeleted("parent-is-search");
|
||||||
|
|
||||||
logFix(`Child branch '${branch.branchId}' has been moved to root since it was a child of a search note '${parentNoteId}'`)
|
// create a replacement branch in root parent
|
||||||
|
new Branch({
|
||||||
|
parentNoteId: 'root',
|
||||||
|
noteId: branch.noteId,
|
||||||
|
prefix: 'recovered'
|
||||||
|
}).save();
|
||||||
|
|
||||||
|
logFix(`Note '${branch.noteId}' has been moved to root since it was a child of a search note '${parentNoteId}'`)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.reloadNeeded = true;
|
this.reloadNeeded = true;
|
||||||
|
|||||||
@@ -100,15 +100,38 @@ function fillEntityChanges(entityName, entityPrimaryKey, condition = '') {
|
|||||||
if (existingRows === 0) {
|
if (existingRows === 0) {
|
||||||
createdCount++;
|
createdCount++;
|
||||||
|
|
||||||
|
let hash;
|
||||||
|
let utcDateChanged;
|
||||||
|
let isSynced;
|
||||||
|
|
||||||
|
if (entityName.endsWith("_contents")) {
|
||||||
|
// FIXME: hacky, not sure if it might cause some problems
|
||||||
|
hash = "fake value";
|
||||||
|
utcDateChanged = dateUtils.utcNowDateTime();
|
||||||
|
isSynced = true; // contents are always synced
|
||||||
|
} else {
|
||||||
const entity = becca.getEntity(entityName, entityId);
|
const entity = becca.getEntity(entityName, entityId);
|
||||||
|
|
||||||
|
if (entity) {
|
||||||
|
hash = entity?.generateHash() || "|deleted";
|
||||||
|
utcDateChanged = entity?.getUtcDateChanged() || dateUtils.utcNowDateTime();
|
||||||
|
isSynced = entityName !== 'options' || !!entity?.isSynced;
|
||||||
|
} else {
|
||||||
|
// entity might be null (not present in becca) when it's deleted
|
||||||
|
// FIXME: hacky, not sure if it might cause some problems
|
||||||
|
hash = "deleted";
|
||||||
|
utcDateChanged = dateUtils.utcNowDateTime();
|
||||||
|
isSynced = true; // deletable (the ones with isDeleted) entities are synced
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addEntityChange({
|
addEntityChange({
|
||||||
entityName,
|
entityName,
|
||||||
entityId,
|
entityId,
|
||||||
hash: entity.generateHash(),
|
hash: hash,
|
||||||
isErased: false,
|
isErased: false,
|
||||||
utcDateChanged: entity.getUtcDateChanged(),
|
utcDateChanged: utcDateChanged,
|
||||||
isSynced: entityName !== 'options' || !!entity.isSynced
|
isSynced: isSynced
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,8 +234,8 @@ const HIDDEN_SUBTREE_DEFINITION = {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
function checkHiddenSubtree() {
|
function checkHiddenSubtree(force = false) {
|
||||||
if (!migrationService.isDbUpToDate()) {
|
if (!force && !migrationService.isDbUpToDate()) {
|
||||||
// on-delete hook might get triggered during some future migration and cause havoc
|
// on-delete hook might get triggered during some future migration and cause havoc
|
||||||
log.info("Will not check hidden subtree until migration is finished.");
|
log.info("Will not check hidden subtree until migration is finished.");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -661,7 +661,8 @@ function undeleteBranch(branchId, deleteId, taskContext) {
|
|||||||
OR (type = 'relation' AND value = ?))`, [deleteId, note.noteId, note.noteId]);
|
OR (type = 'relation' AND value = ?))`, [deleteId, note.noteId, note.noteId]);
|
||||||
|
|
||||||
for (const attribute of attributes) {
|
for (const attribute of attributes) {
|
||||||
new Attribute(attribute).save();
|
// relation might point to a note which hasn't been undeleted yet and would thus throw up
|
||||||
|
new Attribute(attribute).save({skipValidation: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
const childBranchIds = sql.getColumn(`
|
const childBranchIds = sql.getColumn(`
|
||||||
|
|||||||
Reference in New Issue
Block a user