Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: refresh calenders on remote changes #6152

Merged
merged 1 commit into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/services/caldavService.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@
return getCalendarHome().findAllCalDAVCollectionsGrouped()
}

/**
* Fetch all calendars in the calendar home from the server
*
* @return {Promise<Calendar[]>}
*/
const findAllCalendars = () => {
return getCalendarHome().findAllCalendars()

Check warning on line 86 in src/services/caldavService.js

View check run for this annotation

Codecov / codecov/patch

src/services/caldavService.js#L86

Added line #L86 was not covered by tests
}

/**
* Fetch all subscriptions in the calendar home from the server
*/
Expand Down Expand Up @@ -252,6 +261,7 @@
initializeClientForUserView,
initializeClientForPublicView,
findAll,
findAllCalendars,
findAllDeletedCalendars,
findPublicCalendarsByTokens,
findSchedulingInbox,
Expand Down
10 changes: 4 additions & 6 deletions src/store/calendarObjects.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,17 +296,15 @@
},

/**
* Adds an array of calendar-objects to the store
* Adds an array of calendar-objects to the store or update them if they already exist
*
* @param {object} data The destructuring object
* @param {object[]} data.calendarObjects Calendar-objects to add
*/
appendCalendarObjectsMutation({ calendarObjects = [] }) {
appendOrUpdateCalendarObjectsMutation({ calendarObjects = [] }) {

Check warning on line 304 in src/store/calendarObjects.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendarObjects.js#L304

Added line #L304 was not covered by tests
for (const calendarObject of calendarObjects) {
if (!this.calendarObjects[calendarObject.id]) {
/// TODO this.calendarObjects[calendarObject.id] = calendarObject
Vue.set(this.calendarObjects, calendarObject.id, calendarObject)
}
/// TODO this.calendarObjects[calendarObject.id] = calendarObject
Vue.set(this.calendarObjects, calendarObject.id, calendarObject)

Check warning on line 307 in src/store/calendarObjects.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendarObjects.js#L307

Added line #L307 was not covered by tests
}
},

Expand Down
36 changes: 34 additions & 2 deletions src/store/calendars.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
calendarsById: {},
initialCalendarsLoaded: false,
editCalendarModal: undefined,
syncTokens: new Map(),
}
},
getters: {
Expand Down Expand Up @@ -209,6 +210,21 @@
})
}
},

/**
* Get the current sync token of a calendar or undefined it the calendar is not present
*
* @param {object} state The pinia state object
* @return {function({id: string}): string | undefined}
*/
getCalendarSyncToken: (state) => (calendar) => {
const existingCalendar = state.calendarsById[calendar.id]

Check warning on line 221 in src/store/calendars.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendars.js#L220-L221

Added lines #L220 - L221 were not covered by tests
if (!existingCalendar) {
return undefined

Check warning on line 223 in src/store/calendars.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendars.js#L223

Added line #L223 was not covered by tests
}

return state.syncTokens.get(calendar.id) ?? existingCalendar.dav.syncToken
},
},
actions: {
/**
Expand Down Expand Up @@ -359,6 +375,7 @@
this.calendars.splice(this.calendars.indexOf(calendar), 1)
/// TODO this.calendarsById.delete(calendar.id)
Vue.delete(this.calendarsById, calendar.id)
this.syncTokens.delete(calendar.id)
},

/**
Expand Down Expand Up @@ -650,7 +667,7 @@
}
}

calendarObjectsStore.appendCalendarObjectsMutation({ calendarObjects })
calendarObjectsStore.appendOrUpdateCalendarObjectsMutation({ calendarObjects })

Check warning on line 670 in src/store/calendars.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendars.js#L670

Added line #L670 was not covered by tests
for (const calendarObjectId of calendarObjectIds) {
if (this.calendarsById[calendar.id].calendarObjects.indexOf(calendarObjectId) === -1) {
this.calendarsById[calendar.id].calendarObjects.push(calendarObjectId)
Expand Down Expand Up @@ -858,7 +875,7 @@
const index = this.calendarsById[calendar.id]?.fetchedTimeRanges.indexOf(fetchedTimeRangeId)

if (index !== -1) {
this.calendarsById[calendar.id].fetchedTimeRanges.slice(index, 1)
this.calendarsById[calendar.id].fetchedTimeRanges.splice(index, 1)

Check warning on line 878 in src/store/calendars.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendars.js#L878

Added line #L878 was not covered by tests
Comment on lines -861 to +878
Copy link
Member Author

@st3iny st3iny Jul 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Evil bug took me 2 hours to debug and locate 🔍

And I was wondering why time ranges are not deleted from the store ...

}
},

Expand Down Expand Up @@ -889,5 +906,20 @@
this.calendarsById[calendar.id].calendarObjects.slice(index, 1)
}
},

/**
* Update the sync token of a given calendar locally
*
* @param {object} data destructuring object
* @param {{id: string}} data.calendar Calendar from the store
* @param {string} data.syncToken New sync token value
*/
updateCalendarSyncToken({ calendar, syncToken }) {

Check warning on line 917 in src/store/calendars.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendars.js#L917

Added line #L917 was not covered by tests
if (!this.getCalendarById(calendar.id)) {
return

Check warning on line 919 in src/store/calendars.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendars.js#L919

Added line #L919 was not covered by tests
}

this.syncTokens.set(calendar.id, syncToken)

Check warning on line 922 in src/store/calendars.js

View check run for this annotation

Codecov / codecov/patch

src/store/calendars.js#L922

Added line #L922 was not covered by tests
},
},
})
11 changes: 3 additions & 8 deletions src/store/fetchedTimeRanges.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,9 @@
* @param {number} data.timeRangeId Id of time-range to remove
*/
removeTimeRange({ timeRangeId }) {
const obj = this.fetchedTimeRangesById[timeRangeId]
const index = this.fetchedTimeRanges.indexOf(obj)

if (index !== -1) {
this.fetchedTimeRanges.splice(index, 1)
/// TODO this.fetchedTimeRangesById.splice(timeRangeId, 1)
Vue.delete(this.fetchedTimeRangesById, timeRangeId)
}
Vue.delete(this.fetchedTimeRangesById, timeRangeId)
this.fetchedTimeRanges = this.fetchedTimeRanges
.filter((timeRange) => timeRange.id !== timeRangeId)

Check warning on line 99 in src/store/fetchedTimeRanges.js

View check run for this annotation

Codecov / codecov/patch

src/store/fetchedTimeRanges.js#L97-L99

Added lines #L97 - L99 were not covered by tests
},

