add move to dialog

This commit is contained in:
zadam 2019-11-11 22:57:51 +01:00
parent 5b4a2bd71c
commit 4cda661c1b
8 changed files with 156 additions and 43 deletions

View File

@ -83,42 +83,25 @@ CREATE TABLE IF NOT EXISTS "branches" (
CREATE INDEX `IDX_branches_noteId` ON `branches` (`noteId`);
CREATE INDEX `IDX_branches_noteId_parentNoteId` ON `branches` (`noteId`,`parentNoteId`);
CREATE INDEX IDX_branches_parentNoteId ON branches (parentNoteId);
CREATE TABLE IF NOT EXISTS "note_revisions" (`noteRevisionId` TEXT NOT NULL PRIMARY KEY,
`noteId` TEXT NOT NULL,
`title` TEXT,
`contentLength` INT NOT NULL,
`isProtected` INT NOT NULL DEFAULT 0,
`utcDateLastEdited` TEXT NOT NULL,
`utcDateCreated` TEXT NOT NULL,
`utcDateModified` TEXT NOT NULL,
`dateLastEdited` TEXT NOT NULL,
`dateCreated` TEXT NOT NULL,
type TEXT DEFAULT '' NOT NULL,
mime TEXT DEFAULT '' NOT NULL,
hash TEXT DEFAULT '' NOT NULL);
CREATE TABLE IF NOT EXISTS "note_revision_contents" (`noteRevisionId` TEXT NOT NULL PRIMARY KEY,
`content` TEXT,
hash TEXT DEFAULT '' NOT NULL,
`utcDateModified` TEXT NOT NULL);
CREATE INDEX `IDX_note_revisions_noteId` ON `note_revisions` (`noteId`);
CREATE INDEX `IDX_note_revisions_utcDateCreated` ON `note_revisions` (`utcDateCreated`);
CREATE INDEX `IDX_note_revisions_utcDateLastEdited` ON `note_revisions` (`utcDateLastEdited`);
CREATE INDEX `IDX_note_revisions_dateCreated` ON `note_revisions` (`dateCreated`);
CREATE INDEX `IDX_note_revisions_dateLastEdited` ON `note_revisions` (`dateLastEdited`);
CREATE TABLE IF NOT EXISTS "notes" (
`noteId` TEXT NOT NULL,
`title` TEXT NOT NULL DEFAULT "note",
`isProtected` INT NOT NULL DEFAULT 0,
`type` TEXT NOT NULL DEFAULT 'text',
`mime` TEXT NOT NULL DEFAULT 'text/html',
`hash` TEXT DEFAULT "" NOT NULL,
`isDeleted` INT NOT NULL DEFAULT 0,
`isErased` INT NOT NULL DEFAULT 0,
`dateCreated` TEXT NOT NULL,
`dateModified` TEXT NOT NULL,
`utcDateCreated` TEXT NOT NULL,
`utcDateModified` TEXT NOT NULL,
PRIMARY KEY(`noteId`));
`noteId` TEXT NOT NULL,
`title` TEXT NOT NULL DEFAULT "note",
`contentLength` INT NOT NULL,
`isProtected` INT NOT NULL DEFAULT 0,
`type` TEXT NOT NULL DEFAULT 'text',
`mime` TEXT NOT NULL DEFAULT 'text/html',
`hash` TEXT DEFAULT "" NOT NULL,
`isDeleted` INT NOT NULL DEFAULT 0,
`isErased` INT NOT NULL DEFAULT 0,
`dateCreated` TEXT NOT NULL,
`dateModified` TEXT NOT NULL,
`utcDateCreated` TEXT NOT NULL,
`utcDateModified` TEXT NOT NULL,
PRIMARY KEY(`noteId`));
CREATE INDEX `IDX_notes_isDeleted` ON `notes` (`isDeleted`);
CREATE INDEX `IDX_notes_title` ON `notes` (`title`);
CREATE INDEX `IDX_notes_type` ON `notes` (`type`);
@ -126,3 +109,22 @@ CREATE INDEX `IDX_notes_dateCreated` ON `notes` (`dateCreated`);
CREATE INDEX `IDX_notes_dateModified` ON `notes` (`dateModified`);
CREATE INDEX `IDX_notes_utcDateModified` ON `notes` (`utcDateModified`);
CREATE INDEX `IDX_notes_utcDateCreated` ON `notes` (`utcDateCreated`);
CREATE TABLE IF NOT EXISTS "note_revisions" (`noteRevisionId` TEXT NOT NULL PRIMARY KEY,
`noteId` TEXT NOT NULL,
`title` TEXT,
`contentLength` INT NOT NULL,
`isErased` INT NOT NULL DEFAULT 0,
`isProtected` INT NOT NULL DEFAULT 0,
`utcDateLastEdited` TEXT NOT NULL,
`utcDateCreated` TEXT NOT NULL,
`utcDateModified` TEXT NOT NULL,
`dateLastEdited` TEXT NOT NULL,
`dateCreated` TEXT NOT NULL,
type TEXT DEFAULT '' NOT NULL,
mime TEXT DEFAULT '' NOT NULL,
hash TEXT DEFAULT '' NOT NULL);
CREATE INDEX `IDX_note_revisions_noteId` ON `note_revisions` (`noteId`);
CREATE INDEX `IDX_note_revisions_utcDateCreated` ON `note_revisions` (`utcDateCreated`);
CREATE INDEX `IDX_note_revisions_utcDateLastEdited` ON `note_revisions` (`utcDateLastEdited`);
CREATE INDEX `IDX_note_revisions_dateCreated` ON `note_revisions` (`dateCreated`);
CREATE INDEX `IDX_note_revisions_dateLastEdited` ON `note_revisions` (`dateLastEdited`);

