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..5d31ae518 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,7 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
+