From 44b9a36eea9e4e77dee04883b561804b9ca66016 Mon Sep 17 00:00:00 2001 From: Daniel Kesselberg Date: Tue, 20 Aug 2024 13:27:15 +0200 Subject: [PATCH 1/2] fix: fetch attendance status when calendars are loaded One may have imported an event, but the attendance status is not properly fetched when rendering the email. The reason is a timing / state problem. - Loading the user principal and collections is initialized in https://github.com/nextcloud/mail/blob/6fc45eb0630b9065f9ccb4c1da5cc9557f7df834/src/App.vue#L49-L50. - If the backend request for the message body is faster, than loading the principal and collections, then Imip.fetchExistingEvent runs without having calendars and changes existingEventFetched to true that prevents the method from running again. - Solution: Render the imip component when principal and collections are fetched. Signed-off-by: Daniel Kesselberg --- src/App.vue | 1 + src/components/Imip.vue | 6 ------ src/components/Message.vue | 5 ++++- src/store/getters.js | 1 + src/store/index.js | 1 + src/store/mutations.js | 3 +++ 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/App.vue b/src/App.vue index bb39fd4022..99644e408b 100644 --- a/src/App.vue +++ b/src/App.vue @@ -48,6 +48,7 @@ export default { this.sync() await this.$store.dispatch('fetchCurrentUserPrincipal') await this.$store.dispatch('loadCollections') + this.$store.commit('hasCurrentUserPrincipalAndCollections', true) }, methods: { reload() { diff --git a/src/components/Imip.vue b/src/components/Imip.vue index 58ef9b677c..ae0366f1bb 100644 --- a/src/components/Imip.vue +++ b/src/components/Imip.vue @@ -374,12 +374,6 @@ export default { await this.fetchExistingEvent(this.attachedVEvent.uid) }, }, - clonedCalendars: { - immediate: true, - async handler() { - await this.fetchExistingEvent(this.attachedVEvent.uid) - }, - }, calendarsForPicker: { immediate: true, handler(calendarsForPicker) { diff --git a/src/components/Message.vue b/src/components/Message.vue index 8067039eed..4e6c8498c3 100644 --- a/src/components/Message.vue +++ b/src/components/Message.vue @@ -20,7 +20,7 @@
-
+
@@ -130,6 +130,9 @@ export default { itineraries() { return this.message.itineraries ?? [] }, + hasCurrentUserPrincipalAndCollections() { + return this.$store.getters.hasCurrentUserPrincipalAndCollections + }, }, methods: { onReply(replyBody = '') { diff --git a/src/store/getters.js b/src/store/getters.js index 312234849b..9e694680ef 100644 --- a/src/store/getters.js +++ b/src/store/getters.js @@ -156,4 +156,5 @@ export const getters = { hasFetchedInitialEnvelopes: (state) => state.hasFetchedInitialEnvelopes, isFollowUpFeatureAvailable: (state) => state.followUpFeatureAvailable, getInternalAddresses: (state) => state.internalAddress?.filter(internalAddress => internalAddress !== undefined), + hasCurrentUserPrincipalAndCollections: (state) => state.hasCurrentUserPrincipalAndCollections, } diff --git a/src/store/index.js b/src/store/index.js index 9176d52e73..98ddc42ad1 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -107,6 +107,7 @@ export default new Store({ hasFetchedInitialEnvelopes: false, followUpFeatureAvailable: false, internalAddress: [], + hasCurrentUserPrincipalAndCollections: false, }, getters, mutations, diff --git a/src/store/mutations.js b/src/store/mutations.js index bc4b86642a..a5cb937757 100644 --- a/src/store/mutations.js +++ b/src/store/mutations.js @@ -513,4 +513,7 @@ export default { setFollowUpFeatureAvailable(state, followUpFeatureAvailable) { state.followUpFeatureAvailable = followUpFeatureAvailable }, + hasCurrentUserPrincipalAndCollections(state, hasCurrentUserPrincipalAndCollections) { + state.hasCurrentUserPrincipalAndCollections = hasCurrentUserPrincipalAndCollections + }, } From 42965856b0761038f699ea7e3092498336a7e439 Mon Sep 17 00:00:00 2001 From: Daniel Kesselberg Date: Tue, 20 Aug 2024 13:46:20 +0200 Subject: [PATCH 2/2] perf: skip non-writable calendars Accepting a calendar invitation should always go to a writable calendar, and therefore we can skip the check if the event exists in a read-only calendar. Signed-off-by: Daniel Kesselberg --- src/components/Imip.vue | 6 +++--- src/store/getters.js | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/Imip.vue b/src/components/Imip.vue index ae0366f1bb..2a8008c1fd 100644 --- a/src/components/Imip.vue +++ b/src/components/Imip.vue @@ -191,7 +191,7 @@ export default { computed: { ...mapGetters({ currentUserPrincipalEmail: 'getCurrentUserPrincipalEmail', - clonedCalendars: 'getClonedCalendars', + clonedWriteableCalendars: 'getClonedWriteableCalendars', }), /** @@ -362,7 +362,7 @@ export default { } } - return this.clonedCalendars + return this.clonedWriteableCalendars .map(getCalendarData) .filter(props => props.components.vevent && props.writable === true) }, @@ -470,7 +470,7 @@ export default { // TODO: can this query be reduced to a single request? const limit = pLimit(5) - const promises = this.clonedCalendars.map(async (calendar) => { + const promises = this.clonedWriteableCalendars.map(async (calendar) => { // Query adapted from https://datatracker.ietf.org/doc/html/rfc4791#section-7.8.6 return limit(() => calendar.calendarQuery([{ name: [NS.IETF_CALDAV, 'comp-filter'], diff --git a/src/store/getters.js b/src/store/getters.js index 9e694680ef..d19e116ac9 100644 --- a/src/store/getters.js +++ b/src/store/getters.js @@ -120,7 +120,9 @@ export const getters = { getCurrentUserPrincipal: (state) => state.currentUserPrincipal, getCurrentUserPrincipalEmail: (state) => state.currentUserPrincipal?.email, getCalendars: (state) => state.calendars, - getClonedCalendars: (state) => state.calendars.map(calendar => { + getClonedWriteableCalendars: (state) => state.calendars.filter(calendar => { + return calendar.isWriteable() + }).map(calendar => { // Hack: We need to clone all calendars because some methods (e.g. calendarQuery) are // unnecessarily mutating the object and causing vue warnings (if used outside of // mutations).