From bc8cca664b24d6c528c874f64860bbb471df6144 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 15 Mar 2025 17:14:17 +0200 Subject: [PATCH 01/13] feat(ci): trigger dev workflow on PR and main branch --- .github/workflows/dev.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index f5e30323d..18ff8190b 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -1,9 +1,9 @@ name: Dev on: push: - branches-ignore: - - 'develop' - - 'feature/update**' + branches: [ develop ] + pull_request: + branches: [ develop ] concurrency: group: ${{ github.workflow }}-${{ github.ref }} From 2b966afbe1f0e4b1ac8ca913f7b46582549d138a Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 15 Mar 2025 17:51:10 +0200 Subject: [PATCH 02/13] fix(test): tests that got broken along the way --- .../view_widgets/calendar_view.spec.ts | 58 +++++++------------ src/services/data_dir.spec.ts | 2 +- src/services/import/markdown.spec.ts | 9 +-- src/services/import/single.spec.ts | 2 +- src/services/in_app_help.ts | 2 +- src/share/routes.spec.ts | 1 + src/share/routes.ts | 2 + 7 files changed, 30 insertions(+), 46 deletions(-) diff --git a/src/public/app/widgets/view_widgets/calendar_view.spec.ts b/src/public/app/widgets/view_widgets/calendar_view.spec.ts index 9623f0172..286792325 100644 --- a/src/public/app/widgets/view_widgets/calendar_view.spec.ts +++ b/src/public/app/widgets/view_widgets/calendar_view.spec.ts @@ -39,8 +39,8 @@ describe("Building events", () => { it("supports custom start date", async () => { const noteIds = buildNotes([ - { title: "Note 1", "#myStartDate": "2025-05-05", "#calendar:startDate": "#myStartDate" }, - { title: "Note 2", "#startDate": "2025-05-07", "#calendar:startDate": "#myStartDate" }, + { title: "Note 1", "#myStartDate": "2025-05-05", "#calendar:startDate": "myStartDate" }, + { title: "Note 2", "#startDate": "2025-05-07", "#calendar:startDate": "myStartDate" }, ]); const events = await CalendarView.buildEvents(noteIds); @@ -59,10 +59,10 @@ describe("Building events", () => { it("supports custom start date and end date", async () => { const noteIds = buildNotes([ - { title: "Note 1", "#myStartDate": "2025-05-05", "#myEndDate": "2025-05-05", "#calendar:startDate": "#myStartDate", "#calendar:endDate": "#myEndDate" }, - { title: "Note 2", "#myStartDate": "2025-05-07", "#endDate": "2025-05-08", "#calendar:startDate": "#myStartDate", "#calendar:endDate": "#myEndDate" }, - { title: "Note 3", "#startDate": "2025-05-05", "#myEndDate": "2025-05-05", "#calendar:startDate": "#myStartDate", "#calendar:endDate": "#myEndDate" }, - { title: "Note 4", "#startDate": "2025-05-07", "#myEndDate": "2025-05-08", "#calendar:startDate": "#myStartDate", "#calendar:endDate": "#myEndDate" }, + { title: "Note 1", "#myStartDate": "2025-05-05", "#myEndDate": "2025-05-05", "#calendar:startDate": "myStartDate", "#calendar:endDate": "myEndDate" }, + { title: "Note 2", "#myStartDate": "2025-05-07", "#endDate": "2025-05-08", "#calendar:startDate": "myStartDate", "#calendar:endDate": "myEndDate" }, + { title: "Note 3", "#startDate": "2025-05-05", "#myEndDate": "2025-05-05", "#calendar:startDate": "myStartDate", "#calendar:endDate": "myEndDate" }, + { title: "Note 4", "#startDate": "2025-05-07", "#myEndDate": "2025-05-08", "#calendar:startDate": "myStartDate", "#calendar:endDate": "myEndDate" }, ]); const events = await CalendarView.buildEvents(noteIds); @@ -75,8 +75,8 @@ describe("Building events", () => { it("supports label as custom title", async () => { const noteIds = buildNotes([ - { title: "Note 1", "#myTitle": "My Custom Title 1", "#startDate": "2025-05-05", "#calendar:title": "#myTitle" }, - { title: "Note 2", "#startDate": "2025-05-07", "#calendar:title": "#myTitle" }, + { title: "Note 1", "#myTitle": "My Custom Title 1", "#startDate": "2025-05-05", "#calendar:title": "myTitle" }, + { title: "Note 2", "#startDate": "2025-05-07", "#calendar:title": "myTitle" }, ]); const events = await CalendarView.buildEvents(noteIds); @@ -88,8 +88,8 @@ describe("Building events", () => { it("supports relation as custom title", async () => { const noteIds = buildNotes([ { id: "mySharedTitle", title: "My shared title" }, - { title: "Note 1", "~myTitle": "mySharedTitle", "#startDate": "2025-05-05", "#calendar:title": "~myTitle" }, - { title: "Note 2", "#startDate": "2025-05-07", "#calendar:title": "~myTitle" }, + { title: "Note 1", "~myTitle": "mySharedTitle", "#startDate": "2025-05-05", "#calendar:title": "myTitle" }, + { title: "Note 2", "#startDate": "2025-05-07", "#calendar:title": "myTitle" }, ]); const events = await CalendarView.buildEvents(noteIds); @@ -100,23 +100,9 @@ describe("Building events", () => { it("supports relation as custom title with custom label", async () => { const noteIds = buildNotes([ - { id: "mySharedTitle", title: "My custom title", "#myTitle": "My shared custom title", "#calendar:title": "#myTitle" }, - { title: "Note 1", "~myTitle": "mySharedTitle", "#startDate": "2025-05-05", "#calendar:title": "~myTitle" }, - { title: "Note 2", "#startDate": "2025-05-07", "#calendar:title": "~myTitle" }, - ]); - const events = await CalendarView.buildEvents(noteIds); - - expect(events).toHaveLength(2); - expect(events[0]).toMatchObject({ title: "My shared custom title", start: "2025-05-05" }); - expect(events[1]).toMatchObject({ title: "Note 2", start: "2025-05-07" }); - }); - - it("discards relation as custom title with custom relation", async () => { - const noteIds = buildNotes([ - { id: "myParentNote", title: "My parent note" }, - { id: "mySharedTitle", title: "My custom title", "~myTitle": "myParentNote", "#calendar:title": "~myTitle" }, - { title: "Note 1", "~myTitle": "mySharedTitle", "#startDate": "2025-05-05", "#calendar:title": "~myTitle" }, - { title: "Note 2", "#startDate": "2025-05-07", "#calendar:title": "~myTitle" }, + { id: "mySharedTitle", title: "My custom title", "#myTitle": "My shared custom title", "#calendar:title": "myTitle" }, + { title: "Note 1", "~myTitle": "mySharedTitle", "#startDate": "2025-05-05", "#calendar:title": "myTitle" }, + { title: "Note 2", "#startDate": "2025-05-07", "#calendar:title": "myTitle" }, ]); const events = await CalendarView.buildEvents(noteIds); @@ -135,15 +121,15 @@ describe("Promoted attributes", () => { "#mood": "happy", "#label:weight": "promoted,number,single,precision=1", "#label:mood": "promoted,alias=Mood,single,text", - "#calendar:promotedAttributes": "label:weight,label:mood" + "#calendar:displayedAttributes": "weight,mood" }); const event = await CalendarView.buildEvent(note, "2025-04-04"); expect(event).toHaveLength(1); - expect(event[0]?.promotedAttributes).toMatchObject({ - weight: "75", - Mood: "happy" - }) + expect(event[0]?.promotedAttributes).toMatchObject([ + [ "weight", "75" ], + [ "mood", "happy" ] + ]); }); it("supports relations", async () => { @@ -152,14 +138,14 @@ describe("Promoted attributes", () => { "~assignee": buildNote({ "title": "Target note" }).noteId, - "#calendar:promotedAttributes": "relation:assignee", + "#calendar:displayedAttributes": "assignee", "#relation:assignee": "promoted,alias=Assignee,single,text", }); const event = await CalendarView.buildEvent(note, "2025-04-04"); expect(event).toHaveLength(1); - expect(event[0]?.promotedAttributes).toMatchObject({ - "Assignee": "Target note" - }) + expect(event[0]?.promotedAttributes).toMatchObject([ + [ "assignee", "Target note" ] + ]) }); }); diff --git a/src/services/data_dir.spec.ts b/src/services/data_dir.spec.ts index 4c94cbe94..24315a5ff 100644 --- a/src/services/data_dir.spec.ts +++ b/src/services/data_dir.spec.ts @@ -272,7 +272,7 @@ describe("data_dir.ts unit tests", async () => { }); describe("#getDataDirs()", () => { - const envKeys: Omit, "TRILIUM_DATA_DIR">[] = ["DOCUMENT_PATH", "BACKUP_DIR", "LOG_DIR", "ANONYMIZED_DB_DIR", "CONFIG_INI_PATH"]; + const envKeys: Omit, "TRILIUM_DATA_DIR">[] = ["DOCUMENT_PATH", "BACKUP_DIR", "LOG_DIR", "ANONYMIZED_DB_DIR", "CONFIG_INI_PATH", "TMP_DIR"]; const setMockedEnv = (prefix: string | null) => { envKeys.forEach((key) => { diff --git a/src/services/import/markdown.spec.ts b/src/services/import/markdown.spec.ts index dc382b896..5d5ccd33c 100644 --- a/src/services/import/markdown.spec.ts +++ b/src/services/import/markdown.spec.ts @@ -40,12 +40,7 @@ describe("markdown", () => { # another one Hello, world `, "title"); - expect(result).toBe(trimIndentation`\ -

Hello

-

world

-

another one

-

Hello, world

- `); + expect(result).toBe(`

Hello

world

another one

Hello, world

`); }); @@ -54,7 +49,7 @@ describe("markdown", () => { # What's new Hi there `, "What's new") - expect(result).toBe(`\n

Hi there

\n`); + expect(result).toBe(`

Hi there

`); }); it("trims unnecessary whitespace", () => { diff --git a/src/services/import/single.spec.ts b/src/services/import/single.spec.ts index e04b657df..1eacd261b 100644 --- a/src/services/import/single.spec.ts +++ b/src/services/import/single.spec.ts @@ -87,7 +87,7 @@ describe("processNoteContent", () => { it("supports markdown note with UTF-16", async () => { const { importedNote } = await testImport("UTF-16LE Text Note.md", "text/markdown"); expect(importedNote.mime).toBe("text/html"); - expect(importedNote.getContent().toString()).toBe("

Hello world

\n

Plain text goes here.

\n"); + expect(importedNote.getContent().toString()).toBe("

Hello world

Plain text goes here.

"); }); it("supports excalidraw note", async () => { diff --git a/src/services/in_app_help.ts b/src/services/in_app_help.ts index b7fd30050..7841ee71b 100644 --- a/src/services/in_app_help.ts +++ b/src/services/in_app_help.ts @@ -13,9 +13,9 @@ export function getHelpHiddenSubtreeData() { const appDir = path.join(srcRoot, "public", isDev ? "app" : "app-dist"); const helpDir = path.join(appDir, "doc_notes", "en", "User Guide"); const metaFilePath = path.join(helpDir, "!!!meta.json"); - const metaFileContent = JSON.parse(fs.readFileSync(metaFilePath).toString("utf-8")); try { + const metaFileContent = JSON.parse(fs.readFileSync(metaFilePath).toString("utf-8")); return parseNoteMetaFile(metaFileContent as NoteMetaFile); } catch (e) { console.warn(e); diff --git a/src/share/routes.spec.ts b/src/share/routes.spec.ts index 86e1927bd..c78e447af 100644 --- a/src/share/routes.spec.ts +++ b/src/share/routes.spec.ts @@ -27,6 +27,7 @@ describe("Share API test", () => { it("requests password for password-protected share", async () => { await supertest(app) .get("/share/YjlPRj2E9fOV") + .expect(200) .expect("WWW-Authenticate", 'Basic realm="User Visible Realm", charset="UTF-8"'); expect(cannotSetHeadersCount).toBe(0); }); diff --git a/src/share/routes.ts b/src/share/routes.ts index 3c6db87d5..2591cce0c 100644 --- a/src/share/routes.ts +++ b/src/share/routes.ts @@ -131,6 +131,7 @@ function renderImageAttachment(image: SNote, res: Response, attachmentName: stri function register(router: Router) { function renderNote(note: SNote, req: Request, res: Response) { if (!note) { + console.log("Unable to find note ", note); res.status(404).render("share/404"); return; } @@ -215,6 +216,7 @@ function register(router: Router) { const { shareId } = req.params; + console.log("Got share ", shareId, shaca.notes, shaca.aliasToNote); const note = shaca.aliasToNote[shareId] || shaca.notes[shareId]; renderNote(note, req, res); From c27f13d49f135eb4ef48b026a317d0b847c7483e Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 15 Mar 2025 18:18:17 +0200 Subject: [PATCH 03/13] fix(test): one more broken test --- src/share/routes.spec.ts | 2 +- src/share/routes.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/share/routes.spec.ts b/src/share/routes.spec.ts index c78e447af..3c86a3f2f 100644 --- a/src/share/routes.spec.ts +++ b/src/share/routes.spec.ts @@ -27,7 +27,7 @@ describe("Share API test", () => { it("requests password for password-protected share", async () => { await supertest(app) .get("/share/YjlPRj2E9fOV") - .expect(200) + .expect(401) .expect("WWW-Authenticate", 'Basic realm="User Visible Realm", charset="UTF-8"'); expect(cannotSetHeadersCount).toBe(0); }); diff --git a/src/share/routes.ts b/src/share/routes.ts index 2591cce0c..9b6c2201d 100644 --- a/src/share/routes.ts +++ b/src/share/routes.ts @@ -216,7 +216,6 @@ function register(router: Router) { const { shareId } = req.params; - console.log("Got share ", shareId, shaca.notes, shaca.aliasToNote); const note = shaca.aliasToNote[shareId] || shaca.notes[shareId]; renderNote(note, req, res); From ac419e8ab45644691218b6ae0542039a815a2cba Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 15 Mar 2025 18:56:55 +0200 Subject: [PATCH 04/13] feat(docs): remove inline warnings and apply admonitions --- docs/User Guide/!!!meta.json | 30 ++++--------- .../Import & Export/Evernote.md | 2 +- docs/User Guide/User Guide/FAQ.md | 24 +++++------ .../User Guide/Installation & Setup/Backup.md | 4 +- .../Docker Server Installation.md | 3 +- .../Kubernetes server installation.md | 2 +- .../Manual server installation.md | 6 ++- .../Packaged server installation.md | 8 ++-- .../Installation & Setup/Web Clipper.md | 2 +- .../Text/Content language & Right-to-le.md | 2 +- docs/User Guide/User Guide/Quick Start.md | 11 ++--- .../app/doc_notes/en/User Guide/!!!meta.json | 42 +++++++------------ .../Import & Export/Evernote.html | 3 +- .../en/User Guide/User Guide/FAQ.html | 36 +++++----------- .../Installation & Setup/Backup.html | 3 +- .../Docker Server Installation.html | 12 +++--- .../Kubernetes server installation.html | 7 ++-- .../Manual server installation.html | 4 +- .../Packaged server installation.html | 12 +++--- .../Installation & Setup/Web Clipper.html | 2 +- .../Text/Content language & Right-to-le.html | 2 +- .../en/User Guide/User Guide/Quick Start.html | 8 +--- .../app/doc_notes/en/User Guide/style.css | 26 ++++++++++++ 23 files changed, 109 insertions(+), 142 deletions(-) diff --git a/docs/User Guide/!!!meta.json b/docs/User Guide/!!!meta.json index 3761a28f7..b16a700b6 100644 --- a/docs/User Guide/!!!meta.json +++ b/docs/User Guide/!!!meta.json @@ -9,7 +9,7 @@ "pOsGYCXsbNQG" ], "title": "User Guide", - "notePosition": 90, + "notePosition": 10, "prefix": null, "isExpanded": false, "type": "text", @@ -1481,13 +1481,6 @@ "type": "text", "mime": "text/markdown", "attributes": [ - { - "type": "relation", - "name": "imageLink", - "value": "JXFeNgU8Xnp1", - "isInheritable": false, - "position": 10 - }, { "type": "relation", "name": "internalLink", @@ -1516,13 +1509,6 @@ "isInheritable": false, "position": 50 }, - { - "type": "relation", - "name": "internalLink", - "value": "BFs8mudNFgCS", - "isInheritable": false, - "position": 60 - }, { "type": "label", "name": "shareAlias", @@ -1648,13 +1634,6 @@ "isInheritable": false, "position": 40 }, - { - "type": "relation", - "name": "internalLink", - "value": "_lbSettings", - "isInheritable": false, - "position": 50 - }, { "type": "label", "name": "iconClass", @@ -6553,6 +6532,13 @@ "value": "bx bx-question-mark", "isInheritable": false, "position": 40 + }, + { + "type": "relation", + "name": "internalLink", + "value": "wy8So3yZZlH9", + "isInheritable": false, + "position": 80 } ], "format": "markdown", diff --git a/docs/User Guide/User Guide/Basic Concepts/Import & Export/Evernote.md b/docs/User Guide/User Guide/Basic Concepts/Import & Export/Evernote.md index 26136cb78..3815c2477 100644 --- a/docs/User Guide/User Guide/Basic Concepts/Import & Export/Evernote.md +++ b/docs/User Guide/User Guide/Basic Concepts/Import & Export/Evernote.md @@ -15,4 +15,4 @@ After importing the ENEX file, go over the imported notes and resources to be su All resources (except for images) are created as note's attachments. -HTML inside ENEX files is not exactly valid so some formatting maybe broken or lost. You can report major problems into [Trilium issue tracker](https://github.com/TriliumNext/Notes/issues). %%{WARNING}%% \ No newline at end of file +HTML inside ENEX files is not exactly valid so some formatting maybe broken or lost. You can report major problems into [Trilium issue tracker](https://github.com/TriliumNext/Notes/issues). \ No newline at end of file diff --git a/docs/User Guide/User Guide/FAQ.md b/docs/User Guide/User Guide/FAQ.md index b9ce905dd..da5cfa02a 100644 --- a/docs/User Guide/User Guide/FAQ.md +++ b/docs/User Guide/User Guide/FAQ.md @@ -1,23 +1,17 @@ # FAQ -## Mac OS support +## macOS support -Originally, desktop builds of Trilium Notes has been available for Windows & Linux, but there has been a considerable demand for macOS build. +Originally, Trilium Notes considered the macOS build unsupported. TriliumNext commits to make the experience on macOS as good as possible. -So I made one, but I underestimated the differences and specifics of Mac platform which seems to require special handling in several places. My lack of knowledge and frankly willingness to learn & code Mac specific functionality resulted in a current state where [Trilium does not integrate well into the OS](https://github.com/TriliumNext/Notes/issues/511)  +if you find any platform-specific issues, feel free to [report them](Troubleshooting/Reporting%20issues.md). -%%{WARNING}%%. +## Translation / localisation support -macOS build is from now on considered "unsupported". I will strive to keep it fundamentally functional, but I won't work on Mac specific features or integrations. Note that this is more of an acknowledgment of an existing state rather than sudden change of direction. +The original Trilium Notes application did not support multiple languages. Since we believe that internationalisation is a core part of an application, we have added support for it. -Of course, PRs are welcome. +Contributions to translations are welcome. -## Translation / localization support - -Trilium is currently available only in English. Translation to other languages is not planned in the near/medium term because it brings a significant maintenance overhead. This decision might be revisited once Trilium stabilizes into a more mature product. - -For Chinese, there's an unofficial fork [here](https://github.com/Nriver/trilium-translation). Use at your own risk. - -## Multi user support +## Multi-user support Common request is to allow multiple users collaborate, share notes etc. So far I'm resisting this because of these reasons: @@ -41,7 +35,9 @@ No. These general purpose sync apps are not suitable to sync database files which are open and being worked on by another application. The result is that they will corrupt the database file, resulting in data loss and this message in the Trilium logs: -> SqliteError: database disk image is malformed +``` +SqliteError: database disk image is malformed +``` The only supported way to sync Trilium's data across the network is to use a [sync/web server](Installation%20%26%20Setup/Synchronization.md). diff --git a/docs/User Guide/User Guide/Installation & Setup/Backup.md b/docs/User Guide/User Guide/Installation & Setup/Backup.md index 0f42dd79a..a67971a49 100644 --- a/docs/User Guide/User Guide/Installation & Setup/Backup.md +++ b/docs/User Guide/User Guide/Installation & Setup/Backup.md @@ -18,7 +18,7 @@ Let's assume you want to restore the weekly backup, here's how to do it: * find [data directory](Data%20directory.md) Trilium uses - easy way is to open "About Trilium Notes" from "Menu" in upper left corner and looking at "data directory" * I'll refer to `~/trilium-data` as data directory from now on -* find `~/trilium-data/backup/backup-weekly.db` - this is the [document](#root/xjSsCcvVZf6H)backup +* find `~/trilium-data/backup/backup-weekly.db` - this is the [document](#root/xjSsCcvVZf6H) backup * at this point stop/kill Trilium * delete `~/trilium-data/document.db`, `~/trilium-data/document.db-wal` and `~/trilium-data/document.db-shm` (latter two files are auto generated) * copy and rename this `~/trilium-data/backup/backup-weekly.db` to `~/trilium-data/document.db` @@ -40,4 +40,4 @@ noBackup=true You can also review the [configuration](../Advanced%20Usage/Configuration%20\(config.ini%20or%20e.md) file to provide all `config.ini` values as environment variables instead. -See [sample config](https://github.com/TriliumNext/Notes/blob/master/config-sample.ini). %%{WARNING}%% \ No newline at end of file +See [sample config](https://github.com/TriliumNext/Notes/blob/master/config-sample.ini). \ No newline at end of file diff --git a/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Docker Server Installation.md b/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Docker Server Installation.md index 1663494df..53d0d9dd2 100644 --- a/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Docker Server Installation.md +++ b/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Docker Server Installation.md @@ -9,7 +9,8 @@ If you need help installing Docker, reference the [Docker Installation Docs](htt **Note:** Trilium's Docker container requires root privileges to operate correctly. -> \[!WARNING\] If you're using a SMB/CIFS share or folder as your Trilium data directory, [you'll need](https://github.com/TriliumNext/Notes/issues/415#issuecomment-2344824400) to add the mount options of `nobrl` and `noperm` when mounting your SMB share. +> [!WARNING] +> If you're using a SMB/CIFS share or folder as your Trilium data directory, [you'll need](https://github.com/TriliumNext/Notes/issues/415#issuecomment-2344824400) to add the mount options of `nobrl` and `noperm` when mounting your SMB share. ## Running with Docker Compose diff --git a/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Kubernetes server installation.md b/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Kubernetes server installation.md index e78ea9ae5..8444cc185 100644 --- a/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Kubernetes server installation.md +++ b/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Kubernetes server installation.md @@ -5,7 +5,7 @@ The recommended way is to use a Helm chart. ## Root privileges -> \[!NOTE\] +> [!NOTE] > The Trilium container at this time needs to be run with root privileges. It will swap to UID and GID `1000:1000` to run the `node` process after execution though, so the main process doesn't run with root privileges. The Trilium docker container needs to be run with root privileges. The node process inside the container will be started with reduced privileges (uid:gid 1000:1000) after some initialization logic. Please make sure that you don't use a security context (PodSecurityContext) which changes the user ID. To use a different uid:gid for file storage and the application, please use the `USER_UID` & `USER_GID` environment variables. diff --git a/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Manual server installation.md b/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Manual server installation.md index 95f178c29..7f1778557 100644 --- a/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Manual server installation.md +++ b/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Manual server installation.md @@ -25,10 +25,12 @@ sudo apt install libpng16-16 libpng-dev pkg-config autoconf libtool build-essent ### Download -You can either download source code zip/tar from [https://github.com/TriliumNext/Notes/releases/latest\]\]](https://github.com/TriliumNext/Notes/releases/latest%5D%5D) %%{WARNING}%%or clone git repository **from stable branch** with +You can either download source code zip/tar from [https://github.com/TriliumNext/Notes/releases/latest](https://github.com/TriliumNext/Notes/releases/latest). + +For the latest version including betas, clone Git repository **from** `**master**` **branch** with: ``` -git clone -b stable https://github.com/triliumnext/notes.git %%{WARNING}%% +git clone -b master https://github.com/triliumnext/notes.git ``` ## Installation diff --git a/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Packaged server installation.md b/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Packaged server installation.md index 576c78891..c0842534e 100644 --- a/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Packaged server installation.md +++ b/docs/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Packaged server installation.md @@ -3,9 +3,9 @@ This is essentially Trilium sources + node modules + node.js runtime packaged in ## Steps -* ssh into your server -* use `wget` (or `curl` or whatever) to download latest [trilium-linux-x64-server-\[VERSION\].xz](https://github.com/TriliumNext/Notes/releases/latest)%%{WARNING}%% (notice -server suffix) on your server -* unpack the archive, e.g. using `tar -xf -d trilium-linux-x64-server-[VERSION].tar.xz` +* SSH into your server +* use `wget` (or `curl`) to download latest `TriliumNextNotes-Server-[VERSION]-linux-x64.tar.xz` (notice `-Server` suffix) on your server. +* unpack the archive, e.g. using `tar -xf -d TriliumNextNotes-Server-[VERSION]-linux-x64.tar.xz` * `cd trilium-linux-x64-server` * `./trilium.sh` * you can open the browser and open http://\[your-server-hostname\]:8080 and you should see Trilium initialization page @@ -20,7 +20,7 @@ The problem with above steps is that once you close the SSH connection, the Tril * After downloading, extract and move Trilium: ``` -tar -xvf trilium-linux-x64-server-[VERSION].tar.xz +tar -xvf TriliumNextNotes-Server-[VERSION]-linux-x64.tar.xz sudo mv trilium-linux-x64-server /opt/trilium ``` diff --git a/docs/User Guide/User Guide/Installation & Setup/Web Clipper.md b/docs/User Guide/User Guide/Installation & Setup/Web Clipper.md index 1124e7346..f88570db2 100644 --- a/docs/User Guide/User Guide/Installation & Setup/Web Clipper.md +++ b/docs/User Guide/User Guide/Installation & Setup/Web Clipper.md @@ -24,7 +24,7 @@ If there's multiple clippings from the same page (and on the same day), then the **Extension is available from:** * [Project release page](https://github.com/TriliumNext/web-clipper/releases) - .xpi for Firefox and .zip for Chromium based browsers. -* %%{WARNING}%% [Chrome Web Store](https://chromewebstore.google.com/detail/trilium-web-clipper/dfhgmnfclbebfobmblelddiejjcijbjm) +* [Chrome Web Store](https://chromewebstore.google.com/detail/trilium-web-clipper/dfhgmnfclbebfobmblelddiejjcijbjm) ## Configuration diff --git a/docs/User Guide/User Guide/Note Types/Text/Content language & Right-to-le.md b/docs/User Guide/User Guide/Note Types/Text/Content language & Right-to-le.md index 7fbee885a..81eb9bd15 100644 --- a/docs/User Guide/User Guide/Note Types/Text/Content language & Right-to-le.md +++ b/docs/User Guide/User Guide/Note Types/Text/Content language & Right-to-le.md @@ -1,5 +1,5 @@ # Content language & Right-to-left support -![](Content%20language%20&%20Right-t.png) +![](api/images/4yHAD34xyvAl/Content%20language%20&%20Right-t.png) A language hint can be provided for text notes. This option informs the browser or the desktop application about the language the note is written in (for example this might help with spellchecking), and it also determines whether the text is displayed from right-to-left for languages such as Arabic, Hebrew, etc. diff --git a/docs/User Guide/User Guide/Quick Start.md b/docs/User Guide/User Guide/Quick Start.md index 0cad4b291..e214387a6 100644 --- a/docs/User Guide/User Guide/Quick Start.md +++ b/docs/User Guide/User Guide/Quick Start.md @@ -9,16 +9,11 @@ 1. [Server installation](Installation%20%26%20Setup/Server%20Installation.md) 2. [Mobile frontend](Installation%20%26%20Setup/Mobile%20Frontend.md) (optional) -3. [![Deploy](Attachments/home-button.svg)](https://heroku.com/deploy?template=https://github.com/feilongfl/trilium-heroku) %%{WARNING}%% -4. [PikaPods managed hosting](https://www.pikapods.com/pods?run=trilium-next) +3. [PikaPods managed hosting](https://www.pikapods.com/pods?run=trilium-next) -**Combination of server and desktop/laptop** - Install the application on both a server, for web access and data synchronization, and desktop instance(s). This allows all the data to be stored on the server and either accessed from the web browser, or the desktop application. The desktop application will sync and store the data locally so that it can be used when offline. +**Combination of server and desktop/laptop** - Install the application on both a server, for web access and data synchronisation, and desktop instance(s). This allows all the data to be stored on the server and either accessed from the web browser, or the desktop application. The desktop application will sync and store the data locally so that it can be used when offline. 1. [Server installation](Installation%20%26%20Setup/Server%20Installation.md) 2. [Mobile frontend](Installation%20%26%20Setup/Mobile%20Frontend.md) (optional) 3. [Desktop installation](Installation%20%26%20Setup/Desktop%20Installation.md) -4. [Synchronization](Installation%20%26%20Setup/Synchronization.md) - -## Basic concepts - -1. Understand [Note](Basic%20Concepts/Note.md) \ No newline at end of file +4. [Synchronization](Installation%20%26%20Setup/Synchronization.md) \ No newline at end of file diff --git a/src/public/app/doc_notes/en/User Guide/!!!meta.json b/src/public/app/doc_notes/en/User Guide/!!!meta.json index 542666e59..54c523b7a 100644 --- a/src/public/app/doc_notes/en/User Guide/!!!meta.json +++ b/src/public/app/doc_notes/en/User Guide/!!!meta.json @@ -9,9 +9,9 @@ "pOsGYCXsbNQG" ], "title": "User Guide", - "notePosition": 110, + "notePosition": 10, "prefix": null, - "isExpanded": false, + "isExpanded": true, "type": "text", "mime": "text/html", "attributes": [], @@ -1481,13 +1481,6 @@ "type": "text", "mime": "text/markdown", "attributes": [ - { - "type": "relation", - "name": "imageLink", - "value": "JXFeNgU8Xnp1", - "isInheritable": false, - "position": 10 - }, { "type": "relation", "name": "internalLink", @@ -1516,13 +1509,6 @@ "isInheritable": false, "position": 50 }, - { - "type": "relation", - "name": "internalLink", - "value": "BFs8mudNFgCS", - "isInheritable": false, - "position": 60 - }, { "type": "label", "name": "shareAlias", @@ -1552,7 +1538,7 @@ "title": "Basic Concepts", "notePosition": 60, "prefix": null, - "isExpanded": false, + "isExpanded": true, "type": "text", "mime": "text/html", "attributes": [ @@ -1648,13 +1634,6 @@ "isInheritable": false, "position": 40 }, - { - "type": "relation", - "name": "internalLink", - "value": "_lbSettings", - "isInheritable": false, - "position": 50 - }, { "type": "label", "name": "iconClass", @@ -3073,7 +3052,7 @@ "title": "Import & Export", "notePosition": 90, "prefix": null, - "isExpanded": false, + "isExpanded": true, "type": "text", "mime": "text/html", "attributes": [], @@ -5554,7 +5533,7 @@ "title": "Installation & Setup", "notePosition": 160, "prefix": null, - "isExpanded": false, + "isExpanded": true, "type": "text", "mime": "text/html", "attributes": [ @@ -5629,7 +5608,7 @@ "title": "Server Installation", "notePosition": 20, "prefix": null, - "isExpanded": false, + "isExpanded": true, "type": "text", "mime": "text/markdown", "attributes": [ @@ -5742,7 +5721,7 @@ "title": "1. Installing the server", "notePosition": 10, "prefix": null, - "isExpanded": false, + "isExpanded": true, "type": "text", "mime": "text/html", "attributes": [], @@ -6553,6 +6532,13 @@ "value": "bx bx-question-mark", "isInheritable": false, "position": 40 + }, + { + "type": "relation", + "name": "internalLink", + "value": "wy8So3yZZlH9", + "isInheritable": false, + "position": 80 } ], "format": "html", diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Basic Concepts/Import & Export/Evernote.html b/src/public/app/doc_notes/en/User Guide/User Guide/Basic Concepts/Import & Export/Evernote.html index 39a4d5c84..2d8457eba 100644 --- a/src/public/app/doc_notes/en/User Guide/User Guide/Basic Concepts/Import & Export/Evernote.html +++ b/src/public/app/doc_notes/en/User Guide/User Guide/Basic Concepts/Import & Export/Evernote.html @@ -28,8 +28,7 @@

Limitations

All resources (except for images) are created as note's attachments.

HTML inside ENEX files is not exactly valid so some formatting maybe broken - or lost. You can report major problems into Trilium issue tracker. - %%{WARNING}%%

+ or lost. You can report major problems into Trilium issue tracker.

diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/FAQ.html b/src/public/app/doc_notes/en/User Guide/User Guide/FAQ.html index ed2c38ea2..1c841a973 100644 --- a/src/public/app/doc_notes/en/User Guide/User Guide/FAQ.html +++ b/src/public/app/doc_notes/en/User Guide/User Guide/FAQ.html @@ -13,27 +13,16 @@

FAQ

-

Mac OS support

-

Originally, desktop builds of Trilium Notes has been available for Windows - & Linux, but there has been a considerable demand for macOS build.

-

So I made one, but I underestimated the differences and specifics of Mac - platform which seems to require special handling in several places. My - lack of knowledge and frankly willingness to learn & code Mac specific - functionality resulted in a current state where Trilium does not integrate well into the OS 

-

%%{WARNING}%%.

-

macOS build is from now on considered "unsupported". I will strive to - keep it fundamentally functional, but I won't work on Mac specific features - or integrations. Note that this is more of an acknowledgment of an existing - state rather than sudden change of direction.

-

Of course, PRs are welcome.

-

Translation / localization support

-

Trilium is currently available only in English. Translation to other languages - is not planned in the near/medium term because it brings a significant - maintenance overhead. This decision might be revisited once Trilium stabilizes - into a more mature product.

-

For Chinese, there's an unofficial fork here. - Use at your own risk.

-

Multi user support

+

macOS support

+

Originally, Trilium Notes considered the macOS build unsupported. TriliumNext + commits to make the experience on macOS as good as possible.

+

if you find any platform-specific issues, feel free to report them.

+

Translation / localisation support

+

The original Trilium Notes application did not support multiple languages. + Since we believe that internationalisation is a core part of an application, + we have added support for it.

+

Contributions to translations are welcome.

+

Multi-user support

Common request is to allow multiple users collaborate, share notes etc. So far I'm resisting this because of these reasons:

    @@ -68,10 +57,7 @@

    These general purpose sync apps are not suitable to sync database files which are open and being worked on by another application. The result is that they will corrupt the database file, resulting in data loss and this - message in the Trilium logs:

    -
    -

    SqliteError: database disk image is malformed

    -
    + message in the Trilium logs:

    SqliteError: database disk image is malformed

    The only supported way to sync Trilium's data across the network is to use a sync/web server.

    Why database instead of flat files?

    diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Backup.html b/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Backup.html index 0bbd775ca..bbd3bde62 100644 --- a/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Backup.html +++ b/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Backup.html @@ -63,8 +63,7 @@ noBackup=true

    You can also review the configuration file to provide all config.ini values as environment variables instead.

    -

    See sample config. - %%{WARNING}%%

    +

    See sample config.

diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Docker Server Installation.html b/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Docker Server Installation.html index eb7fb661e..e56e70d01 100644 --- a/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Docker Server Installation.html +++ b/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Docker Server Installation.html @@ -23,12 +23,12 @@

Note: Trilium's Docker container requires root privileges to operate correctly.

-
-

[!WARNING] If you're using a SMB/CIFS share or folder as your Trilium - data directory, you'll need to - add the mount options of nobrl and noperm when mounting - your SMB share.

-
+

Running with Docker Compose

Grab the latest docker-compose.yml:

wget https://raw.githubusercontent.com/TriliumNext/Notes/master/docker-compose.yml

Optionally, edit the docker-compose.yml file to configure the diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Kubernetes server installation.html b/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Kubernetes server installation.html index 4a78feb28..bc2f06ae3 100644 --- a/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Kubernetes server installation.html +++ b/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Kubernetes server installation.html @@ -18,12 +18,11 @@ own Kubernetes deployment.

The recommended way is to use a Helm chart.

Root privileges

-
-

[!NOTE] -
The Trilium container at this time needs to be run with root privileges. +

+

The Trilium docker container needs to be run with root privileges. The node process inside the container will be started with reduced privileges (uid:gid 1000:1000) after some initialization logic. Please make sure that diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Manual server installation.html b/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Manual server installation.html index 48df65ee9..d125ca2c8 100644 --- a/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Manual server installation.html +++ b/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Manual server installation.html @@ -29,8 +29,8 @@ its derivatives (like Ubuntu) below:

sudo apt install libpng16-16 libpng-dev pkg-config autoconf libtool build-essential nasm libx11-dev libxkbfile-dev

Installation

Download

-

You can either download source code zip/tar from https://github.com/TriliumNext/Notes/releases/latest]] %%{WARNING}%%or - clone git repository from stable branch with

git clone -b stable https://github.com/triliumnext/notes.git %%{WARNING}%%
+

You can either download source code zip/tar from https://github.com/TriliumNext/Notes/releases/latest.

+

For the latest version including betas, clone Git repository from master branch with:

git clone -b master https://github.com/triliumnext/notes.git

Installation

cd trilium
 
 # download all node dependencies
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Packaged server installation.html b/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Packaged server installation.html
index 57c94f685..afbf79512 100644
--- a/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Packaged server installation.html	
+++ b/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Packaged server installation.html	
@@ -17,12 +17,10 @@
           into one 7z file.

Steps

    -
  • ssh into your server
  • -
  • use wget (or curl or whatever) to download latest - trilium-linux-x64-server-[VERSION].xz%%{WARNING}%% (notice -server - suffix) on your server
  • -
  • unpack the archive, e.g. using tar -xf -d trilium-linux-x64-server-[VERSION].tar.xz +
  • SSH into your server
  • +
  • use wget (or curl) to download latest TriliumNextNotes-Server-[VERSION]-linux-x64.tar.xz (notice -Server suffix) + on your server.
  • +
  • unpack the archive, e.g. using tar -xf -d TriliumNextNotes-Server-[VERSION]-linux-x64.tar.xz
  • cd trilium-linux-x64-server
  • @@ -41,7 +39,7 @@

    Configure Trilium to auto-run on boot with systemd

    • After downloading, extract and move Trilium:
    • -
    tar -xvf trilium-linux-x64-server-[VERSION].tar.xz
    +        
tar -xvf TriliumNextNotes-Server-[VERSION]-linux-x64.tar.xz
 sudo mv trilium-linux-x64-server /opt/trilium
  • Create the service:
  • diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Web Clipper.html b/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Web Clipper.html index e828be349..899ef8874 100644 --- a/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Web Clipper.html +++ b/src/public/app/doc_notes/en/User Guide/User Guide/Installation & Setup/Web Clipper.html @@ -42,7 +42,7 @@

    Configuration

    diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Text/Content language & Right-to-le.html b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Text/Content language & Right-to-le.html index 44c1e9ead..dcf97a09d 100644 --- a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Text/Content language & Right-to-le.html +++ b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Text/Content language & Right-to-le.html @@ -14,7 +14,7 @@

    -

    A language hint can be provided for text notes. This option informs the diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Quick Start.html b/src/public/app/doc_notes/en/User Guide/User Guide/Quick Start.html index 01f6dab01..caadb1cd5 100644 --- a/src/public/app/doc_notes/en/User Guide/User Guide/Quick Start.html +++ b/src/public/app/doc_notes/en/User Guide/User Guide/Quick Start.html @@ -27,12 +27,11 @@

  • Server installation
  • Mobile frontend (optional)
  • -
  • Deploy%%{WARNING}%%
  • PikaPods managed hosting
  • Combination of server and desktop/laptop - Install the - application on both a server, for web access and data synchronization, + application on both a server, for web access and data synchronisation, and desktop instance(s). This allows all the data to be stored on the server and either accessed from the web browser, or the desktop application. The desktop application will sync and store the data locally so that it can @@ -46,11 +45,6 @@

  • Synchronization
  • -

    Basic concepts

    -
      -
    1. Understand Note -
    2. -
    diff --git a/src/public/app/doc_notes/en/User Guide/style.css b/src/public/app/doc_notes/en/User Guide/style.css index 4243d146a..806e431a9 100644 --- a/src/public/app/doc_notes/en/User Guide/style.css +++ b/src/public/app/doc_notes/en/User Guide/style.css @@ -17,6 +17,32 @@ margin: 0 !important; } +.ck-content .admonition { + --accent-color: var(--card-border-color); + border: 1px solid var(--accent-color); + box-shadow: var(--card-box-shadow); + background: var(--card-background-color); + border-radius: 0.5em; + padding: 1em; + margin: 1.25em 0; + margin-right: 14px; + position: relative; +} + +.ck-content .admonition p:last-child { + margin-bottom: 0; +} + +.ck-content .admonition p, h2 { + margin-top: 0; +} + +.ck-content .admonition.note { --accent-color: #69c7ff; } +.ck-content .admonition.tip { --accent-color: #40c025; } +.ck-content .admonition.important { --accent-color: #9839f7; } +.ck-content .admonition.caution { --accent-color: #ff2e2e; } +.ck-content .admonition.warning { --accent-color: #e2aa03; } + /* * CKEditor 5 (v41.0.0) content styles. * Generated on Fri, 26 Jan 2024 10:23:49 GMT. From 00106580ca2d8a7acf40b2fde6f3452a574e8e1f Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 15 Mar 2025 19:31:45 +0200 Subject: [PATCH 05/13] fix(admonitions): floating images breaking out --- libraries/ckeditor/ckeditor-content.css | 1 + src/public/stylesheets/style.css | 1 + 2 files changed, 2 insertions(+) diff --git a/libraries/ckeditor/ckeditor-content.css b/libraries/ckeditor/ckeditor-content.css index 806e431a9..526d61f62 100644 --- a/libraries/ckeditor/ckeditor-content.css +++ b/libraries/ckeditor/ckeditor-content.css @@ -27,6 +27,7 @@ margin: 1.25em 0; margin-right: 14px; position: relative; + overflow: hidden; } .ck-content .admonition p:last-child { diff --git a/src/public/stylesheets/style.css b/src/public/stylesheets/style.css index c28735fec..42fdf0d97 100644 --- a/src/public/stylesheets/style.css +++ b/src/public/stylesheets/style.css @@ -1733,6 +1733,7 @@ footer.file-footer button { margin-right: 14px; position: relative; padding-left: 2.5em; + overflow: hidden; } .ck-content .admonition p:last-child { From 36fa0af706202f8f1a804268cce6324e582eb66e Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 15 Mar 2025 19:44:15 +0200 Subject: [PATCH 06/13] fix(docs): update calendar view documentation --- .../Note Types/Book/Calendar View.md | 14 +- .../Note Types/Book/Calendar View.html | 506 +++++++++--------- 2 files changed, 271 insertions(+), 249 deletions(-) diff --git a/docs/User Guide/User Guide/Note Types/Book/Calendar View.md b/docs/User Guide/User Guide/Note Types/Book/Calendar View.md index 03dcff25e..3aa113406 100644 --- a/docs/User Guide/User Guide/Note Types/Book/Calendar View.md +++ b/docs/User Guide/User Guide/Note Types/Book/Calendar View.md @@ -52,18 +52,22 @@ For each note of the calendar, the following attributes can be used: | `#calendar:color` | Similar to `#color`, but applies the color only for the event in the calendar and not for other places such as the note tree. | | `#iconClass` | If present, the icon of the note will be displayed to the left of the event title. | | `#calendar:title` | Changes the title of an event to point to an attribute of the note other than the title, either a label (e.g. `#assignee`) or a relation (e.g. `~for`). See _Advanced use-cases_ for more information. | -| `#calendar:promotedAttributes` | Allows displaying the value of one or more promoted attributes in the calendar like this: ![](13_Calendar%20View_image.png)

    `
    #label:weight="promoted,number,single,precision=1"
    #label:mood="promoted,alias=Mood,single,text"
    #calendar:promotedAttributes="label:weight,label:mood"
    `

    It can also be used with relations, case in which it will display the title of the target note:

    `
    #relation:assignee="promoted,alias=Assignee,single,text"
    #calendar:promotedAttributes="relation:assignee"
    ~assignee=@My assignee 
    ` | -| `#calendar:startDate` | Allows using a different label to represent the start date, other than `#startDate` (e.g. `#expiryDate`). The label name must be prefixed with `#`. If the label is not defined for a note, the default will be used instead. | -| `#calendar:endDate` | Allows using a different label to represent the start date, other than `#endDate`. The label name must be prefixed with `#`. If the label is not defined for a note, the default will be used instead. | +| `#calendar:displayedAttributes` | Allows displaying the value of one or more attributes in the calendar like this: 

    ![](13_Calendar%20View_image.png)

    ```
    #weight="70"
    #Mood="Good"
    #calendar:displayedAttributes="weight,Mood"
    ```

    It can also be used with relations, case in which it will display the title of the target note:

    ```
    ~assignee=@My assignee
    #calendar:displayedAttributes="assignee"
    ``` | +| `#calendar:startDate` | Allows using a different label to represent the start date, other than `startDate` (e.g. `expiryDate`). The label name **must not be** prefixed with `#`. If the label is not defined for a note, the default will be used instead. | +| `#calendar:endDate` | Allows using a different label to represent the start date, other than `endDate`. The label name **must not be** prefixed with `#`. If the label is not defined for a note, the default will be used instead. | ## How the calendar works -![](17_Calendar%20View_image.png)The calendar displays all the child notes of the book that have a `#startDate`. An `#endDate` can optionally be added. +![](17_Calendar%20View_image.png) + +The calendar displays all the child notes of the book that have a `#startDate`. An `#endDate` can optionally be added. If editing the start date and end date from the note itself is desirable, the following attributes can be added to the book note: ``` -#viewType=calendar #label:startDate(inheritable)="promoted,alias=Start Date,single,date" #label:endDate(inheritable)="promoted,alias=End Date,single,date" #hidePromotedAttributes +#viewType=calendar #label:startDate(inheritable)="promoted,alias=Start Date,single,date" +#label:endDate(inheritable)="promoted,alias=End Date,single,date" +#hidePromotedAttributes ``` This will result in: diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/Calendar View.html b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/Calendar View.html index 1965c2335..d834e0be5 100644 --- a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/Calendar View.html +++ b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/Calendar View.html @@ -21,34 +21,36 @@

    Unlike other Book view types, the Calendar view also allows some kind of interaction, such as moving events around as well as creating new ones.

    Creating a calendar

    - - - - - - - - - - - - - - - - - - - - -
    1 - - The Calendar View works only for Book note types. To create a new note, - right click on the note tree on the left and select Insert note after, - or Insert child note and then select Book.
    2 - - Once created, the “View type” of the Book needs changed to “Calendar”, - by selecting the “Book Properties” tab in the ribbon.
    +
    + + + + + + + + + + + + + + + + + + + + +
       
    1 + + The Calendar View works only for Book note types. To create a new note, + right click on the note tree on the left and select Insert note after, + or Insert child note and then select Book.
    2 + + Once created, the “View type” of the Book needs changed to “Calendar”, + by selecting the “Book Properties” tab in the ribbon.
    +

    Creating a new event/note

    • Clicking on a day will create a new child note and assign it to that particular @@ -81,226 +83,242 @@

    Configuring the calendar

    The following attributes can be added to the book type:

    - - - - - - - - - - - - - - - - - - - - - -
    NameDescription
    #calendar:hideWeekends - When present (regardless of value), it will hide Saturday and Sundays - from the calendar.
    #calendar:weekNumbers - When present (regardless of value), it will show the number of the week - on the calendar.
    ~child:template - Defines the template for newly created notes in the calendar (via dragging - or clicking).
    +
    + + + + + + + + + + + + + + + + + + + + + +
    NameDescription
    #calendar:hideWeekends + When present (regardless of value), it will hide Saturday and Sundays + from the calendar.
    #calendar:weekNumbers + When present (regardless of value), it will show the number of the week + on the calendar.
    ~child:template + Defines the template for newly created notes in the calendar (via dragging + or clicking).
    +

    In addition, the first day of the week can be either Sunday or Monday and can be adjusted from the application settings.

    Configuring the calendar events

    For each note of the calendar, the following attributes can be used:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameDescription
    #startDate - The date the event starts, which will display it in the calendar. The - format is YYYY-MM-DD (year, month and day separated by a minus - sign).
    #endDate - Similar to startDate, mentions the end date if the event spans - across multiple days. The date is inclusive, so the end day is also considered. - The attribute can be missing for single-day events.
    #color - Displays the event with a specified color (named such as red, gray or - hex such as #FF0000). This will also change the color of the - note in other places such as the note tree.
    #calendar:color - Similar to #color, but applies the color only for the event - in the calendar and not for other places such as the note tree.
    #iconClass - If present, the icon of the note will be displayed to the left of the - event title.
    #calendar:title - Changes the title of an event to point to an attribute of the note other - than the title, either a label (e.g. #assignee) or a relation - (e.g. ~for). See Advanced use-cases for more information.
    #calendar:promotedAttributes - Allows displaying the value of one or more promoted attributes in the - calendar like this: - -
    -
    <br>#label:weight="promoted,number,single,precision=1"<br>#label:mood="promoted,alias=Mood,single,text"<br>#calendar:promotedAttributes="label:weight,label:mood" <br> -
    -
    It can also be used with relations, case in which it will display the - title of the target note: -
    -
    <br>#relation:assignee="promoted,alias=Assignee,single,text"<br>#calendar:promotedAttributes="relation:assignee" <br>~assignee=@My assignee <br> -
    #calendar:startDate - Allows using a different label to represent the start date, other than #startDate (e.g. #expiryDate). - The label name must be prefixed with #. If the label is not - defined for a note, the default will be used instead.
    #calendar:endDate - Allows using a different label to represent the start date, other than #endDate. - The label name must be prefixed with #. If the label is not - defined for a note, the default will be used instead.
    -

    How the calendar works

    -

    - The calendar displays all the child notes of the book that have a #startDate. - An #endDate can optionally be added.

    -

    If editing the start date and end date from the note itself is desirable, - the following attributes can be added to the book note:

    #viewType=calendar #label:startDate(inheritable)="promoted,alias=Start Date,single,date" #label:endDate(inheritable)="promoted,alias=End Date,single,date" #hidePromotedAttributes 
    -

    This will result in:

    -

    - -

    -

    When not used in a Journal, the calendar is recursive. That is, it will - look for events not just in its child notes but also in the children of - these child notes.

    -

    Use-cases

    -

    Using with the Journal / calendar

    -

    It is possible to integrate the calendar view into the Journal with day - notes. In order to do so change the note type of the Journal note (calendar - root) to Book and then select the Calendar View.

    -

    Based on the #calendarRoot (or #workspaceCalendarRoot) - attribute, the calendar will know that it's in a calendar and apply the - following:

    -
      -
    • The calendar events are now rendered based on their dateNote attribute - rather than startDate.
    • -
    • Interactive editing such as dragging over an empty era or resizing an - event is no longer possible.
    • -
    • Clicking on the empty space on a date will automatically open that day's - note or create it if it does not exist.
    • -
    • Direct children of a day note will be displayed on the calendar despite - not having a dateNote attribute. Children of the child notes - will not be displayed.
    • -
    -

    - -

    -

    Using a different attribute as event title

    -

    By default, events are displayed on the calendar by their note title. - However, it is possible to configure a different attribute to be displayed - instead.

    -

    To do so, assign #calendar:title to the child note (not the - calendar/book note), with the value being #name where name can - be any label. The attribute can also come through inheritance such as a - template attribute. If the note does not have the requested label, the - title of the note will be used instead.

    - - - - - - - - - - - - - -
    - - - -
    -

    Using a relation attribute as event title

    -

    Similarly to using an attribute, use #calendar:title and set - it to ~name where name is the name of the relation - to use.

    -

    Moreover, if there are more relations of the same name, they will be displayed - as multiple events coming from the same note.

    - - - - - - - - - - - - - -
    - - - -
    -

    Note that it's even possible to have a #calendar:title on the - target note (e.g. “John Smith”) which will try to render an attribute of - it. Note that it's not possible to use a relation here as well for safety - reasons (an accidental recursion  of attributes could cause the application - to loop infinitely).

    - - - - - - - - - - - - - -
    - - - -
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameDescription
    #startDate + The date the event starts, which will display it in the calendar. The + format is YYYY-MM-DD (year, month and day separated by a minus + sign).
    #endDate + Similar to startDate, mentions the end date if the event spans + across multiple days. The date is inclusive, so the end day is also considered. + The attribute can be missing for single-day events.
    #color + Displays the event with a specified color (named such as red, gray or + hex such as #FF0000). This will also change the color of the + note in other places such as the note tree.
    #calendar:color + Similar to #color, but applies the color only for the event + in the calendar and not for other places such as the note tree.
    #iconClass + If present, the icon of the note will be displayed to the left of the + event title.
    #calendar:title + Changes the title of an event to point to an attribute of the note other + than the title, either a label (e.g. #assignee) or a relation + (e.g. ~for). See Advanced use-cases for more information.
    #calendar:displayedAttributes + +

    Allows displaying the value of one or more attributes in the calendar + like this: 

    +

    + +

    #weight="70"
    +#Mood="Good"
    +#calendar:displayedAttributes="weight,Mood"
    +

    It can also be used with relations, case in which it will display the + title of the target note:

    ~assignee=@My assignee
    +#calendar:displayedAttributes="assignee"
    +
    #calendar:startDate + Allows using a different label to represent the start date, other than startDate (e.g. expiryDate). + The label name must not be prefixed with #. + If the label is not defined for a note, the default will be used instead.
    #calendar:endDate + Allows using a different label to represent the start date, other than endDate. + The label name must not be prefixed with #. + If the label is not defined for a note, the default will be used instead.
    +
    +

    How the calendar works

    +

    + +

    +

    The calendar displays all the child notes of the book that have a #startDate. + An #endDate can optionally be added.

    +

    If editing the start date and end date from the note itself is desirable, + the following attributes can be added to the book note:

    #viewType=calendar #label:startDate(inheritable)="promoted,alias=Start Date,single,date"
    +#label:endDate(inheritable)="promoted,alias=End Date,single,date"
    +#hidePromotedAttributes 
    +

    This will result in:

    +

    + +

    +

    When not used in a Journal, the calendar is recursive. That is, it will + look for events not just in its child notes but also in the children of + these child notes.

    +

    Use-cases

    +

    Using with the Journal / calendar

    +

    It is possible to integrate the calendar view into the Journal with day + notes. In order to do so change the note type of the Journal note (calendar + root) to Book and then select the Calendar View.

    +

    Based on the #calendarRoot (or #workspaceCalendarRoot) + attribute, the calendar will know that it's in a calendar and apply the + following:

    +
      +
    • The calendar events are now rendered based on their dateNote attribute + rather than startDate.
    • +
    • Interactive editing such as dragging over an empty era or resizing an + event is no longer possible.
    • +
    • Clicking on the empty space on a date will automatically open that day's + note or create it if it does not exist.
    • +
    • Direct children of a day note will be displayed on the calendar despite + not having a dateNote attribute. Children of the child notes + will not be displayed.
    • +
    +

    + +

    +

    Using a different attribute as event title

    +

    By default, events are displayed on the calendar by their note title. + However, it is possible to configure a different attribute to be displayed + instead.

    +

    To do so, assign #calendar:title to the child note (not the + calendar/book note), with the value being #name where name can + be any label. The attribute can also come through inheritance such as a + template attribute. If the note does not have the requested label, the + title of the note will be used instead.

    +
    + + + + + + + + + + + + + +
      
    + + + +
    +
    +

    Using a relation attribute as event title

    +

    Similarly to using an attribute, use #calendar:title and set + it to ~name where name is the name of the relation + to use.

    +

    Moreover, if there are more relations of the same name, they will be displayed + as multiple events coming from the same note.

    +
    + + + + + + + + + + + + + +
      
    + + + +
    +
    +

    Note that it's even possible to have a #calendar:title on the + target note (e.g. “John Smith”) which will try to render an attribute of + it. Note that it's not possible to use a relation here as well for safety + reasons (an accidental recursion  of attributes could cause the application + to loop infinitely).

    +
    + + + + + + + + + + + + + +
      
    + + + +
    +
    From 30593eeeacd210b6c61f838f568f5f753e3b06da Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 15 Mar 2025 21:07:02 +0200 Subject: [PATCH 07/13] refactor(import/markdown): change renderer instead of applying an uglifier --- src/services/import/markdown.ts | 72 +++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/src/services/import/markdown.ts b/src/services/import/markdown.ts index e42846404..bff72e592 100644 --- a/src/services/import/markdown.ts +++ b/src/services/import/markdown.ts @@ -1,36 +1,49 @@ "use strict"; import { parse, Renderer, type Tokens } from "marked"; -import { minify as minifyHtml } from "html-minifier"; + +class CustomMarkdownRenderer extends Renderer { + + heading(data: Tokens.Heading): string { + return super.heading(data).trimEnd(); + } + + paragraph(data: Tokens.Paragraph): string { + return super.paragraph(data).trimEnd(); + } + + code({ text, lang, escaped }: Tokens.Code): string { + if (!text) { + return ""; + } + + const ckEditorLanguage = getNormalizedMimeFromMarkdownLanguage(lang); + return `
    ${text}
    `; + } + + blockquote({ tokens }: Tokens.Blockquote): string { + const body = renderer.parser.parse(tokens); + + const admonitionMatch = /^

    \[\!([A-Z]+)\]/.exec(body); + if (Array.isArray(admonitionMatch) && admonitionMatch.length === 2) { + const type = admonitionMatch[1].toLowerCase(); + + if (ADMONITION_TYPE_MAPPINGS[type]) { + const bodyWithoutHeader = body + .replace(/^

    \[\!([A-Z]+)\]/, "

    ") + .replace(/^

    <\/p>/, ""); // Having a heading will generate an empty paragraph that we need to remove. + + return `

    \n`; + } + } + + return `
    \n${body}
    \n`; + } + +} // Keep renderer code up to date with https://github.com/markedjs/marked/blob/master/src/Renderer.ts. -const renderer = new Renderer({ async: false }); -renderer.code = ({ text, lang, escaped }: Tokens.Code) => { - if (!text) { - return ""; - } - - const ckEditorLanguage = getNormalizedMimeFromMarkdownLanguage(lang); - return `
    ${text}
    `; -}; -renderer.blockquote = ({ tokens }: Tokens.Blockquote) => { - const body = renderer.parser.parse(tokens); - - const admonitionMatch = /^

    \[\!([A-Z]+)\]/.exec(body); - if (Array.isArray(admonitionMatch) && admonitionMatch.length === 2) { - const type = admonitionMatch[1].toLowerCase(); - - if (ADMONITION_TYPE_MAPPINGS[type]) { - const bodyWithoutHeader = body - .replace(/^

    \[\!([A-Z]+)\]/, "

    ") - .replace(/^

    <\/p>/, ""); // Having a heading will generate an empty paragraph that we need to remove. - - return `

    \n`; - } - } - - return `
    \n${body}
    \n`; -}; +const renderer = new CustomMarkdownRenderer({ async: false }); import htmlSanitizer from "../html_sanitizer.js"; import importUtils from "./utils.js"; @@ -46,9 +59,6 @@ function renderToHtml(content: string, title: string) { // h1 handling needs to come before sanitization html = importUtils.handleH1(html, title); html = htmlSanitizer.sanitize(html); - html = minifyHtml(html, { - collapseWhitespace: true - }); return html; } From 1bf16bfa226e6bb8b8a618fb7129534828998bc9 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 15 Mar 2025 21:20:44 +0200 Subject: [PATCH 08/13] feat(import/markdown): remove spaces in lists --- src/services/import/markdown.spec.ts | 8 +++++++- src/services/import/markdown.ts | 24 ++++++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/services/import/markdown.spec.ts b/src/services/import/markdown.spec.ts index 5d5ccd33c..b6cddcc2b 100644 --- a/src/services/import/markdown.spec.ts +++ b/src/services/import/markdown.spec.ts @@ -62,10 +62,16 @@ Title code block 1 second line 2 \`\`\` + +* Hello +* world + +1. Hello +2. World `; const expected = `\

    Heading 1

    Title

    code block 1
    -second line 2
    `; +second line 2
  • Hello
  • world
  1. Hello
  2. World
`; expect(markdownService.renderToHtml(input, "Troubleshooting")).toBe(expected); }); diff --git a/src/services/import/markdown.ts b/src/services/import/markdown.ts index bff72e592..42462dfa2 100644 --- a/src/services/import/markdown.ts +++ b/src/services/import/markdown.ts @@ -2,6 +2,9 @@ import { parse, Renderer, type Tokens } from "marked"; +/** + * Keep renderer code up to date with https://github.com/markedjs/marked/blob/master/src/Renderer.ts. + */ class CustomMarkdownRenderer extends Renderer { heading(data: Tokens.Heading): string { @@ -12,13 +15,23 @@ class CustomMarkdownRenderer extends Renderer { return super.paragraph(data).trimEnd(); } - code({ text, lang, escaped }: Tokens.Code): string { + code({ text, lang }: Tokens.Code): string { if (!text) { - return ""; - } + return ""; + } - const ckEditorLanguage = getNormalizedMimeFromMarkdownLanguage(lang); - return `
${text}
`; + const ckEditorLanguage = getNormalizedMimeFromMarkdownLanguage(lang); + return `
${text}
`; + } + + list(token: Tokens.List): string { + return super.list(token) + .replace("\n", "") // we replace the first one only. + .trimEnd(); + } + + listitem(item: Tokens.ListItem): string { + return super.listitem(item).trimEnd(); } blockquote({ tokens }: Tokens.Blockquote): string { @@ -42,7 +55,6 @@ class CustomMarkdownRenderer extends Renderer { } -// Keep renderer code up to date with https://github.com/markedjs/marked/blob/master/src/Renderer.ts. const renderer = new CustomMarkdownRenderer({ async: false }); import htmlSanitizer from "../html_sanitizer.js"; From 182bccad39ccd397826837b2ddc13d7f85de7c2e Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 15 Mar 2025 22:14:21 +0200 Subject: [PATCH 09/13] chore(client/ts): port some dialogs --- src/public/app/services/import.ts | 14 ++++----- ...sword.js => protected_session_password.ts} | 9 ++++-- .../{recent_changes.js => recent_changes.ts} | 31 +++++++++++++------ ...ort_child_notes.js => sort_child_notes.ts} | 7 ++++- ...d_attachments.js => upload_attachments.ts} | 28 ++++++++++++----- 5 files changed, 62 insertions(+), 27 deletions(-) rename src/public/app/widgets/dialogs/{protected_session_password.js => protected_session_password.ts} (89%) rename src/public/app/widgets/dialogs/{recent_changes.js => recent_changes.ts} (86%) rename src/public/app/widgets/dialogs/{sort_child_notes.js => sort_child_notes.ts} (96%) rename src/public/app/widgets/dialogs/{upload_attachments.js => upload_attachments.ts} (80%) diff --git a/src/public/app/services/import.ts b/src/public/app/services/import.ts index 0c6c25f11..453449e3c 100644 --- a/src/public/app/services/import.ts +++ b/src/public/app/services/import.ts @@ -6,15 +6,15 @@ import appContext from "../components/app_context.js"; import { t } from "./i18n.js"; interface UploadFilesOptions { - safeImport: boolean; - shrinkImages: boolean; - textImportedAsText: boolean; - codeImportedAsCode: boolean; - explodeArchives: boolean; - replaceUnderscoresWithSpaces: boolean; + safeImport?: boolean; + shrinkImages: "true" | "false"; + textImportedAsText?: boolean; + codeImportedAsCode?: boolean; + explodeArchives?: boolean; + replaceUnderscoresWithSpaces?: boolean; } -export async function uploadFiles(entityType: string, parentNoteId: string, files: string[], options: UploadFilesOptions) { +export async function uploadFiles(entityType: string, parentNoteId: string, files: string[] | File[], options: UploadFilesOptions) { if (!["notes", "attachments"].includes(entityType)) { throw new Error(`Unrecognized import entity type '${entityType}'.`); } diff --git a/src/public/app/widgets/dialogs/protected_session_password.js b/src/public/app/widgets/dialogs/protected_session_password.ts similarity index 89% rename from src/public/app/widgets/dialogs/protected_session_password.js rename to src/public/app/widgets/dialogs/protected_session_password.ts index 600a0f165..abc383624 100644 --- a/src/public/app/widgets/dialogs/protected_session_password.js +++ b/src/public/app/widgets/dialogs/protected_session_password.ts @@ -27,14 +27,19 @@ const TPL = ` `; export default class ProtectedSessionPasswordDialog extends BasicWidget { + + private modal!: bootstrap.Modal; + private $passwordForm!: JQuery; + private $passwordInput!: JQuery; + doRender() { this.$widget = $(TPL); - this.modal = Modal.getOrCreateInstance(this.$widget); + this.modal = Modal.getOrCreateInstance(this.$widget[0]); this.$passwordForm = this.$widget.find(".protected-session-password-form"); this.$passwordInput = this.$widget.find(".protected-session-password"); this.$passwordForm.on("submit", () => { - const password = this.$passwordInput.val(); + const password = String(this.$passwordInput.val()); this.$passwordInput.val(""); protectedSessionService.setupProtectedSession(password); diff --git a/src/public/app/widgets/dialogs/recent_changes.js b/src/public/app/widgets/dialogs/recent_changes.ts similarity index 86% rename from src/public/app/widgets/dialogs/recent_changes.js rename to src/public/app/widgets/dialogs/recent_changes.ts index 0d3cd9803..9961817b1 100644 --- a/src/public/app/widgets/dialogs/recent_changes.js +++ b/src/public/app/widgets/dialogs/recent_changes.ts @@ -1,6 +1,6 @@ import { formatDateTime } from "../../utils/formatters.js"; import { t } from "../../services/i18n.js"; -import appContext from "../../components/app_context.js"; +import appContext, { type EventData } from "../../components/app_context.js"; import BasicWidget from "../basic_widget.js"; import dialogService from "../../services/dialog.js"; import froca from "../../services/froca.js"; @@ -28,10 +28,23 @@ const TPL = ` `; +// TODO: Deduplicate with server. +interface RecentChangesRow { + noteId: string; + date: string; +} + export default class RecentChangesDialog extends BasicWidget { + + private ancestorNoteId?: string; + + private modal!: bootstrap.Modal; + private $content!: JQuery; + private $eraseDeletedNotesNow!: JQuery; + doRender() { this.$widget = $(TPL); - this.modal = Modal.getOrCreateInstance(this.$widget); + this.modal = Modal.getOrCreateInstance(this.$widget[0]); this.$content = this.$widget.find(".recent-changes-content"); this.$eraseDeletedNotesNow = this.$widget.find(".erase-deleted-notes-now-button"); @@ -44,7 +57,7 @@ export default class RecentChangesDialog extends BasicWidget { }); } - async showRecentChangesEvent({ ancestorNoteId }) { + async showRecentChangesEvent({ ancestorNoteId }: EventData<"showRecentChanges">) { this.ancestorNoteId = ancestorNoteId; await this.refresh(); @@ -57,7 +70,7 @@ export default class RecentChangesDialog extends BasicWidget { this.ancestorNoteId = hoistedNoteService.getHoistedNoteId(); } - const recentChangesRows = await server.get(`recent-changes/${this.ancestorNoteId}`); + const recentChangesRows = await server.get(`recent-changes/${this.ancestorNoteId}`); // preload all notes into cache await froca.getNotes( @@ -110,7 +123,7 @@ export default class RecentChangesDialog extends BasicWidget { } } else { const note = await froca.getNote(change.noteId); - const notePath = note.getBestNotePathString(); + const notePath = note?.getBestNotePathString(); if (notePath) { $noteLink = await linkService.createLink(notePath, { @@ -118,7 +131,7 @@ export default class RecentChangesDialog extends BasicWidget { showNotePath: true }); } else { - $noteLink = $("").text(note.title); + $noteLink = $("").text(note?.title ?? ""); } } @@ -131,9 +144,7 @@ export default class RecentChangesDialog extends BasicWidget { appContext.tabManager.getActiveContext().setNote(change.noteId); } }) - .addClass(() => { - if (change.current_isDeleted) return "deleted-note"; - }) + .toggleClass("deleted-note", !!change.current_isDeleted) .append($("").text(formattedTime).attr("title", change.date)) .append($noteLink.addClass("note-title")) ); @@ -143,7 +154,7 @@ export default class RecentChangesDialog extends BasicWidget { } } - groupByDate(rows) { + groupByDate(rows: RecentChangesRow[]) { const groupedByDate = new Map(); for (const row of rows) { diff --git a/src/public/app/widgets/dialogs/sort_child_notes.js b/src/public/app/widgets/dialogs/sort_child_notes.ts similarity index 96% rename from src/public/app/widgets/dialogs/sort_child_notes.js rename to src/public/app/widgets/dialogs/sort_child_notes.ts index 3253b29c9..5549fadb8 100644 --- a/src/public/app/widgets/dialogs/sort_child_notes.js +++ b/src/public/app/widgets/dialogs/sort_child_notes.ts @@ -1,3 +1,4 @@ +import type { EventData } from "../../components/app_context.js"; import { t } from "../../services/i18n.js"; import server from "../../services/server.js"; import utils from "../../services/utils.js"; @@ -79,6 +80,10 @@ const TPL = `