Add reordering tasks

This commit is contained in:
kolaente 2021-07-27 18:04:00 +02:00
parent 7434640525
commit 5a29982e99
Signed by: konrad
GPG Key ID: F40E70337AB24C9B
6 changed files with 85 additions and 30 deletions

View File

@ -33,6 +33,7 @@
"vue-i18n": "8.25.0",
"vue-shortkey": "3.1.7",
"vue-smooth-dnd": "0.8.1",
"vuedraggable": "^2.24.3",
"vuex": "3.6.2",
"workbox-precaching": "6.1.5"
},

View File

@ -66,6 +66,12 @@ export default {
this.labelService = new LabelService()
this.labelTaskService = new LabelTaskService()
},
props: {
defaultPosition: {
type: Number,
required: false,
},
},
methods: {
addTask() {
if (this.newTaskTitle === '') {
@ -74,7 +80,7 @@ export default {
}
this.errorMessage = ''
this.createNewTask(this.newTaskTitle, 0, this.$store.state.auth.settings.defaultListId)
this.createNewTask(this.newTaskTitle, 0, this.$store.state.auth.settings.defaultListId, this.defaultPosition)
.then(task => {
this.newTaskTitle = ''
this.$emit('taskAdded', task)

View File

@ -22,7 +22,7 @@ export default {
labels: state => state.labels.labels,
}),
methods: {
createNewTask(newTaskTitle, bucketId = 0, lId = 0) {
createNewTask(newTaskTitle, bucketId = 0, lId = 0, position = 0) {
const parsedTask = parseTaskText(newTaskTitle)
const assignees = []
@ -57,6 +57,7 @@ export default {
priority: parsedTask.priority,
assignees: assignees,
bucketId: bucketId,
position: position,
})
return this.taskService.create(task)
.then(task => {

View File

@ -1,5 +1,6 @@
import TaskCollectionService from '../../../services/taskCollection'
import cloneDeep from 'lodash/cloneDeep'
import {calculateTaskPosition} from '../../../helpers/calculateTaskPosition'
/**
* This mixin provides a base set of methods and properties to get tasks on a list.
@ -20,7 +21,7 @@ export default {
showTaskFilter: false,
params: {
sort_by: ['done', 'id'],
sort_by: ['position', 'id'],
order_by: ['asc', 'desc'],
filter_by: ['done'],
filter_value: ['false'],
@ -187,5 +188,23 @@ export default {
},
}
},
saveTaskPosition(e) {
console.log(e.oldIndex, e.newIndex)
console.log('elem', this.tasks[e.newIndex].title)
const task = this.tasks[e.newIndex]
const taskBefore = this.tasks[e.newIndex - 1] ?? null
const taskAfter = this.tasks[e.newIndex + 1] ?? null
task.position = calculateTaskPosition(taskBefore !== null ? taskBefore.position : null, taskAfter !== null ? taskAfter.position : null)
this.$store.dispatch('tasks/update', task)
.then(r => {
this.$set(this.tasks, e.newIndex, r)
})
.catch(e => {
this.error(e)
})
},
},
}

View File

@ -21,7 +21,7 @@
v-model="searchTerm"
/>
<span class="icon is-left">
<icon icon="search" />
<icon icon="search"/>
</span>
</div>
<div class="control">
@ -63,16 +63,15 @@
<add-task
@taskAdded="updateTaskList"
ref="newTaskInput"
:default-position="firstNewPosition"
/>
</template>
<nothing v-if="ctaVisible && tasks.length === 0 && !taskCollectionService.loading">
{{ $t('list.list.empty') }}
<a @click="focusNewTaskInput()">
{{ $t('list.list.newTaskCta') }}
</a>
</nothing>
<div class="tasks-container">
@ -81,23 +80,25 @@
class="tasks mt-0"
v-if="tasks && tasks.length > 0"
>
<single-task-in-list
:show-list-color="false"
:disabled="!canWrite"
:key="t.id"
:the-task="t"
@taskUpdated="updateTasks"
task-detail-route="task.detail"
v-for="t in tasks"
>
<div
@click="editTask(t.id)"
class="icon settings"
v-if="!list.isArchived && canWrite"
<draggable v-model="tasks" group="tasks" @end="saveTaskPosition">
<single-task-in-list
:show-list-color="false"
:disabled="!canWrite"
:key="t.id"
:the-task="t"
@taskUpdated="updateTasks"
task-detail-route="task.detail"
v-for="t in tasks"
>
<icon icon="pencil-alt" />
</div>
</single-task-in-list>
<div
@click="editTask(t.id)"
class="icon settings"
v-if="!list.isArchived && canWrite"
>
<icon icon="pencil-alt"/>
</div>
</single-task-in-list>
</draggable>
</div>
<card
v-if="isTaskEdit"
@ -150,7 +151,7 @@
<!-- This router view is used to show the task popup while keeping the kanban board itself -->
<transition name="modal">
<router-view />
<router-view/>
</transition>
</div>
</template>
@ -163,14 +164,17 @@ import EditTask from '../../../components/tasks/edit-task'
import AddTask from '../../../components/tasks/add-task'
import SingleTaskInList from '../../../components/tasks/partials/singleTaskInList'
import taskList from '../../../components/tasks/mixins/taskList'
import { saveListView } from '@/helpers/saveListView'
import {saveListView} from '@/helpers/saveListView'
import Rights from '../../../models/rights.json'
import { mapState } from 'vuex'
import FilterPopup from '@/components/list/partials/filter-popup.vue'
import { HAS_TASKS } from '@/store/mutation-types'
import {HAS_TASKS} from '@/store/mutation-types'
import Nothing from '@/components/misc/nothing.vue'
import createTask from '@/components/tasks/mixins/createTask'
import {mapState} from 'vuex'
import draggable from 'vuedraggable'
import {calculateTaskPosition} from '../../../helpers/calculateTaskPosition'
export default {
name: 'List',
data() {
@ -191,6 +195,7 @@ export default {
SingleTaskInList,
EditTask,
AddTask,
draggable,
},
created() {
this.taskService = new TaskService()
@ -199,10 +204,21 @@ export default {
// We use local storage and not vuex here to make it persistent across reloads.
saveListView(this.$route.params.listId, this.$route.name)
},
computed: mapState({
canWrite: state => state.currentList.maxRight > Rights.READ,
list: state => state.currentList,
}),
computed: {
firstNewPosition() {
if (this.tasks.length === 0) {
return 0
}
const p = calculateTaskPosition(null, this.tasks[0].position)
console.log('newp', p)
return p
},
...mapState({
canWrite: state => state.currentList.maxRight > Rights.READ,
list: state => state.currentList,
}),
},
mounted() {
this.$nextTick(() => (this.ctaVisible = true))
},

View File

@ -7245,6 +7245,11 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0"
use "^3.1.0"
sortablejs@1.10.2:
version "1.10.2"
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.10.2.tgz#6e40364d913f98b85a14f6678f92b5c1221f5290"
integrity sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A==
source-map-js@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e"
@ -8169,6 +8174,13 @@ vue@2.6.14:
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
integrity sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==
vuedraggable@^2.24.3:
version "2.24.3"
resolved "https://registry.yarnpkg.com/vuedraggable/-/vuedraggable-2.24.3.tgz#43c93849b746a24ce503e123d5b259c701ba0d19"
integrity sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==
dependencies:
sortablejs "1.10.2"
vuex@3.6.2:
version "3.6.2"
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.6.2.tgz#236bc086a870c3ae79946f107f16de59d5895e71"