Merge remote-tracking branch 'origin/develop' into renovate/csrf-csrf-4.x

This commit is contained in:
Elian Doran 2025-05-16 19:34:19 +03:00
commit f38105ef05
No known key found for this signature in database
19 changed files with 331 additions and 296 deletions

View File

@ -82,7 +82,7 @@ jobs:
require-healthy: true
- name: Run Playwright tests
run: TRILIUM_DOCKER=1 TRILIUM_PORT=8082 pnpx nx run -t e2e
run: TRILIUM_DOCKER=1 TRILIUM_PORT=8082 pnpx nx run server-e2e:e2e
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
@ -129,7 +129,6 @@ jobs:
- name: Set TEST_TAG to lowercase
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
@ -142,6 +141,9 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run the TypeScript build
run: pnpm run server:build
- name: Update build info
run: pnpm run chore:update-build-info

View File

@ -14,7 +14,7 @@ import { applySingleBlockSyntaxHighlight, applySyntaxHighlight } from "./syntax_
import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js";
import { normalizeMimeTypeForCKEditor } from "./mime_type_definitions.js";
import renderDoc from "./doc_renderer.js";
import { t } from "i18next";
import { t } from "../services/i18n.js";
import WheelZoom from 'vanilla-js-wheel-zoom';
let idCounter = 1;

View File

@ -590,11 +590,6 @@ table.promoted-attributes-in-tooltip th {
}
.tooltip-trigger {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: transparent;
pointer-events: none;
}

View File

@ -81,9 +81,6 @@
}
/* Checked list item */
:root ul.ck.ck-list button.ck-button.ck-on:not(:hover) {
background: transparent !important;
}
:root ul.ck.ck-list button.ck-button:hover,
:root ul.ck.ck-list button.ck-button.ck-on:hover {

View File

@ -1,7 +1,6 @@
import { Dropdown } from "bootstrap";
import NoteContextAwareWidget from "./note_context_aware_widget.js";
import { getAvailableLocales, getLocaleById } from "../services/i18n.js";
import { t } from "i18next";
import { getAvailableLocales, getLocaleById, t } from "../services/i18n.js";
import type { EventData } from "../components/app_context.js";
import type FNote from "../entities/fnote.js";
import attributes from "../services/attributes.js";

View File

@ -72,7 +72,7 @@ export default class AbstractCodeTypeWidget extends TypeWidget {
* @param the note that was changed.
* @param new content of the note.
*/
_update(note: FNote, content: string) {
_update(note: { mime: string }, content: string) {
this.codeEditor.setText(content);
this.codeEditor.setMimeType(note.mime);
this.codeEditor.clearHistory();

View File

@ -1,6 +1,7 @@
import server from "../../../services/server.js";
import AbstractCodeTypeWidget from "../abstract_code_type_widget.js";
import type { EventData } from "../../../components/app_context.js";
import type { EditorConfig } from "@triliumnext/codemirror";
const TPL = /*html*/`<div style="height: 100%; display: flex; flex-direction: column;">
<style>
@ -21,9 +22,9 @@ export default class BackendLogWidget extends AbstractCodeTypeWidget {
private $refreshBackendLog!: JQuery<HTMLElement>;
doRender() {
super.doRender();
this.$widget = $(TPL);
this.$editor = this.$widget.find(".backend-log-editor");
super.doRender();
}
async refresh() {
@ -38,9 +39,10 @@ export default class BackendLogWidget extends AbstractCodeTypeWidget {
this.refresh();
}
getExtraOpts(): Partial<CodeMirrorOpts> {
getExtraOpts(): Partial<EditorConfig> {
return {
readOnly: true
readOnly: true,
preferPerformance: true
};
}

View File

@ -40,7 +40,7 @@ import ShareSettingsOptions from "./options/other/share_settings.js";
import AiSettingsOptions from "./options/ai_settings.js";
import type FNote from "../../entities/fnote.js";
import type NoteContextAwareWidget from "../note_context_aware_widget.js";
import { t } from "i18next";
import { t } from "../../services/i18n.js";
import LanguageOptions from "./options/i18n/language.js";
import type BasicWidget from "../basic_widget.js";
import CodeTheme from "./options/code_notes/code_theme.js";

View File

@ -1,7 +1,7 @@
import OptionsWidget from "../options_widget.js";
import type { OptionMap } from "@triliumnext/commons";
import { getAvailableLocales } from "../../../../services/i18n.js";
import { t } from "i18next";
import { t } from "../../../../services/i18n.js";
const TPL = /*html*/`
<div class="options-section">

View File

@ -18,7 +18,7 @@
"@types/electron-squirrel-startup": "1.0.2",
"@triliumnext/server": "workspace:*",
"copy-webpack-plugin": "13.0.0",
"electron": "36.2.0",
"electron": "36.2.1",
"@electron-forge/cli": "7.8.1",
"@electron-forge/maker-deb": "7.8.1",
"@electron-forge/maker-dmg": "7.8.1",
@ -57,7 +57,7 @@
"command": "cross-env DEBUG=* tsx scripts/electron-rebuild.mts {projectRoot}/dist"
},
"nixos": {
"command": "cross-env DEBUG=* tsx scripts/electron-rebuild.mts {projectRoot}/dist $(nix-shell -p electron_33 --run \"electron --version\")"
"command": "cross-env DEBUG=* tsx scripts/electron-rebuild.mts {projectRoot}/dist $(nix-shell -p electron_35 --run \"electron --version\")"
}
}
},
@ -73,7 +73,7 @@
"cwd": "{projectRoot}/dist"
},
"nixos": {
"command": "nix-shell -p electron_33 --run \"electron {projectRoot}/dist/main.js\"",
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.js\"",
"cwd": ".",
"forwardAllArgs": false
}
@ -91,7 +91,7 @@
"cwd": "{projectRoot}/dist"
},
"nixos": {
"command": "nix-shell -p electron_33 --run \"electron {projectRoot}/dist/main.js\"",
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.js\"",
"cwd": ".",
"forwardAllArgs": false
}

