Notes/src/services/special_notes.ts

288 lines
8.9 KiB
TypeScript
Raw Normal View History

import attributeService from "./attributes.js";
import dateNoteService from "./date_notes.js";
import becca from "../becca/becca.js";
import noteService from "./notes.js";
import dateUtils from "./date_utils.js";
import log from "./log.js";
import hoistedNoteService from "./hoisted_note.js";
import searchService from "./search/services/search.js";
import SearchContext from "./search/search_context.js";
import hiddenSubtree from "./hidden_subtree.js";
2024-10-25 21:04:13 +03:00
import { t } from "i18next";
const { LBTPL_NOTE, LBTPL_CUSTOM_WIDGET, LBTPL_SPACER, LBTPL_SCRIPT } = hiddenSubtree;
2024-04-03 23:05:06 +03:00
function getInboxNote(date: string) {
2022-12-23 15:07:48 +01:00
const workspaceNote = hoistedNoteService.getWorkspaceNote();
2024-04-03 23:05:06 +03:00
if (!workspaceNote) {
throw new Error("Unable to find workspace note");
}
let inbox;
2022-12-23 15:07:48 +01:00
if (!workspaceNote.isRoot()) {
2025-01-09 18:07:02 +02:00
inbox = workspaceNote.searchNoteInSubtree("#workspaceInbox");
if (!inbox) {
2025-01-09 18:07:02 +02:00
inbox = workspaceNote.searchNoteInSubtree("#inbox");
}
if (!inbox) {
2022-12-23 15:07:48 +01:00
inbox = workspaceNote;
}
2025-01-09 18:07:02 +02:00
} else {
inbox = attributeService.getNoteWithLabel("inbox") || dateNoteService.getDayNote(date);
}
return inbox;
}
function createSqlConsole() {
2025-01-09 18:07:02 +02:00
const { note } = noteService.createNewNote({
parentNoteId: getMonthlyParentNoteId("_sqlConsole", "sqlConsole"),
title: "SQL Console - " + dateUtils.localNowDate(),
content: "SELECT title, isDeleted, isProtected FROM notes WHERE noteId = ''\n\n\n\n",
2025-01-09 18:07:02 +02:00
type: "code",
mime: "text/x-sqlite;schema=trilium"
});
2025-01-09 18:07:02 +02:00
note.setLabel("iconClass", "bx bx-data");
note.setLabel("keepCurrentHoisting");
return note;
}
2024-04-03 23:05:06 +03:00
function saveSqlConsole(sqlConsoleNoteId: string) {
const sqlConsoleNote = becca.getNote(sqlConsoleNoteId);
2024-04-03 23:05:06 +03:00
if (!sqlConsoleNote) throw new Error(`Unable to find SQL console note ID: ${sqlConsoleNoteId}`);
const today = dateUtils.localNowDate();
2025-01-09 18:07:02 +02:00
const sqlConsoleHome = attributeService.getNoteWithLabel("sqlConsoleHome") || dateNoteService.getDayNote(today);
const result = sqlConsoleNote.cloneTo(sqlConsoleHome.noteId);
for (const parentBranch of sqlConsoleNote.getParentBranches()) {
2025-01-09 18:07:02 +02:00
if (parentBranch.parentNote?.hasAncestor("_hidden")) {
parentBranch.markAsDeleted();
}
}
return result;
}
2024-04-03 23:05:06 +03:00
function createSearchNote(searchString: string, ancestorNoteId: string) {
2025-01-09 18:07:02 +02:00
const { note } = noteService.createNewNote({
parentNoteId: getMonthlyParentNoteId("_search", "search"),
2024-10-25 21:04:13 +03:00
title: `${t("special_notes.search_prefix")} ${searchString}`,
content: "",
2025-01-09 18:07:02 +02:00
type: "search",
mime: "application/json"
});
2025-01-09 18:07:02 +02:00
note.setLabel("searchString", searchString);
note.setLabel("keepCurrentHoisting");
if (ancestorNoteId) {
2025-01-09 18:07:02 +02:00
note.setRelation("ancestor", ancestorNoteId);
}
return note;
}
function getSearchHome() {
2022-12-23 15:07:48 +01:00
const workspaceNote = hoistedNoteService.getWorkspaceNote();
2024-04-03 23:05:06 +03:00
if (!workspaceNote) {
throw new Error("Unable to find workspace note");
}
2022-12-23 15:07:48 +01:00
if (!workspaceNote.isRoot()) {
2025-01-09 18:07:02 +02:00
return workspaceNote.searchNoteInSubtree("#workspaceSearchHome") || workspaceNote.searchNoteInSubtree("#searchHome") || workspaceNote;
} else {
const today = dateUtils.localNowDate();
2025-01-09 18:07:02 +02:00
return workspaceNote.searchNoteInSubtree("#searchHome") || dateNoteService.getDayNote(today);
}
}
2024-04-03 23:05:06 +03:00
function saveSearchNote(searchNoteId: string) {
const searchNote = becca.getNote(searchNoteId);
2024-04-03 23:05:06 +03:00
if (!searchNote) {
throw new Error("Unable to find search note");
}
const searchHome = getSearchHome();
const result = searchNote.cloneTo(searchHome.noteId);
for (const parentBranch of searchNote.getParentBranches()) {
2025-01-09 18:07:02 +02:00
if (parentBranch.parentNote?.hasAncestor("_hidden")) {
parentBranch.markAsDeleted();
}
}
return result;
}
2024-04-03 23:05:06 +03:00
function getMonthlyParentNoteId(rootNoteId: string, prefix: string) {
2022-12-15 16:38:05 +01:00
const month = dateUtils.localNowDate().substring(0, 7);
2022-12-23 14:18:40 +01:00
const labelName = `${prefix}MonthNote`;
2022-12-15 16:38:05 +01:00
2025-01-09 18:07:02 +02:00
let monthNote = searchService.findFirstNoteWithQuery(`#${labelName}="${month}"`, new SearchContext({ ancestorNoteId: rootNoteId }));
2022-12-15 16:38:05 +01:00
if (!monthNote) {
monthNote = noteService.createNewNote({
parentNoteId: rootNoteId,
title: month,
2025-01-09 18:07:02 +02:00
content: "",
2022-12-15 16:38:05 +01:00
isProtected: false,
2025-01-09 18:07:02 +02:00
type: "book"
}).note;
2022-12-15 16:38:05 +01:00
monthNote.addLabel(labelName, month);
}
return monthNote.noteId;
}
2024-04-03 23:05:06 +03:00
function createScriptLauncher(parentNoteId: string, forceNoteId?: string) {
const note = noteService.createNewNote({
noteId: forceNoteId,
title: "Script Launcher",
2025-01-09 18:07:02 +02:00
type: "launcher",
content: "",
parentNoteId: parentNoteId
}).note;
2025-01-09 18:07:02 +02:00
note.addRelation("template", LBTPL_SCRIPT);
return note;
}
export type LauncherType = "launcher" | "note" | "script" | "customWidget" | "spacer";
2024-04-03 23:05:06 +03:00
interface LauncherConfig {
parentNoteId: string;
launcherType: LauncherType;
noteId?: string;
2024-04-03 23:05:06 +03:00
}
function createLauncher({ parentNoteId, launcherType, noteId }: LauncherConfig) {
2022-08-07 15:34:59 +02:00
let note;
2025-01-09 18:07:02 +02:00
if (launcherType === "note") {
2022-08-07 15:34:59 +02:00
note = noteService.createNewNote({
noteId: noteId,
2022-12-07 12:46:41 +01:00
title: "Note Launcher",
2025-01-09 18:07:02 +02:00
type: "launcher",
content: "",
2022-08-07 15:34:59 +02:00
parentNoteId: parentNoteId
}).note;
2022-11-29 16:16:57 +01:00
note.addRelation("template", LBTPL_NOTE);
2025-01-09 18:07:02 +02:00
} else if (launcherType === "script") {
note = createScriptLauncher(parentNoteId, noteId);
2025-01-09 18:07:02 +02:00
} else if (launcherType === "customWidget") {
2022-08-07 15:34:59 +02:00
note = noteService.createNewNote({
noteId: noteId,
2022-12-07 12:46:41 +01:00
title: "Widget Launcher",
2025-01-09 18:07:02 +02:00
type: "launcher",
content: "",
2022-08-07 15:34:59 +02:00
parentNoteId: parentNoteId
}).note;
2025-01-09 18:07:02 +02:00
note.addRelation("template", LBTPL_CUSTOM_WIDGET);
} else if (launcherType === "spacer") {
2022-08-07 15:34:59 +02:00
note = noteService.createNewNote({
noteId: noteId,
branchId: noteId,
2022-08-07 15:34:59 +02:00
title: "Spacer",
2025-01-09 18:07:02 +02:00
type: "launcher",
content: "",
2022-08-07 15:34:59 +02:00
parentNoteId: parentNoteId
}).note;
2022-08-07 13:23:03 +02:00
2025-01-09 18:07:02 +02:00
note.addRelation("template", LBTPL_SPACER);
2022-08-07 15:34:59 +02:00
} else {
2022-12-07 12:46:41 +01:00
throw new Error(`Unrecognized launcher type '${launcherType}'`);
2022-08-07 13:23:03 +02:00
}
2022-08-07 15:34:59 +02:00
return {
success: true,
note
};
2022-08-07 13:23:03 +02:00
}
2024-04-03 23:05:06 +03:00
function resetLauncher(noteId: string) {
2022-12-06 23:48:44 +01:00
const note = becca.getNote(noteId);
2022-11-25 15:29:57 +01:00
2024-04-03 23:05:06 +03:00
if (note?.isLaunchBarConfig()) {
2022-11-25 15:29:57 +01:00
if (note) {
if (noteId === "_lbRoot" || noteId === "_lbMobileRoot") {
2022-11-25 15:29:57 +01:00
// deleting hoisted notes are not allowed, so we just reset the children
for (const childNote of note.getChildNotes()) {
childNote.deleteNote();
}
} else {
note.deleteNote();
}
} else {
log.info(`Note ${noteId} has not been found and cannot be reset.`);
}
} else {
2022-12-01 10:16:57 +01:00
log.info(`Note ${noteId} is not a resettable launcher note.`);
2022-11-25 15:29:57 +01:00
}
// the re-building deleted launchers will be done in handlers
2022-11-25 15:29:57 +01:00
}
/**
* This exists to ease transition into the new launchbar, but it's not meant to be a permanent functionality.
* Previously, the launchbar was fixed and the only way to add buttons was through this API, so a lot of buttons have been
* created just to fill this user hole.
*
2022-12-22 14:59:20 +01:00
* Another use case was for script-packages (e.g. demo Task manager) which could this way register automatically/easily
* into the launchbar - for this it's recommended to use backend API's createOrUpdateLauncher()
*/
2025-01-09 18:07:02 +02:00
function createOrUpdateScriptLauncherFromApi(opts: { id: string; title: string; action: string; icon?: string; shortcut?: string }) {
2022-12-22 14:57:00 +01:00
if (opts.id && !/^[a-z0-9]+$/i.test(opts.id)) {
throw new Error(`Launcher ID can be alphanumeric only, '${opts.id}' given`);
}
2025-01-09 18:07:02 +02:00
const launcherId = opts.id || `tb_${opts.title.toLowerCase().replace(/[^[a-z0-9]/gi, "")}`;
if (!opts.title) {
throw new Error("Title is mandatory property to create or update a launcher.");
}
2025-01-09 18:07:02 +02:00
const launcherNote = becca.getNote(launcherId) || createScriptLauncher("_lbVisibleLaunchers", launcherId);
launcherNote.title = opts.title;
launcherNote.setContent(`(${opts.action})()`);
2025-01-09 18:07:02 +02:00
launcherNote.setLabel("scriptInLauncherContent"); // there's no target note, the script is in the launcher's content
launcherNote.mime = "application/javascript;env=frontend";
launcherNote.save();
if (opts.shortcut) {
2025-01-09 18:07:02 +02:00
launcherNote.setLabel("keyboardShortcut", opts.shortcut);
} else {
2025-01-09 18:07:02 +02:00
launcherNote.removeLabel("keyboardShortcut");
}
if (opts.icon) {
2025-01-09 18:07:02 +02:00
launcherNote.setLabel("iconClass", `bx bx-${opts.icon}`);
} else {
2025-01-09 18:07:02 +02:00
launcherNote.removeLabel("iconClass");
}
return launcherNote;
}
export default {
getInboxNote,
createSqlConsole,
saveSqlConsole,
createSearchNote,
saveSearchNote,
2022-12-01 10:16:57 +01:00
createLauncher,
resetLauncher,
createOrUpdateScriptLauncherFromApi
};