Merge pull request #236 from nextcloud/drag-and-drop
Implement drag and drop, fixes #78
This commit is contained in:
commit
7a651fe68b
11 changed files with 351 additions and 57 deletions
|
@ -451,6 +451,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.sortable-ghost .task-body {
|
||||
background-color: rgba( $color-primary, .3 );
|
||||
}
|
||||
|
||||
&.dragover > div.subtasks-container > ol {
|
||||
min-height: 37px;
|
||||
}
|
||||
|
||||
.subtasks-container {
|
||||
margin-left: 35px;
|
||||
|
||||
|
|
13
package-lock.json
generated
13
package-lock.json
generated
|
@ -13614,6 +13614,11 @@
|
|||
"kind-of": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"sortablejs": {
|
||||
"version": "1.8.4",
|
||||
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.8.4.tgz",
|
||||
"integrity": "sha512-Brqnzelu1AhFuc0Fn3N/qFex1tlIiuQIUsfu2J8luJ4cRgXYkWrByxa+y5mWEBlj8A0YoABukflIJwvHyrwJ6Q=="
|
||||
},
|
||||
"source-list-map": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
|
||||
|
@ -15839,6 +15844,14 @@
|
|||
"fecha": "^2.3.3"
|
||||
}
|
||||
},
|
||||
"vuedraggable": {
|
||||
"version": "2.20.0",
|
||||
"resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.20.0.tgz",
|
||||
"integrity": "sha512-mrSWGkzY40nkgLDuuoxrs6/0u+A7VwXtQRruLQYOVjwd8HcT3BZatRvzw4qVCwJczsAYPbaMubkGOEtzDOzhsQ==",
|
||||
"requires": {
|
||||
"sortablejs": "^1.8.4"
|
||||
}
|
||||
},
|
||||
"vuex": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.1.0.tgz",
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
"vue": "^2.6.10",
|
||||
"vue-clipboard2": "^0.3.0",
|
||||
"vue-router": "3.0.6",
|
||||
"vuedraggable": "^2.20.0",
|
||||
"vuex": "^3.1.0",
|
||||
"vuex-router-sync": "^5.0.0"
|
||||
},
|
||||
|
|
|
@ -113,13 +113,16 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
>
|
||||
</form>
|
||||
</div>
|
||||
<ol v-if="!task.hideSubtasks || searchQuery" :calendarID="task.calendar.uri">
|
||||
<task-drag-container v-if="!task.hideSubtasks || searchQuery"
|
||||
:task-id="task.uri"
|
||||
:calendar-id="task.calendar.uri"
|
||||
>
|
||||
<TaskBodyComponent v-for="subtask in filteredSubtasks"
|
||||
:key="subtask.uid"
|
||||
:task="subtask"
|
||||
class="subtask"
|
||||
/>
|
||||
</ol>
|
||||
</task-drag-container>
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
|
@ -131,6 +134,7 @@ import { mapGetters, mapActions } from 'vuex'
|
|||
import focus from '../directives/focus'
|
||||
import { linkify } from '../directives/linkify.js'
|
||||
import TaskStatusDisplay from './TaskStatusDisplay'
|
||||
import TaskDragContainer from './TaskDragContainer'
|
||||
|
||||
export default {
|
||||
name: 'TaskBodyComponent',
|
||||
|
@ -141,6 +145,7 @@ export default {
|
|||
},
|
||||
components: {
|
||||
TaskStatusDisplay,
|
||||
TaskDragContainer,
|
||||
},
|
||||
filters: {
|
||||
formatDate: function(date) {
|
||||
|
@ -311,7 +316,7 @@ export default {
|
|||
|
||||
this.createTask(task)
|
||||
this.newTaskName = ''
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
194
src/components/TaskDragContainer.vue
Normal file
194
src/components/TaskDragContainer.vue
Normal file
|
@ -0,0 +1,194 @@
|
|||
<!--
|
||||
Nextcloud - Tasks
|
||||
|
||||
@author Raimund Schlüßler
|
||||
@copyright 2018 Raimund Schlüßler <raimund.schluessler@mailbox.org>
|
||||
|
||||
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/>.
|
||||
|
||||
-->
|
||||
|
||||
<template>
|
||||
<draggable tag="ol"
|
||||
:list="['']"
|
||||
v-bind="{group: 'tasks', swapThreshold: 0.30}"
|
||||
:move="onMove"
|
||||
@end="onEnd"
|
||||
>
|
||||
<slot :move="onMove" />
|
||||
</draggable>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
import { mapGetters, mapActions } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
draggable,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getCalendar: 'getCalendarById',
|
||||
getTask: 'getTaskByUri',
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
...mapActions([
|
||||
'moveTask',
|
||||
'setPriority',
|
||||
'setPercentComplete',
|
||||
'setDue',
|
||||
'setStart',
|
||||
]),
|
||||
|
||||
/**
|
||||
* Called when a task is dragged.
|
||||
*
|
||||
* @param {Object} $event The event which caused the move
|
||||
*/
|
||||
onMove: function($event) {
|
||||
this.cleanUpDragging()
|
||||
$event.related.classList.add('dragover')
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a task is dropped.
|
||||
*
|
||||
* @param {Object} $event The event which caused the drop
|
||||
*/
|
||||
onEnd: function($event) {
|
||||
var task
|
||||
// The task to move
|
||||
var taskAttribute = $event.item.attributes['task-id']
|
||||
if (taskAttribute) {
|
||||
task = this.getTask(taskAttribute.value)
|
||||
}
|
||||
// Move the task to a new calendar or parent.
|
||||
this.prepareMoving(task, $event)
|
||||
this.prepareCollecting(task, $event)
|
||||
this.cleanUpDragging()
|
||||
$event.stopPropagation()
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when we stopped dragging. Cleans up temporarily added classes.
|
||||
*/
|
||||
cleanUpDragging: function() {
|
||||
var items = document.getElementsByClassName('task-item')
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
items[i].classList.remove('dragover')
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Function to move a task to a new calendar or parent
|
||||
*
|
||||
* @param {Task} task The task to change
|
||||
* @param {Object} $event The event which caused the move
|
||||
*/
|
||||
prepareMoving: function(task, $event) {
|
||||
var parent, calendar
|
||||
// The new calendar --> make the moved task a root task
|
||||
var calendarAttribute = $event.to.attributes['calendar-id']
|
||||
if (calendarAttribute) {
|
||||
calendar = this.getCalendar(calendarAttribute.value)
|
||||
}
|
||||
// The new parent task --> make the moved task a subtask
|
||||
var parentAttribute = $event.to.attributes['task-id']
|
||||
if (parentAttribute) {
|
||||
parent = this.getTask(parentAttribute.value)
|
||||
// If we move to a parent task, the calendar has to be the parents calendar.
|
||||
calendar = parent.calendar
|
||||
}
|
||||
// If no calendar is given (e.g. in week collection), the calendar is unchanged.
|
||||
if (!calendar) {
|
||||
calendar = task.calendar
|
||||
}
|
||||
// Move the task to the appropriate calendar and parent.
|
||||
this.moveTask({ task: task, calendar: calendar, parent: parent })
|
||||
},
|
||||
|
||||
/**
|
||||
* Function to add a task to a collection.
|
||||
*
|
||||
* @param {Task} task The task to change
|
||||
* @param {Object} $event The event which caused the change
|
||||
*/
|
||||
prepareCollecting: function(task, $event) {
|
||||
// The new collection --> make the moved task a member of this collection
|
||||
// This is necessary for the collections {starred, today, completed, uncompleted and week}
|
||||
var collectionAttribute = $event.to.attributes['collection-id']
|
||||
if (collectionAttribute) {
|
||||
var collectionId = collectionAttribute.value
|
||||
// Split the collectionId in case we deal with 'week-x'
|
||||
collectionId = collectionId.split('-')
|
||||
switch (collectionId[0]) {
|
||||
case 'starred':
|
||||
this.setPriority({ task: task, priority: 1 })
|
||||
break
|
||||
case 'completed':
|
||||
this.setPercentComplete({ task: task, complete: 100 })
|
||||
break
|
||||
case 'uncompleted':
|
||||
if (task.completed) {
|
||||
this.setPercentComplete({ task: task, complete: 0 })
|
||||
}
|
||||
break
|
||||
case 'today':
|
||||
this.setDate(task, 0)
|
||||
break
|
||||
case 'week':
|
||||
this.setDate(task, collectionId[1])
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the start or due date to the given day
|
||||
*
|
||||
* @param {Task} task The task to change
|
||||
* @param {Integer} day The day to set
|
||||
*/
|
||||
setDate: function(task, day) {
|
||||
var start = moment(task.start, 'YYYYMMDDTHHmmss').startOf('day')
|
||||
var due = moment(task.due, 'YYYYMMDDTHHmmss').startOf('day')
|
||||
day = moment().startOf('day').add(day, 'days')
|
||||
|
||||
var diff
|
||||
// Adjust start date
|
||||
if (start.isValid()) {
|
||||
diff = start.diff(moment().startOf('day'), 'days')
|
||||
diff = diff < 0 ? 0 : diff
|
||||
if (diff !== day) {
|
||||
var newStart = moment(task.start, 'YYYYMMDDTHHmmss').year(day.year()).month(day.month()).date(day.date())
|
||||
this.setStart({ task: task, start: newStart })
|
||||
}
|
||||
// Adjust due date
|
||||
} else if (due.isValid()) {
|
||||
diff = due.diff(moment().startOf('day'), 'days')
|
||||
diff = diff < 0 ? 0 : diff
|
||||
if (diff !== day) {
|
||||
var newDue = moment(task.due, 'YYYYMMDDTHHmmss').year(day.year()).month(day.month()).date(day.date())
|
||||
this.setDue({ task: task, due: newDue })
|
||||
}
|
||||
// Set the due date to appropriate value
|
||||
} else {
|
||||
this.setDue({ task: task, due: day })
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -39,30 +39,31 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
<SortorderDropdown />
|
||||
<div class="task-list">
|
||||
<div class="grouped-tasks">
|
||||
<ol :calendarId="calendarId"
|
||||
<task-drag-container
|
||||
:calendar-id="calendarId"
|
||||
class="tasks"
|
||||
collectionId="uncompleted"
|
||||
collection-id="uncompleted"
|
||||
type="list"
|
||||
>
|
||||
<Task v-for="task in sort(uncompletedRootTasks(calendar.tasks), sortOrder, sortDirection)"
|
||||
:key="task.id"
|
||||
:task="task"
|
||||
/>
|
||||
</ol>
|
||||
</task-drag-container>
|
||||
<h2 v-show="completedCount(calendarId)" class="heading-hiddentasks icon-triangle-s reactive" @click="toggleHidden">
|
||||
{{ completedCountString }}
|
||||
</h2>
|
||||
<ol v-if="showHidden"
|
||||
:calendarId="calendarId"
|
||||
<task-drag-container v-if="showHidden"
|
||||
:calendar-id="calendarId"
|
||||
class="completed-tasks"
|
||||
collectionId="completed"
|
||||
collection-id="completed"
|
||||
type="list"
|
||||
>
|
||||
<Task v-for="task in sort(completedRootTasks(calendar.tasks), sortOrder, sortDirection)"
|
||||
:key="task.id"
|
||||
:task="task"
|
||||
/>
|
||||
</ol>
|
||||
</task-drag-container>
|
||||
<LoadCompletedButton :calendar="calendar" />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -75,12 +76,14 @@ import { sort } from '../../store/storeHelper'
|
|||
import SortorderDropdown from '../SortorderDropdown'
|
||||
import LoadCompletedButton from '../LoadCompletedButton'
|
||||
import Task from '../Task'
|
||||
import TaskDragContainer from '../TaskDragContainer'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
'Task': Task,
|
||||
'SortorderDropdown': SortorderDropdown,
|
||||
'LoadCompletedButton': LoadCompletedButton
|
||||
'LoadCompletedButton': LoadCompletedButton,
|
||||
TaskDragContainer,
|
||||
},
|
||||
props: {
|
||||
calendarId: {
|
||||
|
@ -146,7 +149,15 @@ export default {
|
|||
addTask: function() {
|
||||
this.createTask({ summary: this.newTaskName, calendar: this.calendar })
|
||||
this.newTaskName = ''
|
||||
}
|
||||
},
|
||||
|
||||
onMove: function($event, $originalEvent) {
|
||||
console.debug($event)
|
||||
console.debug($event.target)
|
||||
console.debug($event.to)
|
||||
// console.debug('target: ' + $event.target.attributes['task-id'].value)
|
||||
// console.debug('to: ' + $event.to.attributes['task-id'].value)
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -45,8 +45,9 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
<h2 class="heading">
|
||||
{{ calendar.displayName }}
|
||||
</h2>
|
||||
<ol :calendarID="calendar.id"
|
||||
:collectionID="collectionId"
|
||||
<task-drag-container
|
||||
:calendar-id="calendar.id"
|
||||
:collection-id="collectionId"
|
||||
class="tasks"
|
||||
type="list"
|
||||
>
|
||||
|
@ -54,7 +55,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
:key="task.id"
|
||||
:task="task"
|
||||
/>
|
||||
</ol>
|
||||
</task-drag-container>
|
||||
<LoadCompletedButton v-if="collectionId === 'completed'" :calendar="calendar" />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -67,12 +68,14 @@ import { sort, isTaskInList, isParentInList } from '../../store/storeHelper'
|
|||
import SortorderDropdown from '../SortorderDropdown'
|
||||
import LoadCompletedButton from '../LoadCompletedButton'
|
||||
import TaskBody from '../Task'
|
||||
import TaskDragContainer from '../TaskDragContainer'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
'TaskBody': TaskBody,
|
||||
'SortorderDropdown': SortorderDropdown,
|
||||
'LoadCompletedButton': LoadCompletedButton
|
||||
'LoadCompletedButton': LoadCompletedButton,
|
||||
TaskDragContainer,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -28,16 +28,16 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
<h2 class="heading">
|
||||
{{ day.diff | formatDay }}
|
||||
</h2>
|
||||
<ol collectionID="week"
|
||||
<task-drag-container
|
||||
:collection-id="'week-' + day.diff"
|
||||
class="tasks"
|
||||
listID=""
|
||||
type="list"
|
||||
>
|
||||
<TaskBody v-for="task in sort(day.tasks, sortOrder, sortDirection)"
|
||||
:key="task.id"
|
||||
:task="task"
|
||||
/>
|
||||
</ol>
|
||||
</task-drag-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -48,11 +48,13 @@ import { mapGetters } from 'vuex'
|
|||
import { sort } from '../../store/storeHelper'
|
||||
import SortorderDropdown from '../SortorderDropdown'
|
||||
import TaskBody from '../Task'
|
||||
import TaskDragContainer from '../TaskDragContainer'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
'TaskBody': TaskBody,
|
||||
'SortorderDropdown': SortorderDropdown
|
||||
'SortorderDropdown': SortorderDropdown,
|
||||
TaskDragContainer,
|
||||
},
|
||||
filters: {
|
||||
formatDay: function(day) {
|
||||
|
|
|
@ -546,7 +546,7 @@ export default {
|
|||
'setDue',
|
||||
'setStart',
|
||||
'toggleAllDay',
|
||||
'moveTaskToCalendar',
|
||||
'moveTask',
|
||||
]),
|
||||
|
||||
removeTask: function() {
|
||||
|
@ -758,7 +758,7 @@ export default {
|
|||
},
|
||||
|
||||
async changeCalendar(calendar) {
|
||||
const task = await this.moveTaskToCalendar({ task: this.task, calendar: calendar })
|
||||
const task = await this.moveTask({ task: this.task, calendar: calendar })
|
||||
// If we are in a calendar view, we have to navigate to the new calendar.
|
||||
if (this.$route.params.calendarId) {
|
||||
this.$router.push('/calendars/' + task.calendar.id + '/tasks/' + task.uri)
|
||||
|
|
|
@ -489,7 +489,8 @@ const actions = {
|
|||
|
||||
// If necessary, add the tasks as subtasks to parent tasks already present in the store.
|
||||
if (!related) {
|
||||
context.commit('addTaskToParent', parent)
|
||||
let parentParent = context.getters.getTaskByUid(parent.related)
|
||||
context.commit('addTaskToParent', { task: parent, parent: parentParent })
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -115,13 +115,49 @@ const getters = {
|
|||
})
|
||||
}
|
||||
// Else, we have to search all calendars
|
||||
return getters.getTaskByUri(rootState.route.params.taskId)
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the task by Uri
|
||||
*
|
||||
* @param {Object} state The store data
|
||||
* @param {Object} getters The store getters
|
||||
* @param {Object} rootState The store root state
|
||||
* @param {String} taskUri The Uri of the task in question
|
||||
* @returns {Task} The task
|
||||
*/
|
||||
getTaskByUri: (state, getters, rootState) => (taskUri) => {
|
||||
// We have to search in all calendars
|
||||
var task
|
||||
for (let calendar of rootState.calendars.calendars) {
|
||||
task = Object.values(calendar.tasks).find(task => {
|
||||
return task.uri === rootState.route.params.taskId
|
||||
return task.uri === taskUri
|
||||
})
|
||||
if (task) return task
|
||||
}
|
||||
return null
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the task by Uri
|
||||
*
|
||||
* @param {Object} state The store data
|
||||
* @param {Object} getters The store getters
|
||||
* @param {Object} rootState The store root state
|
||||
* @param {String} taskUid The Uid of the task in question
|
||||
* @returns {Task} The task
|
||||
*/
|
||||
getTaskByUid: (state, getters, rootState) => (taskUid) => {
|
||||
// We have to search in all calendars
|
||||
var task
|
||||
for (let calendar of rootState.calendars.calendars) {
|
||||
task = Object.values(calendar.tasks).find(task => {
|
||||
return task.uid === taskUid
|
||||
})
|
||||
if (task) return task
|
||||
}
|
||||
return null
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -244,17 +280,14 @@ const mutations = {
|
|||
* Deletes a task from the parent
|
||||
*
|
||||
* @param {Object} state The store data
|
||||
* @param {Task} task The task to delete
|
||||
* @param {Task} task The task to delete from the parents subtask list
|
||||
* @param {Task} parent The paren task
|
||||
*/
|
||||
deleteTaskFromParent(state, task) {
|
||||
deleteTaskFromParent(state, { task, parent }) {
|
||||
if (task instanceof Task) {
|
||||
// Remove task from parents subTask list if necessary
|
||||
if (task.related) {
|
||||
let tasks = task.calendar.tasks
|
||||
let parent = Object.values(tasks).find(search => search.uid === task.related)
|
||||
if (parent) {
|
||||
Vue.delete(parent.subTasks, task.uid)
|
||||
}
|
||||
if (task.related && parent) {
|
||||
Vue.delete(parent.subTasks, task.uid)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -263,15 +296,12 @@ const mutations = {
|
|||
* Adds a task to parent task as subtask
|
||||
*
|
||||
* @param {Object} state The store data
|
||||
* @param {Task} task The task to add
|
||||
* @param {Task} task The task to add to the parents subtask list
|
||||
* @param {Task} parent The paren task
|
||||
*/
|
||||
addTaskToParent(state, task) {
|
||||
if (task.related) {
|
||||
let tasks = task.calendar.tasks
|
||||
let parent = Object.values(tasks).find(search => search.uid === task.related)
|
||||
if (parent) {
|
||||
Vue.set(parent.subTasks, task.uid, task)
|
||||
}
|
||||
addTaskToParent(state, { task, parent }) {
|
||||
if (task.related && parent) {
|
||||
Vue.set(parent.subTasks, task.uid, task)
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -564,7 +594,8 @@ const actions = {
|
|||
task.syncstatus = new TaskStatus('success', 'Successfully created the task.')
|
||||
context.commit('appendTask', task)
|
||||
context.commit('addTaskToCalendar', task)
|
||||
context.commit('addTaskToParent', task)
|
||||
let parent = context.getters.getTaskByUid(task.related)
|
||||
context.commit('addTaskToParent', { task: task, parent: parent })
|
||||
})
|
||||
.catch((error) => { throw error })
|
||||
}
|
||||
|
@ -592,7 +623,8 @@ const actions = {
|
|||
})
|
||||
}
|
||||
context.commit('deleteTask', task)
|
||||
context.commit('deleteTaskFromParent', task)
|
||||
let parent = context.getters.getTaskByUid(task.related)
|
||||
context.commit('deleteTaskFromParent', { task: task, parent: parent })
|
||||
context.commit('deleteTaskFromCalendar', task)
|
||||
},
|
||||
|
||||
|
@ -829,34 +861,54 @@ const actions = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Moves a task to the provided calendar
|
||||
* Moves a task to a new parent task
|
||||
*
|
||||
* @param {Object} context The store mutations
|
||||
* @param {Object} data Destructuring object
|
||||
* @param {Task} data.task The task to move
|
||||
* @param {Task} data.parent The new parent task
|
||||
*/
|
||||
async setTaskParent(context, { task, parent }) {
|
||||
var parentId = parent ? parent.uid : null
|
||||
// Only update the parent in case it differs from the current one.
|
||||
if (task.related !== parentId) {
|
||||
// Remove the task from the old parents subtask list
|
||||
let oldParent = context.getters.getTaskByUid(task.related)
|
||||
context.commit('deleteTaskFromParent', { task: task, parent: oldParent })
|
||||
// Link to new parent
|
||||
Vue.set(task, 'related', parentId)
|
||||
// Add task to new parents subtask list
|
||||
if (parent) {
|
||||
Vue.set(parent.subTasks, task.uid, task)
|
||||
// If the parent is completed, we complete the task
|
||||
if (parent.completed) {
|
||||
await context.dispatch('setPercentComplete', { task: task, complete: 100 })
|
||||
}
|
||||
}
|
||||
// We have to send an update.
|
||||
await context.dispatch('scheduleTaskUpdate', task)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Moves a task to a new calendar or parent task
|
||||
*
|
||||
* @param {Object} context The store mutations
|
||||
* @param {Object} data Destructuring object
|
||||
* @param {Task} data.task The task to move
|
||||
* @param {Calendar} data.calendar The calendar to move the task to
|
||||
* @param {Boolean} data.removeParent If the task has a parent, remove the link to the parent
|
||||
* @param {Task} data.parent The new parent task
|
||||
* @returns {Task} The moved task
|
||||
*/
|
||||
async moveTaskToCalendar(context, { task, calendar, removeParent = true }) {
|
||||
// Only local move if the task doesn't exist on the server.
|
||||
async moveTask(context, { task, calendar, parent = null }) {
|
||||
|
||||
// Don't move if source and target calendar are the same.
|
||||
if (task.dav && task.calendar !== calendar) {
|
||||
// Move all subtasks first
|
||||
await Promise.all(Object.values(task.subTasks).map(async(subTask) => {
|
||||
await context.dispatch('moveTaskToCalendar', { task: subTask, calendar: calendar, removeParent: false })
|
||||
await context.dispatch('moveTask', { task: subTask, calendar: calendar, parent: task })
|
||||
}))
|
||||
|
||||
// If a task has a parent task which is not moved, remove the reference to it.
|
||||
if (removeParent && task.related !== null) {
|
||||
// Remove the task from the parents subtask list
|
||||
context.commit('deleteTaskFromParent', task)
|
||||
// Unlink the related parent task
|
||||
context.commit('setTaskParent', { task: task, related: null })
|
||||
// We have to send an update.
|
||||
await context.dispatch('updateTask', task)
|
||||
}
|
||||
|
||||
await task.dav.move(calendar.dav)
|
||||
.then((response) => {
|
||||
context.commit('deleteTaskFromCalendar', task)
|
||||
|
@ -871,6 +923,10 @@ const actions = {
|
|||
OC.Notification.showTemporary(t('calendars', 'An error occurred'))
|
||||
})
|
||||
}
|
||||
|
||||
// Set the new parent
|
||||
await context.dispatch('setTaskParent', { task: task, parent: parent })
|
||||
|
||||
return task
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue