Merge branch 'main' of https://github.com/TriliumNext/Trilium into feat/ui-improvements

This commit is contained in:
Adorian Doran 2025-11-02 23:00:20 +02:00
commit e6d2009605
15 changed files with 124 additions and 55 deletions

View File

@ -10,7 +10,7 @@ export const byNoteType: Record<Exclude<NoteType, "book">, string | null> = {
file: null, file: null,
image: null, image: null,
launcher: null, launcher: null,
mermaid: null, mermaid: "s1aBHPd79XYj",
mindMap: null, mindMap: null,
noteMap: null, noteMap: null,
relationMap: null, relationMap: null,

View File

@ -1450,10 +1450,6 @@
"etapi": { "etapi": {
"title": "ETAPI", "title": "ETAPI",
"description": "ETAPI is a REST API used to access Trilium instance programmatically, without UI.", "description": "ETAPI is a REST API used to access Trilium instance programmatically, without UI.",
"see_more": "See more details in the {{- link_to_wiki}} and the {{- link_to_openapi_spec}} or the {{- link_to_swagger_ui }}.",
"wiki": "wiki",
"openapi_spec": "ETAPI OpenAPI spec",
"swagger_ui": "ETAPI Swagger UI",
"create_token": "Create new ETAPI token", "create_token": "Create new ETAPI token",
"existing_tokens": "Existing tokens", "existing_tokens": "Existing tokens",
"no_tokens_yet": "There are no tokens yet. Click on the button above to create one.", "no_tokens_yet": "There are no tokens yet. Click on the button above to create one.",

View File

@ -2,7 +2,7 @@ import type { ComponentChildren } from "preact";
import { CSSProperties } from "preact/compat"; import { CSSProperties } from "preact/compat";
interface OptionsSectionProps { interface OptionsSectionProps {
title?: string; title?: ComponentChildren;
children: ComponentChildren; children: ComponentChildren;
noCard?: boolean; noCard?: boolean;
style?: CSSProperties; style?: CSSProperties;

View File

@ -11,6 +11,7 @@ import dialog from "../../../services/dialog";
import { formatDateTime } from "../../../utils/formatters"; import { formatDateTime } from "../../../utils/formatters";
import ActionButton from "../../react/ActionButton"; import ActionButton from "../../react/ActionButton";
import { useTriliumEvent } from "../../react/hooks"; import { useTriliumEvent } from "../../react/hooks";
import HelpButton from "../../react/HelpButton";
type RenameTokenCallback = (tokenId: string, oldName: string) => Promise<void>; type RenameTokenCallback = (tokenId: string, oldName: string) => Promise<void>;
type DeleteTokenCallback = (tokenId: string, name: string ) => Promise<void>; type DeleteTokenCallback = (tokenId: string, name: string ) => Promise<void>;
@ -48,19 +49,13 @@ export default function EtapiSettings() {
message: t("etapi.token_created_message"), message: t("etapi.token_created_message"),
defaultValue: authToken defaultValue: authToken
}); });
}, []); }, []);
return ( return (
<OptionsSection title={t("etapi.title")}> <OptionsSection title={t("etapi.title")}>
<FormText> <FormText>
{t("etapi.description")}<br /> {t("etapi.description")}
<RawHtml <HelpButton helpPage="pgxEVkzLl1OP" />
html={t("etapi.see_more", {
link_to_wiki: `<a class="tn-link" href="https://triliumnext.github.io/Docs/Wiki/etapi.html">${t("etapi.wiki")}</a>`,
// TODO: We use window.open src/public/app/services/link.ts -> prevents regular click behavior on "a" element here because it's a relative path
link_to_openapi_spec: `<a class="tn-link" onclick="window.open('etapi/etapi.openapi.yaml')" href="etapi/etapi.openapi.yaml">${t("etapi.openapi_spec")}</a>`,
link_to_swagger_ui: `<a class="tn-link" href="#_help_f3xpgx6H01PW">${t("etapi.swagger_ui")}</a>`
})} />
</FormText> </FormText>
<Button <Button
@ -68,6 +63,7 @@ export default function EtapiSettings() {
text={t("etapi.create_token")} text={t("etapi.create_token")}
onClick={createTokenCallback} onClick={createTokenCallback}
/> />
<hr /> <hr />
<h5>{t("etapi.existing_tokens")}</h5> <h5>{t("etapi.existing_tokens")}</h5>
@ -123,7 +119,7 @@ function TokenList({ tokens }: { tokens: EtapiToken[] }) {
text={t("etapi.rename_token")} text={t("etapi.rename_token")}
onClick={() => renameCallback(etapiTokenId, name)} onClick={() => renameCallback(etapiTokenId, name)}
/> />
<ActionButton <ActionButton
icon="bx bx-trash" icon="bx bx-trash"
text={t("etapi.delete_token")} text={t("etapi.delete_token")}

File diff suppressed because one or more lines are too long

View File

@ -1,11 +1,13 @@
<aside class="admonition tip">
<p>For a quick start, consult the&nbsp;<a class="reference-link" href="#root/pgxEVkzLl1OP/_help_9qPsTWBorUhQ">API Reference</a>.</p>
</aside>
<p>ETAPI is Trilium's public/external REST API. It is available since Trilium <p>ETAPI is Trilium's public/external REST API. It is available since Trilium
v0.50.</p> v0.50.</p>
<p>The documentation is in OpenAPI format, available <a href="https://github.com/TriliumNext/Trilium/blob/master/src/etapi/etapi.openapi.yaml">here</a>.</p>
<h2>API clients</h2> <h2>API clients</h2>
<p>As an alternative to calling the API directly, there are client libraries <p>As an alternative to calling the API directly, there are client libraries
to simplify this</p> to simplify this</p>
<ul> <ul>
<li><a href="https://github.com/Nriver/trilium-py">trilium-py</a>, you can <li data-list-item-id="e3342ddfa108f6c8c6c47d7d3da8b02fa"><a href="https://github.com/Nriver/trilium-py">trilium-py</a>, you can
use Python to communicate with Trilium.</li> use Python to communicate with Trilium.</li>
</ul> </ul>
<h2>Obtaining a token</h2> <h2>Obtaining a token</h2>
@ -23,10 +25,10 @@ Authorization: ETAPITOKEN</code></pre>
<p>Since v0.56 you can also use basic auth format:</p><pre><code class="language-text-x-trilium-auto">GET https://myserver.com/etapi/app-info <p>Since v0.56 you can also use basic auth format:</p><pre><code class="language-text-x-trilium-auto">GET https://myserver.com/etapi/app-info
Authorization: Basic BATOKEN</code></pre> Authorization: Basic BATOKEN</code></pre>
<ul> <ul>
<li>Where <code>BATOKEN = BASE64(username + ':' + password)</code> - this is <li data-list-item-id="ec59ac570a3d2a846da38378a5f2428ed">Where <code>BATOKEN = BASE64(username + ':' + password)</code> - this is
a standard Basic Auth serialization</li> a standard Basic Auth serialization</li>
<li>Where <code>username</code> is "etapi"</li> <li data-list-item-id="e18e2e73ebecc949dd4a51cd9f8bb0b91">Where <code>username</code> is "etapi"</li>
<li>And <code>password</code> is the generated ETAPI token described above.</li> <li data-list-item-id="ee892223f95cef4a53caec5477ab31edb">And <code>password</code> is the generated ETAPI token described above.</li>
</ul> </ul>
<p>Basic Auth is meant to be used with tools which support only basic auth.</p> <p>Basic Auth is meant to be used with tools which support only basic auth.</p>
<h2>Interaction using Bash scripts</h2> <h2>Interaction using Bash scripts</h2>
@ -42,10 +44,10 @@ NOTE_ID="i6ra4ZshJhgN"
curl "$SERVER/etapi/notes/$NOTE_ID/content" -H "Authorization: $TOKEN" </code></pre> curl "$SERVER/etapi/notes/$NOTE_ID/content" -H "Authorization: $TOKEN" </code></pre>
<p>Make sure to replace the values of:</p> <p>Make sure to replace the values of:</p>
<ul> <ul>
<li><code>TOKEN</code> with your ETAPI token.</li> <li data-list-item-id="e68020f83acc951e180bb405d149a64a5"><code>TOKEN</code> with your ETAPI token.</li>
<li><code>SERVER</code> with the correct protocol, host name and port to your <li data-list-item-id="ef4c31df5f6d18811e7de0ee8ff95f3a7"><code>SERVER</code> with the correct protocol, host name and port to your
Trilium instance.</li> Trilium instance.</li>
<li><code>NOTE_ID</code> with an existing note ID to download.</li> <li data-list-item-id="e25086bb4c54d32259f987f9366e22204"><code>NOTE_ID</code> with an existing note ID to download.</li>
</ul> </ul>
<p>As another example, to obtain a .zip export of a note and place it in <p>As another example, to obtain a .zip export of a note and place it in
a directory called <code>out</code>, simply replace the last statement in a directory called <code>out</code>, simply replace the last statement in

View File

@ -1,3 +1,8 @@
<aside class="admonition tip">
<p>For a quick understanding of the Mermaid syntax, see&nbsp;<a class="reference-link"
href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/s1aBHPd79XYj/_help_WWgeUaBb7UfC">Syntax reference</a>&nbsp;(official
documentation).</p>
</aside>
<figure class="image image-style-align-center"> <figure class="image image-style-align-center">
<img style="aspect-ratio:886/663;" src="2_Mermaid Diagrams_image.png" <img style="aspect-ratio:886/663;" src="2_Mermaid Diagrams_image.png"
width="886" height="663"> width="886" height="663">
@ -6,14 +11,13 @@
as flowchart, sequence diagram, class diagram, state diagram, pie charts, as flowchart, sequence diagram, class diagram, state diagram, pie charts,
etc., all using a text description of the chart instead of manually drawing etc., all using a text description of the chart instead of manually drawing
the diagram.</p> the diagram.</p>
<p>For the official documentation of Mermaid.js see <a href="https://mermaid.js.org/intro/">mermaid.js.org/intro/</a>.</p>
<h2>Layouts</h2> <h2>Layouts</h2>
<p>Depending on the chart being edited and user preference, there are two <p>Depending on the chart being edited and user preference, there are two
layouts supported by the Mermaid note type:</p> layouts supported by the Mermaid note type:</p>
<ul> <ul>
<li>Horizontal, where the source code (editable part) is on the left side <li data-list-item-id="e5998f20495a1079ee7b6e284dc4d14e4">Horizontal, where the source code (editable part) is on the left side
of the screen and the preview is to the right.</li> of the screen and the preview is to the right.</li>
<li>Vertical, where the source code is at the bottom of the screen and the <li data-list-item-id="ebebfbd8cf2125c70056e3e9075d8681e">Vertical, where the source code is at the bottom of the screen and the
preview is at the top.</li> preview is at the top.</li>
</ul> </ul>
<p>It's possible to switch between the two layouts at any time by pressing <p>It's possible to switch between the two layouts at any time by pressing
@ -21,44 +25,48 @@
<img src="Mermaid Diagrams_image.png">icon in the&nbsp;<a class="reference-link" href="#root/_help_XpOYSgsLkTJy">Floating buttons</a>&nbsp;area.</p> <img src="Mermaid Diagrams_image.png">icon in the&nbsp;<a class="reference-link" href="#root/_help_XpOYSgsLkTJy">Floating buttons</a>&nbsp;area.</p>
<h2>Interaction</h2> <h2>Interaction</h2>
<ul> <ul>
<li>The source code of the diagram (in Mermaid format) is displayed on the <li data-list-item-id="e67d8f093c4793e19e2ade2d58728ae81">The source code of the diagram (in Mermaid format) is displayed on the
left or bottom side of the note (depending on the layout). left or bottom side of the note (depending on the layout).
<ul> <ul>
<li>Changing the diagram code will refresh automatically the diagram.</li> <li data-list-item-id="e4d777ef787093815b961d734021ccc55">Changing the diagram code will refresh automatically the diagram.</li>
</ul> </ul>
</li> </li>
<li>The preview of the diagram is displayed at the right or top side of the <li data-list-item-id="e6faf589831e3252f8cda42f62248377a">The preview of the diagram is displayed at the right or top side of the
note (depending on the layout): note (depending on the layout):
<ul> <ul>
<li>There are dedicated buttons at the bottom-right of the preview to control <li data-list-item-id="e1dc5994137e511eb29657629d9e729a3">There are dedicated buttons at the bottom-right of the preview to control
the zoom in, zoom out or re-center the diagram: the zoom in, zoom out or re-center the diagram:
<img src="1_Mermaid Diagrams_image.png"> <img src="1_Mermaid Diagrams_image.png">
</li> </li>
<li>The preview can be moved around by holding the left mouse button and dragging.</li> <li data-list-item-id="e51812ca016db170ceb6814007a60eb10">The preview can be moved around by holding the left mouse button and dragging.</li>
<li>Zooming can also be done by using the scroll wheel.</li> <li
<li>The zoom and position on the preview will remain fixed as the diagram data-list-item-id="e617128e494ed43ca5d0f5c749a8c9208">Zooming can also be done by using the scroll wheel.</li>
changes, to be able to work more easily with large diagrams.</li> <li data-list-item-id="e7b87c55d329003996861f24d8d162b85">The zoom and position on the preview will remain fixed as the diagram
</ul> changes, to be able to work more easily with large diagrams.</li>
</ul>
</li> </li>
<li>The size of the source/preview panes can be adjusted by hovering over <li data-list-item-id="e11cf4ecd9d2408ce5a46b949dea40b06">The size of the source/preview panes can be adjusted by hovering over
the border between them and dragging it with the mouse.</li> the border between them and dragging it with the mouse.</li>
<li>In the&nbsp;<a class="reference-link" href="#root/_help_XpOYSgsLkTJy">Floating buttons</a>&nbsp;area: <li data-list-item-id="ebc96b0fe8366ef4e00561de1c866d53b">In the&nbsp;<a class="reference-link" href="#root/_help_XpOYSgsLkTJy">Floating buttons</a>&nbsp;area:
<ul> <ul>
<li>The source/preview can be laid out left-right or bottom-top via the <em>Move editing pane to the left / bottom</em> option.</li> <li data-list-item-id="e12f31dc31db3c8be1fe87822ca2f451e">The source/preview can be laid out left-right or bottom-top via the <em>Move editing pane to the left / bottom</em> option.</li>
<li>Press <em>Lock editing</em> to automatically mark the note as read-only. <li
data-list-item-id="ed29e7616e6c77105103a68b1e8a6f7b3">Press <em>Lock editing</em> to automatically mark the note as read-only.
In this mode, the code pane is hidden and the diagram is displayed full-size. In this mode, the code pane is hidden and the diagram is displayed full-size.
Similarly, press <em>Unlock editing</em> to mark a read-only note as editable.</li> Similarly, press <em>Unlock editing</em> to mark a read-only note as editable.</li>
<li>Press the <em>Copy image reference to the clipboard</em> to be able to insert <li
the image representation of the diagram into a text note. See&nbsp;<a class="reference-link" data-list-item-id="e2bc7d5d8d1f8f02e61a6d86a3faae3b4">Press the <em>Copy image reference to the clipboard</em> to be able to insert
href="#root/_help_0Ofbk1aSuVRu">Image references</a>&nbsp;for more information.</li> the image representation of the diagram into a text note. See&nbsp;<a class="reference-link"
<li>Press the <em>Export diagram as SVG</em> to download a scalable/vector rendering href="#root/_help_0Ofbk1aSuVRu">Image references</a>&nbsp;for more information.</li>
of the diagram. Can be used to present the diagram without degrading when <li
zooming.</li> data-list-item-id="ecaac01dc52bce394f720be2826e82026">Press the <em>Export diagram as SVG</em> to download a scalable/vector rendering
<li>Press the <em>Export diagram as PNG</em> to download a normal image (at of the diagram. Can be used to present the diagram without degrading when
zooming.</li>
<li data-list-item-id="e9c815090884a394d60e06628b9e38add">Press the <em>Export diagram as PNG</em> to download a normal image (at
1x scale, raster) of the diagram. Can be used to send the diagram in more 1x scale, raster) of the diagram. Can be used to send the diagram in more
traditional channels such as e-mail.</li> traditional channels such as e-mail.</li>
</ul> </ul>
</li> </li>
</ul> </ul>
<h2>Errors in the diagram</h2> <h2>Errors in the diagram</h2>
<p>If there is an error in the source code, the error will be displayed in <p>If there is an error in the source code, the error will be displayed in

View File

@ -98,6 +98,21 @@ describe("Hidden Subtree", () => {
expect(updatedBoardTemplate?.title).not.toBe("My renamed board"); expect(updatedBoardTemplate?.title).not.toBe("My renamed board");
}); });
it("enforces webviewSrc of templates", () => {
const apiRefNote = becca.getNote("_help_9qPsTWBorUhQ");
expect(apiRefNote).toBeDefined();
cls.init(() => {
apiRefNote!.setAttribute("label", "webViewSrc", "foo");
apiRefNote!.save();
hiddenSubtreeService.checkHiddenSubtree(true);
});
const updatedApiRefNote = becca.getNote("_help_9qPsTWBorUhQ");
expect(updatedApiRefNote).toBeDefined();
expect(updatedApiRefNote?.getLabelValue("webViewSrc")).not.toBe("foo");
});
it("maintains launchers hidden, if they were shown by default but moved by the user", () => { it("maintains launchers hidden, if they were shown by default but moved by the user", () => {
const launcher = becca.getNote("_lbLlmChat"); const launcher = becca.getNote("_lbLlmChat");
const branch = launcher?.getParentBranches()[0]; const branch = launcher?.getParentBranches()[0];

View File

@ -451,8 +451,16 @@ function checkHiddenSubtreeRecursively(parentNoteId: string, item: HiddenSubtree
// Enforce attribute structure if needed. // Enforce attribute structure if needed.
if (item.enforceAttributes) { if (item.enforceAttributes) {
for (const attribute of note.getAttributes()) { for (const attribute of note.getAttributes()) {
if (!attrs.some(a => a.name === attribute.name)) { // Remove unwanted attributes.
const attrDef = attrs.find(a => a.name === attribute.name);
if (!attrDef) {
attribute.markAsDeleted(); attribute.markAsDeleted();
continue;
}
// Ensure value is consistent.
if (attribute.value !== attrDef.value) {
note.setAttributeValueById(attribute.attributeId, attrDef.value);
} }
} }
} }

View File

@ -78,6 +78,7 @@ export function parseNoteMeta(noteMeta: NoteMeta, docNameRoot: string): HiddenSu
// Handle web views // Handle web views
if (noteMeta.type === "webView") { if (noteMeta.type === "webView") {
item.type = "webView"; item.type = "webView";
item.enforceAttributes = true;
} }
// Handle children // Handle children

View File

@ -8838,6 +8838,13 @@
"value": "bx bx-selection", "value": "bx bx-selection",
"isInheritable": false, "isInheritable": false,
"position": 20 "position": 20
},
{
"type": "relation",
"name": "internalLink",
"value": "WWgeUaBb7UfC",
"isInheritable": false,
"position": 30
} }
], ],
"format": "markdown", "format": "markdown",
@ -8921,6 +8928,33 @@
"dataFileName": "ELK layout_ELK on.svg" "dataFileName": "ELK layout_ELK on.svg"
} }
] ]
},
{
"isClone": false,
"noteId": "WWgeUaBb7UfC",
"notePath": [
"pOsGYCXsbNQG",
"KSZ04uQ2D1St",
"s1aBHPd79XYj",
"WWgeUaBb7UfC"
],
"title": "Syntax reference",
"notePosition": 40,
"prefix": null,
"isExpanded": false,
"type": "webView",
"mime": "",
"attributes": [
{
"type": "label",
"name": "webViewSrc",
"value": "https://mermaid.js.org/intro/syntax-reference.html",
"isInheritable": false,
"position": 10
}
],
"dataFileName": "Syntax reference.dat",
"attachments": []
} }
] ]
}, },
@ -12568,6 +12602,13 @@
"value": "bx bx-extension", "value": "bx bx-extension",
"isInheritable": false, "isInheritable": false,
"position": 30 "position": 30
},
{
"type": "relation",
"name": "internalLink",
"value": "9qPsTWBorUhQ",
"isInheritable": false,
"position": 40
} }
], ],
"format": "markdown", "format": "markdown",

