Skip to content

Commit 660d9ee

Browse files
authored
Merge branch 'TriliumNext:main' into fix/7641
2 parents 69da8f8 + c744e36 commit 660d9ee

File tree

130 files changed

+2399
-1293
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+2399
-1293
lines changed

.github/workflows/main-docker.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ jobs:
155155
- name: Update build info
156156
run: pnpm run chore:update-build-info
157157

158+
- name: Update nightly version
159+
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
160+
run: pnpm run chore:ci-update-nightly-version
161+
158162
- name: Run the TypeScript build
159163
run: pnpm run server:build
160164

.github/workflows/nightly.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ jobs:
5757
- name: Install dependencies
5858
run: pnpm install --frozen-lockfile
5959
- name: Update nightly version
60-
run: npm run chore:ci-update-nightly-version
60+
run: pnpm run chore:ci-update-nightly-version
6161
- name: Run the build
6262
uses: ./.github/actions/build-electron
6363
with:

_regroup/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@
3939
"@stylistic/eslint-plugin": "5.5.0",
4040
"@types/express": "5.0.5",
4141
"@types/node": "24.10.1",
42-
"@types/yargs": "17.0.34",
42+
"@types/yargs": "17.0.35",
4343
"@vitest/coverage-v8": "3.2.4",
4444
"eslint": "9.39.1",
4545
"eslint-plugin-simple-import-sort": "12.1.1",
4646
"esm": "3.2.25",
4747
"jsdoc": "4.0.5",
4848
"lorem-ipsum": "2.0.8",
49-
"rcedit": "5.0.0",
49+
"rcedit": "5.0.1",
5050
"rimraf": "6.1.0",
5151
"tslib": "2.8.1"
5252
},

apps/client/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"autocomplete.js": "0.38.1",
3737
"bootstrap": "5.3.8",
3838
"boxicons": "2.1.4",
39-
"color": "5.0.2",
39+
"color": "5.0.3",
4040
"dayjs": "1.11.19",
4141
"dayjs-plugin-utc": "0.1.2",
4242
"debounce": "3.0.0",
@@ -53,9 +53,9 @@
5353
"leaflet": "1.9.4",
5454
"leaflet-gpx": "2.2.0",
5555
"mark.js": "8.11.1",
56-
"marked": "16.4.2",
56+
"marked": "17.0.0",
5757
"mermaid": "11.12.1",
58-
"mind-elixir": "5.3.5",
58+
"mind-elixir": "5.3.6",
5959
"normalize.css": "8.0.1",
6060
"panzoom": "9.4.3",
6161
"preact": "10.27.2",

apps/client/src/components/tab_manager.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,32 @@ export default class TabManager extends Component {
647647
...this.noteContexts.slice(-noteContexts.length),
648648
...this.noteContexts.slice(lastClosedTab.position, -noteContexts.length)
649649
];
650-
this.noteContextReorderEvent({ ntxIdsInOrder: ntxsInOrder.map((nc) => nc.ntxId).filter((id) => id !== null) });
650+
651+
// Update mainNtxId if the restored pane is the main pane in the split pane
652+
const { oldMainNtxId, newMainNtxId } = (() => {
653+
if (noteContexts.length !== 1) {
654+
return { oldMainNtxId: undefined, newMainNtxId: undefined };
655+
}
656+
657+
const mainNtxId = noteContexts[0]?.mainNtxId;
658+
const index = this.noteContexts.findIndex(c => c.ntxId === mainNtxId);
659+
660+
// No need to update if the restored position is after mainNtxId
661+
if (index === -1 || lastClosedTab.position > index) {
662+
return { oldMainNtxId: undefined, newMainNtxId: undefined };
663+
}
664+
665+
return {
666+
oldMainNtxId: this.noteContexts[index].ntxId ?? undefined,
667+
newMainNtxId: noteContexts[0]?.ntxId ?? undefined
668+
};
669+
})();
670+
671+
this.triggerCommand("noteContextReorder", {
672+
ntxIdsInOrder: ntxsInOrder.map((nc) => nc.ntxId).filter((id) => id !== null),
673+
oldMainNtxId,
674+
newMainNtxId
675+
});
651676

