refactor(url -> link): let link refer to url and path.

before there was polysemy in word url that is now resolved by making
link hypernym to url and path.
This commit is contained in:
Jakob Schlanstedt 2025-11-21 09:55:03 +01:00
parent 71b3ad5027
commit eca5a4a072
16 changed files with 50 additions and 49 deletions

View File

@ -25,7 +25,7 @@ import TouchBarComponent from "./touch_bar.js";
import type { CKTextEditor } from "@triliumnext/ckeditor5"; import type { CKTextEditor } from "@triliumnext/ckeditor5";
import type CodeMirror from "@triliumnext/codemirror"; import type CodeMirror from "@triliumnext/codemirror";
import { StartupChecks } from "./startup_checks.js"; import { StartupChecks } from "./startup_checks.js";
import type { CreateNoteOpts, CreateNoteWithUrlOpts } from "../services/note_create.js"; import type { CreateNoteOpts, CreateNoteWithLinkOpts } from "../services/note_create.js";
import { ColumnComponent } from "tabulator-tables"; import { ColumnComponent } from "tabulator-tables";
import { ChooseNoteTypeCallback } from "../widgets/dialogs/note_type_chooser.jsx"; import { ChooseNoteTypeCallback } from "../widgets/dialogs/note_type_chooser.jsx";
import type RootContainer from "../widgets/containers/root_container.js"; import type RootContainer from "../widgets/containers/root_container.js";
@ -359,7 +359,7 @@ export type CommandMappings = {
// Table view // Table view
addNewRow: CommandData & { addNewRow: CommandData & {
customOpts?: CreateNoteWithUrlOpts; customOpts?: CreateNoteWithLinkOpts;
}; };
addNewTableColumn: CommandData & { addNewTableColumn: CommandData & {
columnToEdit?: ColumnComponent; columnToEdit?: ColumnComponent;

View File

@ -51,7 +51,7 @@ export default class MainTreeExecutors extends Component {
await noteCreateService.createNote( await noteCreateService.createNote(
{ {
target: "into", target: "into",
parentNoteUrl: activeNoteContext.notePath, parentNoteLink: activeNoteContext.notePath,
isProtected: activeNoteContext.note.isProtected, isProtected: activeNoteContext.note.isProtected,
saveSelection: false, saveSelection: false,
promptForType: false, promptForType: false,
@ -80,7 +80,7 @@ export default class MainTreeExecutors extends Component {
await noteCreateService.createNote( await noteCreateService.createNote(
{ {
target: "after", target: "after",
parentNoteUrl: parentNotePath, parentNoteLink: parentNotePath,
targetBranchId: node.data.branchId, targetBranchId: node.data.branchId,
isProtected: isProtected, isProtected: isProtected,
saveSelection: false saveSelection: false

View File

@ -45,7 +45,7 @@ export default class RootCommandExecutor extends Component {
} }
async searchInSubtreeCommand({ notePath }: CommandListenerData<"searchInSubtree">) { async searchInSubtreeCommand({ notePath }: CommandListenerData<"searchInSubtree">) {
const noteId = treeService.getNoteIdFromUrl(notePath); const noteId = treeService.getNoteIdFromLink(notePath);
this.searchNotesCommand({ ancestorNoteId: noteId }); this.searchNotesCommand({ ancestorNoteId: noteId });
} }
@ -242,7 +242,7 @@ export default class RootCommandExecutor extends Component {
const result = await noteCreateService.createNote( const result = await noteCreateService.createNote(
{ {
parentNoteUrl: rootNoteId, parentNoteLink: rootNoteId,
target: "into", target: "into",
title: "New AI Chat", title: "New AI Chat",
type: "aiChat", type: "aiChat",

View File

@ -74,10 +74,10 @@ export default class TabManager extends Component {
// preload all notes at once // preload all notes at once
await froca.getNotes([...noteContextsToOpen.flatMap((tab: NoteContextState) => await froca.getNotes([...noteContextsToOpen.flatMap((tab: NoteContextState) =>
[treeService.getNoteIdFromUrl(tab.notePath), tab.hoistedNoteId])], true); [treeService.getNoteIdFromLink(tab.notePath), tab.hoistedNoteId])], true);
const filteredNoteContexts = noteContextsToOpen.filter((openTab: NoteContextState) => { const filteredNoteContexts = noteContextsToOpen.filter((openTab: NoteContextState) => {
const noteId = treeService.getNoteIdFromUrl(openTab.notePath); const noteId = treeService.getNoteIdFromLink(openTab.notePath);
if (!noteId || !(noteId in froca.notes)) { if (!noteId || !(noteId in froca.notes)) {
// note doesn't exist so don't try to open tab for it // note doesn't exist so don't try to open tab for it
return false; return false;

View File

@ -287,7 +287,7 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
noteCreateService.createNote( noteCreateService.createNote(
{ {
target: "after", target: "after",
parentNoteUrl: parentNotePath, parentNoteLink: parentNotePath,
targetBranchId: this.node.data.branchId, targetBranchId: this.node.data.branchId,
type: type, type: type,
isProtected: isProtected, isProtected: isProtected,
@ -301,7 +301,7 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
noteCreateService.createNote( noteCreateService.createNote(
{ {
target: "into", target: "into",
parentNoteUrl: parentNotePath, parentNoteLink: parentNotePath,
type: type, type: type,
isProtected: this.node.data.isProtected, isProtected: this.node.data.isProtected,
templateNoteId: templateNoteId, templateNoteId: templateNoteId,

View File

@ -50,7 +50,7 @@ async function checkNoteAccess(notePath: string, noteContext: NoteContext) {
const hoistedNoteId = noteContext.hoistedNoteId; const hoistedNoteId = noteContext.hoistedNoteId;
if (!resolvedNotePath.includes(hoistedNoteId) && (!resolvedNotePath.includes("_hidden") || resolvedNotePath.includes("_lbBookmarks"))) { if (!resolvedNotePath.includes(hoistedNoteId) && (!resolvedNotePath.includes("_hidden") || resolvedNotePath.includes("_lbBookmarks"))) {
const noteId = treeService.getNoteIdFromUrl(resolvedNotePath); const noteId = treeService.getNoteIdFromLink(resolvedNotePath);
if (!noteId) { if (!noteId) {
return false; return false;
} }

View File

@ -261,7 +261,7 @@ export function parseNavigationStateFromUrl(url: string | undefined) {
return { return {
notePath, notePath,
noteId: treeService.getNoteIdFromUrl(notePath), noteId: treeService.getNoteIdFromLink(notePath),
ntxId, ntxId,
hoistedNoteId, hoistedNoteId,
viewScope, viewScope,

View File

@ -84,25 +84,26 @@ type CreateNoteBase = {
* Serves as a base for "into", "before", and "after" variants, * Serves as a base for "into", "before", and "after" variants,
* sharing common URL-related fields. * sharing common URL-related fields.
*/ */
export type CreateNoteWithUrlOpts = export type CreateNoteWithLinkOpts =
| (CreateNoteBase & { | (CreateNoteBase & {
target: "into"; target: "into";
parentNoteUrl?: string; parentNoteLink?: string;
// No branch ID needed for "into" // No branch ID needed for "into"
}) })
| (CreateNoteBase & { | (CreateNoteBase & {
target: "before" | "after"; target: "before" | "after";
parentNoteUrl?: string; // Either an Url or a Path
parentNoteLink?: string;
// Required for "before"/"after" // Required for "before"/"after"
targetBranchId: string; targetBranchId: string;
}); });
export type CreateNoteIntoDefaultOpts = CreateNoteBase & { export type CreateNoteIntoDefaultOpts = CreateNoteBase & {
target: "default"; target: "default";
parentNoteUrl?: never; parentNoteLink?: never;
}; };
export type CreateNoteOpts = CreateNoteWithUrlOpts | CreateNoteIntoDefaultOpts; export type CreateNoteOpts = CreateNoteWithLinkOpts | CreateNoteIntoDefaultOpts;
interface Response { interface Response {
// TODO: Deduplicate with server once we have client/server architecture. // TODO: Deduplicate with server once we have client/server architecture.
@ -139,7 +140,7 @@ async function createNote(
case "into": case "into":
case "before": case "before":
case "after": case "after":
return createNoteWithUrl(resolvedOptions); return createNoteWithLink(resolvedOptions);
} }
} }
@ -148,7 +149,7 @@ async function createNoteFromAction(
action: CreateNoteAction, action: CreateNoteAction,
promptForType: boolean, promptForType: boolean,
title: string | undefined, title: string | undefined,
parentNoteUrl: string | undefined, parentNoteLink: string | undefined,
): Promise<{ note: FNote | null; branch: FBranch | undefined }> { ): Promise<{ note: FNote | null; branch: FBranch | undefined }> {
switch (action) { switch (action) {
case CreateNoteAction.CreateNote: { case CreateNoteAction.CreateNote: {
@ -174,7 +175,7 @@ async function createNoteFromAction(
return resp; return resp;
} }
case CreateNoteAction.CreateChildNote: { case CreateNoteAction.CreateChildNote: {
if (!parentNoteUrl) { if (!parentNoteLink) {
console.warn("Missing parentNotePath in createNoteFromCkEditor()"); console.warn("Missing parentNotePath in createNoteFromCkEditor()");
return { note: null, branch: undefined }; return { note: null, branch: undefined };
} }
@ -182,7 +183,7 @@ async function createNoteFromAction(
const resp = await createNote( const resp = await createNote(
{ {
target: "into", target: "into",
parentNoteUrl, parentNoteLink,
title, title,
activate: true, activate: true,
promptForType: true, promptForType: true,
@ -191,14 +192,14 @@ async function createNoteFromAction(
return resp return resp
} }
case CreateNoteAction.CreateAndLinkChildNote: { case CreateNoteAction.CreateAndLinkChildNote: {
if (!parentNoteUrl) { if (!parentNoteLink) {
console.warn("Missing parentNotePath in createNoteFromCkEditor()"); console.warn("Missing parentNotePath in createNoteFromCkEditor()");
return { note: null, branch: undefined }; return { note: null, branch: undefined };
} }
const resp = await createNote( const resp = await createNote(
{ {
target: "into", target: "into",
parentNoteUrl: parentNoteUrl, parentNoteLink: parentNoteLink,
title, title,
activate: false, activate: false,
promptForType: promptForType, promptForType: promptForType,
@ -233,7 +234,7 @@ async function promptForType(
resolvedOptions = { resolvedOptions = {
...resolvedOptions, ...resolvedOptions,
target: "into", target: "into",
parentNoteUrl: notePath, parentNoteLink: notePath,
}; };
} }
@ -247,8 +248,8 @@ async function promptForType(
* @param options - Note creation options * @param options - Note creation options
* @returns A promise resolving with the created note and its branch. * @returns A promise resolving with the created note and its branch.
*/ */
async function createNoteWithUrl( async function createNoteWithLink(
options: CreateNoteWithUrlOpts options: CreateNoteWithLinkOpts
): Promise<{ note: FNote | null; branch: FBranch | undefined }> { ): Promise<{ note: FNote | null; branch: FBranch | undefined }> {
options = Object.assign( options = Object.assign(
{ {
@ -273,8 +274,8 @@ async function createNoteWithUrl(
[options.title, options.content] = parseSelectedHtml(options.textEditor.getSelectedHtml()); [options.title, options.content] = parseSelectedHtml(options.textEditor.getSelectedHtml());
} }
const parentNoteUrl = options.parentNoteUrl; const parentNoteLink = options.parentNoteLink;
const parentNoteId = treeService.getNoteIdFromUrl(parentNoteUrl); const parentNoteId = treeService.getNoteIdFromLink(parentNoteLink);
if (options.type === "mermaid" && !options.content && !options.templateNoteId) { if (options.type === "mermaid" && !options.content && !options.templateNoteId) {
options.content = `graph TD; options.content = `graph TD;
@ -348,11 +349,11 @@ async function createNoteIntoDefaultLocation(
inboxNote.isProtected && protectedSessionHolder.isProtectedSessionAvailable(); inboxNote.isProtected && protectedSessionHolder.isProtectedSessionAvailable();
} }
const result = await createNoteWithUrl( const result = await createNoteWithLink(
{ {
...options, ...options,
target: "into", target: "into",
parentNoteUrl: inboxNote.noteId, parentNoteLink: inboxNote.noteId,
} }
); );
@ -385,7 +386,7 @@ function parseSelectedHtml(selectedHtml: string) {
} }
async function duplicateSubtree(noteId: string, parentNotePath: string) { async function duplicateSubtree(noteId: string, parentNotePath: string) {
const parentNoteId = treeService.getNoteIdFromUrl(parentNotePath); const parentNoteId = treeService.getNoteIdFromLink(parentNotePath);
const { note } = await server.post<DuplicateResponse>(`notes/${noteId}/duplicate/${parentNoteId}`); const { note } = await server.post<DuplicateResponse>(`notes/${noteId}/duplicate/${parentNoteId}`);
await ws.waitForMaxKnownEntityChangeId(); await ws.waitForMaxKnownEntityChangeId();

View File

@ -92,7 +92,7 @@ async function resolveNotePathToSegments(notePath: string, hoistedNoteId = "root
if (effectivePathSegments.includes(hoistedNoteId) && effectivePathSegments.includes('root')) { if (effectivePathSegments.includes(hoistedNoteId) && effectivePathSegments.includes('root')) {
return effectivePathSegments; return effectivePathSegments;
} else { } else {
const noteId = getNoteIdFromUrl(notePath); const noteId = getNoteIdFromLink(notePath);
if (!noteId) { if (!noteId) {
throw new Error(`Unable to find note with ID: ${noteId}.`); throw new Error(`Unable to find note with ID: ${noteId}.`);
} }
@ -129,7 +129,7 @@ function getParentProtectedStatus(node: Fancytree.FancytreeNode) {
return hoistedNoteService.isHoistedNode(node) ? false : node.getParent().data.isProtected; return hoistedNoteService.isHoistedNode(node) ? false : node.getParent().data.isProtected;
} }
function getNoteIdFromUrl(urlOrNotePath: string | null | undefined) { function getNoteIdFromLink(urlOrNotePath: string | null | undefined) {
if (!urlOrNotePath) { if (!urlOrNotePath) {
return null; return null;
} }
@ -306,7 +306,7 @@ export default {
getParentProtectedStatus, getParentProtectedStatus,
getNotePath, getNotePath,
getNotePathTitleComponents, getNotePathTitleComponents,
getNoteIdFromUrl, getNoteIdFromLink,
getNoteIdAndParentIdFromUrl, getNoteIdAndParentIdFromUrl,
getBranchIdFromUrl, getBranchIdFromUrl,
getNoteTitle, getNoteTitle,

View File

@ -41,7 +41,7 @@ export default class BoardApi {
// Create a new note as a child of the parent note // Create a new note as a child of the parent note
const { note: newNote, branch: newBranch } = await note_create.createNote({ const { note: newNote, branch: newBranch } = await note_create.createNote({
target: "into", target: "into",
parentNoteUrl: parentNotePath, parentNoteLink: parentNotePath,
activate: false, activate: false,
title, title,
}); });
@ -146,7 +146,7 @@ export default class BoardApi {
const { note, branch } = await note_create.createNote( const { note, branch } = await note_create.createNote(
{ {
target: direction, target: direction,
parentNoteUrl: this.parentNote.noteId, parentNoteLink: this.parentNote.noteId,
activate: false, activate: false,
targetBranchId: relativeToBranchId, targetBranchId: relativeToBranchId,
title: t("board_view.new-item"), title: t("board_view.new-item"),

View File

@ -182,7 +182,7 @@ export function showRowContextMenu(parentComponent: Component, e: MouseEvent, ro
enabled: !sorters.length, enabled: !sorters.length,
handler: () => parentComponent?.triggerCommand("addNewRow", { handler: () => parentComponent?.triggerCommand("addNewRow", {
customOpts: { customOpts: {
parentNoteUrl: parentNoteId, parentNoteLink: parentNoteId,
target: "before", target: "before",
targetBranchId: rowData.branchId, targetBranchId: rowData.branchId,
} }
@ -199,7 +199,7 @@ export function showRowContextMenu(parentComponent: Component, e: MouseEvent, ro
} }
parentComponent?.triggerCommand("addNewRow", { parentComponent?.triggerCommand("addNewRow", {
customOpts: { customOpts: {
parentNoteUrl: note.noteId, parentNoteLink: note.noteId,
target: "after", target: "after",
targetBranchId: branchId, targetBranchId: branchId,
} }
@ -212,7 +212,7 @@ export function showRowContextMenu(parentComponent: Component, e: MouseEvent, ro
enabled: !sorters.length, enabled: !sorters.length,
handler: () => parentComponent?.triggerCommand("addNewRow", { handler: () => parentComponent?.triggerCommand("addNewRow", {
customOpts: { customOpts: {
parentNoteUrl: parentNoteId, parentNoteLink: parentNoteId,
target: "after", target: "after",
targetBranchId: rowData.branchId, targetBranchId: rowData.branchId,
} }

View File

@ -21,9 +21,9 @@ export default function useRowTableEditing(api: RefObject<Tabulator>, attributeD
}; };
} }
const noteUrl = customOpts.parentNoteUrl ?? parentNotePath; const noteUrl = customOpts.parentNoteLink ?? parentNotePath;
if (noteUrl) { if (noteUrl) {
customOpts.parentNoteUrl = noteUrl; customOpts.parentNoteLink = noteUrl;
customOpts.activate = false; customOpts.activate = false;
note_create.createNote(customOpts).then(({ branch }) => { note_create.createNote(customOpts).then(({ branch }) => {
if (branch) { if (branch) {

View File

@ -58,7 +58,7 @@ export default function AddLinkDialog() {
} }
if (suggestion.notePath) { if (suggestion.notePath) {
const noteId = tree.getNoteIdFromUrl(suggestion.notePath); const noteId = tree.getNoteIdFromLink(suggestion.notePath);
if (noteId) { if (noteId) {
setDefaultLinkTitle(noteId); setDefaultLinkTitle(noteId);
} }

View File

@ -70,8 +70,8 @@ export default function IncludeNoteDialog() {
) )
} }
async function includeNote(notePath: string, editorApi: CKEditorApi, boxSize: BoxSize) { async function includeNote(notePath: string, textTypeWidget: EditableTextTypeWidget, boxSize: BoxSize) {
const noteId = tree.getNoteIdFromUrl(notePath); const noteId = tree.getNoteIdFromLink(notePath);
if (!noteId) { if (!noteId) {
return; return;
} }

View File

@ -34,7 +34,7 @@ export default function MobileDetailMenu() {
if (parentNoteUrl) { if (parentNoteUrl) {
note_create.createNote({ note_create.createNote({
target: "into", target: "into",
parentNoteUrl, parentNoteLink: parentNoteUrl,
}); });
} }
} else if (command === "delete") { } else if (command === "delete") {

View File

@ -227,7 +227,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
noteCreateService.createNote( noteCreateService.createNote(
{ {
target: "into", target: "into",
parentNoteUrl: parentNotePath, parentNoteLink: parentNotePath,
isProtected: node.data.isProtected isProtected: node.data.isProtected
}, },
); );
@ -1409,10 +1409,10 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
let node: Fancytree.FancytreeNode | null | undefined = await this.expandToNote(activeNotePath, false); let node: Fancytree.FancytreeNode | null | undefined = await this.expandToNote(activeNotePath, false);
if (node && node.data.noteId !== treeService.getNoteIdFromUrl(activeNotePath)) { if (node && node.data.noteId !== treeService.getNoteIdFromLink(activeNotePath)) {
// if the active note has been moved elsewhere then it won't be found by the path, // if the active note has been moved elsewhere then it won't be found by the path,
// so we switch to the alternative of trying to find it by noteId // so we switch to the alternative of trying to find it by noteId
const noteId = treeService.getNoteIdFromUrl(activeNotePath); const noteId = treeService.getNoteIdFromLink(activeNotePath);
if (noteId) { if (noteId) {
const notesById = this.getNodesByNoteId(noteId); const notesById = this.getNodesByNoteId(noteId);
@ -1845,7 +1845,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
noteCreateService.createNote( noteCreateService.createNote(
{ {
target: "into", target: "into",
parentNoteUrl: notePath, parentNoteLink: notePath,
isProtected: node.data.isProtected isProtected: node.data.isProtected
} }
) )