Merge pull request #414 from nextcloud/delete-completed

Allow to delete completed tasks, closes #69
This commit is contained in:
Raimund Schlüßler 2019-05-22 14:54:06 +02:00 committed by GitHub
commit d99f62fdb8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 199 additions and 4 deletions

View file

@ -1345,3 +1345,36 @@
box-shadow: 0 0 0 0 rgba(50, 50, 50, 0);
}
}
.delete-completed {
margin: 50px;
width: auto;
min-width: 30vw;
&__button {
display: inline-block;
padding: 10px;
padding-left: 34px;
background-position: 10px center;
text-align: left;
margin: 0;
width: unset !important;
height: unset !important;
background-size: unset !important;
}
&__header {
padding-top: 20px;
max-width: 80%;
margin: 12px auto;
}
&__progress {
width: 80%;
margin: auto;
}
&__tracker {
display: flex;
justify-content: space-between;
width: 80%;
margin: auto;
padding-top: 10px;
}
}

View file

@ -0,0 +1,152 @@
<!--
Nextcloud - Tasks
@author Raimund Schlüßler
@copyright 2019 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>
<div class="loadmore reactive">
<span v-show="completedTasksCount" @click="openModal">
{{ t('tasks', 'Delete all completed tasks.') }}
</span>
<Modal v-if="modalOpen"
:out-transition="true"
@close="closeModal"
>
<div class="emptycontent delete-completed">
<p class="icon-delete" />
<div v-if="completedTasksCount">
<h3 class="delete-completed__header">
{{ n('tasks',
'This will delete {taskCount} completed task and its subtasks from calendar "{calendarName}".',
'This will delete {taskCount} completed tasks and their subtasks from calendar "{calendarName}".',
initialCompletedRootTasksCount,
{
taskCount: initialCompletedRootTasksCount,
calendarName: calendar.displayName
}
) }}
</h3>
<button class="delete-completed__button icon-delete" type="button"
@click="deleteCompletedTasks"
>
{{ t('tasks', 'Delete completed tasks.') }}
</button>
</div>
<div v-else>
<h3 class="delete-completed__header">
{{ t('tasks', 'Deleted all completed tasks from calendar "{calendarName}".', {calendarName: calendar.displayName}) }}
</h3>
</div>
<div>
<progress :max="initialCompletedTasksCount" :value="progress" class="delete-completed__progress" />
<p class="delete-completed__tracker">
<span>{{ percentage }} %</span>
<span v-if="failed === 0">
{{ t('tasks', 'No errors') }}
</span>
<span v-else v-tooltip.auto="t('tasks', 'Open your browser console for more details')">
{{ n('tasks',
'Could not delete {failedCount} task.',
'Could not delete {failedCount} tasks.',
failed,
{ failedCount: failed }
) }}
</span>
</p>
</div>
</div>
</Modal>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import { Modal } from 'nextcloud-vue'
export default {
components: {
Modal,
},
props: {
calendar: {
type: Object,
required: true
}
},
data() {
return {
modalOpen: false,
initialCompletedTasksCount: 0,
initialCompletedRootTasksCount: 0,
}
},
computed: {
loadedCompleted() {
return this.calendar.loadedCompleted
},
tasks() {
return this.completedRootTasks(this.calendar.tasks)
},
completedTasksCount() {
var completedCount = function counter(tasks) {
var i = tasks.length
tasks.map((task) => {
i += counter(Object.values(task.subTasks))
})
return i
}
return completedCount(this.tasks)
},
failed() {
return 0
},
progress() {
return this.initialCompletedTasksCount - this.completedTasksCount
},
percentage() {
return this.initialCompletedTasksCount <= 0
? 0
: Math.floor(this.progress / this.initialCompletedTasksCount * 100)
},
...mapGetters({
completedCount: 'getCalendarCountCompleted',
completedRootTasks: 'findCompletedRootTasks',
}),
},
methods: {
...mapActions([
'deleteTask',
]),
openModal() {
this.modalOpen = true
this.initialCompletedTasksCount = this.completedTasksCount
// Number of completed root tasks
this.initialCompletedRootTasksCount = this.tasks.length
},
closeModal() {
this.modalOpen = false
},
deleteCompletedTasks() {
this.tasks.map(
(task) => this.deleteTask({ task: task, dav: true })
)
}
},
}
</script>

View file

@ -65,6 +65,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
/>
</task-drag-container>
<LoadCompletedButton :calendar="calendar" />
<DeleteCompletedModal v-if="calendar.loadedCompleted" :calendar="calendar" />
</div>
</div>
</div>
@ -75,6 +76,7 @@ import { mapGetters, mapActions } from 'vuex'
import { sort } from '../../store/storeHelper'
import SortorderDropdown from '../SortorderDropdown'
import LoadCompletedButton from '../LoadCompletedButton'
import DeleteCompletedModal from '../DeleteCompletedModal'
import Task from '../Task'
import TaskDragContainer from '../TaskDragContainer'
@ -84,6 +86,7 @@ export default {
'SortorderDropdown': SortorderDropdown,
'LoadCompletedButton': LoadCompletedButton,
TaskDragContainer,
DeleteCompletedModal,
},
props: {
calendarId: {

View file

@ -634,6 +634,12 @@ const actions = {
* @param {Boolean} [data.dav = true] Trigger a dav deletion
*/
async deleteTask(context, { task, dav = true }) {
function deleteTaskFromStore() {
context.commit('deleteTask', task)
let parent = context.getters.getTaskByUid(task.related)
context.commit('deleteTaskFromParent', { task: task, parent: parent })
context.commit('deleteTaskFromCalendar', task)
}
// delete all subtasks first
await Promise.all(Object.values(task.subTasks).map(async(subTask) => {
await context.dispatch('deleteTask', { task: subTask, dav: true })
@ -641,15 +647,16 @@ const actions = {
// only local delete if the task doesn't exists on the server
if (task.dav && dav) {
await task.dav.delete()
.then(() => {
deleteTaskFromStore()
})
.catch((error) => {
console.debug(error)
task.syncstatus = new TaskStatus('error', t('tasks', 'Could not delete the task.'))
})
} else {
deleteTaskFromStore()
}
context.commit('deleteTask', task)
let parent = context.getters.getTaskByUid(task.related)
context.commit('deleteTaskFromParent', { task: task, parent: parent })
context.commit('deleteTaskFromCalendar', task)
},
/**