Merge alarm, repeat and details tabs

Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
This commit is contained in:
Richard Steinmetz 2021-10-01 15:04:41 +02:00 committed by greta
parent 1b80ef0685
commit e5a502798f
20 changed files with 356 additions and 344 deletions

View File

@ -48,8 +48,7 @@
.editor-invitee-list-empty-message,
.editor-reminders-list-empty-message,
.editor-invitee-list-no-email-configured-message,
.repeat-option-set-summary-read-only {
.editor-invitee-list-no-email-configured-message {
margin-top: 20px;
&__icon {
@ -220,33 +219,13 @@
}
}
&--summary {
display: flex;
justify-content: space-between;
line-height: 34px;
}
&__label {
margin-right: auto;
}
}
.repeat-option-warning {
display: flex;
align-items: center;
margin-top: 20px;
&__icon {
height: 32px;
width: 32px;
min-width: 32px;
min-height: 32px;
background-size: 32px;
}
&__info {
text-align: center;
}
text-align: center;
}
.property-title-time-picker {
@ -336,7 +315,7 @@
}
}
.property-alarm-new {
.property-alarm-list {
width: 100%;
}
@ -346,16 +325,19 @@
min-height: 44px;
&__icon {
width: 32px;
height: 32px;
background-color: var(--color-border-dark);
border-radius: 50%;
align-self: flex-start;
&--hidden {
visibility: hidden;
}
.icon {
opacity: .7;
height: 32px;
width: 32px;
background-size: 20px;
width: 34px;
height: 44px;
margin-left: -5px;
margin-right: 5px;
// TODO: enable me again if the other icons on the details tab have an opacity too
// opacity: .7;
}
}
@ -364,6 +346,7 @@
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
align-self: center;
}
&__options {
@ -374,46 +357,96 @@
}
&__edit {
padding: 0 8px;
display: flex;
align-items: center;
width: 100%;
min-width: 0;
padding-right: 8px;
input[type=number] {
width: 4em;
width: 3em;
}
.multiselect {
flex: 1 auto;
height: 34px;
min-width: 0;
}
.mx-datepicker {
flex: 1 auto;
}
&--timed {
.multiselect {
width: 100%;
}
}
&--all-day {
justify-content: space-between;
flex-wrap: wrap;
margin-bottom: 5px;
gap: 0 5px;
.multiselect {
width: unset !important; // TODO - remove
min-width: 8em !important;
&__distance,
&__time {
display: flex;
flex: 1;
align-items: center;
}
.before-at-label {
margin: 0 auto;
&__distance {
.multiselect {
width: 6em;
}
}
.mx-datepicker {
width: 8em !important;
&__time {
&__before-at-label {
flex: 0 0 auto;
margin-right: 5px;
}
.mx-datepicker {
width: 7em;
}
}
}
&--absolute {
.mx-datepicker {
width: 100% !important;
width: unset;
}
}
}
}
.property-repeat {
width: 100%;
&__summary {
display: flex;
align-items: center;
margin-bottom: 5px;
&__icon {
width: 34px;
height: 34px;
margin-left: -5px;
margin-right: 5px;
}
&__content {
flex: 1 auto;
padding: 0 7px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
&__options {
margin-bottom: 5px;
}
}
.resource-search__multiselect,
.invitees-search__multiselect {
width: 100%;
@ -537,6 +570,12 @@
width: 34px;
}
&__icon {
&--hidden {
visibility: hidden;
}
}
&__info {
display: flex;
justify-content: center;

View File

@ -2,6 +2,7 @@
- @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
-
- @author Georg Ehrke <oc.list@georgehrke.com>
- @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@ -22,31 +23,30 @@
<template>
<div class="property-alarm-list">
<!-- TODO: probably not use index here for the key -->
<AlarmListItem
v-for="(alarm, index) in alarms"
:key="index"
:alarm="alarm"
:calendar-object-instance="calendarObjectInstance"
:is-read-only="isReadOnly"
:show-icon="index === 0"
@remove-alarm="removeAlarm" />
<AlarmListNew
v-if="!isReadOnly"
:is-all-day="calendarObjectInstance.isAllDay"
:show-icon="alarms.length === 0"
@add-alarm="addAlarm" />
<NoAlarmView
v-if="isListEmpty" />
</div>
</template>
<script>
import AlarmListNew from './AlarmListNew'
import AlarmListItem from './AlarmListItem'
import NoAlarmView from './NoAlarmView.vue'
export default {
name: 'AlarmList',
components: {
NoAlarmView,
AlarmListItem,
AlarmListNew,
},
@ -64,9 +64,6 @@ export default {
alarms() {
return this.calendarObjectInstance.alarms
},
isListEmpty() {
return this.alarms.length === 0
},
},
methods: {
/**

View File

@ -2,6 +2,7 @@
- @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
-
- @author Georg Ehrke <oc.list@georgehrke.com>
- @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@ -25,8 +26,13 @@
<div
v-click-outside="closeAlarmEditor"
class="property-alarm-item">
<div class="property-alarm-item__icon">
<component :is="icon" :size="18" class="icon" />
<div
class="property-alarm-item__icon"
:class="{ 'property-alarm-item__icon--hidden': !showIcon }">
<Bell
:size="20"
:title="t('calendar', 'Reminder')"
class="icon" />
</div>
<div
v-if="!isEditing"
@ -52,24 +58,29 @@
<div
v-if="isEditing && isRelativeAlarm && isAllDay"
class="property-alarm-item__edit property-alarm-item__edit--all-day">
<input
type="number"
min="0"
max="3600"
:value="alarm.relativeAmountAllDay"
@input="changeRelativeAmountAllDay">
<AlarmTimeUnitSelect
:is-all-day="isAllDay"
:count="alarm.relativeAmountAllDay"
:unit="alarm.relativeUnitAllDay"
:disabled="false"
@change="changeRelativeUnitAllDay" />
<span>
{{ $t('calendar', 'before at') }}
</span>
<TimePicker
:date="relativeAllDayDate"
@change="changeRelativeHourMinuteAllDay" />
<div class="property-alarm-item__edit--all-day__distance">
<input
type="number"
min="0"
max="3600"
:value="alarm.relativeAmountAllDay"
@input="changeRelativeAmountAllDay">
<AlarmTimeUnitSelect
:is-all-day="isAllDay"
:count="alarm.relativeAmountAllDay"
:unit="alarm.relativeUnitAllDay"
:disabled="false"
class="time-unit-select"
@change="changeRelativeUnitAllDay" />
</div>
<div class="property-alarm-item__edit--all-day__time">
<span class="property-alarm-item__edit--all-day__time__before-at-label">
{{ $t('calendar', 'before at') }}
</span>
<TimePicker
:date="relativeAllDayDate"
@change="changeRelativeHourMinuteAllDay" />
</div>
</div>
<div
v-if="isEditing && isAbsoluteAlarm"
@ -171,14 +182,10 @@ import AlarmTimeUnitSelect from './AlarmTimeUnitSelect.vue'
import moment from '@nextcloud/moment'
import TimePicker from '../../Shared/TimePicker.vue'
import DatePicker from '../../Shared/DatePicker.vue'
import Bell from 'vue-material-design-icons/Bell.vue'
import Check from 'vue-material-design-icons/Check.vue'
import Cog from 'vue-material-design-icons/Cog.vue'
import Delete from 'vue-material-design-icons/Delete.vue'
import Email from 'vue-material-design-icons/Email.vue'
import Pencil from 'vue-material-design-icons/Pencil.vue'
import VolumeHigh from 'vue-material-design-icons/VolumeHigh.vue'
export default {
name: 'AlarmListItem',
@ -192,11 +199,8 @@ export default {
ActionSeparator,
Bell,
Check,
Cog,
Delete,
Email,
Pencil,
VolumeHigh,
},
directives: {
ClickOutside,
@ -217,6 +221,10 @@ export default {
type: Boolean,
required: true,
},
showIcon: {
type: Boolean,
required: true,
},
},
data() {
return {
@ -277,21 +285,6 @@ export default {
isAbsoluteAlarm() {
return !this.isRelativeAlarm
},
icon() {
switch (this.alarm.type) {
case 'AUDIO':
return 'VolumeHigh'
case 'DISPLAY':
return 'Bell'
case 'EMAIL':
return 'Email'
default:
return 'Cog'
}
},
currentUserTimezone() {
return this.$store.getters.getResolvedTimezone
},

View File

@ -2,6 +2,7 @@
- @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
-
- @author Georg Ehrke <oc.list@georgehrke.com>
- @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@ -21,19 +22,16 @@
-->
<template>
<Multiselect
<PropertySelect
:prop-model="propModel"
:is-read-only="false"
:value="null"
:show-icon="showIcon"
class="property-alarm-new"
track-by="value"
label="label"
open-direction="bottom"
:placeholder="$t('calendar', '+ Add reminder')"
:options="options"
:searchable="false"
@select="addReminderFromSelect" />
@update:value="addReminderFromSelect" />
</template>
<script>
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
import { mapState } from 'vuex'
import { getDefaultAlarms } from '../../../defaults/defaultAlarmProvider.js'
import {
@ -41,17 +39,22 @@ import {
getAmountHoursMinutesAndUnitForAllDayEvents,
} from '../../../utils/alarms.js'
import alarmFormat from '../../../filters/alarmFormat.js'
import PropertySelect from '../Properties/PropertySelect'
export default {
name: 'AlarmListNew',
components: {
Multiselect,
PropertySelect,
},
props: {
isAllDay: {
type: Boolean,
required: true,
},
showIcon: {
type: Boolean,
required: true,
},
},
computed: {
...mapState({
@ -70,15 +73,22 @@ export default {
}
})
},
propModel() {
return {
options: this.options,
icon: 'Bell',
placeholder: this.$t('calendar', '+ Add reminder'),
readableName: this.$t('calendar', 'Add reminder'),
}
},
},
methods: {
/**
* This emits the add alarm event
*
* @param {object} data the destructuring object
* @param {object} data.value the alarm value
* @param {object} value The alarm value
*/
addReminderFromSelect({ value }) {
addReminderFromSelect(value) {
this.$emit('add-alarm', value)
},
/**

View File

@ -1,43 +0,0 @@
<!--
- @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>
<div class="editor-invitee-list-empty-message">
<div class="icon editor-invitee-list-empty-message__icon">
<Bell :size="50" decorative />
</div>
<div class="editor-invitee-list-empty-message__caption">
{{ $t('calendar', 'No reminders yet') }}
</div>
</div>
</template>
<script>
import Bell from 'vue-material-design-icons/Bell.vue'
export default {
name: 'NoAlarmView',
components: {
Bell,
},
}
</script>

View File

@ -2,6 +2,7 @@
- @copyright Copyright (c) 2020 Georg Ehrke <oc.list@georgehrke.com>
-
- @author Georg Ehrke <oc.list@georgehrke.com>
- @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@ -25,8 +26,9 @@
<component
:is="icon"
:size="20"
class="property-color__icon"
:title="readableName"
class="property-color__icon"
:class="{ 'property-color__icon--hidden': !showIcon }"
decorative />
<div

View File

@ -2,6 +2,7 @@
- @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
-
- @author Georg Ehrke <oc.list@georgehrke.com>
- @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@ -26,7 +27,8 @@
:is="icon"
:size="20"
:title="readableName"
class="property-select__icon" />
class="property-select__icon"
:class="{ 'property-select__icon--hidden': !showIcon }" />
<div
class="property-select__input"
@ -38,6 +40,7 @@
:allow-empty="false"
:title="readableName"
:value="selectedValue"
:placeholder="placeholder"
track-by="value"
label="label"
@select="changeValue" />

View File

@ -2,6 +2,7 @@
- @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
-
- @author Georg Ehrke <oc.list@georgehrke.com>
- @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@ -26,7 +27,8 @@
:is="icon"
:size="20"
:title="readableName"
class="property-select-multiple__icon" />
class="property-select-multiple__icon"
:class="{ 'property-select-multiple__icon--hidden': !showIcon }" />
<div
class="property-select-multiple__input"
@ -42,6 +44,8 @@
:value="value"
:multiple="true"
:taggable="true"
track-by="value"
label="label"
@select="selectValue"
@tag="selectValue"
@remove="unselectValue">
@ -56,7 +60,7 @@
<div v-else class="property-select-multiple-colored-tag-wrapper">
<PropertySelectMultipleColoredTag
v-for="singleValue in value"
:key="singleValue"
:key="singleValue.value"
:option="singleValue" />
</div>
</div>
@ -97,6 +101,10 @@ export default {
type: Boolean,
default: false,
},
closeOnSelect: {
type: Boolean,
default: false,
},
},
computed: {
display() {
@ -104,16 +112,26 @@ export default {
},
options() {
const options = this.propModel.options.slice()
for (const value of (this.value || [])) {
if (options.includes(value)) {
for (const value of (this.value ?? [])) {
if (options.find(option => option.value === value)) {
continue
}
options.push(value)
// Add pseudo options for unknown values
options.push({
value,
label: value,
})
}
return options
.sort((a, b) => a.localeCompare(b, getLocale().replace('_', '-'), { sensitivity: 'base' }))
.sort((a, b) => {
return a.label.localeCompare(
b.label,
getLocale().replace('_', '-'),
{ sensitivity: 'base' },
)
})
},
},
methods: {
@ -122,14 +140,14 @@ export default {
return
}
this.$emit('add-single-value', value)
this.$emit('add-single-value', value.value)
},
unselectValue(value) {
if (!value) {
return
}
this.$emit('remove-single-value', value)
this.$emit('remove-single-value', value.value)
},
},
}

View File

@ -2,6 +2,7 @@
- @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
-
- @author Georg Ehrke <oc.list@georgehrke.com>
- @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@ -29,6 +30,7 @@
<script>
import { uidToColor } from '../../../utils/uidToColor.js'
import logger from '../../../utils/logger'
export default {
name: 'PropertySelectMultipleColoredOption',
@ -40,6 +42,8 @@ export default {
},
computed: {
label() {
const option = this.option
logger.debug('Option render', { option })
if (typeof this.option === 'string') {
return this.option
}

View File

@ -2,6 +2,7 @@
- @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
-
- @author Georg Ehrke <oc.list@georgehrke.com>
- @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@ -21,7 +22,9 @@
-->
<template>
<span :key="option" class="multiselect__tag" :style="{ 'background-color': color, 'border-color': borderColor, color: textColor }">
<span
class="multiselect__tag"
:style="{ 'background-color': color, 'border-color': borderColor, color: textColor }">
<span>{{ option }}</span>
</span>
</template>

View File

@ -2,6 +2,7 @@
- @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
-
- @author Georg Ehrke <oc.list@georgehrke.com>
- @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@ -26,7 +27,8 @@
:is="icon"
:size="20"
:title="readableName"
class="property-text__icon" />
class="property-text__icon"
:class="{ 'property-text__icon--hidden': !showIcon }" />
<div
class="property-text__input"

View File

@ -2,6 +2,7 @@
- @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
-
- @author Georg Ehrke <oc.list@georgehrke.com>
- @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@ -21,60 +22,79 @@
-->
<template>
<div>
<RepeatFreqInterval
v-if="!isRecurrenceException && !isReadOnly"
:frequency="recurrenceRule.frequency"
:interval="recurrenceRule.interval"
@change-interval="changeInterval"
@change-frequency="changeFrequency" />
<RepeatFreqWeeklyOptions
v-if="isFreqWeekly && !isRecurrenceException && !isReadOnly"
:by-day="recurrenceRule.byDay"
@add-by-day="addByDay"
@remove-by-day="removeByDay" />
<RepeatFreqMonthlyOptions
v-if="isFreqMonthly && !isRecurrenceException && !isReadOnly"
:by-day="recurrenceRule.byDay"
:by-month-day="recurrenceRule.byMonthDay"
:by-set-position="recurrenceRule.bySetPosition"
@add-by-month-day="addByMonthDay"
@remove-by-month-day="removeByMonthDay"
@change-by-day="setByDay"
@change-by-set-position="setBySetPosition"
@change-to-by-set-position="changeToBySetPositionMonthly"
@change-to-by-day="changeToByDayMonthly" />
<RepeatFreqYearlyOptions
v-if="isFreqYearly && !isRecurrenceException && !isReadOnly"
:by-day="recurrenceRule.byDay"
:by-month="recurrenceRule.byMonth"
:by-set-position="recurrenceRule.bySetPosition"
@change-by-day="setByDay"
@change-by-set-position="setBySetPosition"
@add-by-month="addByMonth"
@remove-by-month="removeByMonth"
@enable-by-set-position="enableBySetPositionYearly"
@disable-by-set-position="disableBySetPositionYearly" />
<RepeatEndRepeat
v-if="isRepeating && !isRecurrenceException && !isReadOnly"
:calendar-object-instance="calendarObjectInstance"
:until="recurrenceRule.until"
:count="recurrenceRule.count"
@set-infinite="setInfinite"
@set-until="setUntil"
@set-count="setCount"
@change-to-count="changeToCount"
@change-to-until="changeToUntil" />
<RepeatSummary
v-if="!isReadOnly"
:recurrence-rule="recurrenceRule" />
<RepeatSummaryReadOnly
v-if="isReadOnly"
:recurrence-rule="recurrenceRule" />
<RepeatUnsupportedWarning
v-if="recurrenceRule.isUnsupported && !isRecurrenceException" />
<RepeatExceptionWarning
v-if="isRecurrenceException" />
<div class="property-repeat">
<div class="property-repeat__summary">
<RepeatIcon
class="property-repeat__summary__icon"
:title="$t('calendar', 'Repeat')"
:size="20" />
<RepeatSummary
class="property-repeat__summary__content"
:recurrence-rule="recurrenceRule" />
<Actions v-if="!isReadOnly">
<ActionButton @click="toggleOptions">
<template #icon>
<component
:is="toggleIcon"
:size="20"
decorative />
</template>
{{ toggleTitle }}
</ActionButton>
</Actions>
</div>
<div
v-if="showOptions"
class="property-repeat__options">
<RepeatFreqInterval
v-if="!isRecurrenceException && !isReadOnly"
:frequency="recurrenceRule.frequency"
:interval="recurrenceRule.interval"
@change-interval="changeInterval"
@change-frequency="changeFrequency" />
<RepeatFreqWeeklyOptions
v-if="isFreqWeekly && !isRecurrenceException && !isReadOnly"
:by-day="recurrenceRule.byDay"
@add-by-day="addByDay"
@remove-by-day="removeByDay" />
<RepeatFreqMonthlyOptions
v-if="isFreqMonthly && !isRecurrenceException && !isReadOnly"
:by-day="recurrenceRule.byDay"
:by-month-day="recurrenceRule.byMonthDay"
:by-set-position="recurrenceRule.bySetPosition"
@add-by-month-day="addByMonthDay"
@remove-by-month-day="removeByMonthDay"
@change-by-day="setByDay"
@change-by-set-position="setBySetPosition"
@change-to-by-set-position="changeToBySetPositionMonthly"
@change-to-by-day="changeToByDayMonthly" />
<RepeatFreqYearlyOptions
v-if="isFreqYearly && !isRecurrenceException && !isReadOnly"
:by-day="recurrenceRule.byDay"
:by-month="recurrenceRule.byMonth"
:by-set-position="recurrenceRule.bySetPosition"
@change-by-day="setByDay"
@change-by-set-position="setBySetPosition"
@add-by-month="addByMonth"
@remove-by-month="removeByMonth"
@enable-by-set-position="enableBySetPositionYearly"
@disable-by-set-position="disableBySetPositionYearly" />
<RepeatEndRepeat
v-if="isRepeating && !isRecurrenceException && !isReadOnly"
:calendar-object-instance="calendarObjectInstance"
:until="recurrenceRule.until"
:count="recurrenceRule.count"
@set-infinite="setInfinite"
@set-until="setUntil"
@set-count="setCount"
@change-to-count="changeToCount"
@change-to-until="changeToUntil" />
<RepeatUnsupportedWarning
v-if="recurrenceRule.isUnsupported && !isRecurrenceException" />
<RepeatExceptionWarning
v-if="isRecurrenceException" />
</div>
</div>
</template>
@ -87,13 +107,16 @@ import RepeatFreqInterval from './RepeatFreqInterval.vue'
import RepeatUnsupportedWarning from './RepeatUnsupportedWarning.vue'
import RepeatExceptionWarning from './RepeatExceptionWarning.vue'
import RepeatSummary from './RepeatSummary.vue'
import RepeatSummaryReadOnly from './RepeatSummaryReadOnly.vue'
import RepeatIcon from 'vue-material-design-icons/Repeat.vue'
import Pencil from 'vue-material-design-icons/Pencil.vue'
import Check from 'vue-material-design-icons/Check.vue'
import Actions from '@nextcloud/vue/dist/Components/Actions'
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
export default {
name: 'Repeat',
components: {
RepeatSummary,
RepeatSummaryReadOnly,
RepeatExceptionWarning,
RepeatFreqInterval,
RepeatFreqYearlyOptions,
@ -101,6 +124,11 @@ export default {
RepeatFreqWeeklyOptions,
RepeatEndRepeat,
RepeatUnsupportedWarning,
RepeatIcon,
Pencil,
Check,
Actions,
ActionButton,
},
props: {
/**
@ -142,6 +170,11 @@ export default {
required: true,
},
},
data() {
return {
showOptions: false,
}
},
computed: {
/**
* Whether or not this event is recurring
@ -175,6 +208,28 @@ export default {
isFreqYearly() {
return this.recurrenceRule.frequency === 'YEARLY'
},
/**
* The name of the icon for the toggle options button
*
* @return {string}
*/
toggleIcon() {
if (this.showOptions) {
return 'Check'
}
return 'Pencil'
},
/**
* The text of the toggle options button
*
* @return {string}
*/
toggleTitle() {
if (this.showOptions) {
return this.t('calendar', 'Save')
}
return this.t('calendar', 'Edit')
},
},
methods: {
/**
@ -424,6 +479,12 @@ export default {
this.$emit('force-this-and-all-future')
}
},
/**
* Toggle visibility of the options
*/
toggleOptions() {
this.showOptions = !this.showOptions
},
},
}
</script>

View File

@ -2,6 +2,7 @@
- @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
-
- @author Georg Ehrke <oc.list@georgehrke.com>
- @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@ -22,8 +23,7 @@
<template>
<div class="repeat-option-warning">
<div class="repeat-option-warning__icon icon icon-info" />
<strong class="repeat-option-warning__info">
<strong>
{{ $t('calendar', 'This event is the recurrence-exception of a recurrence-set. You cannot add a recurrence-rule to it.') }}
</strong>
</div>

View File

@ -2,6 +2,7 @@
- @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
-
- @author Georg Ehrke <oc.list@georgehrke.com>
- @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@ -21,12 +22,12 @@
-->
<template>
<div v-if="display" class="repeat-option-set repeat-option-set--summary">
<span class="repeat-option-set-summary__label">{{ $t('calendar', 'Summary') }}:</span>
<span class="repeat-option-set-summary__summary">
{{ recurrenceRule | formatRecurrenceRule(locale) }}
</span>
</div>
<span v-if="display">
{{ recurrenceRule | formatRecurrenceRule(locale) }}
</span>
<span v-else>
{{ $t('calendar', 'No recurrence') }}
</span>
</template>
<script>

View File

@ -1,56 +0,0 @@
<!--
- @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>
<div class="repeat-option-set repeat-option-set-summary-read-only">
<div class="repeat-option-set-summary-read-only__icon icon icon-repeat" />
<div class="repeat-option-set-summary-read-only__caption">
{{ recurrenceRule | formatRecurrenceRule(locale) }}
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import formatRecurrenceRule from '../../../filters/recurrenceRuleFormat.js'
export default {
name: 'RepeatSummaryReadOnly',
filters: {
formatRecurrenceRule,
},
props: {
/**
* The recurrence-rule object as defined on the eventComponent
*/
recurrenceRule: {
type: Object,
required: true,
},
},
computed: {
...mapState({
locale: (state) => state.settings.momentLocale,
}),
},
}
</script>

View File

@ -2,6 +2,7 @@
- @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
-
- @author Georg Ehrke <oc.list@georgehrke.com>
- @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@ -22,8 +23,7 @@
<template>
<div class="repeat-option-warning">
<div class="repeat-option-warning__icon icon icon-info" />
<strong class="repeat-option-warning__info">
<strong>
{{ $t('calendar', 'The recurrence definition of this event is not fully supported by Nextcloud. If you edit the recurrence-options, certain recurrences may be lost.') }}
</strong>
</div>

View File

@ -5,6 +5,8 @@
*
* @author Georg Ehrke
*
* @author Richard Steinmetz <richard@steinmetz.cloud>
*
* 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
@ -26,7 +28,7 @@ import { translate as t } from '@nextcloud/l10n'
*/
export function getDefaultCategories() {
// This list was taken from https://tools.ietf.org/html/rfc5545#section-5
return [
const values = [
t('calendar', 'Anniversary'),
t('calendar', 'Appointment'),
t('calendar', 'Business'),
@ -43,6 +45,7 @@ export function getDefaultCategories() {
t('calendar', 'Travel'),
t('calendar', 'Vacation'),
]
return values.map(value => ({ value, label: value }))
}
export default getDefaultCategories

View File

@ -3,6 +3,8 @@
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @author Richard Steinmetz <richard@steinmetz.cloud>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
@ -34,6 +36,7 @@ import EyedropperVariant from 'vue-material-design-icons/EyedropperVariant.vue'
import MapMarker from 'vue-material-design-icons/MapMarker.vue'
import Tag from 'vue-material-design-icons/Tag.vue'
import TextBoxOutline from 'vue-material-design-icons/TextBoxOutline.vue'
import Bell from 'vue-material-design-icons/Bell.vue'
export default {
components: {
@ -44,6 +47,7 @@ export default {
MapMarker,
Tag,
TextBoxOutline,
Bell,
},
props: {
/**
@ -70,6 +74,14 @@ export default {
value: {
required: true,
},
/**
* Show the icon left of the input.
* Will be shown by default.
*/
showIcon: {
type: Boolean,
default: true,
},
},
computed: {
/**

View File

@ -162,6 +162,20 @@
:prop-model="rfcProps.color"
:value="color"
@update:value="updateColor" />
<AlarmList
:calendar-object-instance="calendarObjectInstance"
:is-read-only="isReadOnly" />
<!-- TODO: If not editing the master item, force updating this and all future -->
<!-- TODO: You can't edit recurrence-rule of no-range recurrence-exception -->
<Repeat
:calendar-object-instance="calendarObjectInstance"
:recurrence-rule="calendarObjectInstance.recurrenceRule"
:is-read-only="isReadOnly"
:is-editing-master-item="isEditingMasterItem"
:is-recurrence-exception="isRecurrenceException"
@force-this-and-all-future="forceModifyingFuture" />
</div>
<SaveButtons
v-if="showSaveButtons"
@ -220,58 +234,6 @@
@save-this-only="saveAndLeave(false)"
@save-this-and-all-future="saveAndLeave(true)" />
</AppSidebarTab>
<AppSidebarTab
v-if="!isLoading && !isError"
id="app-sidebar-tab-reminders"
class="app-sidebar-tab"
:name="$t('calendar', 'Reminders')"
:order="3">
<template #icon>
<Bell :size="20" decorative />
</template>
<div class="app-sidebar-tab__content">
<AlarmList
:calendar-object-instance="calendarObjectInstance"
:is-read-only="isReadOnly" />
</div>
<SaveButtons
v-if="showSaveButtons"
class="app-sidebar-tab__buttons"
:can-create-recurrence-exception="canCreateRecurrenceException"
:is-new="isNew"
:force-this-and-all-future="forceThisAndAllFuture"
@save-this-only="saveAndLeave(false)"
@save-this-and-all-future="saveAndLeave(true)" />
</AppSidebarTab>
<AppSidebarTab
v-if="!isLoading && !isError"
id="app-sidebar-tab-repeat"
class="app-sidebar-tab"
:name="$t('calendar', 'Repeat')"
:order="4">
<template #icon>
<RepeatIcon :size="20" decorative />
</template>
<div class="app-sidebar-tab__content">
<!-- TODO: If not editing the master item, force updating this and all future -->
<!-- TODO: You can't edit recurrence-rule of no-range recurrence-exception -->
<Repeat
:calendar-object-instance="calendarObjectInstance"
:recurrence-rule="calendarObjectInstance.recurrenceRule"
:is-read-only="isReadOnly"
:is-editing-master-item="isEditingMasterItem"
:is-recurrence-exception="isRecurrenceException"
@force-this-and-all-future="forceModifyingFuture" />
</div>
<SaveButtons
v-if="showSaveButtons"
class="app-sidebar-tab__buttons"
:can-create-recurrence-exception="canCreateRecurrenceException"
:is-new="isNew"
:force-this-and-all-future="forceThisAndAllFuture"
@save-this-only="saveAndLeave(false)"
@save-this-and-all-future="saveAndLeave(true)" />
</AppSidebarTab>
</AppSidebar>
</template>
<script>
@ -301,13 +263,11 @@ import PropertyColor from '../components/Editor/Properties/PropertyColor.vue'
import ResourceList from '../components/Editor/Resources/ResourceList'
import AccountMultiple from 'vue-material-design-icons/AccountMultiple.vue'
import Bell from 'vue-material-design-icons/Bell.vue'
import CalendarBlank from 'vue-material-design-icons/CalendarBlank.vue'
import Delete from 'vue-material-design-icons/Delete.vue'
import Download from 'vue-material-design-icons/Download.vue'
import InformationOutline from 'vue-material-design-icons/InformationOutline.vue'
import MapMarker from 'vue-material-design-icons/MapMarker.vue'
import RepeatIcon from 'vue-material-design-icons/Repeat.vue'
export default {
name: 'EditSidebar',
@ -330,13 +290,11 @@ export default {
PropertyTitleTimePicker,
Repeat,
AccountMultiple,
Bell,
CalendarBlank,
Delete,
Download,
InformationOutline,
MapMarker,
RepeatIcon,
},
mixins: [
EditorMixin,

View File

@ -34,7 +34,7 @@ describe('defaults/defaultCategories test suite', () => {
translate
.mockImplementation((app, str) => str)
expect(defaultCategories()).toEqual([
const categories = [
'Anniversary',
'Appointment',
'Business',
@ -50,7 +50,12 @@ describe('defaults/defaultCategories test suite', () => {
'Special occasion',
'Travel',
'Vacation',
])
]
expect(defaultCategories()).toEqual(categories.map(category => ({
value: category,
label: category,
})))
expect(translate).toHaveBeenCalledTimes(15)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Anniversary')