Skip to content
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
3 changes: 2 additions & 1 deletion css/app-settings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@
}

&--slotDuration,
&--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 @@ -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');
Expand All @@ -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);

Expand Down
23 changes: 23 additions & 0 deletions lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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();
}
}
3 changes: 3 additions & 0 deletions lib/Controller/ViewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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');
Expand All @@ -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);

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 @@ -76,6 +76,16 @@
@select="changeSlotDuration" />
</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 class="settings-fieldset-interior-item" icon="icon-clippy" @click.prevent.stop="copyPrimaryCalDAV">
{{ $t('calendar', 'Copy primary CalDAV address') }}
</ActionButton>
Expand All @@ -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'
Expand Down Expand Up @@ -129,6 +141,7 @@ export default {
Multiselect,
SettingsImportSection,
SettingsTimezoneSelect,
CalendarPicker,
},
props: {
loadingCalendars: {
Expand All @@ -143,6 +156,7 @@ export default {
savingTasks: false,
savingPopover: false,
savingSlotDuration: false,
savingDefaultCalendarId: false,
savingWeekend: false,
savingWeekNumber: false,
displayKeyboardShortcuts: false,
Expand All @@ -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
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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.
*/
Expand Down
10 changes: 7 additions & 3 deletions src/components/Shared/CalendarPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Multiselect
label="displayName"
track-by="displayName"
:disabled="isDisabled"
:disabled="isMultiselectDisabled"
:options="calendars"
:value="calendar"
@select="change">
Expand Down Expand Up @@ -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: {
Expand Down
3 changes: 2 additions & 1 deletion src/mixins/EditorMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions src/store/calendarObjectInstance.js
Original file line number Diff line number Diff line change
Expand Up @@ -1413,15 +1413,15 @@ 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,
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
5 changes: 2 additions & 3 deletions src/store/calendarObjects.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ const actions = {
* @param {Boolean} data.isAllDay foo
* @returns {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 @@ -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))
},

/**
Expand Down
31 changes: 31 additions & 0 deletions src/store/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const state = {
talkEnabled: false,
tasksEnabled: false,
timezone: null,
defaultCalendarId: null,
}

const mutations = {
Expand Down Expand Up @@ -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
*
Expand All @@ -130,6 +142,7 @@ const mutations = {
state.talkEnabled = settings.talkEnabled
state.tasksEnabled = settings.tasksEnabled
state.timezone = settings.timezone
state.defaultCalendarId = settings.defaultCalendarId
},

/**
Expand Down Expand Up @@ -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
*
Expand Down
3 changes: 3 additions & 0 deletions src/views/Calendar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
:header="showHeader"
:height="windowResize"
:slot-duration="slotDuration"
:default-calendar-id="defaultCalendarId"
:week-numbers="showWeekNumbers"
:weekends="showWeekends"
:event-sources="eventSources"
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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'),
Expand Down