diff --git a/src/components/AppNavigation/ListItemCalendar.vue b/src/components/AppNavigation/ListItemCalendar.vue
index 36700f83e..e5116b95d 100644
--- a/src/components/AppNavigation/ListItemCalendar.vue
+++ b/src/components/AppNavigation/ListItemCalendar.vue
@@ -552,12 +552,6 @@ $color-error: #e9322d;
display: none;
position: relative;
- &.error input.edit {
- color: var(--color-error);
- border-color: var(--color-error) !important;
- box-shadow: 0 0 6px transparentize( $color-error, .7 );
- }
-
form {
display: flex;
diff --git a/src/components/AppSidebar/Alarm/AlarmList.vue b/src/components/AppSidebar/Alarm/AlarmList.vue
index 029ca5ec7..ec3780479 100644
--- a/src/components/AppSidebar/Alarm/AlarmList.vue
+++ b/src/components/AppSidebar/Alarm/AlarmList.vue
@@ -9,7 +9,7 @@
+
+
+
diff --git a/src/models/alarm.js b/src/models/alarm.js
index b10543976..2f932e6bc 100644
--- a/src/models/alarm.js
+++ b/src/models/alarm.js
@@ -8,6 +8,7 @@ import {
getDateFromDateTimeValue,
} from '../utils/alarms.js'
import { AlarmComponent } from '@nextcloud/calendar-js'
+import ICAL from 'ical.js'
/**
* Creates a complete alarm object based on given props
@@ -97,6 +98,22 @@ const mapAlarmComponentToAlarmObject = (alarmComponent) => {
}
}
+/**
+ * @param {Array} alarms ICAL.js alarms
+ */
+export function mapICALAlarmsToAlarmObjects(alarms) {
+ return alarms.map((alarm) => {
+ try {
+ return mapAlarmComponentToAlarmObject(AlarmComponent.fromICALJs(alarm))
+ } catch (e) {
+ // Instead of breaking the whole page when parsing an invalid alarm,
+ // we just print a warning on the console.
+ console.warn(e)
+ return false
+ }
+ }).filter(Boolean)
+}
+
/**
* @param {number} time Total amount of seconds for the trigger
* @param {boolean} relatedToStart If the alarm is related to the start of the event
diff --git a/src/models/task.js b/src/models/task.js
index dedbc0667..e3652b25b 100644
--- a/src/models/task.js
+++ b/src/models/task.js
@@ -626,18 +626,21 @@ export default class Task {
/**
* Remove an alarm
*
- * @param {number} index The index of the alarm-list
+ * @param {number[]} indexes The indexes of the alarm-list
*/
- removeAlarm(index) {
+ removeAlarm(indexes) {
const valarms = this.vtodo.getAllSubcomponents('valarm')
- const valarmToDelete = valarms[index]
- if (valarmToDelete) {
- this.vtodo.removeSubcomponent(valarms[index])
+ for (const index of indexes) {
+ const valarmToDelete = valarms[index]
- this.updateLastModified()
- this._alarms = this.getAlarms()
+ if (valarmToDelete) {
+ this.vtodo.removeSubcomponent(valarmToDelete)
+ }
}
+
+ this.updateLastModified()
+ this._alarms = this.getAlarms()
}
/**
diff --git a/src/store/tasks.js b/src/store/tasks.js
index 362d0afff..4b33b7dc4 100644
--- a/src/store/tasks.js
+++ b/src/store/tasks.js
@@ -502,10 +502,10 @@ const mutations = {
* @param {object} state The store data
* @param {object} data Destructuring object
* @param {Task} data.task The task
- * @param {number} data.index The index of the alarm-item to remove
+ * @param {number[]} data.indexes The indexes of the alarm-items to remove
*/
- removeAlarm(state, { task, index }) {
- task.removeAlarm(index)
+ removeAlarm(state, { task, indexes }) {
+ task.removeAlarm(indexes)
},
/**
@@ -1282,10 +1282,10 @@ const actions = {
* Removes an alarm from a task
*
* @param {object} context The store context
- * @param {Task} task The task to update
+ * @param {Task} task The task to remove
*/
- async removeAlarm(context, { task, index }) {
- context.commit('removeAlarm', { task, index })
+ async removeAlarm(context, { task, indexes }) {
+ context.commit('removeAlarm', { task, indexes })
context.dispatch('updateTask', task)
},
diff --git a/src/utils/alarms.js b/src/utils/alarms.js
index 88bbab968..6acbeda8f 100644
--- a/src/utils/alarms.js
+++ b/src/utils/alarms.js
@@ -258,3 +258,14 @@ export function getDateFromDateTimeValue(dateTimeValue) {
0,
)
}
+
+/**
+ * Takes the related date and the relative trigger of an alarm and
+ * calculates the absolute date-time when the alarm will trigger.
+ *
+ * @param {Date} relatedDate Related date
+ * @param {number} relativeTrigger Relative trigger in seconds
+ */
+export function calculateAbsoluteDateFromRelativeTrigger(relatedDate, relativeTrigger) {
+ return new Date(((relatedDate.valueOf() / 1000) + relativeTrigger) * 1000)
+}
diff --git a/src/views/AppSidebar.vue b/src/views/AppSidebar.vue
index 5e2e43019..ca93aff9e 100644
--- a/src/views/AppSidebar.vue
+++ b/src/views/AppSidebar.vue
@@ -234,14 +234,15 @@ License along with this library. If not, see .
icon="TagMultiple"
@add-tag="updateTag"
@set-tags="updateTags" />
-
+ @remove-alarm="removeAlarmItem"
+ @restore-date="restoreDate">
@@ -282,7 +283,7 @@ import TagsItem from '../components/AppSidebar/TagsItem.vue'
import TextItem from '../components/AppSidebar/TextItem.vue'
import NotesItem from '../components/AppSidebar/NotesItem.vue'
import TaskCheckbox from '../components/TaskCheckbox.vue'
-// import TaskStatusDisplay from '../components/TaskStatusDisplay'
+import { mapICALAlarmsToAlarmObjects } from '../models/alarm.js'
import Task from '../models/task.js'
import { startDateString, dueDateString } from '../utils/dateStrings.js'
@@ -354,7 +355,6 @@ export default {
CalendarPickerItem,
NotesItem,
TaskCheckbox,
- // TaskStatusDisplay,
},
/**
* Before we navigate to a new task, we save possible edits to the task summary.
@@ -410,6 +410,9 @@ export default {
task() {
return this.getTaskByRoute(this.$route)
},
+ alarms() {
+ return mapICALAlarmsToAlarmObjects(this.task.alarms)
+ },
summary() {
return this.task ? this.task.summary : ''
},
@@ -601,12 +604,6 @@ export default {
return !!this.$store.state.settings.settings.allDay
}
},
- hasStartDate() {
- return !!this.task.start
- },
- hasDueDate() {
- return !!this.task.due
- },
showInCalendar() {
// Only tasks with a due date show up in the calendar
return !!this.showTaskInCalendar && this.task.dueMoment.isValid()
@@ -916,12 +913,30 @@ export default {
},
/**
- * Removes an alarm
+ * Removes one or more alarms
*
- * @param {number} index The index of the alarm-item to remove
+ * @param {number[]} indexes The indexes of the alarm-items to remove
*/
- removeAlarmItem(index) {
- this.removeAlarm({ task: this.task, index })
+ removeAlarmItem(indexes) {
+ this.removeAlarm({ task: this.task, indexes })
+ },
+
+ /**
+ * Restores the start or due-date
+ *
+ * This can happen if a start or due-date is deleted while there are still
+ * alarms relating to it. In case the user cancels the triggered modal, we
+ * have to restore the date.
+ *
+ * @param {Date} date The date previously deleted
+ * @param {boolean} isRelatedToStart True if the date is a start-date
+ */
+ restoreDate(date, isRelatedToStart) {
+ if (isRelatedToStart) {
+ this.setStartDate({ task: this.task, value: date })
+ } else {
+ this.setDueDate({ task: this.task, value: date })
+ }
},
async changeCalendar(calendar) {