diff --git a/package-lock.json b/package-lock.json
index d2e243efbc..0d24989e53 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5930,11 +5930,18 @@
"dev": true
},
"cdav-library": {
- "version": "git+https://github.com/nextcloud/cdav-library.git#c4f7d8225c2c8cfa5a3d269b3d986698d257dd5d",
+ "version": "git+https://github.com/nextcloud/cdav-library.git#7fdc09ccc4917635c5189a878be9a899ee81f799",
"from": "git+https://github.com/nextcloud/cdav-library.git",
"requires": {
- "core-js": "^3.12.1",
+ "core-js": "^3.13.0",
"regenerator-runtime": "^0.13.7"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.13.1.tgz",
+ "integrity": "sha512-JqveUc4igkqwStL2RTRn/EPFGBOfEZHxJl/8ej1mXJR75V3go2mFF4bmUYkEIT1rveHKnkUlcJX/c+f1TyIovQ=="
+ }
}
},
"chalk": {
diff --git a/src/components/AppNavigation/AppNavigationHeader/AppNavigationHeaderDatePicker.vue b/src/components/AppNavigation/AppNavigationHeader/AppNavigationHeaderDatePicker.vue
index eeaff526e6..44f0f02fb5 100644
--- a/src/components/AppNavigation/AppNavigationHeader/AppNavigationHeaderDatePicker.vue
+++ b/src/components/AppNavigation/AppNavigationHeader/AppNavigationHeaderDatePicker.vue
@@ -83,7 +83,7 @@ export default {
locale: (state) => state.settings.momentLocale,
}),
selectedDate() {
- return getDateFromFirstdayParam(this.$route.params.firstDay)
+ return getDateFromFirstdayParam(this.$route.params?.firstDay ?? 'now')
},
previousShortKeyConf() {
return {
diff --git a/src/components/AppNavigation/CalendarList/Moment.vue b/src/components/AppNavigation/CalendarList/Moment.vue
new file mode 100644
index 0000000000..960edf8ebb
--- /dev/null
+++ b/src/components/AppNavigation/CalendarList/Moment.vue
@@ -0,0 +1,29 @@
+
+ {{ formatted }}
+
+
+
diff --git a/src/components/AppNavigation/CalendarList/Trashbin.vue b/src/components/AppNavigation/CalendarList/Trashbin.vue
new file mode 100644
index 0000000000..7e052867cd
--- /dev/null
+++ b/src/components/AppNavigation/CalendarList/Trashbin.vue
@@ -0,0 +1,180 @@
+
+
+
+
+
+
+
+
{{ t('calendar', 'Trashbin') }}
+
{{ t('calendar', 'You do not have any deleted calendars or events') }}
+
+
+ | {{ t('calendar', 'Name') }} |
+
+ {{ t('calendar', 'Deleted at') }}
+ |
+ |
+
+
+ | {{ item.name }} |
+
+
+ |
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/services/caldavService.js b/src/services/caldavService.js
index df271ff5c1..f1f445a53c 100644
--- a/src/services/caldavService.js
+++ b/src/services/caldavService.js
@@ -75,10 +75,30 @@ const initializeClientForPublicView = async() => {
/**
* Fetch all calendars from the server
*
+ * @returns {Promise}
+ */
+const getCalendarHome = () => getClient().calendarHomes[0]
+
+/**
+ * Fetch all collections in the calendar home from the server
+ *
+ * @returns {Promise}
+ */
+const findAll = () => {
+ return getCalendarHome().findAllCalDAVCollectionsGrouped()
+}
+
+/**
+ * Fetch all deleted calendars from the server
+ *
* @returns {Promise}
*/
-const findAllCalendars = () => {
- return getClient().calendarHomes[0].findAllCalendars()
+const findAllDeletedCalendars = async() => {
+ const collections = await getClient()
+ .calendarHomes[0]
+ .findAll()
+ return collections
+ .filter(coll => coll._props['{DAV:}resourcetype'].includes('{http://nextcloud.com/ns}deleted-calendar'))
}
/**
@@ -116,7 +136,7 @@ const findPublicCalendarsByTokens = async(tokens) => {
* @returns {Promise}
*/
const findSchedulingInbox = async() => {
- const inboxes = await getClient().calendarHomes[0].findAllScheduleInboxes()
+ const inboxes = await getCalendarHome().findAllScheduleInboxes()
return inboxes[0]
}
@@ -134,7 +154,7 @@ const findSchedulingInbox = async() => {
* @returns {Promise}
*/
const findSchedulingOutbox = async() => {
- const outboxes = await getClient().calendarHomes[0].findAllScheduleOutboxes()
+ const outboxes = await getCalendarHome().findAllScheduleOutboxes()
return outboxes[0]
}
@@ -149,7 +169,7 @@ const findSchedulingOutbox = async() => {
* @returns {Promise}
*/
const createCalendar = async(displayName, color, components, order, timezoneIcs) => {
- return getClient().calendarHomes[0].createCalendarCollection(displayName, color, components, order, timezoneIcs)
+ return getCalendarHome().createCalendarCollection(displayName, color, components, order, timezoneIcs)
}
/**
@@ -164,7 +184,7 @@ const createCalendar = async(displayName, color, components, order, timezoneIcs)
* @returns {Promise}
*/
const createSubscription = async(displayName, color, source, order) => {
- return getClient().calendarHomes[0].createSubscribedCollection(displayName, color, source, order)
+ return getCalendarHome().createSubscribedCollection(displayName, color, source, order)
}
/**
@@ -173,7 +193,7 @@ const createSubscription = async(displayName, color, source, order) => {
* @returns {Promise}
*/
const enableBirthdayCalendar = async() => {
- await getClient().calendarHomes[0].enableBirthdayCalendar()
+ await getCalendarHome().enableBirthdayCalendar()
return getBirthdayCalendar()
}
@@ -183,7 +203,7 @@ const enableBirthdayCalendar = async() => {
* @returns {Promise}
*/
const getBirthdayCalendar = async() => {
- return getClient().calendarHomes[0].find(CALDAV_BIRTHDAY_CALENDAR)
+ return getCalendarHome().find(CALDAV_BIRTHDAY_CALENDAR)
}
/**
@@ -218,7 +238,8 @@ const findPrincipalByUrl = async(url) => {
export {
initializeClientForUserView,
initializeClientForPublicView,
- findAllCalendars,
+ findAll,
+ findAllDeletedCalendars,
findPublicCalendarsByTokens,
findSchedulingInbox,
findSchedulingOutbox,
diff --git a/src/services/windowTitleService.js b/src/services/windowTitleService.js
index 435d598b79..8b61935573 100644
--- a/src/services/windowTitleService.js
+++ b/src/services/windowTitleService.js
@@ -74,6 +74,9 @@ export default function(router, store) {
if (mutation.type !== 'setMomentLocale') {
return
}
+ if (!router.currentRoute.params?.firstDay) {
+ return
+ }
const date = getDateFromFirstdayParam(router.currentRoute.params.firstDay)
const view = router.currentRoute.params.view
diff --git a/src/store/calendars.js b/src/store/calendars.js
index ebbf7bd405..cc5b449145 100644
--- a/src/store/calendars.js
+++ b/src/store/calendars.js
@@ -27,7 +27,8 @@ import Vue from 'vue'
import {
createCalendar,
createSubscription,
- findAllCalendars,
+ findAll,
+ findAllDeletedCalendars,
findPublicCalendarsByTokens,
} from '../services/caldavService.js'
import { mapCDavObjectToCalendarObject } from '../models/calendarObject'
@@ -47,6 +48,9 @@ import {
const state = {
calendars: [],
+ trashBin: undefined,
+ deletedCalendars: [],
+ deletedCalendarObjects: [],
calendarsById: {},
initialCalendarsLoaded: false,
}
@@ -63,10 +67,68 @@ const mutations = {
addCalendar(state, { calendar }) {
const object = getDefaultCalendarObject(calendar)
- state.calendars.push(object)
+ if (!state.calendars.some(existing => existing.id === object.id)) {
+ state.calendars.push(object)
+ }
Vue.set(state.calendarsById, object.id, object)
},
+ addTrashBin(state, { trashBin }) {
+ state.trashBin = trashBin
+ },
+
+ /**
+ * Adds deleted calendar into state
+ *
+ * @param {Object} state the store data
+ * @param {Object} data destructuring object
+ * @param {Object} data.calendar calendar the calendar to add
+ */
+ addDeletedCalendar(state, { calendar }) {
+ if (state.deletedCalendars.some(c => c.url === calendar.url)) {
+ // This calendar is already known
+ return
+ }
+ state.deletedCalendars.push(calendar)
+ },
+
+ /**
+ * Removes a deleted calendar
+ *
+ * @param {Object} state the store data
+ * @param {Object} data destructuring object
+ * @param {Object} data.calendar the deleted calendar to remove
+ */
+ removeDeletedCalendar(state, { calendar }) {
+ state.deletedCalendars = state.deletedCalendars.filter(c => c !== calendar)
+ },
+
+ /**
+ * Removes a deleted calendar object
+ *
+ * @param {Object} state the store data
+ * @param {Object} data destructuring object
+ * @param {Object} data.vobject the deleted calendar object to remove
+ */
+ removeDeletedCalendarObject(state, { vobject }) {
+ state.deletedCalendarObjects = state.deletedCalendarObjects.filter(vo => vo.id !== vobject.id)
+ },
+
+ /**
+ * Adds a deleted vobject into state
+ *
+ * @param {Object} state the store data
+ * @param {Object} data destructuring object
+ * @param {Object} data.vobject the calendar vobject to add
+ */
+ addDeletedCalendarObject(state, { vobject }) {
+ if (state.deletedCalendarObjects.some(c => c.uri === vobject.uri)) {
+ // This vobject is already known
+ return
+ }
+ state.deletedCalendarObjects.push(vobject)
+ },
+
/**
* Deletes a calendar
*
@@ -338,6 +400,45 @@ const getters = {
.sort((a, b) => a.order - b.order)
},
+ hasTrashBin(state) {
+ return state.trashBin !== undefined
+ },
+
+ trashBin(state) {
+ return state.trashBin
+ },
+
+ /**
+ * List of deleted sorted calendars
+ *
+ * @param {Object} state the store data
+ * @returns {Array}
+ */
+ sortedDeletedCalendars(state) {
+ return state.deletedCalendars
+ .sort((a, b) => a.deletedAt - b.deletedAt)
+ },
+
+ /**
+ * List of deleted calendars objects
+ *
+ * @param {Object} state the store data
+ * @returns {Array}
+ */
+ deletedCalendarObjects(state) {
+ const calendarUriMap = {}
+ state.calendars.forEach(calendar => {
+ const withoutTrail = calendar.url.replace(/\/$/, '')
+ const uri = withoutTrail.substr(withoutTrail.lastIndexOf('/') + 1)
+ calendarUriMap[uri] = calendar
+ })
+
+ return state.deletedCalendarObjects.map(obj => ({
+ calendar: calendarUriMap[obj.dav._props['{http://nextcloud.com/ns}calendar-uri']],
+ ...obj,
+ }))
+ },
+
/**
* List of sorted subscriptions
*
@@ -432,19 +533,55 @@ const getters = {
const actions = {
/**
- * Retrieve and commit calendars
+ * Retrieve and commit calendars and other collections
*
* @param {Object} context the store mutations
- * @returns {Promise} the calendars
+ * @returns {Promise