This commit is contained in:
Adorian Doran 2025-12-01 14:08:32 +02:00
commit f906fb9b4c
8 changed files with 30 additions and 13 deletions

View File

@ -79,7 +79,7 @@ jobs:
if: failure() if: failure()
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v5
with: with:
name: e2e report name: e2e report ${{ matrix.arch }}
path: apps/server-e2e/test-output path: apps/server-e2e/test-output
- name: Kill the server - name: Kill the server

View File

@ -207,7 +207,7 @@ function toObject<T, R>(array: T[], fn: (arg0: T) => [key: string, value: R]) {
return obj; return obj;
} }
function randomString(len: number) { export function randomString(len: number) {
let text = ""; let text = "";
const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

View File

@ -736,8 +736,8 @@
"zoom_out_title": "Zoom Out" "zoom_out_title": "Zoom Out"
}, },
"zpetne_odkazy": { "zpetne_odkazy": {
"backlink": "{{count}} Backlink", "backlink_one": "{{count}} Backlink",
"backlinks": "{{count}} Backlinks", "backlink_other": "{{count}} Backlinks",
"relation": "relation" "relation": "relation"
}, },
"mobile_detail_menu": { "mobile_detail_menu": {

View File

@ -1362,8 +1362,9 @@
"title": "Factorul de zoom (doar pentru versiunea desktop)" "title": "Factorul de zoom (doar pentru versiunea desktop)"
}, },
"zpetne_odkazy": { "zpetne_odkazy": {
"backlink": "{{count}} legături de retur", "backlink_one": "{{count}} legătură de retur",
"backlinks": "{{count}} legături de retur", "backlink_few": "{{count}} legături de retur",
"backlink_other": "{{count}} de legături de retur",
"relation": "relație" "relation": "relație"
}, },
"svg_export_button": { "svg_export_button": {

View File

@ -18,6 +18,7 @@ import froca from "../services/froca";
import NoteLink from "./react/NoteLink"; import NoteLink from "./react/NoteLink";
import RawHtml from "./react/RawHtml"; import RawHtml from "./react/RawHtml";
import { ViewTypeOptions } from "./collections/interface"; import { ViewTypeOptions } from "./collections/interface";
import attributes from "../services/attributes";
export interface FloatingButtonContext { export interface FloatingButtonContext {
parentComponent: Component; parentComponent: Component;
@ -310,13 +311,24 @@ function Backlinks({ note, isDefaultViewMode }: FloatingButtonContext) {
let [ popupOpen, setPopupOpen ] = useState(false); let [ popupOpen, setPopupOpen ] = useState(false);
const backlinksContainerRef = useRef<HTMLDivElement>(null); const backlinksContainerRef = useRef<HTMLDivElement>(null);
useEffect(() => { function refresh() {
if (!isDefaultViewMode) return; if (!isDefaultViewMode) return;
server.get<BacklinkCountResponse>(`note-map/${note.noteId}/backlink-count`).then(resp => { server.get<BacklinkCountResponse>(`note-map/${note.noteId}/backlink-count`).then(resp => {
setBacklinkCount(resp.count); setBacklinkCount(resp.count);
}); });
}, [ note ]); }
useEffect(() => refresh(), [ note ]);
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
loadResults.getAttributeRows().some(attr =>
attr.type === "relation" &&
attr.name === "internalLink" &&
attributes.isAffecting(attr, note))
{
refresh();
}
});
// Determine the max height of the container. // Determine the max height of the container.
const { windowHeight } = useWindowSize(); const { windowHeight } = useWindowSize();

View File

@ -14,8 +14,10 @@ import ws from "../services/ws";
import { UpdateAttributeResponse } from "@triliumnext/commons"; import { UpdateAttributeResponse } from "@triliumnext/commons";
import attributes from "../services/attributes"; import attributes from "../services/attributes";
import debounce from "../services/debounce"; import debounce from "../services/debounce";
import { randomString } from "../services/utils";
interface Cell { interface Cell {
uniqueId: string;
definitionAttr: FAttribute; definitionAttr: FAttribute;
definition: DefinitionObject; definition: DefinitionObject;
valueAttr: Attribute; valueAttr: Attribute;
@ -44,6 +46,7 @@ export default function PromotedAttributes() {
<div className="promoted-attributes-widget"> <div className="promoted-attributes-widget">
{cells && cells.length > 0 && <div className="promoted-attributes-container"> {cells && cells.length > 0 && <div className="promoted-attributes-container">
{note && cells?.map(cell => <PromotedAttributeCell {note && cells?.map(cell => <PromotedAttributeCell
key={cell.uniqueId}
cell={cell} cell={cell}
cells={cells} setCells={setCells} cells={cells} setCells={setCells}
shouldFocus={cell === cellToFocus} setCellToFocus={setCellToFocus} shouldFocus={cell === cellToFocus} setCellToFocus={setCellToFocus}
@ -103,7 +106,8 @@ function usePromotedAttributeData(note: FNote | null | undefined, componentId: s
valueAttr.attributeId = ""; valueAttr.attributeId = "";
} }
cells.push({ definitionAttr, definition, valueAttr, valueName }); const uniqueId = randomString(10);
cells.push({ definitionAttr, definition, valueAttr, valueName, uniqueId });
} }
} }
setCells(cells); setCells(cells);

View File

@ -43,7 +43,7 @@ test("User can change language from settings", async ({ page, context }) => {
// Check that the default value (English) is set. // Check that the default value (English) is set.
await expect(app.currentNoteSplit).toContainText("First day of the week"); await expect(app.currentNoteSplit).toContainText("First day of the week");
const languageCombobox = app.dropdown(app.currentNoteSplit.locator(".options-section .dropdown").first()); const languageCombobox = app.dropdown(app.currentNoteSplit.locator(".options-section .dropdown").first());
await expect(languageCombobox).toContainText("English"); await expect(languageCombobox).toContainText("English (United States)");
// Select Chinese and ensure the translation is set. // Select Chinese and ensure the translation is set.
await languageCombobox.selectOptionByText("简体中文"); await languageCombobox.selectOptionByText("简体中文");
@ -53,8 +53,8 @@ test("User can change language from settings", async ({ page, context }) => {
await expect(languageCombobox).toContainText("简体中文"); await expect(languageCombobox).toContainText("简体中文");
// Select English again. // Select English again.
await languageCombobox.selectOptionByText("English"); await languageCombobox.selectOptionByText("English (United States)");
await app.currentNoteSplit.locator("button[name=restart-app-button]").click(); await app.currentNoteSplit.locator("button[name=restart-app-button]").click();
await expect(app.currentNoteSplit).toContainText("Language", { timeout: 15000 }); await expect(app.currentNoteSplit).toContainText("Language", { timeout: 15000 });
await expect(languageCombobox).toContainText("English"); await expect(languageCombobox).toContainText("English (United States)");
}); });

View File

@ -14,7 +14,7 @@ export interface Locale {
const UNSORTED_LOCALES = [ const UNSORTED_LOCALES = [
{ id: "cn", name: "简体中文", electronLocale: "zh_CN" }, { id: "cn", name: "简体中文", electronLocale: "zh_CN" },
{ id: "de", name: "Deutsch", electronLocale: "de" }, { id: "de", name: "Deutsch", electronLocale: "de" },
{ id: "en", name: "English", electronLocale: "en" }, { id: "en", name: "English (United States)", electronLocale: "en" },
{ id: "en-GB", name: "English (United Kingdom)", electronLocale: "en_GB" }, { id: "en-GB", name: "English (United Kingdom)", electronLocale: "en_GB" },
{ id: "es", name: "Español", electronLocale: "es" }, { id: "es", name: "Español", electronLocale: "es" },
{ id: "fr", name: "Français", electronLocale: "fr" }, { id: "fr", name: "Français", electronLocale: "fr" },