652677
let mainNtx = noteContexts.find((nc) => nc.isMainContext());
653678
if (mainNtx) {

apps/client/src/entities/fnote.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,9 @@ export default class FNote {
257257
}
258258

259259
async getChildNoteIdsWithArchiveFiltering(includeArchived = false) {
260-
if (!includeArchived) {
260+
const isHiddenNote = this.noteId.startsWith("_");
261+
const isSearchNote = this.type === "search";
262+
if (!includeArchived && !isHiddenNote && !isSearchNote) {
261263
const unorderedIds = new Set(await search.searchForNoteIds(`note.parents.noteId="${this.noteId}" #!archived`));
262264
const results: string[] = [];
263265
for (const id of this.children) {
@@ -804,6 +806,16 @@ export default class FNote {
804806
return this.getAttributeValue(LABEL, name);
805807
}
806808

809+
getLabelOrRelation(nameWithPrefix: string) {
810+
if (nameWithPrefix.startsWith("#")) {
811+
return this.getLabelValue(nameWithPrefix.substring(1));
812+
} else if (nameWithPrefix.startsWith("~")) {
813+
return this.getRelationValue(nameWithPrefix.substring(1));
814+
} else {
815+
return this.getLabelValue(nameWithPrefix);
816+
}
817+
}
818+
807819
/**
808820
* @param name - relation name
809821
* @returns relation value if relation exists, null otherwise

apps/client/src/print.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import FNote from "./entities/fnote";
22
import { render } from "preact";
3-
import { CustomNoteList } from "./widgets/collections/NoteList";
3+
import { CustomNoteList, useNoteViewType } from "./widgets/collections/NoteList";
44
import { useCallback, useLayoutEffect, useRef } from "preact/hooks";
55
import content_renderer from "./services/content_renderer";
66

@@ -85,7 +85,9 @@ function SingleNoteRenderer({ note, onReady }: RendererProps) {
8585
}
8686

8787
function CollectionRenderer({ note, onReady }: RendererProps) {
88+
const viewType = useNoteViewType(note);
8889
return <CustomNoteList
90+
viewType={viewType}
8991
isEnabled
9092
note={note}
9193
notePath={note.getBestNotePath().join("/")}

apps/client/src/services/attributes.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@ export async function setLabel(noteId: string, name: string, value: string = "",
2222
});
2323
}
2424

25+
export async function setRelation(noteId: string, name: string, value: string = "", isInheritable = false) {
26+
await server.put(`notes/${noteId}/set-attribute`, {
27+
type: "relation",
28+
name: name,
29+
value: value,
30+
isInheritable
31+
});
32+
}
33+
2534
async function removeAttributeById(noteId: string, attributeId: string) {
2635
await server.remove(`notes/${noteId}/attributes/${attributeId}`);
2736
}
@@ -51,6 +60,23 @@ function removeOwnedLabelByName(note: FNote, labelName: string) {
5160
return false;
5261
}
5362

63+
/**
64+
* Removes a relation identified by its name from the given note, if it exists. Note that the relation must be owned, i.e.
65+
* it will not remove inherited attributes.
66+
*
67+
* @param note the note from which to remove the relation.
68+
* @param relationName the name of the relation to remove.
69+
* @returns `true` if an attribute was identified and removed, `false` otherwise.
70+
*/
71+
function removeOwnedRelationByName(note: FNote, relationName: string) {
72+
const relation = note.getOwnedRelation(relationName);
73+
if (relation) {
74+
removeAttributeById(note.noteId, relation.attributeId);
75+
return true;
76+
}
77+
return false;
78+
}
79+
5480
/**
5581
* Sets the attribute of the given note to the provided value if its truthy, or removes the attribute if the value is falsy.
5682
* For an attribute with an empty value, pass an empty string instead.
@@ -116,8 +142,10 @@ function isAffecting(attrRow: AttributeRow, affectedNote: FNote | null | undefin
116142
export default {
117143
addLabel,
118144
setLabel,
145+
setRelation,
119146
setAttribute,
120147
removeAttributeById,
121148
removeOwnedLabelByName,
149+
removeOwnedRelationByName,
122150
isAffecting
123151
};

apps/client/src/services/doc_renderer.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type FNote from "../entities/fnote.js";
2+
import { applyReferenceLinks } from "../widgets/type_widgets/text/read_only_helper.js";
23
import { getCurrentLanguage } from "./i18n.js";
34
import { formatCodeBlocks } from "./syntax_highlight.js";
45

@@ -10,18 +11,18 @@ export default function renderDoc(note: FNote) {
1011
if (docName) {
1112
// find doc based on language
1213
const url = getUrl(docName, getCurrentLanguage());
13-
$content.load(url, (response, status) => {
14+
$content.load(url, async (response, status) => {
1415
// fallback to english doc if no translation available
1516
if (status === "error") {
1617
const fallbackUrl = getUrl(docName, "en");
17-
$content.load(fallbackUrl, () => {
18-
processContent(fallbackUrl, $content)
18+
$content.load(fallbackUrl, async () => {
19+
await processContent(fallbackUrl, $content)
1920
resolve($content);
2021
});
2122
return;
2223
}
2324

24-
processContent(url, $content);
25+
await processContent(url, $content);
2526
resolve($content);
2627
});
2728
} else {
@@ -32,7 +33,7 @@ export default function renderDoc(note: FNote) {
3233
});
3334
}
3435

35-
function processContent(url: string, $content: JQuery<HTMLElement>) {
36+
async function processContent(url: string, $content: JQuery<HTMLElement>) {
3637
const dir = url.substring(0, url.lastIndexOf("/"));
3738

3839
// Images are relative to the docnote but that will not work when rendered in the application since the path breaks.
@@ -42,6 +43,9 @@ function processContent(url: string, $content: JQuery<HTMLElement>) {
4243
});
4344

4445
formatCodeBlocks($content);
46+
47+
// Apply reference links.
48+
await applyReferenceLinks($content[0]);
4549
}
4650

4751
function getUrl(docNameValue: string, language: string) {

apps/client/src/services/keyboard_actions.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ async function getActionsForScope(scope: string) {
2929
}
3030

3131
async function setupActionsForElement(scope: string, $el: JQuery<HTMLElement>, component: Component) {
32+
if (!$el[0]) return [];
33+
3234
const actions = await getActionsForScope(scope);
3335
const bindings: ShortcutBinding[] = [];
3436

0 commit comments

Comments
 (0)