mirror of
https://github.com/zadam/trilium.git
synced 2026-01-09 08:04:23 +01:00
Merge branch 'main' into feat/extra-window
Some checks failed
Checks / main (push) Has been cancelled
Some checks failed
Checks / main (push) Has been cancelled
This commit is contained in:
commit
80404b83b0
1
.gitignore
vendored
1
.gitignore
vendored
@ -51,3 +51,4 @@ upload
|
||||
# docs
|
||||
site/
|
||||
apps/*/coverage
|
||||
scripts/translation/.language*.json
|
||||
@ -194,7 +194,7 @@ function renderFile(entity: FNote | FAttachment, type: string, $renderedContent:
|
||||
|
||||
if (type === "pdf") {
|
||||
const $pdfPreview = $('<iframe class="pdf-preview" style="width: 100%; flex-grow: 100;"></iframe>');
|
||||
$pdfPreview.attr("src", openService.getUrlForDownload(`api/${entityType}/${entityId}/open`));
|
||||
$pdfPreview.attr("src", openService.getUrlForDownload(`pdfjs/web/viewer.html?file=../../api/${entityType}/${entityId}/open`));
|
||||
|
||||
$content.append($pdfPreview);
|
||||
} else if (type === "audio") {
|
||||
@ -218,14 +218,14 @@ function renderFile(entity: FNote | FAttachment, type: string, $renderedContent:
|
||||
// in attachment list
|
||||
const $downloadButton = $(`
|
||||
<button class="file-download btn btn-primary" type="button">
|
||||
<span class="bx bx-download"></span>
|
||||
<span class="tn-icon bx bx-download"></span>
|
||||
${t("file_properties.download")}
|
||||
</button>
|
||||
`);
|
||||
|
||||
const $openButton = $(`
|
||||
<button class="file-open btn btn-primary" type="button">
|
||||
<span class="bx bx-link-external"></span>
|
||||
<span class="tn-icon bx bx-link-external"></span>
|
||||
${t("file_properties.open")}
|
||||
</button>
|
||||
`);
|
||||
|
||||
@ -1596,7 +1596,9 @@
|
||||
"toggle-sidebar": "切换侧边栏",
|
||||
"dropping-not-allowed": "不允许移动笔记到此处。",
|
||||
"shared-indicator-tooltip": "此笔记已公开分享",
|
||||
"shared-indicator-tooltip-with-url": "此笔记已公开分享至:{{- url}}"
|
||||
"shared-indicator-tooltip-with-url": "此笔记已公开分享至:{{- url}}",
|
||||
"clone-indicator-tooltip": "此笔记有 {{- count}} 个父级: {{- parents}}",
|
||||
"clone-indicator-tooltip-single": "此笔记已克隆(1 个额外的父级:{{- parent}})"
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "保持此窗口置顶"
|
||||
@ -2194,7 +2196,14 @@
|
||||
"execute_sql_description": "这是一篇 SQL 笔记。点击即可执行 SQL 查询。",
|
||||
"shared_copy_to_clipboard": "复制链接到剪贴板",
|
||||
"shared_open_in_browser": "在浏览器中打开链接",
|
||||
"shared_unshare": "取消共享"
|
||||
"shared_unshare": "取消共享",
|
||||
"save_status_saved": "已保存",
|
||||
"save_status_saving": "保存中...",
|
||||
"save_status_unsaved": "未保存",
|
||||
"save_status_error": "保存失败",
|
||||
"save_status_unsaved_tooltip": "还有一些更改尚未保存。它们将稍后自动保存。",
|
||||
"save_status_error_tooltip": "保存笔记时出错。如果可以,请尝试将笔记内容复制到其他位置并重新加载应用程序。",
|
||||
"save_status_saving_tooltip": "更改正在保存。"
|
||||
},
|
||||
"status_bar": {
|
||||
"language_title": "更改内容语言",
|
||||
|
||||
@ -2196,7 +2196,14 @@
|
||||
"execute_sql_description": "このノートは SQL ノートです。クリックすると SQL クエリが実行されます。",
|
||||
"shared_copy_to_clipboard": "リンクをクリップボードにコピー",
|
||||
"shared_open_in_browser": "ブラウザでリンクを開く",
|
||||
"shared_unshare": "共有を削除"
|
||||
"shared_unshare": "共有を削除",
|
||||
"save_status_saved": "保存されました",
|
||||
"save_status_saving": "保存中...",
|
||||
"save_status_unsaved": "未保存",
|
||||
"save_status_error": "保存に失敗しました",
|
||||
"save_status_saving_tooltip": "変更を保存しています。",
|
||||
"save_status_unsaved_tooltip": "未保存の変更があります。すぐに自動的に保存されます。",
|
||||
"save_status_error_tooltip": "ノートの保存中にエラーが発生しました。可能であれば、ノートの内容を別の場所にコピーして、アプリケーションを再読み込みしてください。"
|
||||
},
|
||||
"status_bar": {
|
||||
"language_title": "コンテンツの言語を変更",
|
||||
|
||||
@ -2200,7 +2200,14 @@
|
||||
"read_only_temporarily_disabled_description": "此筆記目前可編輯,但通常為唯讀狀態。當您切換至其他筆記時,本筆記將立即恢復為唯讀模式。\n\n點擊此處重新啟用唯讀模式。",
|
||||
"clipped_note_description": "本筆記原始來源為 {{url}}。\n\n點擊此處前往原網頁。",
|
||||
"execute_script_description": "此筆記為腳本筆記。點擊以執行腳本。",
|
||||
"execute_sql_description": "此筆記為 SQL 筆記。點擊以執行 SQL 查詢。"
|
||||
"execute_sql_description": "此筆記為 SQL 筆記。點擊以執行 SQL 查詢。",
|
||||
"save_status_saved": "已儲存",
|
||||
"save_status_saving": "正在儲存…",
|
||||
"save_status_unsaved": "未儲存",
|
||||
"save_status_error": "儲存失敗",
|
||||
"save_status_saving_tooltip": "正在儲存更動。",
|
||||
"save_status_unsaved_tooltip": "仍有更動尚未儲存。它們將在稍後自動儲存。",
|
||||
"save_status_error_tooltip": "在儲存筆記時發生錯誤。如果可以,請嘗試將筆記內容複製至他處並重新載入應用程式。"
|
||||
},
|
||||
"breadcrumb": {
|
||||
"hoisted_badge": "聚焦",
|
||||
@ -2246,6 +2253,6 @@
|
||||
"pages_one": "共 {{count}} 頁",
|
||||
"pages_other": "",
|
||||
"pages_alt": "第 {{pageNumber}} 頁",
|
||||
"pages_loading": "載入中…"
|
||||
"pages_loading": "正在載入…"
|
||||
}
|
||||
}
|
||||
|
||||
5
apps/client/src/types-pdfjs.d.ts
vendored
5
apps/client/src/types-pdfjs.d.ts
vendored
@ -45,6 +45,10 @@ interface WithContext {
|
||||
|
||||
interface PdfDocumentModifiedMessage extends WithContext {
|
||||
type: "pdfjs-viewer-document-modified";
|
||||
}
|
||||
|
||||
interface PdfDocumentBlobResultMessage extends WithContext {
|
||||
type: "pdfjs-viewer-blob";
|
||||
data: Uint8Array<ArrayBufferLike>;
|
||||
}
|
||||
|
||||
@ -113,4 +117,5 @@ type PdfMessageEvent = MessageEvent<
|
||||
| PdfViewerThumbnailMessage
|
||||
| PdfViewerAttachmentsMessage
|
||||
| PdfViewerLayersMessage
|
||||
| PdfDocumentBlobResultMessage
|
||||
>;
|
||||
|
||||
@ -1,27 +1,29 @@
|
||||
import { DateSelectArg, EventChangeArg, EventMountArg, EventSourceFuncArg, LocaleInput, PluginDef } from "@fullcalendar/core/index.js";
|
||||
import { ViewModeProps } from "../interface";
|
||||
import Calendar from "./calendar";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||
import "./index.css";
|
||||
import { useNoteLabel, useNoteLabelBoolean, useResizeObserver, useSpacedUpdate, useTriliumEvent, useTriliumOption, useTriliumOptionInt } from "../../react/hooks";
|
||||
import { DISPLAYABLE_LOCALE_IDS } from "@triliumnext/commons";
|
||||
|
||||
import { Calendar as FullCalendar } from "@fullcalendar/core";
|
||||
import { parseStartEndDateFromEvent, parseStartEndTimeFromEvent } from "./utils";
|
||||
import dialog from "../../../services/dialog";
|
||||
import { t } from "../../../services/i18n";
|
||||
import { buildEvents, buildEventsForCalendar } from "./event_builder";
|
||||
import { changeEvent, newEvent } from "./api";
|
||||
import froca from "../../../services/froca";
|
||||
import date_notes from "../../../services/date_notes";
|
||||
import appContext from "../../../components/app_context";
|
||||
import { DateSelectArg, EventChangeArg, EventMountArg, EventSourceFuncArg, LocaleInput, PluginDef } from "@fullcalendar/core/index.js";
|
||||
import { DateClickArg } from "@fullcalendar/interaction";
|
||||
import FNote from "../../../entities/fnote";
|
||||
import Button, { ButtonGroup } from "../../react/Button";
|
||||
import ActionButton from "../../react/ActionButton";
|
||||
import { DISPLAYABLE_LOCALE_IDS } from "@triliumnext/commons";
|
||||
import { RefObject } from "preact";
|
||||
import TouchBar, { TouchBarButton, TouchBarLabel, TouchBarSegmentedControl, TouchBarSpacer } from "../../react/TouchBar";
|
||||
import { openCalendarContextMenu } from "./context_menu";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||
|
||||
import appContext from "../../../components/app_context";
|
||||
import FNote from "../../../entities/fnote";
|
||||
import date_notes from "../../../services/date_notes";
|
||||
import dialog from "../../../services/dialog";
|
||||
import froca from "../../../services/froca";
|
||||
import { t } from "../../../services/i18n";
|
||||
import { isMobile } from "../../../services/utils";
|
||||
import ActionButton from "../../react/ActionButton";
|
||||
import Button, { ButtonGroup } from "../../react/Button";
|
||||
import { useNoteLabel, useNoteLabelBoolean, useResizeObserver, useSpacedUpdate, useTriliumEvent, useTriliumOption, useTriliumOptionInt } from "../../react/hooks";
|
||||
import TouchBar, { TouchBarButton, TouchBarLabel, TouchBarSegmentedControl, TouchBarSpacer } from "../../react/TouchBar";
|
||||
import { ViewModeProps } from "../interface";
|
||||
import { changeEvent, newEvent } from "./api";
|
||||
import Calendar from "./calendar";
|
||||
import { openCalendarContextMenu } from "./context_menu";
|
||||
import { buildEvents, buildEventsForCalendar } from "./event_builder";
|
||||
import { parseStartEndDateFromEvent, parseStartEndTimeFromEvent } from "./utils";
|
||||
|
||||
interface CalendarViewData {
|
||||
|
||||
@ -59,7 +61,7 @@ const CALENDAR_VIEWS = [
|
||||
previousText: t("calendar.month_previous"),
|
||||
nextText: t("calendar.month_next")
|
||||
}
|
||||
]
|
||||
];
|
||||
|
||||
const SUPPORTED_CALENDAR_VIEW_TYPE = CALENDAR_VIEWS.map(v => v.type);
|
||||
|
||||
@ -75,6 +77,7 @@ export const LOCALE_MAPPINGS: Record<DISPLAYABLE_LOCALE_IDS, (() => Promise<{ de
|
||||
ru: () => import("@fullcalendar/core/locales/ru"),
|
||||
ja: () => import("@fullcalendar/core/locales/ja"),
|
||||
pt: () => import("@fullcalendar/core/locales/pt"),
|
||||
pl: () => import("@fullcalendar/core/locales/pl"),
|
||||
"pt_br": () => import("@fullcalendar/core/locales/pt-br"),
|
||||
uk: () => import("@fullcalendar/core/locales/uk"),
|
||||
en: null,
|
||||
@ -102,9 +105,9 @@ export default function CalendarView({ note, noteIds }: ViewModeProps<CalendarVi
|
||||
const eventBuilder = useMemo(() => {
|
||||
if (!isCalendarRoot) {
|
||||
return async () => await buildEvents(noteIds);
|
||||
} else {
|
||||
return async (e: EventSourceFuncArg) => await buildEventsForCalendar(note, e);
|
||||
}
|
||||
}
|
||||
return async (e: EventSourceFuncArg) => await buildEventsForCalendar(note, e);
|
||||
|
||||
}, [isCalendarRoot, noteIds]);
|
||||
|
||||
const plugins = usePlugins(isEditable, isCalendarRoot);
|
||||
@ -178,7 +181,7 @@ function CalendarHeader({ calendarRef }: { calendarRef: RefObject<FullCalendar>
|
||||
<ActionButton icon="bx bx-chevron-right" text={currentViewData?.nextText ?? ""} frame onClick={() => calendarRef.current?.next()} />
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function usePlugins(isEditable: boolean, isCalendarRoot: boolean) {
|
||||
@ -293,7 +296,7 @@ function useEventDisplayCustomization(parentNote: FNote) {
|
||||
if (promotedAttributes) {
|
||||
let promotedAttributesHtml = "";
|
||||
for (const [name, value] of promotedAttributes) {
|
||||
promotedAttributesHtml = promotedAttributesHtml + /*html*/`\
|
||||
promotedAttributesHtml = `${promotedAttributesHtml /*html*/}\
|
||||
<div class="promoted-attribute">
|
||||
<span class="promoted-attribute-name">${name}</span>: <span class="promoted-attribute-value">${value}</span>
|
||||
</div>`;
|
||||
|
||||
@ -142,4 +142,10 @@
|
||||
border: 1px solid var(--main-border-color);
|
||||
background: var(--more-accented-background-color);
|
||||
}
|
||||
|
||||
.note-list.grid-view .note-path {
|
||||
margin-left: 0.5em;
|
||||
vertical-align: middle;
|
||||
opacity: 0.5;
|
||||
}
|
||||
/* #endregion */
|
||||
|
||||
@ -7,7 +7,6 @@ import attribute_renderer from "../../../services/attribute_renderer";
|
||||
import content_renderer from "../../../services/content_renderer";
|
||||
import { t } from "../../../services/i18n";
|
||||
import link from "../../../services/link";
|
||||
import tree from "../../../services/tree";
|
||||
import { useImperativeSearchHighlighlighting, useNoteLabel, useNoteLabelBoolean } from "../../react/hooks";
|
||||
import Icon from "../../react/Icon";
|
||||
import NoteLink from "../../react/NoteLink";
|
||||
@ -103,16 +102,7 @@ function ListNoteCard({ note, parentNote, highlightedTokens, currentLevel, expan
|
||||
}
|
||||
|
||||
function GridNoteCard({ note, parentNote, highlightedTokens }: { note: FNote, parentNote: FNote, highlightedTokens: string[] | null | undefined }) {
|
||||
const titleRef = useRef<HTMLSpanElement>(null);
|
||||
const [ noteTitle, setNoteTitle ] = useState<string>();
|
||||
const notePath = getNotePath(parentNote, note);
|
||||
const highlightSearch = useImperativeSearchHighlighlighting(highlightedTokens);
|
||||
|
||||
useEffect(() => {
|
||||
tree.getNoteTitle(note.noteId, parentNote.noteId).then(setNoteTitle);
|
||||
}, [ note ]);
|
||||
|
||||
useEffect(() => highlightSearch(titleRef.current), [ noteTitle, highlightedTokens ]);
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -123,7 +113,7 @@ function GridNoteCard({ note, parentNote, highlightedTokens }: { note: FNote, pa
|
||||
>
|
||||
<h5 className="note-book-header">
|
||||
<Icon className="note-icon" icon={note.getIcon()} />
|
||||
<span ref={titleRef} className="note-book-title">{noteTitle}</span>
|
||||
<NoteLink className="note-book-title" notePath={notePath} noPreview showNotePath={parentNote.type === "search"} highlightedTokens={highlightedTokens} />
|
||||
<NoteAttributes note={note} />
|
||||
</h5>
|
||||
<NoteContent
|
||||
|
||||
@ -170,6 +170,73 @@ export function useEditorSpacedUpdate({ note, noteType, noteContext, getData, on
|
||||
return spacedUpdate;
|
||||
}
|
||||
|
||||
export function useBlobEditorSpacedUpdate({ note, noteType, noteContext, getData, onContentChange, dataSaved, updateInterval, replaceWithoutRevision }: {
|
||||
noteType: NoteType;
|
||||
note: FNote,
|
||||
noteContext: NoteContext | null | undefined,
|
||||
getData: () => Promise<Blob | undefined> | Blob | undefined,
|
||||
onContentChange: (newBlob: FBlob) => void,
|
||||
dataSaved?: (savedData: Blob) => void,
|
||||
updateInterval?: number;
|
||||
/** If set to true, then the blob is replaced directly without saving a revision before. */
|
||||
replaceWithoutRevision?: boolean;
|
||||
}) {
|
||||
const parentComponent = useContext(ParentComponent);
|
||||
const blob = useNoteBlob(note, parentComponent?.componentId);
|
||||
|
||||
const callback = useMemo(() => {
|
||||
return async () => {
|
||||
const data = await getData();
|
||||
|
||||
// for read only notes
|
||||
if (data === undefined || note.type !== noteType) return;
|
||||
|
||||
protected_session_holder.touchProtectedSessionIfNecessary(note);
|
||||
await server.upload(`notes/${note.noteId}/file?replace=${replaceWithoutRevision ? "1" : "0"}`, new File([ data ], note.title, { type: note.mime }), parentComponent?.componentId);
|
||||
dataSaved?.(data);
|
||||
};
|
||||
}, [ note, getData, dataSaved, noteType, parentComponent, replaceWithoutRevision ]);
|
||||
const stateCallback = useCallback<StateCallback>((state) => {
|
||||
noteContext?.setContextData("saveState", {
|
||||
state
|
||||
});
|
||||
}, [ noteContext ]);
|
||||
const spacedUpdate = useSpacedUpdate(callback, updateInterval, stateCallback);
|
||||
|
||||
// React to note/blob changes.
|
||||
useEffect(() => {
|
||||
if (!blob) return;
|
||||
spacedUpdate.allowUpdateWithoutChange(() => onContentChange(blob));
|
||||
}, [ blob ]);
|
||||
|
||||
// React to update interval changes.
|
||||
useEffect(() => {
|
||||
if (!updateInterval) return;
|
||||
spacedUpdate.setUpdateInterval(updateInterval);
|
||||
}, [ updateInterval ]);
|
||||
|
||||
// Save if needed upon switching tabs.
|
||||
useTriliumEvent("beforeNoteSwitch", async ({ noteContext: eventNoteContext }) => {
|
||||
if (eventNoteContext.ntxId !== noteContext?.ntxId) return;
|
||||
await spacedUpdate.updateNowIfNecessary();
|
||||
});
|
||||
|
||||
// Save if needed upon tab closing.
|
||||
useTriliumEvent("beforeNoteContextRemove", async ({ ntxIds }) => {
|
||||
if (!noteContext?.ntxId || !ntxIds.includes(noteContext.ntxId)) return;
|
||||
await spacedUpdate.updateNowIfNecessary();
|
||||
});
|
||||
|
||||
// Save if needed upon window/browser closing.
|
||||
useEffect(() => {
|
||||
const listener = () => spacedUpdate.isAllSavedAndTriggerUpdate();
|
||||
appContext.addBeforeUnloadListener(listener);
|
||||
return () => appContext.removeBeforeUnloadListener(listener);
|
||||
}, []);
|
||||
|
||||
return spacedUpdate;
|
||||
}
|
||||
|
||||
export function useNoteSavedData(noteId: string | undefined) {
|
||||
return useSyncExternalStore(
|
||||
(cb) => noteId ? noteSavedDataStore.subscribe(noteId, cb) : () => {},
|
||||
|
||||
@ -37,6 +37,7 @@ const LOCALE_MAPPINGS: Record<DISPLAYABLE_LOCALE_IDS, Options["locale"] | null>
|
||||
it: "it",
|
||||
ja: "ja",
|
||||
pt: "pt",
|
||||
pl: null,
|
||||
pt_br: "pt",
|
||||
ro: "ro",
|
||||
ru: "ru",
|
||||
|
||||
@ -13,6 +13,7 @@ export const LANGUAGE_MAPPINGS: Record<DISPLAYABLE_LOCALE_IDS, Language["code"]
|
||||
it: "it-IT",
|
||||
ja: "ja-JP",
|
||||
pt: "pt-PT",
|
||||
pl: "pl-PL",
|
||||
pt_br: "pt-BR",
|
||||
ro: "ro-RO",
|
||||
ru: "ru-RU",
|
||||
|
||||
@ -4,9 +4,8 @@ import appContext from "../../../components/app_context";
|
||||
import type NoteContext from "../../../components/note_context";
|
||||
import FBlob from "../../../entities/fblob";
|
||||
import FNote from "../../../entities/fnote";
|
||||
import server from "../../../services/server";
|
||||
import { useViewModeConfig } from "../../collections/NoteList";
|
||||
import { useTriliumEvent } from "../../react/hooks";
|
||||
import { useBlobEditorSpacedUpdate, useTriliumEvent } from "../../react/hooks";
|
||||
import PdfViewer from "./PdfViewer";
|
||||
|
||||
export default function PdfPreview({ note, blob, componentId, noteContext }: {
|
||||
@ -18,12 +17,48 @@ export default function PdfPreview({ note, blob, componentId, noteContext }: {
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
const historyConfig = useViewModeConfig<HistoryData>(note, "pdfHistory");
|
||||
|
||||
const spacedUpdate = useBlobEditorSpacedUpdate({
|
||||
note,
|
||||
noteType: "file",
|
||||
noteContext,
|
||||
getData() {
|
||||
if (!iframeRef.current?.contentWindow) return undefined;
|
||||
|
||||
return new Promise<Blob>((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
reject(new Error("Timeout while waiting for blob response"));
|
||||
}, 10_000);
|
||||
|
||||
const onMessageReceived = (event: PdfMessageEvent) => {
|
||||
if (event.data.type !== "pdfjs-viewer-blob") return;
|
||||
if (event.data.noteId !== note.noteId || event.data.ntxId !== noteContext.ntxId) return;
|
||||
const blob = new Blob([event.data.data as Uint8Array<ArrayBuffer>], { type: note.mime });
|
||||
|
||||
clearTimeout(timeout);
|
||||
window.removeEventListener("message", onMessageReceived);
|
||||
resolve(blob);
|
||||
};
|
||||
|
||||
window.addEventListener("message", onMessageReceived);
|
||||
iframeRef.current?.contentWindow?.postMessage({
|
||||
type: "trilium-request-blob",
|
||||
}, window.location.origin);
|
||||
});
|
||||
},
|
||||
onContentChange() {
|
||||
if (iframeRef.current?.contentWindow) {
|
||||
iframeRef.current.contentWindow.location.reload();
|
||||
}
|
||||
},
|
||||
replaceWithoutRevision: true
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
function handleMessage(event: PdfMessageEvent) {
|
||||
if (event.data?.type === "pdfjs-viewer-document-modified") {
|
||||
const blob = new Blob([event.data.data as Uint8Array<ArrayBuffer>], { type: note.mime });
|
||||
if (event.data.noteId === note.noteId && event.data.ntxId === noteContext.ntxId) {
|
||||
server.upload(`notes/${note.noteId}/file`, new File([blob], note.title, { type: note.mime }), componentId);
|
||||
spacedUpdate.resetUpdateTimer();
|
||||
spacedUpdate.scheduleUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,13 +173,6 @@ export default function PdfPreview({ note, blob, componentId, noteContext }: {
|
||||
};
|
||||
}, [ note, historyConfig, componentId, blob, noteContext ]);
|
||||
|
||||
// Refresh when blob changes.
|
||||
useEffect(() => {
|
||||
if (iframeRef.current?.contentWindow) {
|
||||
iframeRef.current.contentWindow.location.reload();
|
||||
}
|
||||
}, [ blob ]);
|
||||
|
||||
useTriliumEvent("customDownload", ({ ntxId }) => {
|
||||
if (ntxId !== noteContext.ntxId) return;
|
||||
iframeRef.current?.contentWindow?.postMessage({
|
||||
@ -171,6 +199,7 @@ export default function PdfPreview({ note, blob, componentId, noteContext }: {
|
||||
});
|
||||
}
|
||||
}}
|
||||
editable
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -15,12 +15,16 @@ interface PdfViewerProps extends Pick<HTMLAttributes<HTMLIFrameElement>, "tabInd
|
||||
/** Note: URLs are relative to /pdfjs/web. */
|
||||
pdfUrl: string;
|
||||
onLoad?(): void;
|
||||
/**
|
||||
* If set, enables editable mode which includes persistence of user settings, annotations as well as specific features such as sending table of contents data for the sidebar.
|
||||
*/
|
||||
editable?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reusable component displaying a PDF. The PDF needs to be provided via a URL.
|
||||
*/
|
||||
export default function PdfViewer({ iframeRef: externalIframeRef, pdfUrl, onLoad }: PdfViewerProps) {
|
||||
export default function PdfViewer({ iframeRef: externalIframeRef, pdfUrl, onLoad, editable }: PdfViewerProps) {
|
||||
const iframeRef = useSyncedRef(externalIframeRef, null);
|
||||
const [ locale ] = useTriliumOption("locale");
|
||||
const [ newLayout ] = useTriliumOptionBool("newLayout");
|
||||
@ -30,7 +34,7 @@ export default function PdfViewer({ iframeRef: externalIframeRef, pdfUrl, onLoad
|
||||
<iframe
|
||||
ref={iframeRef}
|
||||
class="pdf-preview"
|
||||
src={`pdfjs/web/viewer.html?file=${pdfUrl}&lang=${locale}&sidebar=${newLayout ? "0" : "1"}`}
|
||||
src={`pdfjs/web/viewer.html?file=${pdfUrl}&lang=${locale}&sidebar=${newLayout ? "0" : "1"}&editable=${editable ? "1" : "0"}`}
|
||||
onLoad={() => {
|
||||
injectStyles();
|
||||
onLoad?.();
|
||||
|
||||
@ -70,6 +70,20 @@ test("Attachments listing works", async ({ page, context }) => {
|
||||
await expect(attachmentsList.locator(".pdf-attachment-item")).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("Download original PDF works", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
await app.goto();
|
||||
await app.goToNoteInNewTab("Dacia Logan.pdf");
|
||||
const pdfHelper = new PdfHelper(app);
|
||||
await pdfHelper.toBeInitialized();
|
||||
|
||||
const [ download ] = await Promise.all([
|
||||
page.waitForEvent("download"),
|
||||
app.currentNoteSplit.locator(".icon-action.bx.bx-download").click()
|
||||
]);
|
||||
expect(download).toBeDefined();
|
||||
});
|
||||
|
||||
test("Layers listing works", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
await app.goto();
|
||||
@ -108,4 +122,8 @@ class PdfHelper {
|
||||
async expectPageToBe(expectedPageNumber: number) {
|
||||
await expect(this.contentFrame.locator("#pageNumber")).toHaveValue(`${expectedPageNumber}`);
|
||||
}
|
||||
|
||||
async toBeInitialized() {
|
||||
await expect(this.contentFrame.locator("#pageNumber")).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ server {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_pass http://host.docker.internal:8082; # change it to a different port if non-default is used
|
||||
proxy_pass http://127.0.0.1:8082;
|
||||
proxy_cookie_path / /trilium/;
|
||||
proxy_read_timeout 90;
|
||||
}
|
||||
|
||||
@ -25,7 +25,8 @@
|
||||
"docker-start-rootless-debian": "pnpm docker-build-rootless-debian && docker run -p 8081:8080 triliumnext-rootless-debian",
|
||||
"docker-start-rootless-alpine": "pnpm docker-build-rootless-alpine && docker run -p 8081:8080 triliumnext-rootless-alpine",
|
||||
"generate-document": "cross-env TRILIUM_ENV=dev TRILIUM_DATA_DIR=data TRILIUM_RESOURCE_DIR=src tsx ./scripts/generate_document.ts",
|
||||
"proxy-traefik": "docker run --name trilium-traefik --rm --network=host -v ./docker/traefik/traefik.yml:/etc/traefik/traefik.yml -v ./docker/traefik/dynamic:/etc/traefik/dynamic traefik:latest"
|
||||
"proxy-traefik": "docker run --name trilium-traefik --rm --network=host -v ./docker/traefik/traefik.yml:/etc/traefik/traefik.yml:ro -v ./docker/traefik/dynamic:/etc/traefik/dynamic traefik:latest",
|
||||
"proxy-nginx-subdir": "docker run --name trilium-nginx-subdir --rm --network=host -v ./docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro nginx:latest"
|
||||
},
|
||||
"dependencies": {
|
||||
"better-sqlite3": "12.5.0",
|
||||
|
||||
@ -28,7 +28,9 @@ function updateFile(req: Request) {
|
||||
};
|
||||
}
|
||||
|
||||
note.saveRevision();
|
||||
if (req.query.replace !== "1") {
|
||||
note.saveRevision();
|
||||
}
|
||||
|
||||
note.mime = file.mimetype.toLowerCase();
|
||||
note.save();
|
||||
|
||||
@ -3,7 +3,8 @@
|
||||
"title": "Kom i gang",
|
||||
"architecture": "Arkitektur:",
|
||||
"desktop_title": "Last ned skrivebordsprogram (v{{version}})",
|
||||
"older_releases": "Se tidligere versjoner"
|
||||
"older_releases": "Se tidligere versjoner",
|
||||
"server_title": "Sett opp en server for adgang fra flere enheter"
|
||||
},
|
||||
"hero_section": {
|
||||
"title": "Organiser tankene dine. Bygg din personlige kunnskapsbase.",
|
||||
@ -13,14 +14,19 @@
|
||||
},
|
||||
"organization_benefits": {
|
||||
"title": "Organisering",
|
||||
"note_structure_title": "Notatstruktur"
|
||||
"note_structure_title": "Notatstruktur",
|
||||
"hoisting_title": "Arbeidsflate og fokusering",
|
||||
"attributes_description": "Bruk relasjoner mellom notater eller legg til etiketter for enkel kategorisering. Bruk fremhevede attributter for å legge inn strukturert informasjon som kan brukes i tabeller og tavler."
|
||||
},
|
||||
"productivity_benefits": {
|
||||
"sync_title": "Synkronisering",
|
||||
"search_title": "Kraftig søk",
|
||||
"web_clipper_title": "Web clipper",
|
||||
"revisions_title": "Notatrevisjon",
|
||||
"protected_notes_title": "Beskyttede notater"
|
||||
"protected_notes_title": "Beskyttede notater",
|
||||
"title": "Produktivitet og sikkerhet",
|
||||
"sync_content": "Bruk en selv-hostet eller cloud-instans for å enkelt synkronisere notater på tvers av enheter, og ha de tilgjengelige fra din mobiltelefon ved hjelp av progressiv web-app.",
|
||||
"jump_to_content": "Hopp raskt til notater eller grensesnittkommandoer over hele hierarkiet ved å søke etter tittel, med \"fuzzy\" matching for å ta hensyn til skrivefeil eller små differanser."
|
||||
},
|
||||
"note_types": {
|
||||
"canvas_title": "Kanvas",
|
||||
@ -33,7 +39,8 @@
|
||||
"extensibility_benefits": {
|
||||
"import_export_title": "Import/eksport",
|
||||
"scripting_title": "Avansert skripting",
|
||||
"api_title": "REST API"
|
||||
"api_title": "REST API",
|
||||
"title": "Deling og utvidbarhet"
|
||||
},
|
||||
"collections": {
|
||||
"title": "Samlinger",
|
||||
@ -41,7 +48,8 @@
|
||||
"table_title": "Tabell",
|
||||
"geomap_title": "Geokart",
|
||||
"presentation_title": "Presentasjon",
|
||||
"board_title": "Kanbantavle"
|
||||
"board_title": "Kanbantavle",
|
||||
"geomap_description": "Planlegg ferien din eller merk deg dine interessepunkter på et geografisk kart ved hjelp av definerbare markører. Vis lagrede GPX-spor for å se reisen din."
|
||||
},
|
||||
"header": {
|
||||
"documentation": "Dokumentasjon",
|
||||
@ -58,12 +66,15 @@
|
||||
"paypal": "PayPal",
|
||||
"title": "Støtt oss",
|
||||
"financial_donations_title": "Finansiell donasjon",
|
||||
"github_sponsors": "GitHub Sponsors"
|
||||
"github_sponsors": "GitHub Sponsors",
|
||||
"financial_donations_description": "Trilium er bygget og vedlikeholdt med <Link>flere hundre timers arbeid</Link>. Ditt bidrag hjelper å holde det åpen kildekode, forbedre funksjonalitet og dekker driftskostnader."
|
||||
},
|
||||
"download_helper_desktop_windows": {
|
||||
"download_scoop": "Scoop",
|
||||
"title_x64": "Windows 64-bit",
|
||||
"download_zip": "Portable (.zip)"
|
||||
"download_zip": "Portable (.zip)",
|
||||
"title_arm64": "Windows på ARM",
|
||||
"download_exe": "Last ned installasjonsprogram (.exe)"
|
||||
},
|
||||
"download_helper_desktop_linux": {
|
||||
"download_deb": ".deb",
|
||||
@ -72,15 +83,19 @@
|
||||
"download_nixpkgs": "nixpkgs",
|
||||
"download_aur": "AUR",
|
||||
"title_x64": "Linux 64-bit",
|
||||
"download_zip": "Portable (.zip)"
|
||||
"download_zip": "Portable (.zip)",
|
||||
"title_arm64": "Linux på ARM"
|
||||
},
|
||||
"download_helper_server_docker": {
|
||||
"download_ghcr": "ghcr.io",
|
||||
"download_dockerhub": "Docker Hub"
|
||||
"download_dockerhub": "Docker Hub",
|
||||
"title": "Selv-hostet med Docker"
|
||||
},
|
||||
"download_helper_desktop_macos": {
|
||||
"download_homebrew_cask": "Homebrew Cask",
|
||||
"download_zip": "Portable (.zip)"
|
||||
"download_zip": "Portable (.zip)",
|
||||
"title_x64": "macOS for Intel",
|
||||
"download_dmg": "Last ned installasjonsprogram (.dmg)"
|
||||
},
|
||||
"final_cta": {
|
||||
"get_started": "Kom i gang"
|
||||
@ -91,7 +106,9 @@
|
||||
"download_now": {
|
||||
"text": "Last ned nå ",
|
||||
"platform_small": "for {{platform}}",
|
||||
"linux_small": "for Linux"
|
||||
"linux_small": "for Linux",
|
||||
"platform_big": "v{{version}} for {{platform}}",
|
||||
"linux_big": "v{{version}} for Linux"
|
||||
},
|
||||
"footer": {
|
||||
"copyright_and_the": " og ",
|
||||
@ -100,9 +117,17 @@
|
||||
"download_helper_server_linux": {
|
||||
"download_tar_x64": "x64 (.tar.xz)",
|
||||
"download_tar_arm64": "ARM (.tar.xz)",
|
||||
"download_nixos": "NixOS modul"
|
||||
"download_nixos": "NixOS modul",
|
||||
"title": "Selv-hostet på Linux"
|
||||
},
|
||||
"download_helper_server_hosted": {
|
||||
"title": "Betalt hosting"
|
||||
"title": "Betalt hosting",
|
||||
"download_triliumcc": "Alternativt sjekk trilium.cc"
|
||||
},
|
||||
"faq": {
|
||||
"title": "Ofte stilte spørsmål"
|
||||
},
|
||||
"404": {
|
||||
"title": "404: Siden ble ikke funnet"
|
||||
}
|
||||
}
|
||||
|
||||
7
docs/User Guide/!!!meta.json
vendored
7
docs/User Guide/!!!meta.json
vendored
@ -10201,6 +10201,13 @@
|
||||
"value": "bx bxs-file-pdf",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "shareAlias",
|
||||
"value": "pdf",
|
||||
"isInheritable": false,
|
||||
"position": 60
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
"typescript": "5.9.3",
|
||||
"vite-plugin-svgo": "~2.0.0",
|
||||
"vitest": "4.0.16",
|
||||
"webdriverio": "9.22.0"
|
||||
"webdriverio": "9.23.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ckeditor5": "47.3.0"
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
"typescript": "5.9.3",
|
||||
"vite-plugin-svgo": "~2.0.0",
|
||||
"vitest": "4.0.16",
|
||||
"webdriverio": "9.22.0"
|
||||
"webdriverio": "9.23.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ckeditor5": "47.3.0"
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
"typescript": "5.9.3",
|
||||
"vite-plugin-svgo": "~2.0.0",
|
||||
"vitest": "4.0.16",
|
||||
"webdriverio": "9.22.0"
|
||||
"webdriverio": "9.23.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ckeditor5": "47.3.0"
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
"typescript": "5.9.3",
|
||||
"vite-plugin-svgo": "~2.0.0",
|
||||
"vitest": "4.0.16",
|
||||
"webdriverio": "9.22.0"
|
||||
"webdriverio": "9.23.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ckeditor5": "47.3.0"
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
"typescript": "5.9.3",
|
||||
"vite-plugin-svgo": "~2.0.0",
|
||||
"vitest": "4.0.16",
|
||||
"webdriverio": "9.22.0"
|
||||
"webdriverio": "9.23.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ckeditor5": "47.3.0"
|
||||
|
||||
@ -47,6 +47,7 @@ export const DAYJS_LOADER: Record<LOCALE_IDS, () => Promise<typeof import("dayjs
|
||||
"ku": () => import("dayjs/locale/ku.js"),
|
||||
"pt_br": () => import("dayjs/locale/pt-br.js"),
|
||||
"pt": () => import("dayjs/locale/pt.js"),
|
||||
"pl": () => import("dayjs/locale/pl.js"),
|
||||
"ro": () => import("dayjs/locale/ro.js"),
|
||||
"ru": () => import("dayjs/locale/ru.js"),
|
||||
"tw": () => import("dayjs/locale/zh-tw.js"),
|
||||
|
||||
@ -23,6 +23,7 @@ const UNSORTED_LOCALES = [
|
||||
{ id: "ja", name: "日本語", electronLocale: "ja" },
|
||||
{ id: "pt_br", name: "Português (Brasil)", electronLocale: "pt_BR" },
|
||||
{ id: "pt", name: "Português (Portugal)", electronLocale: "pt_PT" },
|
||||
{ id: "pl", name: "Polski", electronLocale: "pl" },
|
||||
{ id: "ro", name: "Română", electronLocale: "ro" },
|
||||
{ id: "ru", name: "Русский", electronLocale: "ru" },
|
||||
{ id: "tw", name: "繁體中文", electronLocale: "zh_TW" },
|
||||
|
||||
@ -3,6 +3,8 @@ import BuildHelper from "../../../scripts/build-utils";
|
||||
import { build as esbuild } from "esbuild";
|
||||
import { LOCALES } from "@triliumnext/commons";
|
||||
import { watch } from "chokidar";
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
import packageJson from "../package.json" with { type: "json " };
|
||||
|
||||
const build = new BuildHelper("packages/pdfjs-viewer");
|
||||
const watchMode = process.argv.includes("--watch");
|
||||
@ -16,6 +18,7 @@ async function main() {
|
||||
for (const file of [ "viewer.css", "viewer.html", "viewer.mjs" ]) {
|
||||
build.copy(`viewer/${file}`, `web/${file}`);
|
||||
}
|
||||
patchCacheBuster(`${build.outDir}/web/viewer.html`);
|
||||
build.copy(`viewer/images`, `web/images`);
|
||||
|
||||
// Copy the custom files.
|
||||
@ -34,8 +37,9 @@ async function main() {
|
||||
build.writeJson("web/locale/locale.json", localeMappings);
|
||||
|
||||
// Copy pdfjs-dist files.
|
||||
build.copy("/node_modules/pdfjs-dist/build/pdf.mjs", "build/pdf.mjs");
|
||||
build.copy("/node_modules/pdfjs-dist/build/pdf.worker.mjs", "build/pdf.worker.mjs");
|
||||
for (const file of [ "pdf.mjs", "pdf.worker.mjs", "pdf.sandbox.mjs" ]) {
|
||||
build.copy(join("/node_modules/pdfjs-dist/build", file), join("build", file));
|
||||
}
|
||||
|
||||
if (watchMode) {
|
||||
watchForChanges();
|
||||
@ -59,6 +63,21 @@ async function rebuildCustomFiles() {
|
||||
build.copy("src/custom.css", "web/custom.css");
|
||||
}
|
||||
|
||||
function patchCacheBuster(htmlFilePath: string) {
|
||||
const version = packageJson.version;
|
||||
console.log(`Versioned URLs: ${version}.`)
|
||||
let html = readFileSync(htmlFilePath, "utf-8");
|
||||
html = html.replace(
|
||||
`<link rel="stylesheet" href="custom.css" />`,
|
||||
`<link rel="stylesheet" href="custom.css?v=${version}" />`);
|
||||
html = html.replace(
|
||||
`<script src="custom.mjs" type="module"></script>`,
|
||||
`<script src="custom.mjs?v=${version}" type="module"></script>`
|
||||
);
|
||||
|
||||
writeFileSync(htmlFilePath, html);
|
||||
}
|
||||
|
||||
function watchForChanges() {
|
||||
console.log("Watching for changes in src directory...");
|
||||
const watcher = watch(join(build.projectDir, "src"), {
|
||||
|
||||
@ -6,11 +6,14 @@ import { setupPdfLayers } from "./layers";
|
||||
|
||||
async function main() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const isEditable = urlParams.get("editable") === "1";
|
||||
if (urlParams.get("sidebar") === "0") {
|
||||
hideSidebar();
|
||||
}
|
||||
|
||||
interceptPersistence(getCustomAppOptions(urlParams));
|
||||
if (isEditable) {
|
||||
interceptPersistence(getCustomAppOptions(urlParams));
|
||||
}
|
||||
|
||||
// Wait for the PDF viewer application to be available.
|
||||
while (!window.PDFViewerApplication) {
|
||||
@ -18,16 +21,18 @@ async function main() {
|
||||
}
|
||||
const app = window.PDFViewerApplication;
|
||||
|
||||
app.eventBus.on("documentloaded", () => {
|
||||
manageSave();
|
||||
manageDownload();
|
||||
extractAndSendToc();
|
||||
setupScrollToHeading();
|
||||
setupActiveHeadingTracking();
|
||||
setupPdfPages();
|
||||
setupPdfAttachments();
|
||||
setupPdfLayers();
|
||||
});
|
||||
if (isEditable) {
|
||||
app.eventBus.on("documentloaded", () => {
|
||||
manageSave();
|
||||
manageDownload();
|
||||
extractAndSendToc();
|
||||
setupScrollToHeading();
|
||||
setupActiveHeadingTracking();
|
||||
setupPdfPages();
|
||||
setupPdfAttachments();
|
||||
setupPdfLayers();
|
||||
});
|
||||
}
|
||||
await app.initializedPromise;
|
||||
};
|
||||
|
||||
@ -55,37 +60,38 @@ function getCustomAppOptions(urlParams: URLSearchParams) {
|
||||
function manageSave() {
|
||||
const app = window.PDFViewerApplication;
|
||||
const storage = app.pdfDocument.annotationStorage;
|
||||
let timeout = null;
|
||||
|
||||
function debouncedSave() {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
timeout = setTimeout(async () => {
|
||||
if (!storage) return;
|
||||
function onChange() {
|
||||
if (!storage) return;
|
||||
window.parent.postMessage({
|
||||
type: "pdfjs-viewer-document-modified",
|
||||
ntxId: window.TRILIUM_NTX_ID,
|
||||
noteId: window.TRILIUM_NOTE_ID
|
||||
} satisfies PdfDocumentModifiedMessage, window.location.origin);
|
||||
storage.resetModified();
|
||||
}
|
||||
|
||||
window.addEventListener("message", async (event) => {
|
||||
if (event.origin !== window.location.origin) return;
|
||||
|
||||
if (event.data?.type === "trilium-request-blob") {
|
||||
const app = window.PDFViewerApplication;
|
||||
const data = await app.pdfDocument.saveDocument();
|
||||
window.parent.postMessage({
|
||||
type: "pdfjs-viewer-document-modified",
|
||||
type: "pdfjs-viewer-blob",
|
||||
data,
|
||||
ntxId: window.TRILIUM_NTX_ID,
|
||||
noteId: window.TRILIUM_NOTE_ID
|
||||
} satisfies PdfDocumentModifiedMessage, window.location.origin);
|
||||
storage.resetModified();
|
||||
timeout = null;
|
||||
}, 2_000);
|
||||
}
|
||||
|
||||
app.pdfDocument.annotationStorage.onSetModified = debouncedSave; // works great for most cases, including forms.
|
||||
app.eventBus.on("annotationeditorcommit", debouncedSave);
|
||||
app.eventBus.on("annotationeditorparamschanged", debouncedSave);
|
||||
app.eventBus.on("annotationeditorstateschanged", evt => { // needed for detecting when annotations are moved around.
|
||||
const { activeEditorId } = evt;
|
||||
|
||||
// When activeEditorId becomes null, an editor was just committed
|
||||
if (activeEditorId === null) {
|
||||
debouncedSave();
|
||||
} satisfies PdfDocumentBlobResultMessage, window.location.origin);
|
||||
}
|
||||
});
|
||||
|
||||
app.pdfDocument.annotationStorage.onSetModified = () => {
|
||||
onChange();
|
||||
}; // works great for most cases, including forms.
|
||||
app.eventBus.on("switchannotationeditorparams", () => {
|
||||
onChange();
|
||||
});
|
||||
}
|
||||
|
||||
function manageDownload() {
|
||||
|
||||
68
pnpm-lock.yaml
generated
68
pnpm-lock.yaml
generated
@ -54,7 +54,7 @@ importers:
|
||||
version: 24.10.4
|
||||
'@vitest/browser-webdriverio':
|
||||
specifier: 4.0.16
|
||||
version: 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)(webdriverio@9.22.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))
|
||||
version: 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)(webdriverio@9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))
|
||||
'@vitest/coverage-v8':
|
||||
specifier: 4.0.16
|
||||
version: 4.0.16(@vitest/browser@4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16))(vitest@4.0.16)
|
||||
@ -945,8 +945,8 @@ importers:
|
||||
specifier: 4.0.16
|
||||
version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
||||
webdriverio:
|
||||
specifier: 9.22.0
|
||||
version: 9.22.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
specifier: 9.23.0
|
||||
version: 9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
|
||||
packages/ckeditor5-footnotes:
|
||||
devDependencies:
|
||||
@ -1005,8 +1005,8 @@ importers:
|
||||
specifier: 4.0.16
|
||||
version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
||||
webdriverio:
|
||||
specifier: 9.22.0
|
||||
version: 9.22.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
specifier: 9.23.0
|
||||
version: 9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
|
||||
packages/ckeditor5-keyboard-marker:
|
||||
devDependencies:
|
||||
@ -1065,8 +1065,8 @@ importers:
|
||||
specifier: 4.0.16
|
||||
version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
||||
webdriverio:
|
||||
specifier: 9.22.0
|
||||
version: 9.22.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
specifier: 9.23.0
|
||||
version: 9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
|
||||
packages/ckeditor5-math:
|
||||
dependencies:
|
||||
@ -1129,8 +1129,8 @@ importers:
|
||||
specifier: 4.0.16
|
||||
version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
||||
webdriverio:
|
||||
specifier: 9.22.0
|
||||
version: 9.22.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
specifier: 9.23.0
|
||||
version: 9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
|
||||
packages/ckeditor5-mermaid:
|
||||
dependencies:
|
||||
@ -1196,8 +1196,8 @@ importers:
|
||||
specifier: 4.0.16
|
||||
version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
||||
webdriverio:
|
||||
specifier: 9.22.0
|
||||
version: 9.22.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
specifier: 9.23.0
|
||||
version: 9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
|
||||
packages/codemirror:
|
||||
dependencies:
|
||||
@ -6065,8 +6065,8 @@ packages:
|
||||
'@vue/shared@3.5.14':
|
||||
resolution: {integrity: sha512-oXTwNxVfc9EtP1zzXAlSlgARLXNC84frFYkS0HHz0h3E4WZSP9sywqjqzGCP9Y34M8ipNmd380pVgmMuwELDyQ==}
|
||||
|
||||
'@wdio/config@9.22.0':
|
||||
resolution: {integrity: sha512-SQsTSZowEI+whPlwPLsX9ICr6BiG39NLmzED7OWfaowribQ0XylRhoWodcRu6cB/ZCzminZajBUG5XgarNWnRw==}
|
||||
'@wdio/config@9.23.0':
|
||||
resolution: {integrity: sha512-hhtngUG2uCxYmScSEor+k22EVlsTW3ARXgke8NPVeQA4p1+GC2CvRZi4P7nmhRTZubgLrENYYsveFcYR+1UXhQ==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
|
||||
'@wdio/logger@9.18.0':
|
||||
@ -6084,8 +6084,8 @@ packages:
|
||||
resolution: {integrity: sha512-zMmAtse2UMCSOW76mvK3OejauAdcFGuKopNRH7crI0gwKTZtvV89yXWRziz9cVXpFgfmJCjf9edxKFWdhuF5yw==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
|
||||
'@wdio/utils@9.22.0':
|
||||
resolution: {integrity: sha512-5j2nn2bBjj41wxXsVT43sUMOKR0qiKNDRG1UcKQ6NkfsWFObSehMAS0a9ZZu//+ooTxRkwHjvLdQrXIrPnTLzg==}
|
||||
'@wdio/utils@9.23.0':
|
||||
resolution: {integrity: sha512-WhXuVSxEvPw/i34bL1aCHAOi+4g29kRkIMyBShNSxH+Shxh2G91RJYsXm4IAiPMGcC4H6G8T2VcbZ32qnGPm5Q==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
|
||||
'@webassemblyjs/ast@1.14.1':
|
||||
@ -14150,12 +14150,12 @@ packages:
|
||||
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
webdriver@9.22.0:
|
||||
resolution: {integrity: sha512-jf4irPhIJAssrF3mqUrBZGZnzjRfM86Q24ePUOgFKWI04LtdvRsnc9SsWU05mrN/a6pTJzGps6GsvLpNhvcalg==}
|
||||
webdriver@9.23.0:
|
||||
resolution: {integrity: sha512-XkZOhjoBOY7maKI3BhDF2rNiDne4wBD6Gw6VUnt4X9b7j9NtfzcCrThBlT0hnA8W77bWNtMRCSpw9Ajy08HqKg==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
|
||||
webdriverio@9.22.0:
|
||||
resolution: {integrity: sha512-sqXZG11hRM9KjqioVPcXCPLIcdJprNM9e+B6JlyacN6ImgC64MQbgs0vtCDLVsSIX7vg+x771lrS/VxXxqlkJw==}
|
||||
webdriverio@9.23.0:
|
||||
resolution: {integrity: sha512-Y5y4jpwHvuduUfup+gXTuCU6AROn/k6qOba3st0laFluKHY+q5SHOpQAJdS8acYLwE8caDQ2dXJhmXyxuJrm0Q==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
peerDependencies:
|
||||
puppeteer-core: '>=22.x || <=24.x'
|
||||
@ -15361,6 +15361,8 @@ snapshots:
|
||||
'@ckeditor/ckeditor5-core': 47.3.0
|
||||
'@ckeditor/ckeditor5-utils': 47.3.0
|
||||
ckeditor5: 47.3.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@ckeditor/ckeditor5-code-block@47.3.0(patch_hash=2361d8caad7d6b5bddacc3a3b4aa37dbfba260b1c1b22a450413a79c1bb1ce95)':
|
||||
dependencies:
|
||||
@ -16091,6 +16093,8 @@ snapshots:
|
||||
'@ckeditor/ckeditor5-ui': 47.3.0
|
||||
'@ckeditor/ckeditor5-utils': 47.3.0
|
||||
ckeditor5: 47.3.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@ckeditor/ckeditor5-restricted-editing@47.3.0':
|
||||
dependencies:
|
||||
@ -20865,11 +20869,11 @@ snapshots:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
|
||||
'@vitest/browser-webdriverio@4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)(webdriverio@9.22.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))':
|
||||
'@vitest/browser-webdriverio@4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)(webdriverio@9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))':
|
||||
dependencies:
|
||||
'@vitest/browser': 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)
|
||||
vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-webdriverio@4.0.16)(@vitest/ui@4.0.16)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)
|
||||
webdriverio: 9.22.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
webdriverio: 9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- msw
|
||||
@ -21027,11 +21031,11 @@ snapshots:
|
||||
|
||||
'@vue/shared@3.5.14': {}
|
||||
|
||||
'@wdio/config@9.22.0':
|
||||
'@wdio/config@9.23.0':
|
||||
dependencies:
|
||||
'@wdio/logger': 9.18.0
|
||||
'@wdio/types': 9.20.0
|
||||
'@wdio/utils': 9.22.0
|
||||
'@wdio/utils': 9.23.0
|
||||
deepmerge-ts: 7.1.5
|
||||
glob: 10.4.5
|
||||
import-meta-resolve: 4.2.0
|
||||
@ -21057,7 +21061,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/node': 20.19.25
|
||||
|
||||
'@wdio/utils@9.22.0':
|
||||
'@wdio/utils@9.23.0':
|
||||
dependencies:
|
||||
'@puppeteer/browsers': 2.10.10
|
||||
'@wdio/logger': 9.18.0
|
||||
@ -30844,7 +30848,7 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@opentelemetry/api': 1.9.0
|
||||
'@types/node': 24.10.4
|
||||
'@vitest/browser-webdriverio': 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)(webdriverio@9.22.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))
|
||||
'@vitest/browser-webdriverio': 4.0.16(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.4)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1))(vitest@4.0.16)(webdriverio@9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))
|
||||
'@vitest/ui': 4.0.16(vitest@4.0.16)
|
||||
happy-dom: 20.0.11
|
||||
jsdom: 26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
@ -30934,15 +30938,15 @@ snapshots:
|
||||
|
||||
web-streams-polyfill@3.3.3: {}
|
||||
|
||||
webdriver@9.22.0(bufferutil@4.0.9)(utf-8-validate@6.0.5):
|
||||
webdriver@9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5):
|
||||
dependencies:
|
||||
'@types/node': 20.19.25
|
||||
'@types/ws': 8.18.1
|
||||
'@wdio/config': 9.22.0
|
||||
'@wdio/config': 9.23.0
|
||||
'@wdio/logger': 9.18.0
|
||||
'@wdio/protocols': 9.16.2
|
||||
'@wdio/types': 9.20.0
|
||||
'@wdio/utils': 9.22.0
|
||||
'@wdio/utils': 9.23.0
|
||||
deepmerge-ts: 7.1.5
|
||||
https-proxy-agent: 7.0.6
|
||||
undici: 6.21.3
|
||||
@ -30953,16 +30957,16 @@ snapshots:
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
webdriverio@9.22.0(bufferutil@4.0.9)(utf-8-validate@6.0.5):
|
||||
webdriverio@9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5):
|
||||
dependencies:
|
||||
'@types/node': 20.19.25
|
||||
'@types/sinonjs__fake-timers': 8.1.5
|
||||
'@wdio/config': 9.22.0
|
||||
'@wdio/config': 9.23.0
|
||||
'@wdio/logger': 9.18.0
|
||||
'@wdio/protocols': 9.16.2
|
||||
'@wdio/repl': 9.16.2
|
||||
'@wdio/types': 9.20.0
|
||||
'@wdio/utils': 9.22.0
|
||||
'@wdio/utils': 9.23.0
|
||||
archiver: 7.0.1
|
||||
aria-query: 5.3.2
|
||||
cheerio: 1.1.2
|
||||
@ -30979,7 +30983,7 @@ snapshots:
|
||||
rgb2hex: 0.2.5
|
||||
serialize-error: 12.0.0
|
||||
urlpattern-polyfill: 10.1.0
|
||||
webdriver: 9.22.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
webdriver: 9.23.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
transitivePeerDependencies:
|
||||
- bare-buffer
|
||||
- bufferutil
|
||||
|
||||
@ -2,7 +2,7 @@ import { execSync } from "child_process";
|
||||
import { build as esbuild } from "esbuild";
|
||||
import { cpSync, existsSync, rmSync, writeFileSync } from "fs";
|
||||
import { copySync, emptyDirSync, mkdirpSync } from "fs-extra";
|
||||
import { join } from "path";
|
||||
import { delimiter, join } from "path";
|
||||
|
||||
export default class BuildHelper {
|
||||
|
||||
@ -20,7 +20,7 @@ export default class BuildHelper {
|
||||
|
||||
copy(projectDirPath: string, outDirPath: string) {
|
||||
let sourcePath: string;
|
||||
if (projectDirPath.startsWith("/")) {
|
||||
if (projectDirPath.startsWith("/") || projectDirPath.startsWith("\\")) {
|
||||
sourcePath = join(this.rootDir, projectDirPath.substring(1));
|
||||
} else {
|
||||
sourcePath = join(this.projectDir, projectDirPath);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
21
scripts/translation/check-translation-coverage.ts
Normal file
21
scripts/translation/check-translation-coverage.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { LOCALES } from "../../packages/commons/src/lib/i18n";
|
||||
import { getLanguageStats } from "./utils";
|
||||
|
||||
async function main() {
|
||||
const languageStats = await getLanguageStats("client");
|
||||
const localeIdsWithCoverage = languageStats.results
|
||||
.filter(language => language.translated_percent > 50)
|
||||
.map(language => language.language_code);
|
||||
|
||||
for (const localeId of localeIdsWithCoverage) {
|
||||
const locale = LOCALES.find(l => l.id === localeId);
|
||||
if (!locale) {
|
||||
console.error(`Locale not found for id: ${localeId}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Translation coverage check passed.");
|
||||
}
|
||||
|
||||
main();
|
||||
@ -1,42 +1,15 @@
|
||||
import { readFile, stat, writeFile, } from "fs/promises";
|
||||
import { readFile, writeFile } from "fs/promises";
|
||||
import { join } from "path";
|
||||
|
||||
import { getLanguageStats } from "./utils";
|
||||
|
||||
const scriptDir = __dirname;
|
||||
const rootDir = join(scriptDir, "../..");
|
||||
const docsDir = join(rootDir, "docs");
|
||||
|
||||
async function getLanguageStats() {
|
||||
const cacheFile = join(scriptDir, ".language-stats.json");
|
||||
|
||||
// Try to read from the cache.
|
||||
try {
|
||||
const cacheStats = await stat(cacheFile);
|
||||
const now = new Date();
|
||||
const oneDay = 24 * 60 * 60 * 1000; // milliseconds
|
||||
if (cacheStats.mtimeMs < now.getTime() + oneDay) {
|
||||
console.log("Reading language stats from cache.");
|
||||
return JSON.parse(await readFile(cacheFile, "utf-8"));
|
||||
}
|
||||
} catch (e) {
|
||||
if (!(e && typeof e === "object" && "code" in e && e.code === "ENOENT")) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Make the request
|
||||
console.log("Reading language stats from Weblate API.");
|
||||
const request = await fetch("https://hosted.weblate.org/api/components/trilium/readme/translations/");
|
||||
const stats = JSON.parse(await request.text());
|
||||
|
||||
// Update the cache
|
||||
await writeFile(cacheFile, JSON.stringify(stats, null, 4));
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
async function rewriteLanguageBar(readme: string) {
|
||||
// Filter languages by their availability.
|
||||
const languageStats = await getLanguageStats();
|
||||
const languageStats = await getLanguageStats("readme");
|
||||
const languagesWithCoverage: any[] = languageStats.results.filter(language => language.translated_percent > 75);
|
||||
const languageLinks = languagesWithCoverage
|
||||
.map(language => `[${language.language.name}](./${language.filename})`)
|
||||
|
||||
33
scripts/translation/utils.ts
Normal file
33
scripts/translation/utils.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { readFile, stat,writeFile } from "fs/promises";
|
||||
import { join } from "path";
|
||||
|
||||
const scriptDir = __dirname;
|
||||
|
||||
export async function getLanguageStats(project: "readme" | "client") {
|
||||
const cacheFile = join(scriptDir, `.language-stats-${project}.json`);
|
||||
|
||||
// Try to read from the cache.
|
||||
try {
|
||||
const cacheStats = await stat(cacheFile);
|
||||
const now = new Date();
|
||||
const oneDay = 24 * 60 * 60 * 1000; // milliseconds
|
||||
if (cacheStats.mtimeMs < now.getTime() + oneDay) {
|
||||
console.log("Reading language stats from cache.");
|
||||
return JSON.parse(await readFile(cacheFile, "utf-8"));
|
||||
}
|
||||
} catch (e) {
|
||||
if (!(e && typeof e === "object" && "code" in e && e.code === "ENOENT")) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Make the request
|
||||
console.log("Reading language stats from Weblate API.");
|
||||
const request = await fetch(`https://hosted.weblate.org/api/components/trilium/${project}/translations/`);
|
||||
const stats = JSON.parse(await request.text());
|
||||
|
||||
// Update the cache
|
||||
await writeFile(cacheFile, JSON.stringify(stats, null, 4));
|
||||
|
||||
return stats;
|
||||
}
|
||||
@ -5,6 +5,7 @@
|
||||
"moduleResolution": "bundler",
|
||||
"target": "es2023",
|
||||
"outDir": "dist",
|
||||
"rootDir": "..",
|
||||
"types": [
|
||||
"node",
|
||||
"express"
|
||||
@ -12,7 +13,8 @@
|
||||
"tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
"scripts/*.ts",
|
||||
"packages/commons/src/lib/i18n.ts"
|
||||
],
|
||||
"references": []
|
||||
}
|
||||
|
||||
@ -11,9 +11,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import { fileURLToPath } from "url";
|
||||
import { dirname, join } from "path";
|
||||
import fs from "fs";
|
||||
import { dirname, join } from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
function processVersion(version) {
|
||||
// Remove the beta suffix if any.
|
||||
@ -42,14 +42,19 @@ function patchPackageJson(packageJsonPath) {
|
||||
|
||||
function main() {
|
||||
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
|
||||
const rootPackageJson = join(scriptDir, "..", "package.json");
|
||||
patchPackageJson(rootPackageJson);
|
||||
|
||||
|
||||
for (const app of ["server", "client"]) {
|
||||
const appPackageJsonPath = join(scriptDir, "..", "apps", app, "package.json");
|
||||
patchPackageJson(appPackageJsonPath);
|
||||
}
|
||||
|
||||
for (const packageName of [ "pdfjs-viewer" ]) {
|
||||
const packageJsonPath = join(scriptDir, "..", "packages", packageName, "package.json");
|
||||
patchPackageJson(packageJsonPath);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user