mirror of https://github.com/nextcloud/calendar
Add Free/Busy UI
Signed-off-by: Georg Ehrke <developer@georgehrke.com>
This commit is contained in:
parent
68c3021925
commit
37bf964908
|
@ -687,3 +687,11 @@
|
|||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.invitees-list-button-group {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
@import 'app-navigation.scss';
|
||||
@import 'app-sidebar.scss';
|
||||
@import 'app-settings.scss';
|
||||
@import 'freebusy.scss';
|
||||
@import 'fullcalendar.scss';
|
||||
@import 'global.scss';
|
||||
@import 'icons.scss';
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* Calendar App
|
||||
*
|
||||
* @copyright 2019 Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
* @author Georg Ehrke
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
.modal--scheduler {
|
||||
position: relative;
|
||||
|
||||
.fc-bgevent {
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
.blocking-event-free-busy {
|
||||
border-color: red;
|
||||
border-style: solid;
|
||||
border-left-width: 1px;
|
||||
border-right-width: 1px;
|
||||
background-color: transparent;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.blocking-event-free-busy.blocking-event-free-busy--first-row {
|
||||
border-top-width: 1px;
|
||||
}
|
||||
|
||||
.blocking-event-free-busy.blocking-event-free-busy--last-row {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.loading-indicator {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 50px;
|
||||
margin-top: 75px;
|
||||
}
|
||||
}
|
||||
|
||||
.freebusy-caption {
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
|
||||
&__calendar-user-types,
|
||||
&__colors {
|
||||
width: 50%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&__colors {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.freebusy-caption-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&__color {
|
||||
height: 1em;
|
||||
width: 2em;
|
||||
display: block;
|
||||
border: var(--color-border-dark);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&__label {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
<!--
|
||||
- @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
|
||||
-
|
||||
- @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
-
|
||||
- @license GNU AGPL version 3 or any later version
|
||||
-
|
||||
- This program is free software: you can redistribute it and/or modify
|
||||
- it under the terms of the GNU Affero General Public License as
|
||||
- published by the Free Software Foundation, either version 3 of the
|
||||
- License, or (at your option) any later version.
|
||||
-
|
||||
- This program is distributed in the hope that it will be useful,
|
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
- GNU Affero General Public License for more details.
|
||||
-
|
||||
- You should have received a copy of the GNU Affero General Public License
|
||||
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-
|
||||
-->
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
size="large"
|
||||
:title="$t('calendar', 'Availability of attendees, resources and rooms')"
|
||||
@close="$emit('close')">
|
||||
<div class="modal__content modal--scheduler">
|
||||
<div v-if="loadingIndicator" class="loading-indicator">
|
||||
<div class="icon-loading" />
|
||||
</div>
|
||||
<FullCalendar
|
||||
ref="freeBusyFullCalendar"
|
||||
default-view="resourceTimelineDay"
|
||||
:editable="false"
|
||||
:selectable="false"
|
||||
height="auto"
|
||||
:plugins="plugins"
|
||||
:event-sources="eventSources"
|
||||
:time-zone="timezoneId"
|
||||
:default-date="startDate"
|
||||
:locales="locales"
|
||||
:resources="resources"
|
||||
:locale="fullCalendarLocale"
|
||||
:first-day="firstDay"
|
||||
scroll-time="06:00:00"
|
||||
:force-event-duration="false"
|
||||
:resource-label-text="$t('calendar', 'Attendees, Resources and Rooms')"
|
||||
scheduler-license-key="GPL-My-Project-Is-Open-Source"
|
||||
@loading="loading" />
|
||||
<div class="freebusy-caption">
|
||||
<div class="freebusy-caption__calendar-user-types" />
|
||||
<div class="freebusy-caption__colors">
|
||||
<div v-for="color in colorCaption" :key="color.color" class="freebusy-caption-item">
|
||||
<div class="freebusy-caption-item__color" :style="{ 'background-color': color.color }" />
|
||||
<div class="freebusy-caption-item__label">
|
||||
{{ color.label }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FullCalendar from '@fullcalendar/vue'
|
||||
import resourceTimelinePlugin from '@fullcalendar/resource-timeline'
|
||||
import {
|
||||
mapGetters,
|
||||
mapState,
|
||||
} from 'vuex'
|
||||
import { getLocale } from '@nextcloud/l10n'
|
||||
import { Modal } from '@nextcloud/vue/dist/Components/Modal'
|
||||
import VTimezoneNamedTimezone from '../../../fullcalendar/vtimezoneNamedTimezoneImpl.js'
|
||||
import freeBusyEventSource from '../../../fullcalendar/freeBusyEventSource.js'
|
||||
import { getColorForFBType } from '../../../utils/freebusy.js'
|
||||
import freeBusyFakeBlockingEventSource from '../../../fullcalendar/freeBusyFakeBlockingEventSource.js'
|
||||
|
||||
export default {
|
||||
name: 'FreeBusy',
|
||||
components: {
|
||||
FullCalendar,
|
||||
Modal,
|
||||
},
|
||||
props: {
|
||||
organizer: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
attendees: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
startDate: {
|
||||
type: Date,
|
||||
required: true,
|
||||
},
|
||||
endDate: {
|
||||
type: Date,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fullCalendarLocale: 'en',
|
||||
locales: [],
|
||||
firstDay: 0,
|
||||
loadingIndicator: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
timezoneId: 'getResolvedTimezone',
|
||||
}),
|
||||
...mapState({
|
||||
showWeekends: state => state.settings.showWeekends,
|
||||
showWeekNumbers: state => state.settings.showWeekNumbers,
|
||||
timezone: state => state.settings.timezone,
|
||||
}),
|
||||
plugins() {
|
||||
return [
|
||||
resourceTimelinePlugin,
|
||||
VTimezoneNamedTimezone,
|
||||
]
|
||||
},
|
||||
eventSources() {
|
||||
return [
|
||||
freeBusyEventSource(
|
||||
this._uid,
|
||||
this.organizer.attendeeProperty,
|
||||
this.attendees.map((a) => a.attendeeProperty)
|
||||
),
|
||||
freeBusyFakeBlockingEventSource(
|
||||
this._uid,
|
||||
this.resources,
|
||||
this.startDate,
|
||||
this.endDate
|
||||
),
|
||||
]
|
||||
},
|
||||
resources() {
|
||||
const resources = []
|
||||
|
||||
// for (const attendee of [this.organizer, ...this.attendees]) {
|
||||
for (const attendee of this.attendees) {
|
||||
resources.push({
|
||||
id: attendee.attendeeProperty.email,
|
||||
title: attendee.commonName || attendee.uri.substr(7),
|
||||
})
|
||||
}
|
||||
|
||||
return resources
|
||||
},
|
||||
colorCaption() {
|
||||
return [{
|
||||
label: this.$t('calendar', 'Busy (tentative)'),
|
||||
color: getColorForFBType('BUSY-TENTATIVE'),
|
||||
}, {
|
||||
label: this.$t('calendar', 'Busy'),
|
||||
color: getColorForFBType('BUSY'),
|
||||
}, {
|
||||
label: this.$t('calendar', 'Out of office'),
|
||||
color: getColorForFBType('BUSY-UNAVAILABLE'),
|
||||
}, {
|
||||
label: this.$t('calendar', 'Unknown'),
|
||||
color: getColorForFBType('UNKNOWN'),
|
||||
}]
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
this.loadFullCalendarLocale()
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* Loads the locale data for full-calendar
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async loadFullCalendarLocale() {
|
||||
let locale = getLocale().replace('_', '-').toLowerCase()
|
||||
try {
|
||||
// try to load the default locale first
|
||||
const fcLocale = await import('@fullcalendar/core/locales/' + locale)
|
||||
this.locales.push(fcLocale)
|
||||
// We have to update firstDay manually till https://github.com/fullcalendar/fullcalendar-vue/issues/36 is fixed
|
||||
this.firstDay = fcLocale.week.dow
|
||||
this.fullCalendarLocale = locale
|
||||
} catch (e) {
|
||||
try {
|
||||
locale = locale.split('-')[0]
|
||||
const fcLocale = await import('@fullcalendar/core/locales/' + locale)
|
||||
this.locales.push(fcLocale)
|
||||
// We have to update firstDay manually till https://github.com/fullcalendar/fullcalendar-vue/issues/36 is fixed
|
||||
this.firstDay = fcLocale.week.dow
|
||||
this.fullCalendarLocale = locale
|
||||
} catch (e) {
|
||||
console.debug('falling back to english locale')
|
||||
}
|
||||
}
|
||||
},
|
||||
loading(isLoading) {
|
||||
this.loadingIndicator = isLoading
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
@import '~@fullcalendar/core/main.css';
|
||||
@import '~@fullcalendar/timeline/main.css';
|
||||
@import '~@fullcalendar/resource-timeline/main.css';
|
||||
|
||||
.modal__content {
|
||||
padding: 50px;
|
||||
}
|
||||
</style>
|
|
@ -43,12 +43,26 @@
|
|||
v-if="!isReadOnly && isListEmpty && hasUserEmailAddress" />
|
||||
<OrganizerNoEmailError
|
||||
v-if="!isReadOnly && isListEmpty && !hasUserEmailAddress" />
|
||||
<button
|
||||
v-if="isCreateTalkRoomButtonVisible"
|
||||
:disabled="isCreateTalkRoomButtonDisabled"
|
||||
@click="createTalkRoom">
|
||||
{{ $t('calendar', 'Create Talk room for this event') }}
|
||||
</button>
|
||||
|
||||
<div class="invitees-list-button-group">
|
||||
<button
|
||||
v-if="isCreateTalkRoomButtonVisible"
|
||||
:disabled="isCreateTalkRoomButtonDisabled"
|
||||
@click="createTalkRoom">
|
||||
{{ $t('calendar', 'Create Talk room for this event') }}
|
||||
</button>
|
||||
|
||||
<button v-if="!isReadOnly" :disabled="isListEmpty" @click="openFreeBusy">
|
||||
{{ $t('calendar', 'Show busy times') }}
|
||||
</button>
|
||||
<FreeBusy
|
||||
v-if="showFreeBusyModel"
|
||||
:attendees="calendarObjectInstance.attendees"
|
||||
:organizer="calendarObjectInstance.organizer"
|
||||
:start-date="calendarObjectInstance.startDate"
|
||||
:end-date="calendarObjectInstance.endDate"
|
||||
@close="closeFreeBusy" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -60,10 +74,12 @@ import OrganizerListItem from './OrganizerListItem'
|
|||
import NoInviteesView from './NoInviteesView.vue'
|
||||
import OrganizerNoEmailError from './OrganizerNoEmailError.vue'
|
||||
import { createTalkRoom, doesDescriptionContainTalkLink } from '../../../services/talkService.js'
|
||||
import FreeBusy from '../FreeBusy/FreeBusy.vue'
|
||||
|
||||
export default {
|
||||
name: 'InviteesList',
|
||||
components: {
|
||||
FreeBusy,
|
||||
OrganizerNoEmailError,
|
||||
NoInviteesView,
|
||||
InviteesListItem,
|
||||
|
@ -83,6 +99,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
creatingTalkRoom: false,
|
||||
showFreeBusyModel: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -191,6 +208,12 @@ export default {
|
|||
attendee,
|
||||
})
|
||||
},
|
||||
openFreeBusy() {
|
||||
this.showFreeBusyModel = true
|
||||
},
|
||||
closeFreeBusy() {
|
||||
this.showFreeBusyModel = false
|
||||
},
|
||||
async createTalkRoom() {
|
||||
const NEW_LINE = '\r\n'
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import getTimezoneManager from '../services/timezoneDataProviderService.js'
|
||||
import { createFreeBusyRequest } from 'calendar-js'
|
||||
import DateTimeValue from 'calendar-js/src/values/dateTimeValue.js'
|
||||
import client from '../services/caldavService.js'
|
||||
import freeBusyEventSourceFunction from './freeBusyEventSourceFunction.js'
|
||||
// import AttendeeProperty from 'calendar-js/src/properties/attendeeProperty.js'
|
||||
|
||||
/**
|
||||
* Returns an event source for free-busy
|
||||
*
|
||||
* @param {String} id Identification for this source
|
||||
* @param {AttendeeProperty} organizer The organizer of the event
|
||||
* @param {AttendeeProperty[]} attendees Array of the event's attendees
|
||||
* @returns {{startEditable: boolean, resourceEditable: boolean, editable: boolean, id: string, durationEditable: boolean, events: events}}
|
||||
*/
|
||||
export default function(id, organizer, attendees) {
|
||||
return {
|
||||
id: 'free-busy-event-source-' + id,
|
||||
editable: false,
|
||||
startEditable: false,
|
||||
durationEditable: false,
|
||||
resourceEditable: false,
|
||||
events: async({ start, end, timeZone }, successCallback, failureCallback) => {
|
||||
console.debug(start, end, timeZone)
|
||||
|
||||
const timezoneObject = getTimezoneManager().getTimezoneForId(timeZone)
|
||||
|
||||
const startDateTime = DateTimeValue.fromJSDate(start, true)
|
||||
const endDateTime = DateTimeValue.fromJSDate(end, true)
|
||||
|
||||
// const organizerAsAttendee = new AttendeeProperty('ATTENDEE', organizer.email)
|
||||
const freeBusyComponent = createFreeBusyRequest(startDateTime, endDateTime, organizer, attendees)
|
||||
const freeBusyICS = freeBusyComponent.toICS()
|
||||
|
||||
let outbox
|
||||
try {
|
||||
const outboxes = await client.calendarHomes[0].findAllScheduleOutboxes()
|
||||
outbox = outboxes[0]
|
||||
} catch (error) {
|
||||
failureCallback(error)
|
||||
return
|
||||
}
|
||||
|
||||
let freeBusyData
|
||||
try {
|
||||
freeBusyData = await outbox.freeBusyRequest(freeBusyICS)
|
||||
} catch (error) {
|
||||
failureCallback(error)
|
||||
return
|
||||
}
|
||||
const events = []
|
||||
for (const [uri, data] of Object.entries(freeBusyData)) {
|
||||
events.push(...freeBusyEventSourceFunction(uri, data.calendarData, data.success, startDateTime, endDateTime, timezoneObject))
|
||||
}
|
||||
|
||||
console.debug(events)
|
||||
successCallback(events)
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
import { getColorForFBType } from '../utils/freebusy.js'
|
||||
import { getParserManager } from 'calendar-js'
|
||||
|
||||
/**
|
||||
* Converts the response
|
||||
*
|
||||
* @param {String} uri URI of the resource
|
||||
* @param {String} calendarData Calendar-data containing free-busy data
|
||||
* @param {boolean} success Whether or not the free-busy request was successful
|
||||
* @param {DateTimeValue} start The start of the fetched time-range
|
||||
* @param {DateTimeValue} end The end of the fetched time-range
|
||||
* @param {Timezone} timezone Timezone of user viewing data
|
||||
* @returns {Object[]}
|
||||
*/
|
||||
export default function(uri, calendarData, success, start, end, timezone) {
|
||||
if (!success) {
|
||||
return [{
|
||||
id: Math.random().toString(36).substring(7),
|
||||
start: start.getInTimezone(timezone).jsDate.toISOString(),
|
||||
end: end.getInTimezone(timezone).jsDate.toISOString(),
|
||||
resourceId: uri,
|
||||
rendering: 'background',
|
||||
allDay: false,
|
||||
backgroundColor: getColorForFBType('UNKNOWN'),
|
||||
borderColor: getColorForFBType('UNKNOWN'),
|
||||
}]
|
||||
}
|
||||
|
||||
const parserManager = getParserManager()
|
||||
const parser = parserManager.getParserForFileType('text/calendar')
|
||||
parser.parse(calendarData)
|
||||
|
||||
// TODO: fix me upstream, parser only exports VEVENT, VJOURNAL and VTODO at the moment
|
||||
const calendarComponent = parser._calendarComponent
|
||||
const freeBusyComponent = calendarComponent.getFirstComponent('VFREEBUSY')
|
||||
if (!freeBusyComponent) {
|
||||
return []
|
||||
}
|
||||
|
||||
const events = []
|
||||
for (const freeBusyProperty of freeBusyComponent.getPropertyIterator('FREEBUSY')) {
|
||||
/** @var {FreeBusyProperty} freeBusyProperty */
|
||||
events.push({
|
||||
id: Math.random().toString(36).substring(7),
|
||||
start: freeBusyProperty.getFirstValue().start.getInTimezone(timezone).jsDate.toISOString(),
|
||||
end: freeBusyProperty.getFirstValue().end.getInTimezone(timezone).jsDate.toISOString(),
|
||||
resourceId: uri,
|
||||
rendering: 'background',
|
||||
backgroundColor: getColorForFBType(freeBusyProperty.type),
|
||||
})
|
||||
}
|
||||
|
||||
return events
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns an event source for free-busy
|
||||
*
|
||||
* @param {String} id Identification for this source
|
||||
* @param {String[]} resources List of resources
|
||||
* @param {Date} eventStart Start of the event being edited / created
|
||||
* @param {Date} eventEnd End of the event being edited / created
|
||||
* @returns {{startEditable: boolean, resourceEditable: boolean, editable: boolean, id: string, durationEditable: boolean, events: events}}
|
||||
*/
|
||||
export default function(id, resources, eventStart, eventEnd) {
|
||||
const resourceIds = resources.map((resource) => resource.id)
|
||||
|
||||
return {
|
||||
id: 'free-busy-fake-blocking-event-source-' + id,
|
||||
editable: false,
|
||||
startEditable: false,
|
||||
durationEditable: false,
|
||||
resourceEditable: false,
|
||||
events: async({ start, end, timeZone }, successCallback, failureCallback) => {
|
||||
if (resources.length === 1) {
|
||||
successCallback([{
|
||||
id: Math.random().toString(36).substring(7),
|
||||
start: eventStart.toISOString(),
|
||||
end: eventEnd.toISOString(),
|
||||
allDay: false,
|
||||
rendering: 'background',
|
||||
classNames: [
|
||||
'blocking-event-free-busy',
|
||||
'blocking-event-free-busy--first-row',
|
||||
'blocking-event-free-busy--last-row',
|
||||
],
|
||||
resourceId: resourceIds[0],
|
||||
}])
|
||||
} else if (resources.length === 2) {
|
||||
successCallback([{
|
||||
id: Math.random().toString(36).substring(7),
|
||||
start: eventStart.toISOString(),
|
||||
end: eventEnd.toISOString(),
|
||||
allDay: false,
|
||||
rendering: 'background',
|
||||
classNames: [
|
||||
'blocking-event-free-busy',
|
||||
'blocking-event-free-busy--first-row',
|
||||
],
|
||||
resourceId: resourceIds[0],
|
||||
}, {
|
||||
id: Math.random().toString(36).substring(7),
|
||||
start: eventStart.toISOString(),
|
||||
end: eventEnd.toISOString(),
|
||||
allDay: false,
|
||||
rendering: 'background',
|
||||
classNames: [
|
||||
'blocking-event-free-busy',
|
||||
'blocking-event-free-busy--last-row',
|
||||
],
|
||||
resourceId: resourceIds[1],
|
||||
}])
|
||||
} else {
|
||||
successCallback([{
|
||||
id: Math.random().toString(36).substring(7),
|
||||
start: eventStart.toISOString(),
|
||||
end: eventEnd.toISOString(),
|
||||
allDay: false,
|
||||
rendering: 'background',
|
||||
classNames: [
|
||||
'blocking-event-free-busy',
|
||||
'blocking-event-free-busy--first-row',
|
||||
],
|
||||
resourceIds: resourceIds.slice(0, 1),
|
||||
}, {
|
||||
id: Math.random().toString(36).substring(7),
|
||||
start: eventStart.toISOString(),
|
||||
end: eventEnd.toISOString(),
|
||||
allDay: false,
|
||||
rendering: 'background',
|
||||
classNames: [
|
||||
'blocking-event-free-busy',
|
||||
],
|
||||
resourceIds: resourceIds.slice(1, -1),
|
||||
}, {
|
||||
id: Math.random().toString(36).substring(7),
|
||||
start: eventStart.toISOString(),
|
||||
end: eventEnd.toISOString(),
|
||||
allDay: false,
|
||||
rendering: 'background',
|
||||
classNames: [
|
||||
'blocking-event-free-busy',
|
||||
'blocking-event-free-busy--last-row',
|
||||
],
|
||||
resourceIds: resourceIds.slice(-1),
|
||||
}])
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
|
@ -144,6 +144,7 @@ function getOrganizerFromEventComponent(eventComponent) {
|
|||
return {
|
||||
commonName: organizerProperty.commonName,
|
||||
uri: organizerProperty.email,
|
||||
attendeeProperty: organizerProperty,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -480,6 +480,7 @@ const mutations = {
|
|||
Vue.set(calendarObjectInstance, 'organizer', {})
|
||||
Vue.set(calendarObjectInstance.organizer, 'commonName', commonName)
|
||||
Vue.set(calendarObjectInstance.organizer, 'uri', email)
|
||||
Vue.set(calendarObjectInstance.organizer, 'attendeeProperty', calendarObjectInstance.eventComponent.getFirstProperty('ORGANIZER'))
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the corresponding color for a given Free/Busy type
|
||||
*
|
||||
* @param {String} type The type of the FreeBusy property
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getColorForFBType(type = 'BUSY') {
|
||||
switch (type) {
|
||||
case 'FREE':
|
||||
return '#55B85F'
|
||||
|
||||
case 'BUSY-TENTATIVE':
|
||||
return '#4C81FF'
|
||||
|
||||
case 'BUSY':
|
||||
return '#273A7F'
|
||||
|
||||
case 'BUSY-UNAVAILABLE':
|
||||
return '#50347F'
|
||||
|
||||
default:
|
||||
return '#DA9CBD'
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue