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

Setting for default calendar when creating new events #4310

Closed
wants to merge 5 commits into from
Closed
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
5 changes: 3 additions & 2 deletions css/app-settings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@
width: 50%;
}
}

&--timezone {

&--timezone,
&--default-calendar {
width: 100%;

.multiselect {
Expand Down
2 changes: 2 additions & 0 deletions lib/Controller/PublicViewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ private function publicIndex(string $token,
$defaultTimezone = $this->config->getAppValue($this->appName, 'timezone', 'automatic');
$defaultSlotDuration = $this->config->getAppValue($this->appName, 'slotDuration', '00:30:00');
$defaultDefaultReminder = $this->config->getAppValue($this->appName, 'defaultReminder', 'none');
$defaultCalendarId = $this->config->getAppValue($this->appName, 'defaultCalendarId', 'none');
$defaultShowTasks = $this->config->getAppValue($this->appName, 'showTasks', 'yes');

$appVersion = $this->config->getAppValue($this->appName, 'installed_version', null);
Expand All @@ -143,6 +144,7 @@ private function publicIndex(string $token,
$this->initialStateService->provideInitialState($this->appName, 'timezone', $defaultTimezone);
$this->initialStateService->provideInitialState($this->appName, 'slot_duration', $defaultSlotDuration);
$this->initialStateService->provideInitialState($this->appName, 'default_reminder', $defaultDefaultReminder);
$this->initialStateService->provideInitialState($this->appName, 'default_calendar_id', $defaultCalendarId);
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to provide this on a public view?

$this->initialStateService->provideInitialState($this->appName, 'show_tasks', $defaultShowTasks === 'yes');
$this->initialStateService->provideInitialState($this->appName, 'tasks_enabled', false);
$this->initialStateService->provideInitialState($this->appName, 'hide_event_export', false);
Expand Down
23 changes: 23 additions & 0 deletions lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ public function setConfig(string $key,
return $this->setSlotDuration($value);
case 'defaultReminder':
return $this->setDefaultReminder($value);
case 'defaultCalendarId':
return $this->setDefaultCalendarId($value);
Comment on lines +92 to +93
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
case 'defaultCalendarId':
return $this->setDefaultCalendarId($value);

Should be moved to the DAV app.

case 'showTasks':
return $this->setShowTasks($value);
default:
Expand Down Expand Up @@ -339,4 +341,25 @@ private function setDefaultReminder(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',
st3iny marked this conversation as resolved.
Show resolved Hide resolved
$value
);
} catch (\Exception $e) {
return new JSONResponse([], Http::STATUS_INTERNAL_SERVER_ERROR);
}

return new JSONResponse();
}
Comment on lines +344 to +364
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/**
* 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();
}

Should be moved to the DAV app.

}
3 changes: 3 additions & 0 deletions lib/Controller/ViewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public function index():TemplateResponse {
$defaultTimezone = $this->config->getAppValue($this->appName, 'timezone', 'automatic');
$defaultSlotDuration = $this->config->getAppValue($this->appName, 'slotDuration', '00:30:00');
$defaultDefaultReminder = $this->config->getAppValue($this->appName, 'defaultReminder', 'none');
$defaultCalendarIdGlobal = $this->config->getAppValue($this->appName, 'defaultCalendarId', '');
$defaultShowTasks = $this->config->getAppValue($this->appName, 'showTasks', 'yes');

$appVersion = $this->config->getAppValue($this->appName, 'installed_version', null);
Expand All @@ -93,6 +94,7 @@ public function index():TemplateResponse {
$timezone = $this->config->getUserValue($this->userId, $this->appName, 'timezone', $defaultTimezone);
$slotDuration = $this->config->getUserValue($this->userId, $this->appName, 'slotDuration', $defaultSlotDuration);
$defaultReminder = $this->config->getUserValue($this->userId, $this->appName, 'defaultReminder', $defaultDefaultReminder);
$defaultCalendarIdUser = $this->config->getUserValue($this->userId, $this->appName, 'defaultCalendarId', $defaultCalendarId);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
$defaultCalendarIdUser = $this->config->getUserValue($this->userId, $this->appName, 'defaultCalendarId', $defaultCalendarId);
$defaultCalendarIdUser = $this->config->getUserValue($this->userId, 'dav', 'defaultCalendar', $defaultCalendarId);

This also needs a reasonable default ($defaultCalendarId) is undefined?!

Copy link
Member

Choose a reason for hiding this comment

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

Instead of using the calendar id, use the calendar uri, then default to CalDavBackend::PERSONAL_CALENDAR_URI.

Copy link
Member

Choose a reason for hiding this comment

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

The personal calendar always gets recreated at some point if there's nothing else

$showTasks = $this->config->getUserValue($this->userId, $this->appName, 'showTasks', $defaultShowTasks) === 'yes';
$hideEventExport = $this->config->getAppValue($this->appName, 'hideEventExport', 'no') === 'yes';
$disableAppointments = $this->config->getAppValue($this->appName, 'disableAppointments', 'no') === 'yes';
Expand All @@ -117,6 +119,7 @@ public function index():TemplateResponse {
$this->initialStateService->provideInitialState('timezone', $timezone);
$this->initialStateService->provideInitialState('slot_duration', $slotDuration);
$this->initialStateService->provideInitialState('default_reminder', $defaultReminder);
$this->initialStateService->provideInitialState($this->appName, 'default_calendar_id', $defaultCalendarIdUser);
$this->initialStateService->provideInitialState('show_tasks', $showTasks);
$this->initialStateService->provideInitialState('tasks_enabled', $tasksEnabled);
$this->initialStateService->provideInitialState('hide_event_export', $hideEventExport);
Expand Down
59 changes: 59 additions & 0 deletions src/components/AppNavigation/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@
@select="changeDefaultReminder" />
</li>
<SettingsTimezoneSelect :is-disabled="loadingCalendars" />
<li class="settings-fieldset-interior-item settings-fieldset-interior-item--default-calendar">
<label>
{{ $t('calendar', 'Default calendar for new events') }}
<CalendarPicker
:calendars="defaultCalendarOptions"
:calendar="defaultCalendar"
:disabled="savingDefaultCalendarId"
@selectCalendar="changeDefaultCalendar" />
</label>
</li>
<ActionButton @click.prevent.stop="copyPrimaryCalDAV">
<template #icon>
<ClipboardArrowLeftOutline :size="20" decorative />
Expand Down Expand Up @@ -121,6 +131,8 @@ import ActionCheckbox from '@nextcloud/vue/dist/Components/ActionCheckbox'
import ActionLink from '@nextcloud/vue/dist/Components/ActionLink'
import AppNavigationSettings from '@nextcloud/vue/dist/Components/AppNavigationSettings'
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
import CalendarPicker from '../Shared/CalendarPicker.vue'

import {
generateRemoteUrl,
generateUrl,
Expand Down Expand Up @@ -166,6 +178,7 @@ export default {
ClipboardArrowLeftOutline,
InformationVariant,
OpenInNewIcon,
CalendarPicker,
},
props: {
loadingCalendars: {
Expand All @@ -181,6 +194,7 @@ export default {
savingPopover: false,
savingSlotDuration: false,
savingDefaultReminder: false,
savingDefaultCalendarId: false,
savingWeekend: false,
savingWeekNumber: false,
displayKeyboardShortcuts: false,
Expand All @@ -200,6 +214,7 @@ export default {
defaultReminder: state => state.settings.defaultReminder,
timezone: state => state.settings.timezone,
locale: (state) => state.settings.momentLocale,
defaultCalendarId: state => state.settings.defaultCalendarId,
}),
isBirthdayCalendarDisabled() {
return this.savingBirthdayCalendar || this.loadingCalendars
Expand Down Expand Up @@ -266,6 +281,28 @@ export default {
availabilitySettingsUrl() {
return generateUrl('/settings/user/groupware')
},
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() {
Expand Down Expand Up @@ -391,6 +428,28 @@ export default {
this.savingDefaultReminder = false
}
},
/**
* Changes the default calendar for new events
szaimen marked this conversation as resolved.
Show resolved Hide resolved
* @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.
*/
Expand Down
2 changes: 2 additions & 0 deletions src/components/CalendarGrid.vue
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,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,
Expand Down Expand Up @@ -141,6 +142,7 @@ export default {
headerToolbar: false,
height: '100%',
slotDuration: this.slotDuration,
defaultCalendarId: this.defaultCalendarId,
expandRows: true,
weekNumbers: this.showWeekNumbers,
weekends: this.showWeekends,
Expand Down
10 changes: 7 additions & 3 deletions src/components/Shared/CalendarPicker.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<Multiselect label="displayName"
track-by="url"
:disabled="isDisabled"
:disabled="isMultiselectDisabled"
:options="calendars"
:value="value"
:multiple="multiple"
Expand Down Expand Up @@ -47,10 +47,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: {
Expand Down
3 changes: 2 additions & 1 deletion src/mixins/EditorMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -673,10 +673,11 @@ 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.loadingCalendars()
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)
Expand Down
5 changes: 3 additions & 2 deletions src/store/calendarObjectInstance.js
Original file line number Diff line number Diff line change
Expand Up @@ -1445,15 +1445,15 @@ const actions = {
* @param {string} data.timezoneId The timezoneId of the new event
* @return {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,
calendarObjectInstance: state.calendarObjectInstance,
})
}

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)
Expand Down Expand Up @@ -1587,6 +1587,7 @@ const actions = {
end: endDate.unixTime,
timezoneId: oldEventComponent.startDate.timezoneId,
isAllDay: oldEventComponent.isAllDay(),
calendarId: oldEventComponent.calendarId,
})
const eventComponent = getObjectAtRecurrenceId(calendarObject, startDate.jsDate)
copyCalendarObjectInstanceIntoEventComponent(oldCalendarObjectInstance, eventComponent)
Expand Down
5 changes: 2 additions & 3 deletions src/store/calendarObjects.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ const actions = {
* @param {boolean} data.isAllDay foo
* @return {Promise<CalendarObject>}
*/
createNewEvent(context, { start, end, timezoneId, isAllDay }) {
createNewEvent(context, { start, end, timezoneId, isAllDay, calendarId }) {
const timezoneManager = getTimezoneManager()
const timezone = timezoneManager.getTimezoneForId(timezoneId)

Expand All @@ -339,8 +339,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))
},

/**
Expand Down
30 changes: 30 additions & 0 deletions src/store/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

import { enableBirthdayCalendar } from '../services/caldavService.js'
import { mapDavCollectionToCalendar } from '../models/calendar'
import { detectTimezone } from '../services/timezoneDetectionService'
Expand Down Expand Up @@ -47,6 +48,7 @@ const state = {
forceEventAlarmType: false,
// user-defined Nextcloud settings
momentLocale: 'en',
defaultCalendarId: null,
}

const mutations = {
Expand Down Expand Up @@ -129,6 +131,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
*
Expand Down Expand Up @@ -185,6 +198,7 @@ Initial settings:
state.hideEventExport = hideEventExport
state.forceEventAlarmType = forceEventAlarmType
state.disableAppointments = disableAppointments
state.defaultCalendarId = defaultCalendarId
},

/**
Expand Down Expand Up @@ -386,6 +400,22 @@ const actions = {
commit('setDefaultReminder', { defaultReminder })
},

/**
* 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 setConfig('defaultCalendarId', calendarId)
commit('setDefaultCalendarId', { calendarId })
},

/**
* Updates the user's timezone
*
Expand Down
2 changes: 2 additions & 0 deletions src/views/Calendar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export default {
showWeekNumbers: state => state.settings.showWeekNumbers,
slotDuration: state => state.settings.slotDuration,
defaultReminder: state => state.settings.defaultReminder,
defaultCalendarId: state => state.settings.defaultCalendarId,
showTasks: state => state.settings.showTasks,
timezone: state => state.settings.timezone,
modificationCount: state => state.calendarObjects.modificationCount,
Expand Down Expand Up @@ -211,6 +212,7 @@ export default {
skipPopover: loadState('calendar', 'skip_popover'),
slotDuration: loadState('calendar', 'slot_duration'),
defaultReminder: loadState('calendar', 'default_reminder'),
defaultCalendarId: loadState('calendar', 'default_calendar_id'),
talkEnabled: loadState('calendar', 'talk_enabled'),
tasksEnabled: loadState('calendar', 'tasks_enabled'),
timezone: loadState('calendar', 'timezone'),
Expand Down
Loading