From b1d6c90dc5ab5b5b664cb98896745ab83d64c6b9 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 b87f235a26..898c83f94b 100644 --- a/src/App.vue +++ b/src/App.vue @@ -66,6 +66,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 34e77bfe1e..bcd10d227c 100644 --- a/src/components/Imip.vue +++ b/src/components/Imip.vue @@ -391,12 +391,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 8ba28f9b95..bbc55e024d 100644 --- a/src/components/Message.vue +++ b/src/components/Message.vue @@ -36,7 +36,7 @@
-
+
@@ -144,6 +144,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 226d17b59a..659fe0db9c 100644 --- a/src/store/getters.js +++ b/src/store/getters.js @@ -157,4 +157,5 @@ export const getters = { }, isOneLineLayout: (state) => state.list, hasFetchedInitialEnvelopes: (state) => state.hasFetchedInitialEnvelopes, + hasCurrentUserPrincipalAndCollections: (state) => state.hasCurrentUserPrincipalAndCollections, } diff --git a/src/store/index.js b/src/store/index.js index 5deb66f57a..b8b4c9fd7c 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -108,6 +108,7 @@ export default new Store({ calendars: [], smimeCertificates: [], hasFetchedInitialEnvelopes: false, + hasCurrentUserPrincipalAndCollections: false, }, getters, mutations, diff --git a/src/store/mutations.js b/src/store/mutations.js index 44a723b3b8..293d5bceca 100644 --- a/src/store/mutations.js +++ b/src/store/mutations.js @@ -512,4 +512,7 @@ export default { setHasFetchedInitialEnvelopes(state, hasFetchedInitialEnvelopes) { state.hasFetchedInitialEnvelopes = hasFetchedInitialEnvelopes }, + hasCurrentUserPrincipalAndCollections(state, hasCurrentUserPrincipalAndCollections) { + state.hasCurrentUserPrincipalAndCollections = hasCurrentUserPrincipalAndCollections + }, } From d5f6a1ee5b130da581db206aa38e784d4ff36c0b 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 bcd10d227c..518f32f4bf 100644 --- a/src/components/Imip.vue +++ b/src/components/Imip.vue @@ -208,7 +208,7 @@ export default { computed: { ...mapGetters({ currentUserPrincipalEmail: 'getCurrentUserPrincipalEmail', - clonedCalendars: 'getClonedCalendars', + clonedWriteableCalendars: 'getClonedWriteableCalendars', }), /** @@ -379,7 +379,7 @@ export default { } } - return this.clonedCalendars + return this.clonedWriteableCalendars .map(getCalendarData) .filter(props => props.components.vevent && props.writable === true) }, @@ -487,7 +487,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 659fe0db9c..431ca6d6ee 100644 --- a/src/store/getters.js +++ b/src/store/getters.js @@ -123,7 +123,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).