diff --git a/css/app-settings.scss b/css/app-settings.scss
index bec64f9129..905d8efcdf 100644
--- a/css/app-settings.scss
+++ b/css/app-settings.scss
@@ -55,7 +55,8 @@
}
&--slotDuration,
- &--timezone {
+ &--timezone,
+ &--default-calendar {
width: 100%;
.multiselect {
diff --git a/lib/Controller/PublicViewController.php b/lib/Controller/PublicViewController.php
index 2ace63956e..31bf3fba72 100644
--- a/lib/Controller/PublicViewController.php
+++ b/lib/Controller/PublicViewController.php
@@ -120,6 +120,7 @@ private function publicIndex(string $token,
$defaultSkipPopover = $this->config->getAppValue($this->appName, 'skipPopover', 'yes');
$defaultTimezone = $this->config->getAppValue($this->appName, 'timezone', 'automatic');
$defaultSlotDuration = $this->config->getAppValue($this->appName, 'slotDuration', '00:30:00');
+ $defaultCalendarId = $this->config->getAppValue($this->appName, 'defaultCalendarId', 'none');
$defaultShowTasks = $this->config->getAppValue($this->appName, 'showTasks', 'yes');
$appVersion = $this->config->getAppValue($this->appName, 'installed_version');
@@ -134,6 +135,7 @@ private function publicIndex(string $token,
$this->initialStateService->provideInitialState($this->appName, 'talk_enabled', false);
$this->initialStateService->provideInitialState($this->appName, 'timezone', $defaultTimezone);
$this->initialStateService->provideInitialState($this->appName, 'slot_duration', $defaultSlotDuration);
+ $this->initialStateService->provideInitialState($this->appName, 'default_calendar_id', $defaultCalendarId);
$this->initialStateService->provideInitialState($this->appName, 'show_tasks', $defaultShowTasks === 'yes');
$this->initialStateService->provideInitialState($this->appName, 'tasks_enabled', false);
diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php
index e31f605346..96726266cb 100644
--- a/lib/Controller/SettingsController.php
+++ b/lib/Controller/SettingsController.php
@@ -87,6 +87,8 @@ public function setConfig(string $key,
return $this->setEventLimit($value);
case 'slotDuration':
return $this->setSlotDuration($value);
+ case 'defaultCalendarId':
+ return $this->setDefaultCalendarId($value);
case 'showTasks':
return $this->setShowTasks($value);
default:
@@ -310,4 +312,25 @@ private function setSlotDuration(string $value):JSONResponse {
return new JSONResponse();
}
+
+ /**
+ * sets defaultCalendarId for user
+ *
+ * @param string $value User-selected option for default calendar when creating new events
+ * @return JSONResponse
+ */
+ private function setDefaultCalendarId(string $value):JSONResponse {
+ try {
+ $this->config->setUserValue(
+ $this->userId,
+ $this->appName,
+ 'defaultCalendarId',
+ $value
+ );
+ } catch (\Exception $e) {
+ return new JSONResponse([], Http::STATUS_INTERNAL_SERVER_ERROR);
+ }
+
+ return new JSONResponse();
+ }
}
diff --git a/lib/Controller/ViewController.php b/lib/Controller/ViewController.php
index 69346c649d..38e712a92f 100644
--- a/lib/Controller/ViewController.php
+++ b/lib/Controller/ViewController.php
@@ -94,6 +94,7 @@ public function index():TemplateResponse {
$defaultSkipPopover = $this->config->getAppValue($this->appName, 'skipPopover', 'no');
$defaultTimezone = $this->config->getAppValue($this->appName, 'timezone', 'automatic');
$defaultSlotDuration = $this->config->getAppValue($this->appName, 'slotDuration', '00:30:00');
+ $defaultCalendarIdGlobal = $this->config->getAppValue($this->appName, 'defaultCalendarId', '');
$defaultShowTasks = $this->config->getAppValue($this->appName, 'showTasks', 'yes');
$appVersion = $this->config->getAppValue($this->appName, 'installed_version');
@@ -105,6 +106,7 @@ public function index():TemplateResponse {
$skipPopover = $this->config->getUserValue($this->userId, $this->appName, 'skipPopover', $defaultSkipPopover) === 'yes';
$timezone = $this->config->getUserValue($this->userId, $this->appName, 'timezone', $defaultTimezone);
$slotDuration = $this->config->getUserValue($this->userId, $this->appName, 'slotDuration', $defaultSlotDuration);
+ $defaultCalendarIdUser = $this->config->getUserValue($this->userId, $this->appName, 'defaultCalendarId', $defaultCalendarId);
$showTasks = $this->config->getUserValue($this->userId, $this->appName, 'showTasks', $defaultShowTasks) === 'yes';
$talkEnabled = $this->appManager->isEnabledForUser('spreed');
@@ -120,6 +122,7 @@ public function index():TemplateResponse {
$this->initialStateService->provideInitialState($this->appName, 'talk_enabled', $talkEnabled);
$this->initialStateService->provideInitialState($this->appName, 'timezone', $timezone);
$this->initialStateService->provideInitialState($this->appName, 'slot_duration', $slotDuration);
+ $this->initialStateService->provideInitialState($this->appName, 'default_calendar_id', $defaultCalendarIdUser);
$this->initialStateService->provideInitialState($this->appName, 'show_tasks', $showTasks);
$this->initialStateService->provideInitialState($this->appName, 'tasks_enabled', $tasksEnabled);
diff --git a/src/components/AppNavigation/Settings.vue b/src/components/AppNavigation/Settings.vue
index d493ca3693..b0de63ffd4 100644
--- a/src/components/AppNavigation/Settings.vue
+++ b/src/components/AppNavigation/Settings.vue
@@ -76,6 +76,16 @@
@select="changeSlotDuration" />
+
+
+
{{ $t('calendar', 'Copy primary CalDAV address') }}
@@ -100,6 +110,8 @@ import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
import ActionCheckbox from '@nextcloud/vue/dist/Components/ActionCheckbox'
import AppNavigationSettings from '@nextcloud/vue/dist/Components/AppNavigationSettings'
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
+import CalendarPicker from '../Shared/CalendarPicker.vue'
+
import {
generateRemoteUrl,
} from '@nextcloud/router'
@@ -129,6 +141,7 @@ export default {
Multiselect,
SettingsImportSection,
SettingsTimezoneSelect,
+ CalendarPicker,
},
props: {
loadingCalendars: {
@@ -143,6 +156,7 @@ export default {
savingTasks: false,
savingPopover: false,
savingSlotDuration: false,
+ savingDefaultCalendarId: false,
savingWeekend: false,
savingWeekNumber: false,
displayKeyboardShortcuts: false,
@@ -161,6 +175,7 @@ export default {
slotDuration: state => state.settings.slotDuration,
timezone: state => state.settings.timezone,
locale: (state) => state.settings.momentLocale,
+ defaultCalendarId: state => state.settings.defaultCalendarId,
}),
isBirthdayCalendarDisabled() {
return this.savingBirthdayCalendar || this.loadingCalendars
@@ -204,6 +219,28 @@ export default {
selectedDurationOption() {
return this.slotDurationOptions.find(o => o.value === this.slotDuration)
},
+ defaultCalendarOptions() {
+ return this.$store.state.calendars.calendars.filter(o => !o.readOnly)
+ },
+ defaultCalendar() {
+ var calendar = this.defaultCalendarOptions.find(o => o.id === this.defaultCalendarId)
+ // If the default calendar is not or no longer available,
+ // pick the first calendar in the list of available calendars.
+ if(calendar === undefined) {
+ calendar = this.defaultCalendarOptions[0]
+ }
+ if(calendar === undefined) {
+ // Create a dummy calendar object so that the calendarpicker
+ // will not complain when no calendar is available.
+ calendar = {
+ color: '#000',
+ displayName: 'No calendar',
+ owner: '',
+ isSharedWithMe: false,
+ }
+ }
+ return calendar
+ },
},
methods: {
async toggleBirthdayEnabled() {
@@ -305,6 +342,28 @@ export default {
this.savingSlotDuration = false
}
},
+ /**
+ * Changes the default calendar for new events
+ * @param {Object} selectedCalendar The new selected default calendar
+ */
+ async changeDefaultCalendar(selectedCalendar) {
+ if (!selectedCalendar) {
+ return
+ }
+
+ this.savingDefaultCalendar = true
+
+ try {
+ await this.$store.dispatch('setDefaultCalendarId', {
+ calendarId: selectedCalendar.id,
+ })
+ this.savingDefaultCalendar = false
+ } catch (error) {
+ console.error(error)
+ showError(this.$t('calendar', 'New setting was not saved successfully.'))
+ this.savingDefaultCalendar = false
+ }
+ },
/**
* Copies the primary CalDAV url to the user's clipboard.
*/
diff --git a/src/components/Shared/CalendarPicker.vue b/src/components/Shared/CalendarPicker.vue
index d951791cb8..923fa43ff6 100644
--- a/src/components/Shared/CalendarPicker.vue
+++ b/src/components/Shared/CalendarPicker.vue
@@ -2,7 +2,7 @@
@@ -37,10 +37,14 @@ export default {
type: Boolean,
default: false,
},
+ disabled: {
+ type: Boolean,
+ default: false,
+ },
},
computed: {
- isDisabled() {
- return this.calendars.length < 2
+ isMultiselectDisabled() {
+ return this.disabled || this.calendars.length < 2
},
},
methods: {
diff --git a/src/mixins/EditorMixin.js b/src/mixins/EditorMixin.js
index 939e8ab373..cb0a8437db 100644
--- a/src/mixins/EditorMixin.js
+++ b/src/mixins/EditorMixin.js
@@ -649,9 +649,10 @@ export default {
const start = parseInt(to.params.dtstart, 10)
const end = parseInt(to.params.dtend, 10)
const timezoneId = vm.$store.getters.getResolvedTimezone
+ const calendarId = vm.$store.state.settings.defaultCalendarId
try {
- await vm.$store.dispatch('getCalendarObjectInstanceForNewEvent', { isAllDay, start, end, timezoneId })
+ await vm.$store.dispatch('getCalendarObjectInstanceForNewEvent', { isAllDay, start, end, timezoneId, calendarId })
vm.calendarId = vm.calendarObject.calendarId
} catch (error) {
console.debug(error)
diff --git a/src/store/calendarObjectInstance.js b/src/store/calendarObjectInstance.js
index 1781becb31..1aa1da0eaa 100644
--- a/src/store/calendarObjectInstance.js
+++ b/src/store/calendarObjectInstance.js
@@ -1413,7 +1413,7 @@ const actions = {
* @param {String} data.timezoneId The timezoneId of the new event
* @returns {Promise<{calendarObject: Object, calendarObjectInstance: Object}>}
*/
- async getCalendarObjectInstanceForNewEvent({ state, dispatch, commit }, { isAllDay, start, end, timezoneId }) {
+ async getCalendarObjectInstanceForNewEvent({ state, dispatch, commit }, { isAllDay, start, end, timezoneId, calendarId }) {
if (state.isNew === true) {
return Promise.resolve({
calendarObject: state.calendarObject,
@@ -1421,7 +1421,7 @@ const actions = {
})
}
- const calendarObject = await dispatch('createNewEvent', { start, end, isAllDay, timezoneId })
+ const calendarObject = await dispatch('createNewEvent', { start, end, isAllDay, timezoneId, calendarId })
const startDate = new Date(start * 1000)
const eventComponent = getObjectAtRecurrenceId(calendarObject, startDate)
const calendarObjectInstance = mapEventComponentToEventObject(eventComponent)
diff --git a/src/store/calendarObjects.js b/src/store/calendarObjects.js
index 4c5d9cca4a..78e2eeda4e 100644
--- a/src/store/calendarObjects.js
+++ b/src/store/calendarObjects.js
@@ -312,7 +312,7 @@ const actions = {
* @param {Boolean} data.isAllDay foo
* @returns {Promise}
*/
- createNewEvent(context, { start, end, timezoneId, isAllDay }) {
+ createNewEvent(context, { start, end, timezoneId, isAllDay, calendarId }) {
const timezoneManager = getTimezoneManager()
const timezone = timezoneManager.getTimezoneForId(timezoneId)
@@ -336,8 +336,7 @@ const actions = {
vObject.undirtify()
}
- const firstCalendar = context.getters.sortedCalendars[0].id
- return Promise.resolve(mapCalendarJsToCalendarObject(calendar, firstCalendar))
+ return Promise.resolve(mapCalendarJsToCalendarObject(calendar, calendarId || context.getters.sortedCalendars[0].id))
},
/**
diff --git a/src/store/settings.js b/src/store/settings.js
index 782a630342..834d888d38 100644
--- a/src/store/settings.js
+++ b/src/store/settings.js
@@ -39,6 +39,7 @@ const state = {
talkEnabled: false,
tasksEnabled: false,
timezone: null,
+ defaultCalendarId: null,
}
const mutations = {
@@ -110,6 +111,17 @@ const mutations = {
state.timezone = timezoneId
},
+ /**
+ * Updates the user's default calendar
+ *
+ * @param {Object} state The Vuex state
+ * @param {Object} data The destructuring object
+ * @param {String} data.calendarId The new calendar id
+ */
+ setDefaultCalendarId(state, { calendarId }) {
+ state.defaultCalendarId = calendarId
+ },
+
/**
* Initialize settings
*
@@ -130,6 +142,7 @@ const mutations = {
state.talkEnabled = settings.talkEnabled
state.tasksEnabled = settings.tasksEnabled
state.timezone = settings.timezone
+ state.defaultCalendarId = settings.defaultCalendarId
},
/**
@@ -294,6 +307,24 @@ const actions = {
context.commit('setSlotDuration', { slotDuration })
},
+ /**
+ * Updates the user's default calendar for new events
+ *
+ * @param {Object} context The Vuex context
+ * @param {Object} data The destructuring object
+ * @param {String} data.slotDuration The id of the new default calendar
+ */
+ async setDefaultCalendarId(context, { calendarId }) {
+ if (context.state.defaultCalendarId === calendarId) {
+ return
+ }
+
+ await HttpClient.post(getLinkToConfig('defaultCalendarId'), {
+ value: calendarId,
+ })
+ context.commit('setDefaultCalendarId', { calendarId })
+ },
+
/**
* Updates the user's timezone
*
diff --git a/src/views/Calendar.vue b/src/views/Calendar.vue
index d1d4b35ff0..5800db7e83 100644
--- a/src/views/Calendar.vue
+++ b/src/views/Calendar.vue
@@ -44,6 +44,7 @@
:header="showHeader"
:height="windowResize"
:slot-duration="slotDuration"
+ :default-calendar-id="defaultCalendarId"
:week-numbers="showWeekNumbers"
:weekends="showWeekends"
:event-sources="eventSources"
@@ -171,6 +172,7 @@ export default {
showWeekends: state => state.settings.showWeekends,
showWeekNumbers: state => state.settings.showWeekNumbers,
slotDuration: state => state.settings.slotDuration,
+ defaultCalendarId: state => state.settings.defaultCalendarId,
showTasks: state => state.settings.showTasks,
timezone: state => state.settings.timezone,
modificationCount: state => state.calendarObjects.modificationCount,
@@ -303,6 +305,7 @@ export default {
showWeekNumbers: loadState('calendar', 'show_week_numbers'),
skipPopover: loadState('calendar', 'skip_popover'),
slotDuration: loadState('calendar', 'slot_duration'),
+ defaultCalendarId: loadState('calendar', 'default_calendar_id'),
talkEnabled: loadState('calendar', 'talk_enabled'),
tasksEnabled: loadState('calendar', 'tasks_enabled'),
timezone: loadState('calendar', 'timezone'),