2
package-lock.json generated
View File

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

View File

@ -0,0 +1,62 @@
import noteAutocompleteService from "../services/note_autocomplete.js";
import utils from "../services/utils.js";
import cloningService from "../services/cloning.js";
import treeUtils from "../services/tree_utils.js";
import toastService from "../services/toast.js";
import treeCache from "../services/tree_cache.js";
import treeChangesService from "../services/branches.js";
import treeService from "../services/tree.js";
const $dialog = $("#move-to-dialog");
const $form = $("#move-to-form");
const $noteAutoComplete = $("#move-to-note-autocomplete");
const $movePrefix = $("#move-prefix");
const $noteList = $("#move-to-note-list");
let movedNodes;
export async function showDialog(nodes) {
movedNodes = nodes;
utils.closeActiveDialog();
glob.activeDialog = $dialog;
$dialog.modal();
$noteAutoComplete.val('').trigger('focus');
$noteList.empty();
for (const node of movedNodes) {
const note = await treeCache.getNote(node.data.noteId);
$noteList.append($("<li>").text(note.title));
}
noteAutocompleteService.initNoteAutocomplete($noteAutoComplete);
noteAutocompleteService.showRecentNotes($noteAutoComplete);
}
async function moveNotesTo(notePath) {
const targetNode = await treeService.getNodeFromPath(notePath);
await treeChangesService.moveToNode(movedNodes, targetNode);
toastService.showMessage(`Selected notes have been moved into ${targetNode.title}`);
}
$form.on('submit', () => {
const notePath = $noteAutoComplete.getSelectedPath();
if (notePath) {
$dialog.modal('hide');
moveNotesTo(notePath);
}
else {
console.error("No path to move to.");
}
return false;
});

View File

