diff --git a/package-lock.json b/package-lock.json
index 7b53113d..cad8e751 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4629,8 +4629,8 @@
"dev": true
},
"cdav-library": {
- "version": "github:nextcloud/cdav-library#ff47e205ef07cd38c174a3d0582f371cd4bc93f9",
- "from": "github:nextcloud/cdav-library",
+ "version": "github:nextcloud/cdav-library#0da67555ae708c903fb11d025397a6f6465b4c39",
+ "from": "github:nextcloud/cdav-library#bugfix/noid/fix_addressbook_calendar_queries",
"requires": {
"@babel/polyfill": "^7.0.0"
}
@@ -5705,7 +5705,7 @@
"dependencies": {
"pify": {
"version": "2.3.0",
- "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
}
@@ -7484,14 +7484,12 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -7506,20 +7504,17 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"core-util-is": {
"version": "1.0.2",
@@ -7636,8 +7631,7 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"ini": {
"version": "1.3.5",
@@ -7649,7 +7643,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -7664,7 +7657,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -7776,8 +7768,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"object-assign": {
"version": "4.1.1",
@@ -7789,7 +7780,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"wrappy": "1"
}
@@ -7911,7 +7901,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -8178,7 +8167,7 @@
"dependencies": {
"pify": {
"version": "2.3.0",
- "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
}
@@ -8212,7 +8201,7 @@
"dependencies": {
"minimist": {
"version": "1.1.3",
- "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.1.3.tgz",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.1.3.tgz",
"integrity": "sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag=",
"dev": true
}
@@ -16139,7 +16128,7 @@
},
"through": {
"version": "2.3.8",
- "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
"dev": true
},
@@ -16766,8 +16755,7 @@
"uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
- "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
- "dev": true
+ "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
},
"v-tooltip": {
"version": "2.0.0-rc.33",
diff --git a/package.json b/package.json
index 3d160f03..8b75cc01 100644
--- a/package.json
+++ b/package.json
@@ -27,11 +27,12 @@
"dependencies": {
"@babel/polyfill": "^7.0.0",
"axios": "^0.18.0",
- "cdav-library": "github:nextcloud/cdav-library",
+ "cdav-library": "github:nextcloud/cdav-library#bugfix/noid/fix_addressbook_calendar_queries",
"ical.js": "~1.2.2",
"jstimezonedetect": "",
"nextcloud-vue": "^0.3.1",
"p-limit": "^2.0.0",
+ "uuid": "^3.3.2",
"v-tooltip": "2.0.0-rc.33",
"vue": "^2.5.17",
"vue-router": "3.0.1",
diff --git a/src/app.vue b/src/app.vue
index 6b4152fd..b4a06ed8 100644
--- a/src/app.vue
+++ b/src/app.vue
@@ -82,7 +82,7 @@ export default {
Promise.all(this.calendars.map(calendar => this.$store.dispatch('getTasksFromCalendar', { calendar })))
.then(results => {
this.loading = false
- console.log(results)
+ // console.log(results)
})
}
}
diff --git a/src/components/Task.vue b/src/components/Task.vue
index 9fce8bf9..73a210c7 100644
--- a/src/components/Task.vue
+++ b/src/components/Task.vue
@@ -72,8 +72,8 @@ License along with this library. If not, see .
{{ task.summary }}
-
- {{ category.name }}
+
+ {{ category }}
diff --git a/src/components/TheDetails.vue b/src/components/TheDetails.vue
index b172dbad..1c6611e8 100644
--- a/src/components/TheDetails.vue
+++ b/src/components/TheDetails.vue
@@ -199,8 +199,6 @@ License along with this library. If not, see .
:tag-placeholder="t('tasks', 'Add this as a new category')"
:close-on-select="false"
class="multiselect-vue"
- track-by="id"
- label="name"
@input="updateCategories"
@tag="addCategory" />
diff --git a/src/models/task.js b/src/models/task.js
index 81484fa7..ffd3deba 100644
--- a/src/models/task.js
+++ b/src/models/task.js
@@ -1,2 +1,206 @@
-export default class {
+/**
+ * Nextcloud - Tasks
+ *
+ * @author John Molakvoæ
+ * @copyright 2018 John Molakvoæ
+ *
+ * @author Raimund Schlüßler
+ * @copyright 2018 Raimund Schlüßler
+ *
+ * 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 .
+ *
+ */
+
+import uuid from 'uuid'
+import ICAL from 'ical.js'
+
+export default class Task {
+
+ /**
+ * Creates an instance of Task
+ *
+ * @param {string} vcalendar the vcalendar data as string with proper new lines
+ * @param {object} calendar the calendar which the task belongs to
+ * @memberof Task
+ */
+ constructor(vcalendar, calendar, raw) {
+ if (typeof vcalendar !== 'string' || vcalendar.length === 0) {
+ throw new Error('Invalid vCalendar')
+ }
+ this.vcalendar = vcalendar
+
+ let jCal = ICAL.parse(vcalendar)
+ if (jCal[0] !== 'vcalendar') {
+ throw new Error('Only one task is allowed in the vCalendar data')
+ }
+
+ this.jCal = jCal
+ this.calendar = calendar
+ this.vCalendar = new ICAL.Component(this.jCal)
+
+ // used to state a task is not up to date with
+ // the server and cannot be pushed (etag)
+ this.conflict = false
+
+ // if no uid set, create one
+ var vtodo = this.vCalendar.getFirstSubcomponent('vtodo')
+ if (!vtodo.hasProperty('uid')) {
+ console.debug('This task did not have a proper uid. Setting a new one for ', this)
+ vtodo.addPropertyWithValue('uid', uuid())
+ }
+
+ this.uri = raw.url.substr(raw.url.lastIndexOf('/') + 1)
+ }
+
+ /**
+ * Update internal data of this task
+ *
+ * @param {jCal} jCal jCal object from ICAL.js
+ * @memberof Task
+ */
+ updateTask(jCal) {
+ this.jCal = jCal
+ this.vCalendar = new ICAL.Component(this.jCal)
+ }
+
+ /**
+ * Update linked calendar of this task
+ *
+ * @param {Object} calendar the calendar
+ * @memberof Contact
+ */
+ updateCalendar(calendar) {
+ this.calendar = calendar
+ }
+
+ /**
+ * Ensure we're normalizing the possible arrays
+ * into a string by taking the first element
+ * e.g. ORG:ABC\, Inc.; will output an array because of the semi-colon
+ *
+ * @param {Array|string} data the data to normalize
+ * @returns {string}
+ * @memberof Task
+ */
+ firstIfArray(data) {
+ return Array.isArray(data) ? data[0] : data
+ }
+
+ /**
+ * Return the url
+ *
+ * @readonly
+ * @memberof Task
+ */
+ get url() {
+ if (this.dav) {
+ return this.dav.url
+ }
+ return ''
+ }
+
+ /**
+ * Return the uid
+ *
+ * @readonly
+ * @memberof Task
+ */
+ get uid() {
+ var vtodo = this.vCalendar.getFirstSubcomponent('vtodo')
+ return vtodo.getFirstPropertyValue('uid') || ''
+ }
+
+ /**
+ * Set the uid
+ *
+ * @param {string} uid the uid to set
+ * @memberof Task
+ */
+ set uid(uid) {
+ this.vCalendar.updatePropertyWithValue('uid', uid)
+ this.vcalendar = this.vCalendar.toString()
+ return true
+ }
+
+ /**
+ * Return the first summary
+ *
+ * @readonly
+ * @memberof Task
+ */
+ get summary() {
+ var vtodo = this.vCalendar.getFirstSubcomponent('vtodo')
+ return vtodo.getFirstPropertyValue('summary');
+ }
+
+ /**
+ * Set the summary
+ *
+ * @param {string} summary the summary
+ * @memberof Task
+ */
+ set summary(summary) {
+ var vtodo = this.vCalendar.getFirstSubcomponent('vtodo')
+ vtodo.updatePropertyWithValue('summary', summary)
+ this.updateLastModified()
+ this.vcalendar = this.vCalendar.toString()
+ }
+
+ /**
+ * Return the categories
+ *
+ * @readonly
+ * @memberof Task
+ */
+ get categories() {
+ var vtodo = this.vCalendar.getFirstSubcomponent('vtodo')
+ var categories = vtodo.getFirstProperty('categories')
+ if (categories) {
+ return categories.getValues()
+ } else {
+ return []
+ }
+ }
+
+ /**
+ * Set the categories
+ *
+ * @param {string} categories the categories
+ * @memberof Task
+ */
+ set categories(cats) {
+ var vtodo = this.vCalendar.getFirstSubcomponent('vtodo')
+ var categories = vtodo.getFirstProperty('categories')
+ if (cats.length > 0) {
+ if (categories) {
+ categories.setValues(cats)
+ } else {
+ var prop = new ICAL.Property('categories')
+ prop.setValues(cats)
+ categories = vtodo.addProperty(prop)
+ }
+ } else {
+ vtodo.removeProperty('categories')
+ }
+ this.updateLastModified()
+ this.vcalendar = this.vCalendar.toString()
+ }
+
+ updateLastModified () {
+ var vtodo = this.vCalendar.getFirstSubcomponent('vtodo')
+ vtodo.updatePropertyWithValue('last-modified', ICAL.Time.now())
+ vtodo.updatePropertyWithValue('dtstamp', ICAL.Time.now())
+ }
+
}
diff --git a/src/store/calendars.js b/src/store/calendars.js
index ba1a0f51..35ec09bf 100644
--- a/src/store/calendars.js
+++ b/src/store/calendars.js
@@ -31,7 +31,6 @@
import Vue from 'vue'
import ICAL from 'ical.js'
-import parseIcs from '../services/parseIcs'
import client from '../services/cdav'
import Task from '../models/task'
import pLimit from 'p-limit'
@@ -258,14 +257,7 @@ const mutations = {
appendTasksToCalendar(state, { calendar, tasks }) {
calendar = state.calendars.find(search => search === calendar)
- // convert list into an array and remove duplicate
- calendar.tasks = tasks.reduce((list, task) => {
- if (list[task.uid]) {
- console.debug('Duplicate task overridden', list[task.uid], task)
- }
- Vue.set(list, task.uid, task)
- return list
- }, calendar.tasks)
+ Vue.set(calendar, 'tasks', tasks)
},
/**
@@ -449,12 +441,12 @@ const actions = {
// We don't want to lose the url information
// so we need to parse one by one
const tasks = response.map(item => {
- let task = new Task(item.data, calendar)
+ let task = new Task(item.data, calendar, item)
Vue.set(task, 'dav', item)
return task
})
context.commit('appendTasksToCalendar', { calendar, tasks })
- context.commit('appendTasks', tasks)
+ // context.commit('appendTasks', tasks)
return tasks
})
.catch((error) => {
diff --git a/src/store/tasks.js b/src/store/tasks.js
index e6de0105..e98bb93b 100644
--- a/src/store/tasks.js
+++ b/src/store/tasks.js
@@ -80,6 +80,9 @@ const getters = {
// If a calendar is given, only search in that calendar.
if (rootState.route.params.calendarId) {
var calendar = getters.getCalendarById(rootState.route.params.calendarId)
+ if (!calendar) {
+ return null
+ }
return calendar.tasks.find(task => {
return task.uri === rootState.route.params.taskId
})