diff --git a/apps/client/src/components/app_context.ts b/apps/client/src/components/app_context.ts index 23924edcb..c73fe5a42 100644 --- a/apps/client/src/components/app_context.ts +++ b/apps/client/src/components/app_context.ts @@ -329,6 +329,7 @@ export type CommandMappings = { exportAsPdf: CommandData; openNoteExternally: CommandData; openNoteCustom: CommandData; + openNoteOnServer: CommandData; renderActiveNote: CommandData; unhoist: CommandData; reloadFrontendApp: CommandData; diff --git a/apps/client/src/components/root_command_executor.ts b/apps/client/src/components/root_command_executor.ts index a2d62eddd..4a1c987f7 100644 --- a/apps/client/src/components/root_command_executor.ts +++ b/apps/client/src/components/root_command_executor.ts @@ -66,6 +66,13 @@ export default class RootCommandExecutor extends Component { } } + openNoteOnServerCommand() { + const noteId = appContext.tabManager.getActiveContextNoteId(); + if (noteId) { + openService.openNoteOnServer(noteId); + } + } + enterProtectedSessionCommand() { protectedSessionService.enterProtectedSession(); } diff --git a/apps/client/src/services/open.ts b/apps/client/src/services/open.ts index 783fcee48..1e5513c86 100644 --- a/apps/client/src/services/open.ts +++ b/apps/client/src/services/open.ts @@ -1,4 +1,5 @@ import utils from "./utils.js"; +import options from "./options.js"; import server from "./server.js"; type ExecFunction = (command: string, cb: (err: string, stdout: string, stderror: string) => void) => void; @@ -171,6 +172,21 @@ function getHost() { return `${url.protocol}//${url.hostname}:${url.port}`; } +async function openNoteOnServer(noteId: string) { + // Get the sync server host from options + const syncServerHost = options.get("syncServerHost"); + + if (!syncServerHost) { + console.error("No sync server host configured"); + return; + } + + const url = new URL(`#root/${noteId}`, syncServerHost).toString(); + + // Use window.open to ensure link opens in external browser in Electron + window.open(url, '_blank', 'noopener,noreferrer'); +} + async function openDirectory(directory: string) { try { if (utils.isElectron()) { @@ -198,5 +214,6 @@ export default { openAttachmentExternally, openNoteCustom, openAttachmentCustom, + openNoteOnServer, openDirectory }; diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 4d2be0ef9..ef9605d5e 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -682,6 +682,7 @@ "open_note_externally": "Open note externally", "open_note_externally_title": "File will be open in an external application and watched for changes. You'll then be able to upload the modified version back to Trilium.", "open_note_custom": "Open note custom", + "open_note_on_server": "Open note on server", "import_files": "Import files", "export_note": "Export note", "delete_note": "Delete note", diff --git a/apps/client/src/widgets/ribbon/NoteActions.tsx b/apps/client/src/widgets/ribbon/NoteActions.tsx index e35284ad4..cbd3bf406 100644 --- a/apps/client/src/widgets/ribbon/NoteActions.tsx +++ b/apps/client/src/widgets/ribbon/NoteActions.tsx @@ -5,6 +5,7 @@ import { ParentComponent } from "../react/react_utils"; import { t } from "../../services/i18n" import { useContext } from "preact/hooks"; import { useIsNoteReadOnly } from "../react/hooks"; +import { useTriliumOption } from "../react/hooks"; import ActionButton from "../react/ActionButton" import appContext, { CommandNames } from "../../components/app_context"; import branches from "../../services/branches"; @@ -53,6 +54,7 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not const isMac = getIsMac(); const hasSource = ["text", "code", "relationMap", "mermaid", "canvas", "mindMap", "aiChat"].includes(note.type); const isSearchOrBook = ["search", "book"].includes(note.type); + const [ syncServerHost ] = useTriliumOption("syncServerHost"); const {isReadOnly, enableEditing} = useIsNoteReadOnly(note, noteContext); return ( @@ -68,7 +70,7 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not command={() => enableEditing()} /> } - + {canBeConvertedToAttachment && } {note.type === "render" && } @@ -90,6 +92,9 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not + {(syncServerHost && isElectron) && + + }