From 07443042a1f0724cde2d2d0e6141879ea1cf4b89 Mon Sep 17 00:00:00 2001 From: "Romain DEP." Date: Sat, 22 Feb 2025 23:34:14 +0100 Subject: [PATCH 1/4] feat(view/calendar): let the user specify attributes to be promoted onto the calendar view, and render them inside the event title --- .../app/widgets/view_widgets/calendar_view.ts | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/public/app/widgets/view_widgets/calendar_view.ts b/src/public/app/widgets/view_widgets/calendar_view.ts index 1a861d9b5..fb375d346 100644 --- a/src/public/app/widgets/view_widgets/calendar_view.ts +++ b/src/public/app/widgets/view_widgets/calendar_view.ts @@ -279,7 +279,10 @@ export default class CalendarView extends ViewMode { const events: EventSourceInput = []; for (const note of notes) { - let startDate = note.getLabelValue("startDate"); + const startDate = note.getLabelValue("startDate"); + if (!startDate) { + continue; + } if (note.hasChildren()) { const childrenEventData = await this.#buildEvents(note.getChildNoteIds()); @@ -288,9 +291,6 @@ export default class CalendarView extends ViewMode { } } - if (!startDate) { - continue; - } const endDate = note.getAttributeValue("label", "endDate"); events.push(await CalendarView.#buildEvent(note, startDate, endDate)); @@ -304,9 +304,24 @@ export default class CalendarView extends ViewMode { const titles = await CalendarView.#parseCustomTitle(customTitle, note); const color = note.getLabelValue("calendar:color") ?? note.getLabelValue("color"); const events: EventInput[] = []; + // the user can specify one or multiple attributes to be promoted onto the calendar view by setting `#calendar:promotedAttributes` at the note level + // their values will then be rentered into the event title and appear as "[eventIcon] $eventTitle [#promotedAttributeX=valueX] [#promotedAttributeY=valueY]" + const promotedAttrs = note + .getAttributes() + .filter((attr) => attr.type == "label" && attr.name == "calendar:promotedAttribute") + .map((attr) => attr.value.substring(1)); + let titleExtended = ""; + if (promotedAttrs && promotedAttrs.length) { + const promotedValues = note + .getAttributes() + .filter((attr) => promotedAttrs.includes(attr.name)) + .map((attr) => [attr.name, attr.value]); + for (const defined of promotedValues) titleExtended = titleExtended + ` [#${defined[0]}="${defined[1]}"]`; + } + for (const title of titles) { const eventData: EventInput = { - title: title, + title: title + titleExtended, start: startDate, url: `#${note.noteId}`, noteId: note.noteId, From 249c42e781889f3fc5cc125903fd32be6b85b8a4 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 23 Feb 2025 18:39:34 +0200 Subject: [PATCH 2/4] fix(view/calendar): guard condition breaking recursion --- src/public/app/widgets/view_widgets/calendar_view.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/public/app/widgets/view_widgets/calendar_view.ts b/src/public/app/widgets/view_widgets/calendar_view.ts index fb375d346..d869b4b5d 100644 --- a/src/public/app/widgets/view_widgets/calendar_view.ts +++ b/src/public/app/widgets/view_widgets/calendar_view.ts @@ -280,9 +280,6 @@ export default class CalendarView extends ViewMode { for (const note of notes) { const startDate = note.getLabelValue("startDate"); - if (!startDate) { - continue; - } if (note.hasChildren()) { const childrenEventData = await this.#buildEvents(note.getChildNoteIds()); @@ -291,6 +288,9 @@ export default class CalendarView extends ViewMode { } } + if (!startDate) { + continue; + } const endDate = note.getAttributeValue("label", "endDate"); events.push(await CalendarView.#buildEvent(note, startDate, endDate)); From 07147bf857f5bc87e9be9bf3db2fa79e45365f04 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 23 Feb 2025 19:14:09 +0200 Subject: [PATCH 3/4] fix(view/calendar): add basic support for promoted attributes --- .../app/widgets/view_widgets/calendar_view.ts | 70 +++++++++++++++---- 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/src/public/app/widgets/view_widgets/calendar_view.ts b/src/public/app/widgets/view_widgets/calendar_view.ts index d869b4b5d..0421fe4db 100644 --- a/src/public/app/widgets/view_widgets/calendar_view.ts +++ b/src/public/app/widgets/view_widgets/calendar_view.ts @@ -48,6 +48,11 @@ const TPL = ` .calendar-container .fc-button { padding: 0.2em 0.5em; } + + .calendar-container .promoted-attribute { + font-size: 0.85em; + opacity: 0.85; + }
@@ -119,13 +124,24 @@ export default class CalendarView extends ViewMode { height: "100%", eventContent: (e => { let html = ""; + const { iconClass, promotedAttributes } = e.event.extendedProps; - const iconClass = e.event.extendedProps.iconClass; + // Title and icon if (iconClass) { html += ` `; } - html += utils.escapeHtml(e.event.title); + + // Promoted attributes + if (promotedAttributes) { + for (const [ name, value ] of Object.entries(promotedAttributes)) { + html += `\ + `; + } + } + return { html }; }), dateClick: async (e) => { @@ -306,27 +322,22 @@ export default class CalendarView extends ViewMode { const events: EventInput[] = []; // the user can specify one or multiple attributes to be promoted onto the calendar view by setting `#calendar:promotedAttributes` at the note level // their values will then be rentered into the event title and appear as "[eventIcon] $eventTitle [#promotedAttributeX=valueX] [#promotedAttributeY=valueY]" - const promotedAttrs = note - .getAttributes() - .filter((attr) => attr.type == "label" && attr.name == "calendar:promotedAttribute") - .map((attr) => attr.value.substring(1)); - let titleExtended = ""; - if (promotedAttrs && promotedAttrs.length) { - const promotedValues = note - .getAttributes() - .filter((attr) => promotedAttrs.includes(attr.name)) - .map((attr) => [attr.name, attr.value]); - for (const defined of promotedValues) titleExtended = titleExtended + ` [#${defined[0]}="${defined[1]}"]`; + + const calendarPromotedAttributes = note.getLabelValue("calendar:promotedAttributes"); + let promotedAttributesData = null; + if (calendarPromotedAttributes) { + promotedAttributesData = await this.#buildPromotedAttributes(note, calendarPromotedAttributes); } for (const title of titles) { const eventData: EventInput = { - title: title + titleExtended, + title: title, start: startDate, url: `#${note.noteId}`, noteId: note.noteId, color: color ?? undefined, - iconClass: note.getLabelValue("iconClass") + iconClass: note.getLabelValue("iconClass"), + promotedAttributes: promotedAttributesData }; const endDateOffset = CalendarView.#offsetDate(endDate ?? startDate, 1); @@ -338,6 +349,35 @@ export default class CalendarView extends ViewMode { return events; } + static async #buildPromotedAttributes(note: FNote, calendarPromotedAttributes: string) { + const promotedAttributeNames = calendarPromotedAttributes.split(","); + const filteredPromotedAttributes = note.getPromotedDefinitionAttributes().filter((attr) => promotedAttributeNames.includes(attr.name)); + const result: Record = {}; + + for (const promotedAttribute of filteredPromotedAttributes) { + const [ type, name ] = promotedAttribute.name.split(":", 2); + const definition = promotedAttribute.getDefinition(); + + if (definition.multiplicity !== "single") { + // TODO: Add support for multiple definitions. + continue; + } + + // TODO: Add support for relations + if (type !== "label" || !note.hasLabel(name)) { + continue; + } + + const value = note.getLabelValue(name); + const friendlyName = definition.promotedAlias ?? name; + if (friendlyName && value) { + result[friendlyName] = value; + } + } + + return result; + } + static async #parseCustomTitle(customTitleValue: string | null, note: FNote, allowRelations = true): Promise { if (customTitleValue) { const attributeName = customTitleValue.substring(1); From 95e6919dcf6d0e4ad35f326fa36efeb39ca41855 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 23 Feb 2025 19:15:33 +0200 Subject: [PATCH 4/4] chore(calendar/view): remove unnecessary comment --- src/public/app/widgets/view_widgets/calendar_view.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/public/app/widgets/view_widgets/calendar_view.ts b/src/public/app/widgets/view_widgets/calendar_view.ts index 0421fe4db..e2987728b 100644 --- a/src/public/app/widgets/view_widgets/calendar_view.ts +++ b/src/public/app/widgets/view_widgets/calendar_view.ts @@ -320,8 +320,6 @@ export default class CalendarView extends ViewMode { const titles = await CalendarView.#parseCustomTitle(customTitle, note); const color = note.getLabelValue("calendar:color") ?? note.getLabelValue("color"); const events: EventInput[] = []; - // the user can specify one or multiple attributes to be promoted onto the calendar view by setting `#calendar:promotedAttributes` at the note level - // their values will then be rentered into the event title and appear as "[eventIcon] $eventTitle [#promotedAttributeX=valueX] [#promotedAttributeY=valueY]" const calendarPromotedAttributes = note.getLabelValue("calendar:promotedAttributes"); let promotedAttributesData = null;