View File

@ -8,7 +8,7 @@
"@triliumnext/desktop": "workspace:*",
"@types/fs-extra": "11.0.4",
"copy-webpack-plugin": "13.0.0",
"electron": "36.2.0",
"electron": "36.2.1",
"fs-extra": "11.3.0"
},
"nx": {

View File

@ -1,4 +1,4 @@
FROM node:22.15.0-bullseye-slim AS builder
FROM node:22.15.1-bullseye-slim AS builder
RUN corepack enable
# Install native dependencies since we might be building cross-platform.
@ -7,7 +7,7 @@ FROM node:22.15.0-bullseye-slim AS builder
# We have to use --no-frozen-lockfile due to CKEditor patches
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
FROM node:22.15.0-bullseye-slim
FROM node:22.15.1-bullseye-slim
# Install only runtime dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \

View File

@ -1,4 +1,4 @@
FROM node:22.15.0-alpine AS builder
FROM node:22.15.1-alpine AS builder
RUN corepack enable
# Install native dependencies since we might be building cross-platform.
@ -7,7 +7,7 @@ FROM node:22.15.0-alpine AS builder
# We have to use --no-frozen-lockfile due to CKEditor patches
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
FROM node:22.15.0-alpine
FROM node:22.15.1-alpine
# Install runtime dependencies
RUN apk add --no-cache su-exec shadow

View File

@ -48,7 +48,7 @@
"jquery": "3.7.1",
"katex": "0.16.22",
"normalize.css": "8.0.1",
"@anthropic-ai/sdk": "0.50.4",
"@anthropic-ai/sdk": "0.51.0",
"@braintree/sanitize-url": "7.1.1",
"@triliumnext/commons": "workspace:*",
"@triliumnext/express-partial-content": "workspace:*",
@ -68,7 +68,7 @@
"debounce": "2.2.0",
"debug": "4.4.1",
"ejs": "3.1.10",
"electron": "36.2.0",
"electron": "36.2.1",
"electron-debug": "4.1.0",
"electron-window-state": "5.0.3",
"escape-html": "1.0.3",

View File

@ -6,7 +6,6 @@ import attributeService from "./attributes.js";
import cloningService from "./cloning.js";
import dayjs from "dayjs";
import hoistedNoteService from "./hoisted_note.js";
import i18next from "i18next";
import isSameOrAfter from "dayjs/plugin/isSameOrAfter.js";
import noteService from "./notes.js";
import optionService from "./options.js";
@ -16,6 +15,7 @@ import searchContext from "../services/search/search_context.js";
import searchService from "../services/search/services/search.js";
import sql from "./sql.js";
import { t } from "i18next";
import { ordinal } from "./i18n.js";
dayjs.extend(isSameOrAfter);
dayjs.extend(quarterOfYear);
@ -67,24 +67,7 @@ function getTimeUnitReplacements(timeUnit: TimeUnit): string[] {
return units.slice(0, index + 1).flatMap(unit => baseReplacements[unit]);
}
async function ordinal(date: Dayjs, lng: string) {
const localeMap: Record<string, string> = {
cn: "zh-cn",
tw: "zh-tw"
};
const dayjsLocale = localeMap[lng] || lng;
try {
await import(`dayjs/locale/${dayjsLocale}.js`);
} catch (err) {
console.warn(`Could not load locale ${dayjsLocale}`, err);
}
return dayjs(date).locale(dayjsLocale).format("Do");
}
async function getJournalNoteTitle(
function getJournalNoteTitle(
rootNote: BNote,
timeUnit: TimeUnit,
dateObj: Dayjs,
@ -102,7 +85,7 @@ async function getJournalNoteTitle(
const monthName = t(MONTH_TRANSLATION_IDS[dateObj.month()]);
const weekDay = t(WEEKDAY_TRANSLATION_IDS[dateObj.day()]);
const numberStr = number.toString();
const ordinalStr = await ordinal(dateObj, i18next.language);
const ordinalStr = ordinal(dateObj);
const allReplacements: Record<string, string> = {
// Common date formats
@ -228,7 +211,7 @@ function getQuarterNumberStr(date: Dayjs) {
return `${date.year()}-Q${date.quarter()}`;
}
async function getQuarterNote(quarterStr: string, _rootNote: BNote | null = null): Promise<BNote> {
function getQuarterNote(quarterStr: string, _rootNote: BNote | null = null): BNote {
const rootNote = _rootNote || getRootCalendarNote();
quarterStr = quarterStr.trim().substring(0, 7);
@ -247,7 +230,7 @@ async function getQuarterNote(quarterStr: string, _rootNote: BNote | null = null
const quarterStartDate = dayjs().year(parseInt(yearStr)).month(firstMonth).date(1);
const yearNote = getYearNote(yearStr, rootNote);
const noteTitle = await getJournalNoteTitle(
const noteTitle = getJournalNoteTitle(
rootNote, "quarter", quarterStartDate, quarterNumber
);
@ -269,7 +252,7 @@ async function getQuarterNote(quarterStr: string, _rootNote: BNote | null = null
return quarterNote as unknown as BNote;
}
async function getMonthNote(dateStr: string, _rootNote: BNote | null = null): Promise<BNote> {
function getMonthNote(dateStr: string, _rootNote: BNote | null = null): BNote {
const rootNote = _rootNote || getRootCalendarNote();
const monthStr = dateStr.substring(0, 7);
@ -286,12 +269,12 @@ async function getMonthNote(dateStr: string, _rootNote: BNote | null = null): Pr
let monthParentNote;
if (rootNote.hasLabel("enableQuarterNote")) {
monthParentNote = await getQuarterNote(getQuarterNumberStr(dayjs(dateStr)), rootNote);
monthParentNote = getQuarterNote(getQuarterNumberStr(dayjs(dateStr)), rootNote);
} else {
monthParentNote = getYearNote(dateStr, rootNote);
}
const noteTitle = await getJournalNoteTitle(
const noteTitle = getJournalNoteTitle(
rootNote, "month", dayjs(dateStr), parseInt(monthNumber)
);
@ -408,7 +391,7 @@ function getWeekFirstDayNote(dateStr: string, rootNote: BNote | null = null) {
* @param _rootNote a {@link BNote} representing the calendar root, or {@code null} or not specified to use the default root calendar note.
* @returns a Promise that resolves to the {@link BNote} corresponding to the week note.
*/
async function getWeekNote(weekStr: string, _rootNote: BNote | null = null): Promise<BNote | null> {
function getWeekNote(weekStr: string, _rootNote: BNote | null = null): BNote | null {
const rootNote = _rootNote || getRootCalendarNote();
if (!rootNote.hasLabel("enableWeekNote")) {
return null;
@ -435,10 +418,10 @@ async function getWeekNote(weekStr: string, _rootNote: BNote | null = null): Pro
const startMonth = startDate.month();
const endMonth = endDate.month();
const monthNote = await getMonthNote(startDate.format("YYYY-MM-DD"), rootNote);
const noteTitle = await getJournalNoteTitle(rootNote, "week", startDate, weekNumber);
const monthNote = getMonthNote(startDate.format("YYYY-MM-DD"), rootNote);
const noteTitle = getJournalNoteTitle(rootNote, "week", startDate, weekNumber);
sql.transactional(async () => {
sql.transactional(() => {
weekNote = createNote(monthNote, noteTitle);
attributeService.createLabel(weekNote.noteId, WEEK_LABEL, weekStr);
@ -452,7 +435,7 @@ async function getWeekNote(weekStr: string, _rootNote: BNote | null = null): Pro
// If the week spans different months, clone the week note in the other month as well
if (startMonth !== endMonth) {
const secondMonthNote = await getMonthNote(endDate.format("YYYY-MM-DD"), rootNote);
const secondMonthNote = getMonthNote(endDate.format("YYYY-MM-DD"), rootNote);
cloningService.cloneNoteToParentNote(weekNote.noteId, secondMonthNote.noteId);
}
});
@ -460,7 +443,7 @@ async function getWeekNote(weekStr: string, _rootNote: BNote | null = null): Pro
return weekNote as unknown as BNote;
}
async function getDayNote(dateStr: string, _rootNote: BNote | null = null): Promise<BNote> {
function getDayNote(dateStr: string, _rootNote: BNote | null = null): BNote {
const rootNote = _rootNote || getRootCalendarNote();
dateStr = dateStr.trim().substring(0, 10);
@ -476,13 +459,13 @@ async function getDayNote(dateStr: string, _rootNote: BNote | null = null): Prom
let dateParentNote;
if (rootNote.hasLabel("enableWeekNote")) {
dateParentNote = await getWeekNote(getWeekNumberStr(dayjs(dateStr)), rootNote);
dateParentNote = getWeekNote(getWeekNumberStr(dayjs(dateStr)), rootNote);
} else {
dateParentNote = await getMonthNote(dateStr, rootNote);
dateParentNote = getMonthNote(dateStr, rootNote);
}
const dayNumber = dateStr.substring(8, 10);
const noteTitle = await getJournalNoteTitle(
const noteTitle = getJournalNoteTitle(
rootNote, "day", dayjs(dateStr), parseInt(dayNumber)
);

View File

@ -5,20 +5,43 @@ import { join } from "path";
import { getResourceDir } from "./utils.js";
import hidden_subtree from "./hidden_subtree.js";
import { LOCALES, type Locale } from "@triliumnext/commons";
import dayjs, { Dayjs } from "dayjs";
const DAYJS_LOCALE_MAP: Record<string, string> = {
cn: "zh-cn",
tw: "zh-tw"
};
let dayjsLocale: string;
export async function initializeTranslations() {
const resourceDir = getResourceDir();
const Backend = (await import("i18next-fs-backend")).default;
const locale = getCurrentLanguage();
// Initialize translations
await i18next.use(Backend).init({
lng: getCurrentLanguage(),
lng: locale,
fallbackLng: "en",
ns: "server",
backend: {
loadPath: join(resourceDir, "assets/translations/{{lng}}/{{ns}}.json")
}
});
// Initialize dayjs locale.
dayjsLocale = DAYJS_LOCALE_MAP[locale] ?? locale;
try {
await import(`dayjs/locale/${dayjsLocale}.js`);
} catch (err) {
console.warn(`Could not load locale ${dayjsLocale}`, err);
}
}
export function ordinal(date: Dayjs) {
return dayjs(date)
.locale(dayjsLocale)
.format("Do");
}
export function getLocales(): Locale[] {

View File

@ -39,6 +39,7 @@
* Slight organization in Appearance settings: code block themes are now in "Text Notes", added a "Related settings" section in Appearance.
* [Added support for opening and activating a note in a new tab using Ctrl+Shift+click on notes in the launcher pane, note tree, or note images](https://github.com/TriliumNext/Notes/pull/1854) by @SiriusXT
* [Style and footnote improvements](https://github.com/TriliumNext/Notes/pull/1913) by @SiriusXT
* Backend log: disable some editor features in order to increase performance for large logs (syntax highlighting, folding, etc.).
## 📖 Documentation

View File

@ -20,6 +20,8 @@ export interface EditorConfig {
lineWrapping?: boolean;
vimKeybindings?: boolean;
readOnly?: boolean;
/** Disables some of the nice-to-have features (bracket matching, syntax highlighting, indentation markers) in order to improve performance. */
preferPerformance?: boolean;
tabIndex?: number;
onContentChanged?: ContentChangedListener;
}
@ -51,19 +53,10 @@ export default class CodeMirror extends EditorView {
...extensions,
languageCompartment.of([]),
lineWrappingCompartment.of(config.lineWrapping ? EditorView.lineWrapping : []),
themeCompartment.of([
syntaxHighlighting(defaultHighlightStyle, { fallback: true })
]),
searchMatchHighlightTheme,
searchHighlightCompartment.of([]),
highlightActiveLine(),
highlightSelectionMatches(),
bracketMatching(),
lineNumbers(),
foldGutter(),
indentationMarkers(),
indentUnit.of(" ".repeat(4)),
keymap.of([
...defaultKeymap,
@ -72,6 +65,19 @@ export default class CodeMirror extends EditorView {
])
]
if (!config.preferPerformance) {
extensions = [
...extensions,
themeCompartment.of([
syntaxHighlighting(defaultHighlightStyle, { fallback: true })
]),
highlightSelectionMatches(),
bracketMatching(),
foldGutter(),
indentationMarkers(),
];
}
if (!config.readOnly) {
// Logic specific to editable notes
if (config.placeholder) {

471
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff