Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot]
a95e29984c chore(deps): update dependency supertest to v7.2.2 2026-01-08 16:23:04 +00:00
26 changed files with 178 additions and 596 deletions

View File

@@ -11,14 +11,6 @@ concurrency:
cancel-in-progress: true
jobs:
sanity-check:
name: Sanity Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Check version consistency
run: pnpm tsx ${{ github.workspace }}/scripts/check-version-consistency.ts ${{ github.ref_name }}
make-electron:
name: Make Electron
strategy:

View File

@@ -1,6 +1,6 @@
{
"name": "@triliumnext/client",
"version": "0.101.3",
"version": "0.101.1",
"description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)",
"private": true,
"license": "AGPL-3.0-only",

View File

@@ -23,12 +23,6 @@ export interface RenderOptions {
imageHasZoom?: boolean;
/** If enabled, it will prevent the default behavior in which an empty note would display a list of children. */
noChildrenList?: boolean;
/** If enabled, it will prevent rendering of included notes. */
noIncludedNotes?: boolean;
/** If enabled, it will include archived notes when rendering children list. */
includeArchivedNotes?: boolean;
/** Set of note IDs that have already been seen during rendering to prevent infinite recursion. */
seenNoteIds?: Set<string>;
}
const CODE_MIME_TYPES = new Set(["application/json"]);

View File

@@ -1,132 +0,0 @@
import { trimIndentation } from "@triliumnext/commons";
import { describe, expect, it } from "vitest";
import { buildNote } from "../test/easy-froca";
import renderText from "./content_renderer_text";
describe("Text content renderer", () => {
it("renders included note", async () => {
const contentEl = document.createElement("div");
const includedNote = buildNote({
title: "Included note",
content: "<p>This is the included note.</p>"
});
const note = buildNote({
title: "New note",
content: trimIndentation`
<p>
Hi there
</p>
<section class="include-note" data-note-id="${includedNote.noteId}" data-box-size="medium">
&nbsp;
</section>
`
});
await renderText(note, $(contentEl));
expect(contentEl.querySelectorAll("section.include-note").length).toBe(1);
expect(contentEl.querySelectorAll("section.include-note p").length).toBe(1);
});
it("skips rendering included note", async () => {
const contentEl = document.createElement("div");
const includedNote = buildNote({
title: "Included note",
content: "<p>This is the included note.</p>"
});
const note = buildNote({
title: "New note",
content: trimIndentation`
<p>
Hi there
</p>
<section class="include-note" data-note-id="${includedNote.noteId}" data-box-size="medium">
&nbsp;
</section>
`
});
await renderText(note, $(contentEl), { noIncludedNotes: true });
expect(contentEl.querySelectorAll("section.include-note").length).toBe(0);
});
it("doesn't enter infinite loop on direct recursion", async () => {
const contentEl = document.createElement("div");
const note = buildNote({
title: "New note",
id: "Y7mBwmRjQyb4",
content: trimIndentation`
<p>
Hi there
</p>
<section class="include-note" data-note-id="Y7mBwmRjQyb4" data-box-size="medium">
&nbsp;
</section>
<section class="include-note" data-note-id="Y7mBwmRjQyb4" data-box-size="medium">
&nbsp;
</section>
`
});
await renderText(note, $(contentEl));
expect(contentEl.querySelectorAll("section.include-note").length).toBe(0);
});
it("doesn't enter infinite loop on indirect recursion", async () => {
const contentEl = document.createElement("div");
buildNote({
id: "first",
title: "Included note",
content: trimIndentation`\
<p>This is the included note.</p>
<section class="include-note" data-note-id="second" data-box-size="medium">
&nbsp;
</section>
`
});
const note = buildNote({
id: "second",
title: "New note",
content: trimIndentation`
<p>
Hi there
</p>
<section class="include-note" data-note-id="first" data-box-size="medium">
&nbsp;
</section>
`
});
await renderText(note, $(contentEl));
expect(contentEl.querySelectorAll("section.include-note").length).toBe(1);
});
it("renders children list when note is empty", async () => {
const contentEl = document.createElement("div");
const parentNote = buildNote({
title: "Parent note",
children: [
{ title: "Child note 1" },
{ title: "Child note 2" }
]
});
await renderText(parentNote, $(contentEl));
const items = contentEl.querySelectorAll("a");
expect(items.length).toBe(2);
expect(items[0].textContent).toBe("Child note 1");
expect(items[1].textContent).toBe("Child note 2");
});
it("skips archived notes in children list", async () => {
const contentEl = document.createElement("div");
const parentNote = buildNote({
title: "Parent note",
children: [
{ title: "Child note 1" },
{ title: "Child note 2", "#archived": "" },
{ title: "Child note 3" }
]
});
await renderText(parentNote, $(contentEl));
const items = contentEl.querySelectorAll("a");
expect(items.length).toBe(2);
expect(items[0].textContent).toBe("Child note 1");
expect(items[1].textContent).toBe("Child note 3");
});
});

View File

@@ -15,14 +15,7 @@ export default async function renderText(note: FNote | FAttachment, $renderedCon
if (blob && !isHtmlEmpty(blob.content)) {
$renderedContent.append($('<div class="ck-content">').html(blob.content));
const seenNoteIds = options.seenNoteIds ?? new Set<string>();
seenNoteIds.add("noteId" in note ? note.noteId : note.attachmentId);
if (!options.noIncludedNotes) {
await renderIncludedNotes($renderedContent[0], seenNoteIds);
} else {
$renderedContent.find("section.include-note").remove();
}
await renderIncludedNotes($renderedContent[0]);
if ($renderedContent.find("span.math-tex").length > 0) {
renderMathInElement($renderedContent[0], { trust: true });
@@ -42,11 +35,11 @@ export default async function renderText(note: FNote | FAttachment, $renderedCon
await rewriteMermaidDiagramsInContainer($renderedContent[0] as HTMLDivElement);
await formatCodeBlocks($renderedContent);
} else if (note instanceof FNote && !options.noChildrenList) {
await renderChildrenList($renderedContent, note, options.includeArchivedNotes ?? false);
await renderChildrenList($renderedContent, note);
}
}
async function renderIncludedNotes(contentEl: HTMLElement, seenNoteIds: Set<string>) {
async function renderIncludedNotes(contentEl: HTMLElement) {
// TODO: Consider duplicating with server's share/content_renderer.ts.
const includeNoteEls = contentEl.querySelectorAll("section.include-note");
@@ -73,18 +66,8 @@ async function renderIncludedNotes(contentEl: HTMLElement, seenNoteIds: Set<stri
continue;
}
if (seenNoteIds.has(noteId)) {
console.warn(`Skipping inclusion of ${noteId} to avoid circular reference.`);
includeNoteEl.remove();
continue;
}
const renderedContent = (await content_renderer.getRenderedContent(note, {
seenNoteIds
})).$renderedContent;
const renderedContent = (await content_renderer.getRenderedContent(note)).$renderedContent;
includeNoteEl.replaceChildren(...renderedContent);
seenNoteIds.add(noteId);
}
}
@@ -115,7 +98,7 @@ export async function applyInlineMermaid(container: HTMLDivElement) {
}
}
async function renderChildrenList($renderedContent: JQuery<HTMLElement>, note: FNote, includeArchivedNotes: boolean) {
async function renderChildrenList($renderedContent: JQuery<HTMLElement>, note: FNote) {
let childNoteIds = note.getChildNoteIds();
if (!childNoteIds.length) {
@@ -125,16 +108,14 @@ async function renderChildrenList($renderedContent: JQuery<HTMLElement>, note: F
$renderedContent.css("padding", "10px");
$renderedContent.addClass("text-with-ellipsis");
// just load the first 10 child notes
if (childNoteIds.length > 10) {
childNoteIds = childNoteIds.slice(0, 10);
}
// just load the first 10 child notes
const childNotes = await froca.getNotes(childNoteIds);
for (const childNote of childNotes) {
if (childNote.isArchived && !includeArchivedNotes) continue;
$renderedContent.append(
await link.createLink(`${note.noteId}/${childNote.noteId}`, {
showTooltip: false,

View File

@@ -21,13 +21,7 @@
},
"bundle-error": {
"title": "Hubo un fallo al cargar un script personalizado",
"message": "El script no pudo ser ejecutado debido a:\n\n{{message}}"
},
"widget-list-error": {
"title": "Hubo un fallo al obtener la lista de widgets del servidor"
},
"widget-render-error": {
"title": "Hubo un fallo al renderizar un widget personalizado de React"
"message": "El script de la nota con ID \"{{id}}\", titulado \"{{title}}\" no pudo ser ejecutado debido a:\n\n{{message}}"
}
},
"add_link": {
@@ -697,7 +691,7 @@
"convert_into_attachment_successful": "La nota '{{title}}' ha sido convertida a un archivo adjunto.",
"convert_into_attachment_prompt": "¿Está seguro que desea convertir la nota '{{title}}' en un archivo adjunto de la nota padre?",
"print_pdf": "Exportar como PDF...",
"open_note_on_server": "Abrir nota en servidor"
"open_note_on_server": "Abrir nota en el servidor"
},
"onclick_button": {
"no_click_handler": "El widget de botón '{{componentId}}' no tiene un controlador de clics definido"
@@ -743,7 +737,7 @@
"zpetne_odkazy": {
"relation": "relación",
"backlink_one": "{{count}} Vínculo de retroceso",
"backlink_many": "{{count}} Vínculos de retroceso",
"backlink_many": "",
"backlink_other": "{{count}} vínculos de retroceso"
},
"mobile_detail_menu": {
@@ -756,10 +750,7 @@
"note_icon": {
"change_note_icon": "Cambiar icono de nota",
"search": "Búsqueda:",
"reset-default": "Restablecer a icono por defecto",
"search_placeholder_one": "Buscar {{number}} icono a través de {{count}} paquetes",
"search_placeholder_many": "Buscar {{number}} iconos a través de {{count}} paquetes",
"search_placeholder_other": "Buscar {{number}} iconos a través de {{count}} paquetes"
"reset-default": "Restablecer a icono por defecto"
},
"basic_properties": {
"note_type": "Tipo de nota",
@@ -799,7 +790,7 @@
"file_type": "Tipo de archivo",
"file_size": "Tamaño del archivo",
"download": "Descargar",
"open": "Abrir externamente",
"open": "Abrir",
"upload_new_revision": "Subir nueva revisión",
"upload_success": "Se ha subido una nueva revisión de archivo.",
"upload_failed": "Error al cargar una nueva revisión de archivo.",
@@ -1312,11 +1303,11 @@
"code_mime_types": {
"title": "Tipos MIME disponibles en el menú desplegable",
"tooltip_syntax_highlighting": "Resaltado de sintaxis",
"tooltip_code_block_syntax": "Bloques de Código en notas de Texto",
"tooltip_code_note_syntax": "Notas de Código"
"tooltip_code_block_syntax": "Bloques de código en notas de texto",
"tooltip_code_note_syntax": "Notas de código"
},
"vim_key_bindings": {
"use_vim_keybindings_in_code_notes": "Combinaciones de teclas Vim",
"use_vim_keybindings_in_code_notes": "Atajos de teclas de Vim",
"enable_vim_keybindings": "Habilitar los atajos de teclas de Vim en la notas de código (no es modo ex)"
},
"wrap_lines": {
@@ -1581,7 +1572,7 @@
"will_be_deleted_in": "Este archivo adjunto se eliminará automáticamente en {{time}}",
"will_be_deleted_soon": "Este archivo adjunto se eliminará automáticamente pronto",
"deletion_reason": ", porque el archivo adjunto no está vinculado en el contenido de la nota. Para evitar la eliminación, vuelva a agregar el enlace del archivo adjunto al contenido o convierta el archivo adjunto en una nota.",
"role_and_size": "Rol: {{role}}, tamaño: {{size}}, MIME: {{- mimeType}}",
"role_and_size": "Rol: {{role}}, Tamaño: {{size}}",
"link_copied": "Enlace del archivo adjunto copiado al portapapeles.",
"unrecognized_role": "Rol de archivo adjunto no reconocido '{{role}}'."
},
@@ -1632,7 +1623,7 @@
"import-into-note": "Importar a nota",
"apply-bulk-actions": "Aplicar acciones en lote",
"converted-to-attachments": "{{count}} notas han sido convertidas en archivos adjuntos.",
"convert-to-attachment-confirm": "¿Está seguro que desea convertir las notas seleccionadas en archivos adjuntos de sus notas padres? Esta operación solo aplica a notas de Imagen, otras notas serán omitidas.",
"convert-to-attachment-confirm": "¿Está seguro que desea convertir las notas seleccionadas en archivos adjuntos de sus notas padres?",
"open-in-popup": "Edición rápida",
"archive": "Archivar",
"unarchive": "Desarchivar"
@@ -1727,10 +1718,7 @@
"note_detail": {
"could_not_find_typewidget": "No se pudo encontrar typeWidget para el tipo '{{type}}'",
"printing": "Impresión en curso...",
"printing_pdf": "Exportando a PDF en curso..",
"print_report_collection_content_one": "{{count}} nota en la colección no se puede imprimir porque no son compatibles o está protegida.",
"print_report_collection_content_many": "{{count}} notas en la colección no se pueden imprimir porque no son compatibles o están protegidas.",
"print_report_collection_content_other": "{{count}} notas en la colección no se pueden imprimir porque no son compatibles o están protegidas."
"printing_pdf": "Exportando a PDF en curso.."
},
"note_title": {
"placeholder": "escriba el título de la nota aquí..."
@@ -1942,7 +1930,7 @@
"unknown_widget": "Widget desconocido para \"{{id}}\"."
},
"note_language": {
"not_set": "Idioma no establecido",
"not_set": "No establecido",
"configure-languages": "Configurar idiomas..."
},
"content_language": {
@@ -1981,7 +1969,7 @@
"hide-weekends": "Ocultar fines de semana",
"show-scale": "Mostrar escala",
"display-week-numbers": "Mostrar números de semana",
"map-style": "Estilo de mapa",
"map-style": "Estilo de mapa:",
"max-nesting-depth": "Máxima profundidad de anidamiento:",
"vector_light": "Vector (claro)",
"vector_dark": "Vector (oscuro)",
@@ -2110,36 +2098,5 @@
"clear-color": "Borrar color de nota",
"set-color": "Asignar color de nota",
"set-custom-color": "Asignar color de nota personalizado"
},
"status_bar": {
"backlinks_one": "{{count}} vínculo de retroceso",
"backlinks_many": "{{count}} vínculos de retroceso",
"backlinks_other": "{{count}} vínculos de retroceso",
"backlinks_title_one": "Ver vínculo de retroceso",
"backlinks_title_many": "Ver vínculos de retroceso",
"backlinks_title_other": "Ver vínculos de retroceso",
"attachments_one": "{{count}} adjunto",
"attachments_many": "{{count}} adjuntos",
"attachments_other": "{{count}} adjuntos",
"attachments_title_one": "Ver adjunto en una nueva pestaña",
"attachments_title_many": "Ver adjuntos en una nueva pestaña",
"attachments_title_other": "Ver adjuntos en una nueva pestaña",
"attributes_one": "{{count}} atributo",
"attributes_many": "{{count}} atributos",
"attributes_other": "{{count}} atributos",
"note_paths_one": "{{count}} ruta",
"note_paths_many": "{{count}} rutas",
"note_paths_other": "{{count}} rutas"
},
"pdf": {
"attachments_one": "{{count}} adjunto",
"attachments_many": "{{count}} adjuntos",
"attachments_other": "{{count}} adjuntos",
"layers_one": "{{count}} capa",
"layers_many": "{{count}} capas",
"layers_other": "{{count}} capas",
"pages_one": "{{count}} página",
"pages_many": "{{count}} páginas",
"pages_other": "{{count}} páginas"
}
}

View File

@@ -215,7 +215,7 @@ export default function NoteDetail() {
return (
<div
ref={containerRef}
class={`component note-detail ${isFullHeight ? "full-height" : ""}`}
class={`note-detail ${isFullHeight ? "full-height" : ""}`}
>
{Object.entries(noteTypesToRender).map(([ itemType, Element ]) => {
return <NoteDetailWrapper

View File

@@ -44,7 +44,6 @@ export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens }
export function GridView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) {
const noteIds = useFilteredNoteIds(note, unfilteredNoteIds);
const { pageNotes, ...pagination } = usePagination(note, noteIds);
const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived");
return (
<div class="note-list grid-view">
@@ -53,7 +52,7 @@ export function GridView({ note, noteIds: unfilteredNoteIds, highlightedTokens }
<div class="note-list-container use-tn-links">
{pageNotes?.map(childNote => (
<GridNoteCard note={childNote} parentNote={note} highlightedTokens={highlightedTokens} includeArchived={includeArchived} />
<GridNoteCard note={childNote} parentNote={note} highlightedTokens={highlightedTokens} />
))}
</div>
@@ -95,16 +94,14 @@ function ListNoteCard({ note, parentNote, highlightedTokens, currentLevel, expan
</h5>
{isExpanded && <>
<NoteContent note={note} highlightedTokens={highlightedTokens} noChildrenList includeArchivedNotes={includeArchived} />
<NoteContent note={note} highlightedTokens={highlightedTokens} noChildrenList />
<NoteChildren note={note} parentNote={parentNote} highlightedTokens={highlightedTokens} currentLevel={currentLevel} expandDepth={expandDepth} includeArchived={includeArchived} />
</>}
</div>
);
}
function GridNoteCard({ note, parentNote, highlightedTokens, includeArchived }: { note: FNote, parentNote: FNote, highlightedTokens: string[] | null | undefined, includeArchived: boolean }) {
const titleRef = useRef<HTMLSpanElement>(null);
const [ noteTitle, setNoteTitle ] = useState<string>();
function GridNoteCard({ note, parentNote, highlightedTokens }: { note: FNote, parentNote: FNote, highlightedTokens: string[] | null | undefined }) {
const notePath = getNotePath(parentNote, note);
return (
@@ -123,7 +120,6 @@ function GridNoteCard({ note, parentNote, highlightedTokens, includeArchived }:
note={note}
trim
highlightedTokens={highlightedTokens}
includeArchivedNotes={includeArchived}
/>
</div>
);
@@ -140,22 +136,14 @@ function NoteAttributes({ note }: { note: FNote }) {
return <span className="note-list-attributes" ref={ref} />;
}
function NoteContent({ note, trim, noChildrenList, highlightedTokens, includeArchivedNotes }: {
note: FNote;
trim?: boolean;
noChildrenList?: boolean;
highlightedTokens: string[] | null | undefined;
includeArchivedNotes: boolean;
}) {
function NoteContent({ note, trim, noChildrenList, highlightedTokens }: { note: FNote, trim?: boolean, noChildrenList?: boolean, highlightedTokens: string[] | null | undefined }) {
const contentRef = useRef<HTMLDivElement>(null);
const highlightSearch = useImperativeSearchHighlighlighting(highlightedTokens);
useEffect(() => {
content_renderer.getRenderedContent(note, {
trim,
noChildrenList,
noIncludedNotes: true,
includeArchivedNotes
noChildrenList
})
.then(({ $renderedContent, type }) => {
if (!contentRef.current) return;

View File

@@ -1,18 +1,17 @@
import { useCallback, useLayoutEffect, useState } from "preact/hooks";
import FNote from "../../entities/fnote";
import froca from "../../services/froca";
import { isDesktop, isMobile } from "../../services/utils";
import CalendarWidget from "./CalendarWidget";
import SpacerWidget from "./SpacerWidget";
import BookmarkButtons from "./BookmarkButtons";
import ProtectedSessionStatusWidget from "./ProtectedSessionStatusWidget";
import SyncStatus from "./SyncStatus";
import HistoryNavigationButton from "./HistoryNavigation";
import { AiChatButton, CommandButton, CustomWidget, NoteLauncher, QuickSearchLauncherWidget, ScriptLauncher, TodayLauncher } from "./LauncherDefinitions";
import { useTriliumEvent } from "../react/hooks";
import { onWheelHorizontalScroll } from "../widget_utils";
import BookmarkButtons from "./BookmarkButtons";
import CalendarWidget from "./CalendarWidget";
import HistoryNavigationButton from "./HistoryNavigation";
import { LaunchBarContext } from "./launch_bar_widgets";
import { AiChatButton, CommandButton, CustomWidget, NoteLauncher, QuickSearchLauncherWidget, ScriptLauncher, TodayLauncher } from "./LauncherDefinitions";
import ProtectedSessionStatusWidget from "./ProtectedSessionStatusWidget";
import SpacerWidget from "./SpacerWidget";
import SyncStatus from "./SyncStatus";
export default function LauncherContainer({ isHorizontalLayout }: { isHorizontalLayout: boolean }) {
const childNotes = useLauncherChildNotes();
@@ -35,19 +34,18 @@ export default function LauncherContainer({ isHorizontalLayout }: { isHorizontal
}}>
{childNotes?.map(childNote => {
if (childNote.type !== "launcher") {
console.warn(`Note '${childNote.noteId}' '${childNote.title}' is not a launcher even though it's in the launcher subtree`);
return false;
throw new Error(`Note '${childNote.noteId}' '${childNote.title}' is not a launcher even though it's in the launcher subtree`);
}
if (!isDesktop() && childNote.isLabelTruthy("desktopOnly")) {
return false;
}
return <Launcher key={childNote.noteId} note={childNote} isHorizontalLayout={isHorizontalLayout} />;
return <Launcher key={childNote.noteId} note={childNote} isHorizontalLayout={isHorizontalLayout} />
})}
</LaunchBarContext.Provider>
</div>
);
)
}
function Launcher({ note, isHorizontalLayout }: { note: FNote, isHorizontalLayout: boolean }) {
@@ -74,7 +72,7 @@ function initBuiltinWidget(note: FNote, isHorizontalLayout: boolean) {
const builtinWidget = note.getLabelValue("builtinWidget");
switch (builtinWidget) {
case "calendar":
return <CalendarWidget launcherNote={note} />;
return <CalendarWidget launcherNote={note} />
case "spacer":
// || has to be inside since 0 is a valid value
const baseSize = parseInt(note.getLabelValue("baseSize") || "40");
@@ -88,15 +86,15 @@ function initBuiltinWidget(note: FNote, isHorizontalLayout: boolean) {
case "syncStatus":
return <SyncStatus />;
case "backInHistoryButton":
return <HistoryNavigationButton launcherNote={note} command="backInNoteHistory" />;
return <HistoryNavigationButton launcherNote={note} command="backInNoteHistory" />
case "forwardInHistoryButton":
return <HistoryNavigationButton launcherNote={note} command="forwardInNoteHistory" />;
return <HistoryNavigationButton launcherNote={note} command="forwardInNoteHistory" />
case "todayInJournal":
return <TodayLauncher launcherNote={note} />;
return <TodayLauncher launcherNote={note} />
case "quickSearch":
return <QuickSearchLauncherWidget />;
return <QuickSearchLauncherWidget />
case "aiChatLauncher":
return <AiChatButton launcherNote={note} />;
return <AiChatButton launcherNote={note} />
default:
throw new Error(`Unrecognized builtin widget ${builtinWidget} for launcher ${note.noteId} "${note.title}"`);
}

View File

@@ -2,14 +2,12 @@ import "./TableOfContents.css";
import { CKTextEditor, ModelElement } from "@triliumnext/ckeditor5";
import clsx from "clsx";
import { useCallback, useEffect, useRef, useState } from "preact/hooks";
import { useCallback, useEffect, useState } from "preact/hooks";
import { t } from "../../services/i18n";
import math from "../../services/math";
import { randomString } from "../../services/utils";
import { useActiveNoteContext, useContentElement, useGetContextData, useIsNoteReadOnly, useNoteProperty, useTextEditor } from "../react/hooks";
import Icon from "../react/Icon";
import RawHtml from "../react/RawHtml";
import RightPanelWidget from "./RightPanelWidget";
//#region Generic impl.
@@ -82,22 +80,6 @@ function TableOfContentsHeading({ heading, scrollToHeading, activeHeadingId }: {
}) {
const [ collapsed, setCollapsed ] = useState(false);
const isActive = heading.id === activeHeadingId;
const contentRef = useRef<HTMLElement>(null);
// Render math equations after component mounts/updates
useEffect(() => {
if (!contentRef.current) return;
const mathElements = contentRef.current.querySelectorAll(".ck-math-tex");
for (const mathEl of mathElements ?? []) {
try {
math.render(mathEl.textContent || "", mathEl as HTMLElement);
} catch (e) {
console.warn("Failed to render math in TOC:", e);
}
}
}, [heading.text]);
return (
<>
<li className={clsx(collapsed && "collapsed", isActive && "active")}>
@@ -108,12 +90,10 @@ function TableOfContentsHeading({ heading, scrollToHeading, activeHeadingId }: {
onClick={() => setCollapsed(!collapsed)}
/>
)}
<RawHtml
containerRef={contentRef}
<span
className="item-content"
onClick={() => scrollToHeading(heading)}
html={heading.text}
/>
>{heading.text}</span>
</li>
{heading.children && (
<ol>
@@ -209,23 +189,9 @@ function extractTocFromTextEditor(editor: CKTextEditor) {
if (type !== "elementStart" || !item.is('element') || !item.name.startsWith('heading')) continue;
const level = Number(item.name.replace( 'heading', '' ));
// Convert model element to view, then to DOM to get HTML
const viewEl = editor.editing.mapper.toViewElement(item);
let text = '';
if (viewEl) {
const domEl = editor.editing.view.domConverter.mapViewToDom(viewEl);
if (domEl instanceof HTMLElement) {
text = domEl.innerHTML;
}
}
// Fallback to plain text if conversion fails
if (!text) {
text = Array.from( item.getChildren() )
.map( c => c.is( '$text' ) ? c.data : '' )
.join( '' );
}
const text = Array.from( item.getChildren() )
.map( c => c.is( '$text' ) ? c.data : '' )
.join( '' );
// Assign a unique ID
let tocId = item.getAttribute(TOC_ID) as string | undefined;

View File

@@ -15,8 +15,6 @@
.note-detail-split .note-detail-split-editor {
width: 100%;
flex-grow: 1;
min-width: 0;
min-height: 0;
}
.note-detail-split .note-detail-split-editor .note-detail-code {
@@ -32,7 +30,6 @@
margin: 5px;
white-space: pre-wrap;
font-size: 0.85em;
overflow: auto;
}
.note-detail-split .note-detail-split-preview {

View File

@@ -1,6 +1,6 @@
{
"name": "@triliumnext/desktop",
"version": "0.101.3",
"version": "0.101.1",
"description": "Build your personal knowledge base with Trilium Notes",
"private": true,
"main": "src/main.ts",

View File

@@ -1,12 +1,12 @@
import test, { expect, Page } from "@playwright/test";
import test, { BrowserContext, expect, Page } from "@playwright/test";
import App from "../support/app";
test.beforeEach(async ({ page, context }) => {
const app = new App(page, context);
await app.goto();
const app = await setLayout({ page, context }, true);
await app.setOption("rightPaneCollapsedItems", "[]");
});
test.afterEach(async ({ page, context }) => await setLayout({ page, context }, false));
test("Table of contents works", async ({ page, context }) => {
const app = new App(page, context);
@@ -73,15 +73,13 @@ test("Attachments listing works", async ({ page, context }) => {
test("Download original PDF works", async ({ page, context }) => {
const app = new App(page, context);
await app.goto();
await app.goToNoteInNewTab("Layers test.pdf");
await app.goToNoteInNewTab("Dacia Logan.pdf");
const pdfHelper = new PdfHelper(app);
await pdfHelper.toBeInitialized();
const downloadButton = app.currentNoteSplit.locator(".icon-action.bx.bx-download");
await expect(downloadButton).toBeVisible();
const [ download ] = await Promise.all([
page.waitForEvent("download"),
downloadButton.click()
app.currentNoteSplit.locator(".icon-action.bx.bx-download").click()
]);
expect(download).toBeDefined();
});
@@ -107,6 +105,13 @@ test("Layers listing works", async ({ page, context }) => {
await expect(layersList.locator(".pdf-layer-item")).toHaveCount(0);
});
async function setLayout({ page, context}: { page: Page; context: BrowserContext }, newLayout: boolean) {
const app = new App(page, context);
await app.goto();
await app.setOption("newLayout", newLayout ? "true" : "false");
return app;
}
class PdfHelper {
private contentFrame: ReturnType<Page["frameLocator"]>;
@@ -120,6 +125,5 @@ class PdfHelper {
async toBeInitialized() {
await expect(this.contentFrame.locator("#pageNumber")).toBeVisible();
await expect(this.contentFrame.locator(".page")).toBeVisible();
}
}

View File

@@ -1,5 +1,4 @@
import { expect, test } from "@playwright/test";
import { test, expect, Page } from "@playwright/test";
import App from "../support/app";
test("Table of contents is displayed", async ({ page, context }) => {
@@ -9,7 +8,7 @@ test("Table of contents is displayed", async ({ page, context }) => {
await app.goToNoteInNewTab("Table of contents");
await expect(app.sidebar).toContainText("Table of Contents");
const rootList = app.sidebar.locator(".toc > ol");
const rootList = app.sidebar.locator(".toc-widget > span > ol");
// Heading 1.1
// Heading 1.1
@@ -43,7 +42,7 @@ test("Highlights list is displayed", async ({ page, context }) => {
await app.closeAllTabs();
await app.goToNoteInNewTab("Highlights list");
await expect(app.sidebar).toContainText("10 highlights");
await expect(app.sidebar).toContainText("Highlights List");
const rootList = app.sidebar.locator(".highlights-list ol");
let index = 0;
for (const highlightedEl of ["Bold 1", "Italic 1", "Underline 1", "Colored text 1", "Background text 1", "Bold 2", "Italic 2", "Underline 2", "Colored text 2", "Background text 2"]) {

View File

@@ -37,7 +37,7 @@ export default class App {
this.noteTreeHoistedNote = this.noteTree.locator(".fancytree-node", { has: page.locator(".unhoist-button") });
this.launcherBar = page.locator("#launcher-container");
this.currentNoteSplit = page.locator(".note-split:not(.hidden-ext)");
this.currentNoteSplitTitle = this.currentNoteSplit.locator(".note-title").first();
this.currentNoteSplitTitle = this.currentNoteSplit.locator(".note-title");
this.currentNoteSplitContent = this.currentNoteSplit.locator(".note-detail-printable.visible");
this.sidebar = page.locator("#right-pane");
}

View File

@@ -1,6 +1,6 @@
{
"name": "@triliumnext/server",
"version": "0.101.3",
"version": "0.101.1",
"description": "The server-side component of TriliumNext, which exposes the client via the web, allows for sync and provides a REST API for both internal and external use.",
"private": true,
"main": "./src/main.ts",
@@ -123,7 +123,7 @@
"stream-throttle": "0.1.3",
"strip-bom": "5.0.0",
"striptags": "3.2.0",
"supertest": "7.1.4",
"supertest": "7.2.2",
"swagger-jsdoc": "6.2.8",
"time2fa": "1.4.2",
"tmp": "0.2.5",

Binary file not shown.

View File

@@ -115,7 +115,7 @@
},
"social_buttons": {
"github": "GitHub",
"github_discussions": "Discusiones de GitHub",
"github_discussions": "GitHub Discussions",
"matrix": "Matrix",
"reddit": "Reddit"
},

View File

@@ -6,9 +6,7 @@
},
"hero_section": {
"title": "अपने विचारों को व्यवस्थित करें। अपना व्यक्तिगत नॉलेज बेस बनाएं।",
"screenshot_alt": "ट्रिलियम नोट्स डेस्कटॉप एप्लिकेशन का स्क्रीनशॉट",
"get_started": "शुरू करें",
"github": "गिटहब"
"screenshot_alt": "ट्रिलियम नोट्स डेस्कटॉप एप्लिकेशन का स्क्रीनशॉट"
},
"organization_benefits": {
"note_structure_title": "नोट संरचना",
@@ -28,67 +26,5 @@
"collections": {
"calendar_title": "कैलेंडर",
"table_title": "टेबल"
},
"download_now": {
"linux_small": "लिनक्स के लिए",
"more_platforms": "अधिक प्लेटफॉर्म और सर्वर सेटअप"
},
"header": {
"get-started": "शुरू करें",
"support-us": "हमें सपोर्ट करें"
},
"social_buttons": {
"github": "गिटहब",
"matrix": "मैट्रिक्स",
"reddit": "रेडिट"
},
"support_us": {
"title": "हमें सपोर्ट करें"
},
"404": {
"description": "आप जो पेज खोज रहे थे वह नहीं मिल पाया। शायद वह डिलीट हो चुका है या यूआरएल (URL) गलत है।"
},
"download_helper_desktop_windows": {
"title_x64": "Windows 64-bit",
"title_arm64": "ARM पर Windows",
"quick_start": "Winget द्वारा इंस्टॉल करने के लिए:",
"download_exe": "इंस्टॉलर (.exe) डाउनलोड करें",
"download_zip": "पोर्टेबल (.zip)"
},
"download_helper_desktop_linux": {
"title_x64": "Linux 64-bit",
"title_arm64": "ARM पर लिनक्स",
"download_deb": ".deb",
"download_rpm": ".rpm",
"download_flatpak": ".flatpak",
"download_zip": "पोर्टेबल (.zip)",
"download_nixpkgs": "nixpkgs"
},
"download_helper_desktop_macos": {
"title_x64": "Intel के लिए macOS",
"title_arm64": "Apple Silicon के लिए macOS",
"description_x64": "macOS Monterey या उसके बाद के वर्ज़न पर चलने वाले Intel-आधारित Macs के लिए।",
"description_arm64": "Apple Silicon Macs के लिए, जैसे कि M1 और M2 चिप्स वाले मॉडल।",
"quick_start": "Homebrew द्वारा इंस्टॉल करने के लिए:",
"download_dmg": "इंस्टॉलर (.dmg) डाउनलोड करें",
"download_homebrew_cask": "Homebrew Cask",
"download_zip": "पोर्टेबल (.zip)"
},
"download_helper_server_docker": {
"title": "Docker द्वारा सेल्फ-होस्टेड",
"description": "Docker कंटेनर का उपयोग करके Windows, Linux या macOS पर आसानी से डिप्लॉय करें।",
"download_ghcr": "ghcr.io"
},
"download_helper_server_linux": {
"title": "Linux पर सेल्फ-होस्टेड",
"description": "ट्रिलियम नोट्स को अपने खुद के सर्वर या VPS पर डिप्लॉय करें, जो अधिकांश डिस्ट्रीब्यूशनो के साथ कम्पेटिबल है।",
"download_tar_x64": "x64 (.tar.xz)",
"download_tar_arm64": "ARM (.tar.xz)",
"download_nixos": "NixOS मॉड्यूल"
},
"download_helper_server_hosted": {
"title": "पेड होस्टिंग",
"download_pikapod": "PikaPods पर सेटअप करें",
"download_triliumcc": "वैकल्पिक रूप से trilium.cc देखें"
}
}

View File

@@ -1,6 +1,6 @@
{
"formatVersion": 2,
"appVersion": "0.101.3",
"appVersion": "0.101.1",
"files": [
{
"isClone": false,
@@ -61,58 +61,6 @@
"attachments": [],
"dirFileName": "Release Notes",
"children": [
{
"isClone": false,
"noteId": "IlBzLeN3MJhw",
"notePath": [
"hD3V4hiu2VW4",
"IlBzLeN3MJhw"
],
"title": "v0.101.3",
"notePosition": 10,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [
{
"type": "relation",
"name": "template",
"value": "wyurrlcDl416",
"isInheritable": false,
"position": 60
}
],
"format": "markdown",
"dataFileName": "v0.101.3.md",
"attachments": []
},
{
"isClone": false,
"noteId": "vcBthaXcwAm6",
"notePath": [
"hD3V4hiu2VW4",
"vcBthaXcwAm6"
],
"title": "v0.101.2",
"notePosition": 20,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [
{
"type": "relation",
"name": "template",
"value": "wyurrlcDl416",
"isInheritable": false,
"position": 60
}
],
"format": "markdown",
"dataFileName": "v0.101.2.md",
"attachments": []
},
{
"isClone": false,
"noteId": "AgUcrU9nFXuW",
@@ -121,7 +69,7 @@
"AgUcrU9nFXuW"
],
"title": "v0.101.1",
"notePosition": 30,
"notePosition": 10,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -147,7 +95,7 @@
"uYwlZ594eyJu"
],
"title": "v0.101.0",
"notePosition": 40,
"notePosition": 20,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -173,7 +121,7 @@
"iPGKEk7pwJXK"
],
"title": "v0.100.0",
"notePosition": 50,
"notePosition": 30,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -199,7 +147,7 @@
"7HKMTjmopLcM"
],
"title": "v0.99.5",
"notePosition": 60,
"notePosition": 40,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -225,7 +173,7 @@
"RMBaNYPsRpIr"
],
"title": "v0.99.4",
"notePosition": 70,
"notePosition": 50,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -251,7 +199,7 @@
"yuroLztFfpu5"
],
"title": "v0.99.3",
"notePosition": 80,
"notePosition": 60,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -277,7 +225,7 @@
"z207sehwMJ6C"
],
"title": "v0.99.2",
"notePosition": 90,
"notePosition": 70,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -303,7 +251,7 @@
"WGQsXq2jNyTi"
],
"title": "v0.99.1",
"notePosition": 100,
"notePosition": 80,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -329,7 +277,7 @@
"cyw2Yue9vXf3"
],
"title": "v0.99.0",
"notePosition": 110,
"notePosition": 90,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -355,7 +303,7 @@
"QOJwjruOUr4k"
],
"title": "v0.98.1",
"notePosition": 120,
"notePosition": 100,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -381,7 +329,7 @@
"PLUoryywi0BC"
],
"title": "v0.98.0",
"notePosition": 130,
"notePosition": 110,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -407,7 +355,7 @@
"lvOuiWsLDv8F"
],
"title": "v0.97.2",
"notePosition": 140,
"notePosition": 120,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -433,7 +381,7 @@
"OtFZ6Nd9vM3n"
],
"title": "v0.97.1",
"notePosition": 150,
"notePosition": 130,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -459,7 +407,7 @@
"SJZ5PwfzHSQ1"
],
"title": "v0.97.0",
"notePosition": 160,
"notePosition": 140,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -485,7 +433,7 @@
"mYXFde3LuNR7"
],
"title": "v0.96.0",
"notePosition": 170,
"notePosition": 150,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -511,7 +459,7 @@
"jthwbL0FdaeU"
],
"title": "v0.95.0",
"notePosition": 180,
"notePosition": 160,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -537,7 +485,7 @@
"7HGYsJbLuhnv"
],
"title": "v0.94.1",
"notePosition": 190,
"notePosition": 170,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -563,7 +511,7 @@
"Neq53ujRGBqv"
],
"title": "v0.94.0",
"notePosition": 200,
"notePosition": 180,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -589,7 +537,7 @@
"VN3xnce1vLkX"
],
"title": "v0.93.0",
"notePosition": 210,
"notePosition": 190,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -607,7 +555,7 @@
"WRaBfQqPr6qo"
],
"title": "v0.92.7",
"notePosition": 220,
"notePosition": 200,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -633,7 +581,7 @@
"a2rwfKNmUFU1"
],
"title": "v0.92.6",
"notePosition": 230,
"notePosition": 210,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -651,7 +599,7 @@
"fEJ8qErr0BKL"
],
"title": "v0.92.5-beta",
"notePosition": 240,
"notePosition": 220,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -669,7 +617,7 @@
"kkkZQQGSXjwy"
],
"title": "v0.92.4",
"notePosition": 250,
"notePosition": 230,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -687,7 +635,7 @@
"vAroNixiezaH"
],
"title": "v0.92.3-beta",
"notePosition": 260,
"notePosition": 240,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -705,7 +653,7 @@
"mHEq1wxAKNZd"
],
"title": "v0.92.2-beta",
"notePosition": 270,
"notePosition": 250,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -723,7 +671,7 @@
"IykjoAmBpc61"
],
"title": "v0.92.1-beta",
"notePosition": 280,
"notePosition": 260,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -741,7 +689,7 @@
"dq2AJ9vSBX4Y"
],
"title": "v0.92.0-beta",
"notePosition": 290,
"notePosition": 270,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -759,7 +707,7 @@
"3a8aMe4jz4yM"
],
"title": "v0.91.6",
"notePosition": 300,
"notePosition": 280,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -777,7 +725,7 @@
"8djQjkiDGESe"
],
"title": "v0.91.5",
"notePosition": 310,
"notePosition": 290,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -795,7 +743,7 @@
"OylxVoVJqNmr"
],
"title": "v0.91.4-beta",
"notePosition": 320,
"notePosition": 300,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -813,7 +761,7 @@
"tANGQDvnyhrj"
],
"title": "v0.91.3-beta",
"notePosition": 330,
"notePosition": 310,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -831,7 +779,7 @@
"hMoBfwSoj1SC"
],
"title": "v0.91.2-beta",
"notePosition": 340,
"notePosition": 320,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -849,7 +797,7 @@
"a2XMSKROCl9z"
],
"title": "v0.91.1-beta",
"notePosition": 350,
"notePosition": 330,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -867,7 +815,7 @@
"yqXFvWbLkuMD"
],
"title": "v0.90.12",
"notePosition": 360,
"notePosition": 340,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -885,7 +833,7 @@
"veS7pg311yJP"
],
"title": "v0.90.11-beta",
"notePosition": 370,
"notePosition": 350,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -903,7 +851,7 @@
"sq5W9TQxRqMq"
],
"title": "v0.90.10-beta",
"notePosition": 380,
"notePosition": 360,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -921,7 +869,7 @@
"yFEGVCUM9tPx"
],
"title": "v0.90.9-beta",
"notePosition": 390,
"notePosition": 370,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -939,7 +887,7 @@
"o4wAGqOQuJtV"
],
"title": "v0.90.8",
"notePosition": 400,
"notePosition": 380,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -972,7 +920,7 @@
"i4A5g9iOg9I0"
],
"title": "v0.90.7-beta",
"notePosition": 410,
"notePosition": 390,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -990,7 +938,7 @@
"ThNf2GaKgXUs"
],
"title": "v0.90.6-beta",
"notePosition": 420,
"notePosition": 400,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1008,7 +956,7 @@
"G4PAi554kQUr"
],
"title": "v0.90.5-beta",
"notePosition": 430,
"notePosition": 410,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1035,7 +983,7 @@
"zATRobGRCmBn"
],
"title": "v0.90.4",
"notePosition": 440,
"notePosition": 420,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1053,7 +1001,7 @@
"sCDLf8IKn3Iz"
],
"title": "v0.90.3",
"notePosition": 450,
"notePosition": 430,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1071,7 +1019,7 @@
"VqqyBu4AuTjC"
],
"title": "v0.90.2-beta",
"notePosition": 460,
"notePosition": 440,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1089,7 +1037,7 @@
"RX3Nl7wInLsA"
],
"title": "v0.90.1-beta",
"notePosition": 470,
"notePosition": 450,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1107,7 +1055,7 @@
"GyueACukPWjk"
],
"title": "v0.90.0-beta",
"notePosition": 480,
"notePosition": 460,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1125,7 +1073,7 @@
"kzjHexDTTeVB"
],
"title": "v0.48",
"notePosition": 490,
"notePosition": 470,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1192,7 +1140,7 @@
"wyurrlcDl416"
],
"title": "Release Template",
"notePosition": 500,
"notePosition": 480,
"prefix": null,
"isExpanded": false,
"type": "text",

View File

@@ -1,22 +0,0 @@
# v0.101.2
> [!NOTE]
> If you are interested in an [official mobile application](https://oss.issuehunt.io/r/TriliumNext/Trilium/issues/7447)  ([#7447](https://github.com/TriliumNext/Trilium/issues/7447)) or [multi-user support](https://oss.issuehunt.io/r/TriliumNext/Trilium/issues/4956) ([#4956](https://github.com/TriliumNext/Trilium/issues/4956)), consider offering financial support via IssueHunt (see links).
> [!IMPORTANT]
> If you enjoyed this release, consider showing a token of appreciation by:
>
> * Pressing the “Star” button on [GitHub](https://github.com/TriliumNext/Trilium) (top-right).
> * Considering a one-time or recurrent donation to the [lead developer](https://github.com/eliandoran) via [GitHub Sponsors](https://github.com/sponsors/eliandoran) or [PayPal](https://paypal.me/eliandoran).
## 🐞 Bugfixes
* [SQL Console: cannot copy table data](https://github.com/TriliumNext/Trilium/pull/8268) by @SiriusXT
* [Title is not selected when creating a note via the launcher](https://github.com/TriliumNext/Trilium/pull/8292) by @SiriusXT
* [Popup editor closing after inserting a note link](https://github.com/TriliumNext/Trilium/pull/8224) by @SiriusXT
* [New Mermaid diagrams do not save content](https://github.com/TriliumNext/Trilium/pull/8220) by @lzinga
* [Can't scroll mermaid diagram code](https://github.com/TriliumNext/Trilium/issues/8299)
* [Max content width is not respected when switching between note types in the same tab](https://github.com/TriliumNext/Trilium/issues/8065)
* [Crash When a Note Includes Itself](https://github.com/TriliumNext/Trilium/issues/8294)
* [Severe Performance Degradation and Crash Issues Due to Recursive Inclusion in Included Notes](https://github.com/TriliumNext/Trilium/issues/8017)
* [<note> is not a launcher even though it's in the launcher subtree](https://github.com/TriliumNext/Trilium/issues/8218)
* [Archived subnotes of direct children appear in grid view without #includeArchived](https://github.com/TriliumNext/Trilium/issues/8184)

View File

@@ -1,24 +0,0 @@
# v0.101.3
> [!NOTE]
> If you are interested in an [official mobile application](https://oss.issuehunt.io/r/TriliumNext/Trilium/issues/7447)  ([#7447](https://github.com/TriliumNext/Trilium/issues/7447)) or [multi-user support](https://oss.issuehunt.io/r/TriliumNext/Trilium/issues/4956) ([#4956](https://github.com/TriliumNext/Trilium/issues/4956)), consider offering financial support via IssueHunt (see links).
> [!IMPORTANT]
> If you enjoyed this release, consider showing a token of appreciation by:
>
> * Pressing the “Star” button on [GitHub](https://github.com/TriliumNext/Trilium) (top-right).
> * Considering a one-time or recurrent donation to the [lead developer](https://github.com/eliandoran) via [GitHub Sponsors](https://github.com/sponsors/eliandoran) or [PayPal](https://paypal.me/eliandoran).
This is a re-release of v0.101.2, which had a cache invalidation issue.
## 🐞 Bugfixes
* [SQL Console: cannot copy table data](https://github.com/TriliumNext/Trilium/pull/8268) by @SiriusXT
* [Title is not selected when creating a note via the launcher](https://github.com/TriliumNext/Trilium/pull/8292) by @SiriusXT
* [Popup editor closing after inserting a note link](https://github.com/TriliumNext/Trilium/pull/8224) by @SiriusXT
* [New Mermaid diagrams do not save content](https://github.com/TriliumNext/Trilium/pull/8220) by @lzinga
* [Can't scroll mermaid diagram code](https://github.com/TriliumNext/Trilium/issues/8299)
* [Max content width is not respected when switching between note types in the same tab](https://github.com/TriliumNext/Trilium/issues/8065)
* [Crash When a Note Includes Itself](https://github.com/TriliumNext/Trilium/issues/8294)
* [Severe Performance Degradation and Crash Issues Due to Recursive Inclusion in Included Notes](https://github.com/TriliumNext/Trilium/issues/8017)
* [is not a launcher even though it's in the launcher subtree](https://github.com/TriliumNext/Trilium/issues/8218)
* [Archived subnotes of direct children appear in grid view without #includeArchived](https://github.com/TriliumNext/Trilium/issues/8184)

View File

@@ -1,6 +1,6 @@
{
"name": "@triliumnext/source",
"version": "0.101.3",
"version": "0.101.1",
"description": "Build your personal knowledge base with Trilium Notes",
"directories": {
"doc": "docs"

View File

@@ -1,6 +1,6 @@
{
"name": "@triliumnext/commons",
"version": "0.101.3",
"version": "0.101.1",
"description": "Shared library between the clients (e.g. browser, Electron) and the server, mostly for type definitions and utility methods.",
"private": true,
"type": "module",

83
pnpm-lock.yaml generated
View File

@@ -775,8 +775,8 @@ importers:
specifier: 3.2.0
version: 3.2.0
supertest:
specifier: 7.1.4
version: 7.1.4
specifier: 7.2.2
version: 7.2.2
swagger-jsdoc:
specifier: 6.2.8
version: 6.2.8(openapi-types@12.1.3)
@@ -8603,6 +8603,10 @@ packages:
resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==}
engines: {node: '>= 6'}
form-data@4.0.5:
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
engines: {node: '>= 6'}
format@0.2.2:
resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==}
engines: {node: '>=0.4.x'}
@@ -12007,6 +12011,10 @@ packages:
resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
engines: {node: '>=0.6'}
qs@6.14.1:
resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==}
engines: {node: '>=0.6'}
quansync@0.2.10:
resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==}
@@ -13277,15 +13285,15 @@ packages:
resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==}
engines: {node: '>= 8.0'}
superagent@10.2.3:
resolution: {integrity: sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==}
superagent@10.3.0:
resolution: {integrity: sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==}
engines: {node: '>=14.18.0'}
supercluster@8.0.1:
resolution: {integrity: sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==}
supertest@7.1.4:
resolution: {integrity: sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg==}
supertest@7.2.2:
resolution: {integrity: sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==}
engines: {node: '>=14.18.0'}
supports-color@5.5.0:
@@ -15299,6 +15307,8 @@ snapshots:
'@ckeditor/ckeditor5-ui': 47.3.0
'@ckeditor/ckeditor5-utils': 47.3.0
ckeditor5: 47.3.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-block-quote@47.3.0':
dependencies:
@@ -15309,6 +15319,8 @@ snapshots:
'@ckeditor/ckeditor5-ui': 47.3.0
'@ckeditor/ckeditor5-utils': 47.3.0
ckeditor5: 47.3.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-bookmark@47.3.0':
dependencies:
@@ -15544,8 +15556,6 @@ snapshots:
'@ckeditor/ckeditor5-widget': 47.3.0
ckeditor5: 47.3.0
es-toolkit: 1.39.5
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-easy-image@47.3.0':
dependencies:
@@ -15583,8 +15593,6 @@ snapshots:
'@ckeditor/ckeditor5-utils': 47.3.0
ckeditor5: 47.3.0
es-toolkit: 1.39.5
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-editor-inline@47.3.0':
dependencies:
@@ -15594,6 +15602,8 @@ snapshots:
'@ckeditor/ckeditor5-utils': 47.3.0
ckeditor5: 47.3.0
es-toolkit: 1.39.5
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-editor-multi-root@47.3.0':
dependencies:
@@ -15616,6 +15626,8 @@ snapshots:
'@ckeditor/ckeditor5-table': 47.3.0
'@ckeditor/ckeditor5-utils': 47.3.0
ckeditor5: 47.3.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-emoji@47.3.0':
dependencies:
@@ -15641,8 +15653,6 @@ snapshots:
'@ckeditor/ckeditor5-core': 47.3.0
'@ckeditor/ckeditor5-engine': 47.3.0
'@ckeditor/ckeditor5-utils': 47.3.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-essentials@47.3.0':
dependencies:
@@ -15674,6 +15684,8 @@ snapshots:
'@ckeditor/ckeditor5-ui': 47.3.0
'@ckeditor/ckeditor5-utils': 47.3.0
ckeditor5: 47.3.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-export-word@47.3.0':
dependencies:
@@ -15698,8 +15710,6 @@ snapshots:
'@ckeditor/ckeditor5-utils': 47.3.0
ckeditor5: 47.3.0
es-toolkit: 1.39.5
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-font@47.3.0':
dependencies:
@@ -15709,6 +15719,8 @@ snapshots:
'@ckeditor/ckeditor5-ui': 47.3.0
'@ckeditor/ckeditor5-utils': 47.3.0
ckeditor5: 47.3.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-footnotes@47.3.0':
dependencies:
@@ -15739,6 +15751,8 @@ snapshots:
'@ckeditor/ckeditor5-ui': 47.3.0
'@ckeditor/ckeditor5-utils': 47.3.0
ckeditor5: 47.3.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-heading@47.3.0':
dependencies:
@@ -15770,8 +15784,6 @@ snapshots:
'@ckeditor/ckeditor5-utils': 47.3.0
'@ckeditor/ckeditor5-widget': 47.3.0
ckeditor5: 47.3.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-html-embed@47.3.0':
dependencies:
@@ -15831,6 +15843,8 @@ snapshots:
'@ckeditor/ckeditor5-ui': 47.3.0
'@ckeditor/ckeditor5-utils': 47.3.0
ckeditor5: 47.3.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-indent@47.3.0':
dependencies:
@@ -15865,8 +15879,6 @@ snapshots:
'@ckeditor/ckeditor5-ui': 47.3.0
'@ckeditor/ckeditor5-utils': 47.3.0
ckeditor5: 47.3.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-link@47.3.0':
dependencies:
@@ -15893,8 +15905,6 @@ snapshots:
'@ckeditor/ckeditor5-ui': 47.3.0
'@ckeditor/ckeditor5-utils': 47.3.0
ckeditor5: 47.3.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-list@47.3.0':
dependencies:
@@ -15947,6 +15957,8 @@ snapshots:
'@ckeditor/ckeditor5-utils': 47.3.0
'@ckeditor/ckeditor5-widget': 47.3.0
ckeditor5: 47.3.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-mention@47.3.0(patch_hash=5981fb59ba35829e4dff1d39cf771000f8a8fdfa7a34b51d8af9549541f2d62d)':
dependencies:
@@ -15956,6 +15968,8 @@ snapshots:
'@ckeditor/ckeditor5-utils': 47.3.0
ckeditor5: 47.3.0
es-toolkit: 1.39.5
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-merge-fields@47.3.0':
dependencies:
@@ -15968,6 +15982,8 @@ snapshots:
'@ckeditor/ckeditor5-widget': 47.3.0
ckeditor5: 47.3.0
es-toolkit: 1.39.5
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-minimap@47.3.0':
dependencies:
@@ -15976,6 +15992,8 @@ snapshots:
'@ckeditor/ckeditor5-ui': 47.3.0
'@ckeditor/ckeditor5-utils': 47.3.0
ckeditor5: 47.3.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-operations-compressor@47.3.0':
dependencies:
@@ -16216,6 +16234,8 @@ snapshots:
'@ckeditor/ckeditor5-widget': 47.3.0
ckeditor5: 47.3.0
es-toolkit: 1.39.5
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-template@47.3.0':
dependencies:
@@ -24392,6 +24412,14 @@ snapshots:
hasown: 2.0.2
mime-types: 2.1.35
form-data@4.0.5:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
es-set-tostringtag: 2.1.0
hasown: 2.0.2
mime-types: 2.1.35
format@0.2.2: {}
formdata-polyfill@4.0.10:
@@ -28317,6 +28345,10 @@ snapshots:
dependencies:
side-channel: 1.1.0
qs@6.14.1:
dependencies:
side-channel: 1.1.0
quansync@0.2.10: {}
query-selector-shadow-dom@1.0.1: {}
@@ -29951,17 +29983,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
superagent@10.2.3:
superagent@10.3.0:
dependencies:
component-emitter: 1.3.1
cookiejar: 2.1.4
debug: 4.4.3(supports-color@8.1.1)
fast-safe-stringify: 2.1.1
form-data: 4.0.4
form-data: 4.0.5
formidable: 3.5.4
methods: 1.1.2
mime: 2.6.0
qs: 6.14.0
qs: 6.14.1
transitivePeerDependencies:
- supports-color
@@ -29969,10 +30001,11 @@ snapshots:
dependencies:
kdbush: 4.0.2
supertest@7.1.4:
supertest@7.2.2:
dependencies:
cookie-signature: 1.2.2
methods: 1.1.2
superagent: 10.2.3
superagent: 10.3.0
transitivePeerDependencies:
- supports-color

View File

@@ -1,33 +0,0 @@
import { readFileSync } from "fs";
import { join } from "path";
const projectRoot = join(__dirname, '..');
const filesToCheck = [
'package.json',
'apps/server/package.json',
'apps/client/package.json',
'apps/desktop/package.json',
'packages/commons/package.json',
]
function main() {
const expectedVersion = process.argv[2];
if (!expectedVersion) {
console.error('Expected version argument is missing.');
process.exit(1);
}
for (const fileToCheck of filesToCheck) {
const packageJsonPath = join(projectRoot, fileToCheck);
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
const version = packageJson.version;
if (version !== expectedVersion) {
console.error(`Version mismatch in ${fileToCheck}: expected ${expectedVersion}, found ${version}`);
process.exit(1);
}
}
console.log('All versions are consistent:', expectedVersion);
}
main();