/**
Expand Down
51 changes: 50 additions & 1 deletion src/views/Calendar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@

// Import CalDAV related methods
import {
findAllCalendars,
initializeClientForPublicView,
initializeClientForUserView,
} from '../services/caldavService.js'
Expand All @@ -99,10 +100,12 @@
import AppointmentConfigList from '../components/AppNavigation/AppointmentConfigList.vue'
import useFetchedTimeRangesStore from '../store/fetchedTimeRanges.js'
import useCalendarsStore from '../store/calendars.js'
import useCalendarObjectsStore from '../store/calendarObjects.js'
import usePrincipalsStore from '../store/principals.js'
import useSettingsStore from '../store/settings.js'
import useWidgetStore from '../store/widget.js'
import { mapStores, mapState } from 'pinia'
import { mapDavCollectionToCalendar } from '../models/calendar.js'

export default {
name: 'Calendar',
Expand Down Expand Up @@ -148,12 +151,20 @@
data() {
return {
loadingCalendars: true,
backgroundSyncJob: null,
timeFrameCacheExpiryJob: null,
showEmptyCalendarScreen: false,
}
},
computed: {
...mapStores(useFetchedTimeRangesStore, useCalendarsStore, usePrincipalsStore, useSettingsStore, useWidgetStore),
...mapStores(
useFetchedTimeRangesStore,

Check warning on line 161 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L161

Added line #L161 was not covered by tests
useCalendarsStore,
useCalendarObjectsStore,
usePrincipalsStore,

Check warning on line 164 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L164

Added line #L164 was not covered by tests
useSettingsStore,
useWidgetStore,

Check warning on line 166 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L166

Added line #L166 was not covered by tests
),
...mapState(useSettingsStore, {
timezoneId: 'getResolvedTimezone',
}),
Expand Down Expand Up @@ -208,6 +219,44 @@
},
},
created() {
this.backgroundSyncJob = setInterval(async () => {
const currentUserPrincipal = this.principalsStore.getCurrentUserPrincipal
const calendars = (await findAllCalendars())
.map((calendar) => mapDavCollectionToCalendar(calendar, currentUserPrincipal))
for (const calendar of calendars) {

Check warning on line 226 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L226

Added line #L226 was not covered by tests
const existingSyncToken = this.calendarsStore.getCalendarSyncToken(calendar)
if (!existingSyncToken && !this.calendarsStore.getCalendarById(calendar.id)) {
// New calendar!
logger.debug(`Adding new calendar ${calendar.url}`)
this.calendarsStore.addCalendarMutation({ calendar })
continue
}

if (calendar.dav.syncToken === existingSyncToken) {
continue

Check warning on line 236 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L236

Added line #L236 was not covered by tests
}

Check warning on line 238 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L238

Added line #L238 was not covered by tests
logger.debug(`Refetching calendar ${calendar.url} (syncToken changed)`)
const fetchedTimeRanges = this.fetchedTimeRangesStore
.getAllTimeRangesForCalendar(calendar.id)

Check warning on line 241 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L241

Added line #L241 was not covered by tests
for (const timeRange of fetchedTimeRanges) {
this.fetchedTimeRangesStore.removeTimeRange({

Check warning on line 243 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L243

Added line #L243 was not covered by tests
timeRangeId: timeRange.id,
})
this.calendarsStore.deleteFetchedTimeRangeFromCalendarMutation({
calendar,

Check warning on line 247 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L245-L247

Added lines #L245 - L247 were not covered by tests
fetchedTimeRangeId: timeRange.id,
})
}

this.calendarsStore.updateCalendarSyncToken({

Check warning on line 252 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L251-L252

Added lines #L251 - L252 were not covered by tests
calendar,
syncToken: calendar.dav.syncToken,
})
this.calendarObjectsStore.modificationCount++
}

Check warning on line 257 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L256-L257

Added lines #L256 - L257 were not covered by tests
}, 1000 * 30)

Check warning on line 259 in src/views/Calendar.vue

View check run for this annotation

Codecov / codecov/patch

src/views/Calendar.vue#L259

Added line #L259 was not covered by tests
this.timeFrameCacheExpiryJob = setInterval(() => {
const timestamp = (getUnixTimestampFromDate(dateFactory()) - 60 * 10)
const timeRanges = this.fetchedTimeRangesStore.getAllTimeRangesOlderThan(timestamp)
Expand Down
Loading