From 10a6a3056ad301fd684281d91071bccc627a830f Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 6 Sep 2025 11:20:39 +0300 Subject: [PATCH] chore(react/collections/calendar): reintroduce tests --- .../calendar/event_builder.spec.ts} | 33 ++++++++++--------- .../collections/calendar/event_builder.ts | 2 +- .../widgets/collections/calendar/index.tsx | 18 ++++++---- .../src/widgets/view_widgets/calendar_view.ts | 22 ------------- 4 files changed, 30 insertions(+), 45 deletions(-) rename apps/client/src/widgets/{view_widgets/calendar_view.spec.ts => collections/calendar/event_builder.spec.ts} (87%) diff --git a/apps/client/src/widgets/view_widgets/calendar_view.spec.ts b/apps/client/src/widgets/collections/calendar/event_builder.spec.ts similarity index 87% rename from apps/client/src/widgets/view_widgets/calendar_view.spec.ts rename to apps/client/src/widgets/collections/calendar/event_builder.spec.ts index ad6c38b02..2c872a14e 100644 --- a/apps/client/src/widgets/view_widgets/calendar_view.spec.ts +++ b/apps/client/src/widgets/collections/calendar/event_builder.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from "vitest"; -import { buildNote, buildNotes } from "../../test/easy-froca.js"; -import CalendarView, { getFullCalendarLocale } from "./calendar_view.js"; +import { buildNote, buildNotes } from "../../../test/easy-froca.js"; +import { buildEvent, buildEvents } from "./event_builder.js"; +import { LOCALE_MAPPINGS } from "./index.js"; import { LOCALES } from "@triliumnext/commons"; describe("Building events", () => { @@ -9,7 +10,7 @@ describe("Building events", () => { { title: "Note 1", "#startDate": "2025-05-05" }, { title: "Note 2", "#startDate": "2025-05-07" }, ]); - const events = await CalendarView.buildEvents(noteIds); + const events = await buildEvents(noteIds); expect(events).toHaveLength(2); expect(events[0]).toMatchObject({ title: "Note 1", start: "2025-05-05", end: "2025-05-06" }); @@ -21,7 +22,7 @@ describe("Building events", () => { { title: "Note 1", "#endDate": "2025-05-05" }, { title: "Note 2", "#endDateDate": "2025-05-07" } ]); - const events = await CalendarView.buildEvents(noteIds); + const events = await buildEvents(noteIds); expect(events).toHaveLength(0); }); @@ -31,7 +32,7 @@ describe("Building events", () => { { title: "Note 1", "#startDate": "2025-05-05", "#endDate": "2025-05-05" }, { title: "Note 2", "#startDate": "2025-05-07", "#endDate": "2025-05-08" }, ]); - const events = await CalendarView.buildEvents(noteIds); + const events = await buildEvents(noteIds); expect(events).toHaveLength(2); expect(events[0]).toMatchObject({ title: "Note 1", start: "2025-05-05", end: "2025-05-06" }); @@ -43,7 +44,7 @@ describe("Building events", () => { { title: "Note 1", "#myStartDate": "2025-05-05", "#calendar:startDate": "myStartDate" }, { title: "Note 2", "#startDate": "2025-05-07", "#calendar:startDate": "myStartDate" }, ]); - const events = await CalendarView.buildEvents(noteIds); + const events = await buildEvents(noteIds); expect(events).toHaveLength(2); expect(events[0]).toMatchObject({ @@ -65,7 +66,7 @@ describe("Building events", () => { { title: "Note 3", "#startDate": "2025-05-05", "#myEndDate": "2025-05-05", "#calendar:startDate": "myStartDate", "#calendar:endDate": "myEndDate" }, { title: "Note 4", "#startDate": "2025-05-07", "#myEndDate": "2025-05-08", "#calendar:startDate": "myStartDate", "#calendar:endDate": "myEndDate" }, ]); - const events = await CalendarView.buildEvents(noteIds); + const events = await buildEvents(noteIds); expect(events).toHaveLength(4); expect(events[0]).toMatchObject({ title: "Note 1", start: "2025-05-05", end: "2025-05-06" }); @@ -79,7 +80,7 @@ describe("Building events", () => { { title: "Note 1", "#myTitle": "My Custom Title 1", "#startDate": "2025-05-05", "#calendar:title": "myTitle" }, { title: "Note 2", "#startDate": "2025-05-07", "#calendar:title": "myTitle" }, ]); - const events = await CalendarView.buildEvents(noteIds); + const events = await buildEvents(noteIds); expect(events).toHaveLength(2); expect(events[0]).toMatchObject({ title: "My Custom Title 1", start: "2025-05-05" }); @@ -92,7 +93,7 @@ describe("Building events", () => { { title: "Note 1", "~myTitle": "mySharedTitle", "#startDate": "2025-05-05", "#calendar:title": "myTitle" }, { title: "Note 2", "#startDate": "2025-05-07", "#calendar:title": "myTitle" }, ]); - const events = await CalendarView.buildEvents(noteIds); + const events = await buildEvents(noteIds); expect(events).toHaveLength(2); expect(events[0]).toMatchObject({ title: "My shared title", start: "2025-05-05" }); @@ -105,7 +106,7 @@ describe("Building events", () => { { title: "Note 1", "~myTitle": "mySharedTitle", "#startDate": "2025-05-05", "#calendar:title": "myTitle" }, { title: "Note 2", "#startDate": "2025-05-07", "#calendar:title": "myTitle" }, ]); - const events = await CalendarView.buildEvents(noteIds); + const events = await buildEvents(noteIds); expect(events).toHaveLength(2); expect(events[0]).toMatchObject({ title: "My shared custom title", start: "2025-05-05" }); @@ -125,7 +126,7 @@ describe("Promoted attributes", () => { "#calendar:displayedAttributes": "weight,mood" }); - const event = await CalendarView.buildEvent(note, { startDate: "2025-04-04" }); + const event = await buildEvent(note, { startDate: "2025-04-04" }); expect(event).toHaveLength(1); expect(event[0]?.promotedAttributes).toMatchObject([ [ "weight", "75" ], @@ -143,7 +144,7 @@ describe("Promoted attributes", () => { "#relation:assignee": "promoted,alias=Assignee,single,text", }); - const event = await CalendarView.buildEvent(note, { startDate: "2025-04-04" }); + const event = await buildEvent(note, { startDate: "2025-04-04" }); expect(event).toHaveLength(1); expect(event[0]?.promotedAttributes).toMatchObject([ [ "assignee", "Target note" ] @@ -155,7 +156,7 @@ describe("Promoted attributes", () => { { title: "Note 1", "#startDate": "2025-05-05", "#startTime": "13:36", "#endTime": "14:56" }, { title: "Note 2", "#startDate": "2025-05-07", "#endDate": "2025-05-08", "#startTime": "13:36", "#endTime": "14:56" }, ]); - const events = await CalendarView.buildEvents(noteIds); + const events = await buildEvents(noteIds); expect(events).toHaveLength(2); expect(events[0]).toMatchObject({ title: "Note 1", start: "2025-05-05T13:36:00", end: "2025-05-05T14:56:00" }); @@ -167,7 +168,7 @@ describe("Promoted attributes", () => { { title: "Note 1", "#startDate": "2025-05-05", "#startTime": "13:30" }, { title: "Note 2", "#startDate": "2025-05-07", "#endDate": "2025-05-08", "#startTime": "13:36" }, ]); - const events = await CalendarView.buildEvents(noteIds); + const events = await buildEvents(noteIds); expect(events).toHaveLength(2); expect(events[0]).toMatchObject({ title: "Note 1", start: "2025-05-05T13:30:00" }); @@ -183,12 +184,12 @@ describe("Building locales", () => { continue; } - const fullCalendarLocale = await getFullCalendarLocale(id); + const fullCalendarLocale = LOCALE_MAPPINGS[id]; if (id !== "en") { expect(fullCalendarLocale, `For locale ${id}`).toBeDefined(); } else { - expect(fullCalendarLocale).toBeUndefined(); + expect(fullCalendarLocale).toBeNull(); } } }); diff --git a/apps/client/src/widgets/collections/calendar/event_builder.ts b/apps/client/src/widgets/collections/calendar/event_builder.ts index c9a13c816..3ea4c1001 100644 --- a/apps/client/src/widgets/collections/calendar/event_builder.ts +++ b/apps/client/src/widgets/collections/calendar/event_builder.ts @@ -75,7 +75,7 @@ export async function buildEventsForCalendar(note: FNote, e: EventSourceFuncArg) return events.flat(); } -async function buildEvent(note: FNote, { startDate, endDate, startTime, endTime }: Event) { +export async function buildEvent(note: FNote, { startDate, endDate, startTime, endTime }: Event) { const customTitleAttributeName = note.getLabelValue("calendar:title"); const titles = await parseCustomTitle(customTitleAttributeName, note); const color = note.getLabelValue("calendar:color") ?? note.getLabelValue("color"); diff --git a/apps/client/src/widgets/collections/calendar/index.tsx b/apps/client/src/widgets/collections/calendar/index.tsx index 52ca329d8..19ff79040 100644 --- a/apps/client/src/widgets/collections/calendar/index.tsx +++ b/apps/client/src/widgets/collections/calendar/index.tsx @@ -3,12 +3,9 @@ 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, useTriliumOption, useTriliumOptionInt } from "../../react/hooks"; -import { CreateChildrenResponse, LOCALE_IDS } from "@triliumnext/commons"; +import { useNoteLabel, useNoteLabelBoolean, useResizeObserver, useSpacedUpdate, useTriliumEvent, useTriliumOption, useTriliumOptionInt } from "../../react/hooks"; +import { LOCALE_IDS } from "@triliumnext/commons"; import { Calendar as FullCalendar } from "@fullcalendar/core"; -import { removeOwnedAttributesByNameOrType, setLabel } from "../../../services/attributes"; -import { circle } from "leaflet"; -import server from "../../../services/server"; import { parseStartEndDateFromEvent, parseStartEndTimeFromEvent } from "./utils"; import dialog from "../../../services/dialog"; import { t } from "../../../services/i18n"; @@ -32,7 +29,7 @@ const CALENDAR_VIEWS = [ ] // Here we hard-code the imports in order to ensure that they are embedded by webpack without having to load all the languages. -const LOCALE_MAPPINGS: Record Promise<{ default: LocaleInput }>) | null> = { +export const LOCALE_MAPPINGS: Record Promise<{ default: LocaleInput }>) | null> = { de: () => import("@fullcalendar/core/locales/de"), es: () => import("@fullcalendar/core/locales/es"), fr: () => import("@fullcalendar/core/locales/fr"), @@ -75,6 +72,15 @@ export default function CalendarView({ note, noteIds }: ViewModeProps { + if (loadResults.getNoteIds().some(noteId => noteIds.includes(noteId)) // note title change. + || loadResults.getAttributeRows().some((a) => noteIds.includes(a.noteId ?? ""))) // subnote change. + { + calendarRef.current?.refetchEvents(); + } + }); + return (plugins &&
{ } } - async onEntitiesReloaded({ loadResults }: EventData<"entitiesReloaded">) { - // Refresh note IDs if they got changed. - if (loadResults.getBranchRows().some((branch) => branch.parentNoteId === this.parentNote.noteId)) { - this.noteIds = this.parentNote.getChildNoteIds(); - } - - // Refresh calendar on attribute change. - if (loadResults.getAttributeRows().some((attribute) => attribute.noteId === this.parentNote.noteId && attribute.name?.startsWith("calendar:") && attribute.name !== "calendar:view")) { - return true; - } - - // Refresh on note title change. - if (loadResults.getNoteIds().some(noteId => this.noteIds.includes(noteId))) { - this.calendar?.refetchEvents(); - } - - // Refresh dataset on subnote change. - if (loadResults.getAttributeRows().some((a) => this.noteIds.includes(a.noteId ?? ""))) { - this.calendar?.refetchEvents(); - } - } - buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) { if (!this.calendar) { return;