@ -18,6 +18,7 @@ const NOTE_INFO = "../dialogs/note_info.js";
const ABOUT = "../dialogs/about.js";
const LINK_MAP = "../dialogs/link_map.js";
const CLONE_TO = "../dialogs/clone_to.js";
const MOVE_TO = "../dialogs/move_to.js";
function registerEntrypoints() {
// hot keys are active also inside inputs and content editables
@ -189,14 +190,22 @@ function registerEntrypoints() {
utils.bindGlobalShortcut('ctrl+shift+c', () => import(CLONE_TO).then(d => {
const activeNode = treeService.getActiveNode();
console.log("activeNode", activeNode);
const selectedOrActiveNodes = treeService.getSelectedOrActiveNodes(activeNode);
console.log("selectedOrActiveNodes", selectedOrActiveNodes);
const noteIds = selectedOrActiveNodes.map(node => node.data.noteId);
d.showDialog(noteIds);
}));
utils.bindGlobalShortcut('ctrl+shift+x', () => import(MOVE_TO).then(d => {
const activeNode = treeService.getActiveNode();
const selectedOrActiveNodes = treeService.getSelectedOrActiveNodes(activeNode);
d.showDialog(selectedOrActiveNodes);
}));
}
export default {

View File

@ -17,11 +17,12 @@ class TreeContextMenu {
getNoteTypeItems(baseCmd) {
return [
{ title: "Text", cmd: baseCmd + "_text", uiIcon: "file" },
{ title: "Code", cmd: baseCmd + "_code", uiIcon: "terminal" },
{ title: "Saved search", cmd: baseCmd + "_search", uiIcon: "search-folder" },
{ title: "Relation Map", cmd: baseCmd + "_relation-map", uiIcon: "map" },
{ title: "Render HTML note", cmd: baseCmd + "_render", uiIcon: "play" }
{ title: "Text", cmd: baseCmd + "_text", uiIcon: "note" },
{ title: "Code", cmd: baseCmd + "_code", uiIcon: "code" },
{ title: "Saved search", cmd: baseCmd + "_search", uiIcon: "file-find" },
{ title: "Relation Map", cmd: baseCmd + "_relation-map", uiIcon: "map-alt" },
{ title: "Render HTML note", cmd: baseCmd + "_render", uiIcon: "extension" },
{ title: "Book", cmd: baseCmd + "_book", uiIcon: "book" }
];
}
@ -63,11 +64,13 @@ class TreeContextMenu {
{ title: "Unprotect subtree", cmd: "unprotectSubtree", uiIcon: "shield", enabled: noSelectedNotes },
{ title: "----" },
{ title: "Copy / clone <kbd>Ctrl+C</kbd>", cmd: "copy", uiIcon: "copy",
enabled: isNotRoot },
enabled: isNotRoot && !isHoisted },
{ title: "Clone to ... <kbd>Ctrl+Shift+C</kbd>", cmd: "cloneTo", uiIcon: "empty",
enabled: isNotRoot },
enabled: isNotRoot && !isHoisted },
{ title: "Cut <kbd>Ctrl+X</kbd>", cmd: "cut", uiIcon: "cut",
enabled: isNotRoot && !isHoisted && parentNotSearch },
{ title: "Move to ... <kbd>Ctrl+Shift+X</kbd>", cmd: "moveTo", uiIcon: "empty",
enabled: isNotRoot && !isHoisted && parentNotSearch },
{ title: "Paste into <kbd>Ctrl+V</kbd>", cmd: "pasteInto", uiIcon: "paste",
enabled: !clipboard.isEmpty() && notSearch && noSelectedNotes },
{ title: "Paste after", cmd: "pasteAfter", uiIcon: "paste",
@ -127,11 +130,16 @@ class TreeContextMenu {
const nodes = treeService.getSelectedOrActiveNodes(this.node);
const noteIds = nodes.map(node => node.data.noteId);
import("../dialogs/clone_to.js").then(d => d.showDialog(noteIds))
import("../dialogs/clone_to.js").then(d => d.showDialog(noteIds));
}
else if (cmd === "cut") {
clipboard.cut(treeService.getSelectedOrActiveNodes(this.node));
}
else if (cmd === "moveTo") {
const nodes = treeService.getSelectedOrActiveNodes(this.node);
import("../dialogs/move_to.js").then(d => d.showDialog(nodes));
}
else if (cmd === "pasteAfter") {
clipboard.pasteAfter(this.node);
}

View File

@ -166,7 +166,7 @@ async function findBrokenReferenceIssues() {
}
});
await findAndFixIssues(`
await findIssues(`
SELECT noteRevisionId, note_revisions.noteId
FROM note_revisions LEFT JOIN notes USING(noteId)
WHERE notes.noteId IS NULL`,

View File

@ -176,6 +176,7 @@
<% include dialogs/note_info.ejs %>
<% include dialogs/link_map.ejs %>
<% include dialogs/clone_to.ejs %>
<% include dialogs/move_to.ejs %>
</div>
<script type="text/javascript">

View File

@ -0,0 +1,31 @@
<div id="move-to-dialog" class="modal mx-auto" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" style="max-width: 1000px" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title mr-auto">Move notes to ...</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" style="margin-left: 0 !important;">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form id="move-to-form">
<div class="modal-body">
<h5>Notes to move</h5>
<ul id="move-to-note-list" style="max-height: 200px; overflow: auto;"></ul>
<div class="form-group">
<label for="move-to-note-autocomplete">Target parent note</label>
<div class="input-group">
<input id="move-to-note-autocomplete" class="form-control" placeholder="search for note by its name">
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Move to selected note <kbd>enter</kbd></button>
</div>
</form>
</div>
</div>
</div>