View File

@ -1,7 +1,8 @@
# ETAPI (REST API) # ETAPI (REST API)
ETAPI is Trilium's public/external REST API. It is available since Trilium v0.50. > [!TIP]
> For a quick start, consult the <a class="reference-link" href="ETAPI%20(REST%20API)/API%20Reference.dat">API Reference</a>.
The documentation is in OpenAPI format, available [here](https://github.com/TriliumNext/Trilium/blob/master/src/etapi/etapi.openapi.yaml). ETAPI is Trilium's public/external REST API. It is available since Trilium v0.50.
## API clients ## API clients

View File

@ -1,10 +1,11 @@
# Mermaid Diagrams # Mermaid Diagrams
> [!TIP]
> For a quick understanding of the Mermaid syntax, see <a class="reference-link" href="Mermaid%20Diagrams/Syntax%20reference.dat">Syntax reference</a> (official documentation).
<figure class="image image-style-align-center"><img style="aspect-ratio:886/663;" src="2_Mermaid Diagrams_image.png" width="886" height="663"></figure> <figure class="image image-style-align-center"><img style="aspect-ratio:886/663;" src="2_Mermaid Diagrams_image.png" width="886" height="663"></figure>
Trilium supports Mermaid, which adds support for various diagrams such as flowchart, sequence diagram, class diagram, state diagram, pie charts, etc., all using a text description of the chart instead of manually drawing the diagram. Trilium supports Mermaid, which adds support for various diagrams such as flowchart, sequence diagram, class diagram, state diagram, pie charts, etc., all using a text description of the chart instead of manually drawing the diagram.
For the official documentation of Mermaid.js see [mermaid.js.org/intro/](https://mermaid.js.org/intro/).
## Layouts ## Layouts
Depending on the chart being edited and user preference, there are two layouts supported by the Mermaid note type: Depending on the chart being edited and user preference, there are two layouts supported by the Mermaid note type: