From 1f61ff6ccaf783313e8a98836be391bdba59b577 Mon Sep 17 00:00:00 2001 From: nathan Date: Thu, 23 Mar 2023 13:08:52 -0600 Subject: [PATCH] Calendar: Fix events from group invitations did not always show up when viewing calendar of a group member Fixed by pre-fetching the group members before trying to display events so they're there when we check --- calendar/js/app.ts | 56 +++++++++++++++++++++++++ calendar/js/et2_widget_daycol.ts | 70 +++++++++++++++++++------------- 2 files changed, 98 insertions(+), 28 deletions(-) diff --git a/calendar/js/app.ts b/calendar/js/app.ts index 5a2e9a474e..f3c5190aae 100644 --- a/calendar/js/app.ts +++ b/calendar/js/app.ts @@ -57,6 +57,8 @@ import {tapAndSwipe} from "../../api/js/tapandswipe"; import {CalendarOwner} from "./CalendarOwner"; import {et2_IInput} from "../../api/js/etemplate/et2_core_interfaces"; import {Et2DateTime} from "../../api/js/etemplate/Et2Date/Et2DateTime"; +import {Et2Select} from "../../api/js/etemplate/Et2Select/Et2Select"; +import type {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions"; /** * UI for calendar @@ -3743,6 +3745,60 @@ export class CalendarApp extends EgwApp ); } + /** + * Pre-fetch the members of any group participants + * + * This is done to avoid rewriting since group fetching is async. We fetch missing group members in advance, + * then hold the data in the sidebox select options for immediate access when checking if an event should be displayed + * in a particular calendar. + * + * @param event + * @return Promise + */ + async _fetch_group_members(event) : Promise + { + let groups = []; + let option_owner = null; + let options : SelectOption[]; + if(app.calendar && app.calendar.sidebox_et2 && app.calendar.sidebox_et2.getWidgetById('owner')) + { + option_owner = app.calendar.sidebox_et2.getWidgetById('owner'); + } + else + { + option_owner = parent.getArrayMgr("sel_options").getRoot().getEntry('owner'); + } + + options = option_owner.select_options; + + for(const id of Object.keys(event.participants)) + { + if(parseInt(id) >= 0) + { + continue; + } + let resource = options.find((o) => o.value === id); + if(!resource || resource && !resource.resources) + { + groups.push(parseInt(id)); + } + } + + // Find missing groups + if(groups.length) + { + return this.egw.request("calendar.calendar_owner_etemplate_widget.ajax_owner", [groups]).then((data) => + { + options = options.concat(Object.values(data)); + option_owner.select_options = options; + }); + } + else + { + return Promise.resolve(); + } + } + /** * We have a list of calendar UIDs of events that need updating. * Public wrapper for _update_events so we can call it from server diff --git a/calendar/js/et2_widget_daycol.ts b/calendar/js/et2_widget_daycol.ts index 1233088640..3e5eb26942 100644 --- a/calendar/js/et2_widget_daycol.ts +++ b/calendar/js/et2_widget_daycol.ts @@ -370,39 +370,53 @@ export class et2_calendar_daycol extends et2_valueWidget implements et2_IDetache _data_callback( event_ids) { const events = []; - if(event_ids == null || typeof event_ids.length == 'undefined') event_ids = []; - for(let i = 0; i < event_ids.length; i++) + const waitForGroups = []; + if(event_ids == null || typeof event_ids.length == 'undefined') { - let event : any = egw.dataGetUIDdata('calendar::'+event_ids[i]); - event = event && event.data || false; - if(event && event.date && et2_calendar_event.owner_check(event, this) && ( - event.date === this.options.date || - // Accept multi-day events - new Date(event.start) <= this.date //&& new Date(event.end) >= this.date - )) - { - events.push(event); - } - else if (event) - { - // Got an ID that doesn't belong - event_ids.splice(i--,1); - } + event_ids = []; } - if(!this.div.is(":visible")) + for(let i = 0; i < event_ids.length; i++) { - // Not visible, defer the layout or it all winds up at the top - // Cancel any existing listener & bind - jQuery(this.getInstanceManager().DOMContainer.parentNode) - .off('show.'+CalendarApp._daywise_cache_id(this.options.date, this.options.owner)) - .one('show.'+CalendarApp._daywise_cache_id(this.options.date, this.options.owner), function() { - this._update_events(events) - }.bind(this)); - return; + let event : any = egw.dataGetUIDdata('calendar::' + event_ids[i]); + event = event && event.data || false; + waitForGroups.push((app.calendar)._fetch_group_members(event).then(() => + { + if(event && event.date && et2_calendar_event.owner_check(event, this) && ( + event.date === this.options.date || + // Accept multi-day events + new Date(event.start) <= this.date //&& new Date(event.end) >= this.date + )) + { + events.push(event); + } + else if(event) + { + // Got an ID that doesn't belong + event_ids.splice(i--, 1); + } + })); } - if(!this.getParent().disabled) - this._update_events(events); + + Promise.all(waitForGroups).then(() => + { + if(!this.div.is(":visible")) + { + // Not visible, defer the layout or it all winds up at the top + // Cancel any existing listener & bind + jQuery(this.getInstanceManager().DOMContainer.parentNode) + .off('show.' + CalendarApp._daywise_cache_id(this.options.date, this.options.owner)) + .one('show.' + CalendarApp._daywise_cache_id(this.options.date, this.options.owner), function() + { + this._update_events(events) + }.bind(this)); + return; + } + if(!this.getParent().disabled) + { + this._update_events(events); + } + }); } set_label( label)