(
onEventHover(item.event.id)}
+ onMouseEnter={() => onEventHover(calendarEventInstanceId(item.event))}
onMouseLeave={() => onEventHover("")}
onDragStart={
canWrite
@@ -546,7 +547,7 @@ function TimedDayColumn({
type="button"
className="calendar-timed-event-content"
onClick={() => onEventSelect(item.event)}
- onFocus={() => onEventHover(item.event.id)}
+ onFocus={() => onEventHover(calendarEventInstanceId(item.event))}
onBlur={() => onEventHover("")}
title={i18nMessage(
"i18n:govoplan-calendar.edit_value.fad75899",
@@ -629,9 +630,9 @@ function CalendarEventChip({
style={calendarEventColorStyle(color)}
draggable={canDrag}
onClick={() => onSelect(event)}
- onMouseEnter={onHover ? () => onHover(event.id) : undefined}
+ onMouseEnter={onHover ? () => onHover(calendarEventInstanceId(event)) : undefined}
onMouseLeave={onHover ? () => onHover("") : undefined}
- onFocus={onHover ? () => onHover(event.id) : undefined}
+ onFocus={onHover ? () => onHover(calendarEventInstanceId(event)) : undefined}
onBlur={onHover ? () => onHover("") : undefined}
onDragStart={
canDrag && onDragStart
diff --git a/webui/src/features/calendar/UpcomingEventsWidget.tsx b/webui/src/features/calendar/UpcomingEventsWidget.tsx
index a4d8a93..8d3dd59 100644
--- a/webui/src/features/calendar/UpcomingEventsWidget.tsx
+++ b/webui/src/features/calendar/UpcomingEventsWidget.tsx
@@ -32,10 +32,11 @@ export default function UpcomingEventsWidget({
end.setDate(end.getDate() + daysAhead);
const response = await listCalendarEvents(settings, {
start_at: start.toISOString(),
- end_at: end.toISOString()
+ end_at: end.toISOString(),
+ expand_recurring: true
});
return [...response.events]
- .filter((event) => event.status !== "cancelled")
+ .filter((event) => event.status.toUpperCase() !== "CANCELLED")
.sort(
(left, right) =>
new Date(left.start_at).getTime() - new Date(right.start_at).getTime()
@@ -57,7 +58,7 @@ export default function UpcomingEventsWidget({
({
- id: event.id,
+ id: event.instance_id || event.id,
title: event.summary,
detail:
showLocation && event.location ? (
diff --git a/webui/src/features/calendar/calendarViewModel.ts b/webui/src/features/calendar/calendarViewModel.ts
index 3af71c8..5780095 100644
--- a/webui/src/features/calendar/calendarViewModel.ts
+++ b/webui/src/features/calendar/calendarViewModel.ts
@@ -74,7 +74,7 @@ const MAX_TIMED_EVENT_COLUMNS = 3;
const CALENDAR_MODE_STORAGE_KEY = "govoplan.calendar.mode";
const CALENDAR_VIEW_PREFERENCES_STORAGE_KEY =
"govoplan.calendar.viewPreferences";
-const DEFAULT_CALENDAR_VIEW_PREFERENCES: CalendarViewPreferences = {
+export const DEFAULT_CALENDAR_VIEW_PREFERENCES: CalendarViewPreferences = {
dimWeekends: true,
dimOffHours: true,
workdayStartHour: 6,
@@ -84,6 +84,10 @@ const DEFAULT_CALENDAR_VIEW_PREFERENCES: CalendarViewPreferences = {
alternateContinuousMonths: true,
};
+export function calendarEventInstanceId(event: CalendarEvent): string {
+ return event.instance_id || event.id;
+}
+
export function rangeForMode(
mode: CalendarMode,
focusDate: Date,
@@ -677,7 +681,7 @@ export function layoutTimedEventsForDay(
}
if (hidden.length > 0) {
overflows.push({
- key: `${dayKey(day)}-${hidden[0].event.id}-overflow`,
+ key: `${dayKey(day)}-${calendarEventInstanceId(hidden[0].event)}-overflow`,
top: Math.min(...hidden.map((item) => item.top)),
column: overflowColumn,
columns: MAX_TIMED_EVENT_COLUMNS,
diff --git a/webui/src/module.ts b/webui/src/module.ts
index 02f8040..e82d6ac 100644
--- a/webui/src/module.ts
+++ b/webui/src/module.ts
@@ -2,7 +2,8 @@ import { createElement, lazy } from "react";
import type {
CalendarPickerUiCapability,
DashboardWidgetsUiCapability,
- PlatformWebModule
+ PlatformWebModule,
+ SettingsSectionsUiCapability
} from "@govoplan/core-webui";
import "./styles/calendar.css";
import { generatedTranslations } from "./i18n/generatedTranslations";
@@ -10,6 +11,9 @@ import CalendarPicker from "./features/calendar/CalendarPicker";
import UpcomingEventsWidget from "./features/calendar/UpcomingEventsWidget";
const CalendarPage = lazy(() => import("./features/calendar/CalendarPage"));
+const CalendarSettingsPanel = lazy(
+ () => import("./features/calendar/CalendarSettingsPanel")
+);
const eventRead = ["calendar:event:read"];
const translations = {
@@ -18,6 +22,20 @@ const translations = {
};
const calendarPicker: CalendarPickerUiCapability = { CalendarPicker };
+const calendarSettingsSections: SettingsSectionsUiCapability = {
+ sections: [
+ {
+ id: "calendar",
+ surfaceId: "calendar.settings.preferences",
+ label: "Calendar",
+ group: "ui",
+ order: 45,
+ anyOf: eventRead,
+ render: ({ settings, auth }) =>
+ createElement(CalendarSettingsPanel, { settings, auth })
+ }
+ ]
+};
const calendarDashboardWidgets: DashboardWidgetsUiCapability = {
widgets: [
{
@@ -87,6 +105,13 @@ export const calendarModule: PlatformWebModule = {
kind: "section",
label: "Upcoming events widget",
order: 40
+ },
+ {
+ id: "calendar.settings.preferences",
+ moduleId: "calendar",
+ kind: "section",
+ label: "Calendar preferences",
+ order: 45
}
],
navItems: [{ to: "/calendar", label: "i18n:govoplan-calendar.calendar.adab5090", iconName: "calendar", anyOf: eventRead, order: 55 }],
@@ -94,7 +119,8 @@ export const calendarModule: PlatformWebModule = {
{ path: "/calendar", anyOf: eventRead, order: 55, render: ({ settings, auth }) => createElement(CalendarPage, { settings, auth }) }],
uiCapabilities: {
"calendar.picker": calendarPicker,
- "dashboard.widgets": calendarDashboardWidgets
+ "dashboard.widgets": calendarDashboardWidgets,
+ "settings.sections": calendarSettingsSections
}
};
diff --git a/webui/tsconfig.calendar-page-tests.json b/webui/tsconfig.calendar-page-tests.json
index 7f2088d..466a469 100644
--- a/webui/tsconfig.calendar-page-tests.json
+++ b/webui/tsconfig.calendar-page-tests.json
@@ -23,13 +23,19 @@
],
"react/jsx-runtime": [
"../../govoplan-core/webui/node_modules/@types/react/jsx-runtime.d.ts"
+ ],
+ "react-router": [
+ "../../govoplan-core/webui/node_modules/react-router/dist/development/index.d.ts"
]
}
},
"include": [
"../../govoplan-core/webui/src/vite-env.d.ts",
+ "src/module.ts",
"src/api/calendar.ts",
"src/features/calendar/CalendarPage.tsx",
+ "src/features/calendar/CalendarSettingsPanel.tsx",
+ "src/features/calendar/UpcomingEventsWidget.tsx",
"src/features/calendar/CalendarViews.tsx",
"src/features/calendar/CalendarCollectionDialogs.tsx",
"src/features/calendar/CalendarEventDialog.tsx",