2020-04-25 23:11:34 +00:00
< template >
2021-01-16 15:50:13 +00:00
< div class = "kanban-view" >
2020-12-24 00:33:25 +00:00
< div class = "filter-container" v-if ="list.isSavedFilter && !list.isSavedFilter()" >
2020-12-22 11:49:34 +00:00
< div class = "items" >
2021-01-17 17:57:57 +00:00
< x -button
@ click . prevent . stop = "showFilters = !showFilters"
icon = "filter"
type = "secondary"
>
2021-06-23 23:24:57 +00:00
{ { $t ( 'filters.title' ) } }
2021-01-17 17:57:57 +00:00
< / x - b u t t o n >
2020-12-22 11:49:34 +00:00
< / div >
2021-01-17 10:36:57 +00:00
< filter -popup
@ change = "() => {filtersChanged = true; loadBuckets()}"
: visible = "showFilters"
v - model = "params"
/ >
2020-12-22 11:49:34 +00:00
< / div >
2020-12-08 17:49:28 +00:00
< div : class = "{ 'is-loading': loading && !oneTaskUpdating}" class = "kanban loader-container" >
2021-07-07 19:58:29 +00:00
< div
: key = "`bucket${bucket.id}`"
class = "bucket"
: class = "{'is-collapsed': collapsedBuckets[bucket.id]}"
2021-07-28 15:49:18 +00:00
v - for = "(bucket, k) in buckets"
2021-07-07 19:58:29 +00:00
>
< div class = "bucket-header" @ click = "() => unCollapseBucket(bucket)" >
2021-03-24 20:16:56 +00:00
< span
v - if = "bucket.isDoneBucket"
class = "icon is-small has-text-success mr-2"
2021-06-23 23:24:57 +00:00
v - tooltip = "$t('list.kanban.doneBucketHint')"
2021-03-24 20:16:56 +00:00
>
< icon icon = "check-double" / >
< / span >
2020-11-22 16:32:35 +00:00
< h2
: ref = "`bucket${bucket.id}title`"
@ focusout = "() => saveBucketTitle(bucket.id)"
2021-01-15 22:46:43 +00:00
@ keydown . enter . prevent . stop = "() => saveBucketTitle(bucket.id)"
2020-11-22 16:32:35 +00:00
class = "title input"
2021-07-07 19:58:29 +00:00
: contenteditable = "canWrite && !collapsedBuckets[bucket.id]"
2020-11-22 16:32:35 +00:00
spellcheck = "false" > { { bucket . title } } < / h2 >
< span
: class = "{'is-max': bucket.tasks.length >= bucket.limit}"
class = "limit"
v - if = "bucket.limit > 0" >
2020-12-28 22:42:09 +00:00
{ { bucket . tasks . length } } / { { bucket . limit } }
< / span >
2021-01-30 16:17:04 +00:00
< dropdown
class = "is-right options"
2021-07-07 19:58:29 +00:00
v - if = "canWrite && !collapsedBuckets[bucket.id]"
2021-01-30 16:17:04 +00:00
trigger - icon = "ellipsis-v"
2021-04-15 15:03:26 +00:00
@ close = "() => showSetLimitInput = false"
2020-11-22 16:32:35 +00:00
>
2021-01-30 16:17:04 +00:00
< a
@ click . stop = "showSetLimitInput = true"
class = "dropdown-item"
>
< div class = "field has-addons" v-if ="showSetLimitInput" >
< div class = "control" >
< input
2021-04-15 14:58:48 +00:00
@ change = "() => setBucketLimit(bucket)"
@ keyup . enter = "() => setBucketLimit(bucket)"
2021-04-15 15:03:26 +00:00
@ keyup . esc = "() => showSetLimitInput = false"
2021-01-30 16:17:04 +00:00
class = "input"
type = "number"
2021-04-15 14:58:48 +00:00
min = "0"
2021-01-30 16:17:04 +00:00
v - focus . always
v - model = "bucket.limit"
/ >
< / div >
< div class = "control" >
< x -button
2021-04-15 14:58:48 +00:00
: disabled = "bucket.limit < 0"
2021-01-30 16:17:04 +00:00
: icon = "['far', 'save']"
: shadow = "false"
/ >
2021-01-23 17:54:22 +00:00
< / div >
2020-11-22 16:32:35 +00:00
< / div >
2021-01-30 16:17:04 +00:00
< template v-else >
2021-07-05 10:29:04 +00:00
{ {
$t ( 'list.kanban.limit' , { limit : bucket . limit > 0 ? bucket . limit : $t ( 'list.kanban.noLimit' ) } )
} }
2021-01-30 16:17:04 +00:00
< / template >
< / a >
2021-03-24 20:16:56 +00:00
< a
2021-07-07 19:58:29 +00:00
@ click . stop = "toggleDoneBucket(bucket)"
2021-03-24 20:16:56 +00:00
class = "dropdown-item"
2021-06-23 23:24:57 +00:00
v - tooltip = "$t('list.kanban.doneBucketHintExtended')"
2021-03-24 20:16:56 +00:00
>
2021-04-15 14:58:48 +00:00
< span class = "icon is-small" : class = "{'has-text-success': bucket.isDoneBucket}" > < icon
icon = "check-double" / > < / span >
2021-06-23 23:24:57 +00:00
{ { $t ( 'list.kanban.doneBucket' ) } }
2021-03-24 20:16:56 +00:00
< / a >
2021-07-07 19:58:29 +00:00
< a
class = "dropdown-item"
@ click . stop = "() => collapseBucket(bucket)"
>
{ { $t ( 'list.kanban.collapse' ) } }
< / a >
2021-01-30 16:17:04 +00:00
< a
: class = "{'is-disabled': buckets.length <= 1}"
2021-07-07 19:58:29 +00:00
@ click . stop = "() => deleteBucketModal(bucket.id)"
2021-01-30 16:17:04 +00:00
class = "dropdown-item has-text-danger"
2021-06-23 23:24:57 +00:00
v - tooltip = "buckets.length <= 1 ? $t('list.kanban.deleteLast') : ''"
2021-01-30 16:17:04 +00:00
>
< span class = "icon is-small" > < icon icon = "trash-alt" / > < / span >
2021-06-23 23:24:57 +00:00
{ { $t ( 'misc.delete' ) } }
2021-01-30 16:17:04 +00:00
< / a >
< / dropdown >
2020-04-25 23:11:34 +00:00
< / div >
2020-11-22 16:32:35 +00:00
< div :ref ="`tasks-container${bucket.id}`" class = "tasks" >
2021-07-28 14:54:30 +00:00
< draggable
v - model = "bucket.tasks"
@ start = "() => drag = true"
2021-07-28 15:49:18 +00:00
@ end = "e => updateTaskPosition(k, e)"
2021-07-28 15:44:00 +00:00
: group = "{name: 'buckets', put: shouldAcceptDrop(bucket)}"
2021-07-28 14:54:30 +00:00
v - bind = "dragOptions"
2021-07-28 15:44:00 +00:00
: disabled = "!canWrite"
2020-08-11 18:18:59 +00:00
>
2021-07-28 14:54:30 +00:00
< transition -group type = "transition" : name = "!drag ? 'move-card': null" >
2021-07-28 15:49:18 +00:00
<!-- Make the component either a div or a draggable component based on the user rights -- >
<!-- < component - - >
<!-- : animation - duration = "150" -- >
<!-- : drop - placeholder = "dropPlaceholderOptions" -- >
<!-- : get - child - payload = "getTaskPayload(bucket.id)" -- >
<!-- : is = "canWrite ? 'Container' : 'div'" -- >
<!-- : should - accept - drop = "() => shouldAcceptDrop(bucket)" -- >
<!-- @ drop = "e => onDrop(bucket.id, e)" -- >
<!-- drag - class = "ghost-task" -- >
<!-- drag - class - drop = "ghost-task-drop" -- >
<!-- drag - handle - selector = ".task.draggable" -- >
<!-- group - name = "buckets" -- >
<!-- > -- >
<!-- & lt ; ! & ndash ; Make the component either a div or a draggable component based on the user rights & ndash ; & gt ; -- >
<!-- < component - - >
<!-- : is = "canWrite ? 'Draggable' : 'div'" -- >
<!-- : key = "`bucket${bucket.id}-task${task.id}`" -- >
<!-- v - for = "task in bucket.tasks" -- >
<!-- > -- >
< kanban -card
: key = "`bucket${bucket.id}-task${task.id}`"
v - for = "task in bucket.tasks"
: task = "task"
/ >
2021-07-28 14:54:30 +00:00
< / t r a n s i t i o n - g r o u p >
<!-- < / component > -- >
<!-- < / component > -- >
< / draggable >
2020-11-22 16:32:35 +00:00
< / div >
< div class = "bucket-footer" v-if ="canWrite" >
< div class = "field" v-if ="showNewTaskInput[bucket.id]" >
2020-12-08 17:49:28 +00:00
< div class = "control" : class = "{'is-loading': taskService.loading || loading}" >
2020-11-22 16:32:35 +00:00
< input
2020-11-28 14:44:48 +00:00
class = "input"
2020-12-08 17:49:28 +00:00
: disabled = "taskService.loading || loading"
2020-11-22 16:32:35 +00:00
@ focusout = "toggleShowNewTaskInput(bucket.id)"
@ keyup . enter = "addTaskToBucket(bucket.id)"
@ keyup . esc = "toggleShowNewTaskInput(bucket.id)"
2021-06-23 23:24:57 +00:00
: placeholder = "$t('list.kanban.addTaskPlaceholder')"
2020-11-22 16:32:35 +00:00
type = "text"
v - focus . always
v - model = "newTaskText"
/ >
< / div >
< p class = "help is-danger" v-if ="newTaskError[bucket.id] && newTaskText === ''" >
2021-06-23 23:24:57 +00:00
{ { $t ( 'list.list.addTitleRequired' ) } }
2020-11-22 16:32:35 +00:00
< / p >
2020-04-25 23:11:34 +00:00
< / div >
2021-01-17 17:57:57 +00:00
< x -button
2020-11-22 16:32:35 +00:00
@ click = "toggleShowNewTaskInput(bucket.id)"
2021-01-17 17:57:57 +00:00
class = "is-transparent is-fullwidth has-text-centered"
: shadow = "false"
v - if = "!showNewTaskInput[bucket.id]"
icon = "plus"
type = "secondary"
>
2021-06-23 23:24:57 +00:00
{ { bucket . tasks . length === 0 ? $t ( 'list.kanban.addTask' ) : $t ( 'list.kanban.addAnotherTask' ) } }
2021-01-17 17:57:57 +00:00
< / x - b u t t o n >
2020-11-22 16:32:35 +00:00
< / div >
2020-04-25 23:11:34 +00:00
< / div >
2021-01-16 19:28:10 +00:00
< div class = "bucket new-bucket" v-if ="canWrite && !loading && buckets.length > 0" >
2020-11-22 16:32:35 +00:00
< input
: class = "{'is-loading': loading}"
: disabled = "loading"
@ focusout = "() => showNewBucketInput = false"
@ keyup . enter = "createNewBucket"
@ keyup . esc = "() => showNewBucketInput = false"
class = "input"
2021-06-23 23:24:57 +00:00
: placeholder = "$t('list.kanban.addBucketPlaceholder')"
2020-11-22 16:32:35 +00:00
type = "text"
v - focus . always
v - if = "showNewBucketInput"
v - model = "newBucketTitle"
/ >
2021-01-17 17:57:57 +00:00
< x -button
2020-11-22 16:32:35 +00:00
@ click = "() => showNewBucketInput = true"
2021-01-17 17:57:57 +00:00
: shadow = "false"
class = "is-transparent is-fullwidth has-text-centered"
v - if = "!showNewBucketInput"
type = "secondary"
icon = "plus"
>
2021-06-23 23:24:57 +00:00
{ { $t ( 'list.kanban.addBucket' ) } }
2021-01-17 17:57:57 +00:00
< / x - b u t t o n >
2020-11-22 16:32:35 +00:00
< / div >
2020-04-25 23:11:34 +00:00
< / div >
<!-- This router view is used to show the task popup while keeping the kanban board itself -- >
< transition name = "modal" >
< router -view / >
< / transition >
2021-01-23 17:54:22 +00:00
< transition name = "modal" >
< modal
@ close = "showBucketDeleteModal = false"
@ submit = "deleteBucket()"
v - if = "showBucketDeleteModal" >
2021-06-23 23:24:57 +00:00
< span slot = "header" > { { $t ( 'list.kanban.deleteHeaderBucket' ) } } < / span >
2021-01-23 17:54:22 +00:00
< p slot = "text" >
2021-06-23 23:24:57 +00:00
{ { $t ( 'list.kanban.deleteBucketText1' ) } } < br / >
{ { $t ( 'list.kanban.deleteBucketText2' ) } }
2021-01-23 17:54:22 +00:00
< / p >
< / modal >
< / transition >
2020-04-25 23:11:34 +00:00
< / div >
< / template >
< script >
2020-09-05 20:35:52 +00:00
import TaskService from '../../../services/task'
import BucketModel from '../../../models/bucket'
import { Container , Draggable } from 'vue-smooth-dnd'
import { filterObject } from '@/helpers/filterObject'
import { applyDrag } from '@/helpers/applyDrag'
import { mapState } from 'vuex'
import { saveListView } from '@/helpers/saveListView'
import Rights from '../../../models/rights.json'
2021-01-30 16:17:04 +00:00
import { LOADING , LOADING _MODULE } from '@/store/mutation-types'
2021-07-25 13:27:15 +00:00
import FilterPopup from '@/components/list/partials/filter-popup.vue'
import Dropdown from '@/components/misc/dropdown.vue'
2021-07-05 10:29:04 +00:00
import createTask from '@/components/tasks/mixins/createTask'
2021-07-07 19:58:29 +00:00
import { getCollapsedBucketState , saveCollapsedBucketState } from '@/helpers/saveCollapsedBucketState'
2021-07-27 20:15:01 +00:00
import { calculateItemPosition } from '../../../helpers/calculateItemPosition'
2021-07-28 14:13:22 +00:00
import draggable from 'vuedraggable'
import KanbanCard from '../../../components/tasks/partials/kanban-card'
2020-09-05 20:35:52 +00:00
export default {
name : 'Kanban' ,
components : {
2021-07-28 14:13:22 +00:00
KanbanCard ,
2021-01-30 16:17:04 +00:00
Dropdown ,
2021-01-17 10:36:57 +00:00
FilterPopup ,
2020-09-05 20:35:52 +00:00
Container ,
Draggable ,
2021-07-28 14:13:22 +00:00
draggable ,
2020-09-05 20:35:52 +00:00
} ,
data ( ) {
return {
taskService : TaskService ,
dropPlaceholderOptions : {
className : 'drop-preview' ,
animationDuration : 150 ,
showOnTop : true ,
} ,
2021-07-28 14:54:30 +00:00
drag : false ,
dragOptions : {
animation : 150 ,
ghostClass : 'ghost' ,
2021-07-28 15:44:00 +00:00
dragClass : 'task-dragging' ,
2021-07-28 14:54:30 +00:00
} ,
2020-09-05 20:35:52 +00:00
sourceBucket : 0 ,
showBucketDeleteModal : false ,
bucketToDelete : 0 ,
newTaskText : '' ,
showNewTaskInput : { } ,
newBucketTitle : '' ,
showNewBucketInput : false ,
newTaskError : { } ,
showSetLimitInput : false ,
2021-07-07 19:58:29 +00:00
collapsedBuckets : { } ,
2020-09-05 20:35:52 +00:00
// We're using this to show the loading animation only at the task when updating it
taskUpdating : { } ,
2020-12-08 17:49:28 +00:00
oneTaskUpdating : false ,
2020-12-22 11:49:34 +00:00
params : {
filter _by : [ ] ,
filter _value : [ ] ,
filter _comparator : [ ] ,
filter _concat : 'and' ,
} ,
showFilters : false ,
filtersChanged : false , // To trigger a reload of the board
2020-09-05 20:35:52 +00:00
}
} ,
2021-07-05 10:29:04 +00:00
mixins : [
createTask ,
] ,
2020-09-05 20:35:52 +00:00
created ( ) {
this . taskService = new TaskService ( )
this . loadBuckets ( )
// Save the current list view to local storage
// We use local storage and not vuex here to make it persistent across reloads.
saveListView ( this . $route . params . listId , this . $route . name )
} ,
watch : {
'$route.params.listId' : 'loadBuckets' ,
} ,
computed : mapState ( {
buckets : state => state . kanban . buckets ,
loadedListId : state => state . kanban . listId ,
2021-01-09 14:24:06 +00:00
loading : state => state [ LOADING ] && state [ LOADING _MODULE ] === 'kanban' ,
taskLoading : state => state [ LOADING ] && state [ LOADING _MODULE ] === 'tasks' ,
2020-09-05 20:35:52 +00:00
canWrite : state => state . currentList . maxRight > Rights . READ ,
2020-12-24 00:33:25 +00:00
list : state => state . currentList ,
2020-09-05 20:35:52 +00:00
} ) ,
methods : {
loadBuckets ( ) {
// Prevent trying to load buckets if the task popup view is active
if ( this . $route . name !== 'list.kanban' ) {
return
2020-04-25 23:11:34 +00:00
}
2020-05-21 09:35:09 +00:00
2020-09-05 20:35:52 +00:00
// Only load buckets if we don't already loaded them
if (
2020-12-22 11:49:34 +00:00
! this . filtersChanged && (
2020-09-05 20:35:52 +00:00
this . loadedListId === this . $route . params . listId ||
2020-12-22 11:49:34 +00:00
this . loadedListId === parseInt ( this . $route . params . listId ) )
2020-09-05 20:35:52 +00:00
) {
return
}
2020-05-21 09:35:09 +00:00
2021-07-07 19:58:29 +00:00
this . collapsedBuckets = getCollapsedBucketState ( this . $route . params . listId )
2020-09-05 20:35:52 +00:00
console . debug ( ` Loading buckets, loadedListId = ${ this . loadedListId } , $ route.params = ` , this . $route . params )
2020-12-22 11:49:34 +00:00
this . filtersChanged = false
2020-07-24 08:42:30 +00:00
2021-03-10 10:59:29 +00:00
const minScrollHeightPercent = 0.25
2020-12-22 11:49:34 +00:00
this . $store . dispatch ( 'kanban/loadBucketsForList' , { listId : this . $route . params . listId , params : this . params } )
2021-03-10 10:59:29 +00:00
. then ( bs => {
bs . forEach ( b => {
const e = this . $refs [ ` tasks-container ${ b . id } ` ] [ 0 ]
2021-03-10 16:45:07 +00:00
e . addEventListener ( 'scroll' , ( ) => {
const scrollTopMax = e . scrollHeight - e . clientHeight
if ( scrollTopMax <= e . scrollTop + e . scrollTop * minScrollHeightPercent ) {
2021-03-10 10:59:29 +00:00
this . $store . dispatch ( 'kanban/loadNextTasksForBucket' , {
listId : this . $route . params . listId ,
params : this . params ,
bucketId : b . id ,
} )
. catch ( e => {
2021-06-22 20:07:57 +00:00
this . error ( e )
2021-03-10 10:59:29 +00:00
} )
}
2021-03-10 16:45:07 +00:00
} )
2021-03-10 10:59:29 +00:00
} )
} )
2020-09-05 20:35:52 +00:00
. catch ( e => {
2021-06-22 20:07:57 +00:00
this . error ( e )
2020-09-05 20:35:52 +00:00
} )
} ,
2021-07-28 15:49:18 +00:00
updateTaskPosition ( bucketIndex , e ) {
2021-07-28 14:54:30 +00:00
this . drag = false
2020-04-25 23:11:34 +00:00
2021-07-28 15:49:18 +00:00
const newBucket = this . buckets [ bucketIndex ]
const task = newBucket . tasks [ e . newIndex ]
const taskBefore = newBucket . tasks [ e . newIndex - 1 ] ? ? null
const taskAfter = newBucket . tasks [ e . newIndex + 1 ] ? ? null
task . kanban _position = calculateItemPosition ( taskBefore !== null ? taskBefore . position : null , taskAfter !== null ? taskAfter . position : null )
task . bucketId = newBucket . id
this . $store . dispatch ( 'tasks/update' , task )
. catch ( e => {
this . error ( e )
} )
. finally ( ( ) => {
this . $set ( this . taskUpdating , task . id , false )
this . oneTaskUpdating = false
} )
} ,
onDrop ( bucketId , dropResult ) {
2020-09-05 20:35:52 +00:00
// Note: A lot of this example comes from the excellent kanban example on https://github.com/kutlugsahin/vue-smooth-dnd/blob/master/demo/src/pages/cards.vue
2020-04-25 23:11:34 +00:00
2021-07-28 14:54:30 +00:00
// const bucketIndex = filterObject(this.buckets, b => b.id === bucketId)
//
// if (dropResult.removedIndex !== null || dropResult.addedIndex !== null) {
//
// // FIXME: This is probably not the best solution and more of a naive brute-force approach
//
// // Duplicate the buckets to avoid stuff moving around without noticing
// const buckets = Object.assign({}, this.buckets)
// // Get the index of the bucket and the bucket itself
// const bucket = buckets[bucketIndex]
//
// // Rebuild the tasks from the bucket, removing/adding the moved task
// bucket.tasks = applyDrag(bucket.tasks, dropResult)
// // Update the bucket in the list of all buckets
// delete buckets[bucketIndex]
// buckets[bucketIndex] = bucket
// // Set the buckets, triggering a state update in vue
// // FIXME: This seems to set some task attributes (like due date) wrong. Commented out, but seems to still work?
// // Not sure what to do about this.
// // this.$store.commit('kanban/setBuckets', buckets)
// }
//
// if (dropResult.addedIndex !== null) {
//
// const taskIndex = dropResult.addedIndex
// const taskBefore = typeof this.buckets[bucketIndex].tasks[taskIndex - 1] === 'undefined' ? null : this.buckets[bucketIndex].tasks[taskIndex - 1]
// const taskAfter = typeof this.buckets[bucketIndex].tasks[taskIndex + 1] === 'undefined' ? null : this.buckets[bucketIndex].tasks[taskIndex + 1]
// const task = this.buckets[bucketIndex].tasks[taskIndex]
// this.$set(this.taskUpdating, task.id, true)
// this.oneTaskUpdating = true
//
// task.kanbanPosition = calculateItemPosition(taskBefore !== null ? taskBefore.kanbanPosition : null, taskAfter !== null ? taskAfter.kanbanPosition : null)
// console.log(task.kanbanPosition)
//
// task.bucketId = bucketId
//
// this.$store.dispatch('tasks/update', task)
// .catch(e => {
// this.error(e)
// })
// .finally(() => {
// this.$set(this.taskUpdating, task.id, false)
// this.oneTaskUpdating = false
// })
// }
2020-09-05 20:35:52 +00:00
} ,
getTaskPayload ( bucketId ) {
return index => {
const bucket = this . buckets [ filterObject ( this . buckets , b => b . id === bucketId ) ]
this . sourceBucket = bucket . id
return bucket . tasks [ index ]
}
} ,
toggleShowNewTaskInput ( bucket ) {
this . $set ( this . showNewTaskInput , bucket , ! this . showNewTaskInput [ bucket ] )
} ,
addTaskToBucket ( bucketId ) {
2020-04-25 23:11:34 +00:00
2020-09-05 20:35:52 +00:00
if ( this . newTaskText === '' ) {
this . $set ( this . newTaskError , bucketId , true )
return
}
this . $set ( this . newTaskError , bucketId , false )
2021-07-05 10:29:04 +00:00
this . createNewTask ( this . newTaskText , bucketId )
2020-09-05 20:35:52 +00:00
. then ( r => {
this . newTaskText = ''
this . $store . commit ( 'kanban/addTaskToBucket' , r )
} )
. catch ( e => {
2021-06-22 20:07:57 +00:00
this . error ( e )
2020-06-11 21:35:50 +00:00
} )
2020-09-05 20:35:52 +00:00
. finally ( ( ) => {
2021-07-05 10:29:04 +00:00
if ( ! this . $refs [ ` tasks-container ${ bucketId } ` ] [ 0 ] ) {
2020-09-05 20:35:52 +00:00
return
}
2021-07-05 10:29:04 +00:00
this . $refs [ ` tasks-container ${ bucketId } ` ] [ 0 ] . scrollTop = this . $refs [ ` tasks-container ${ bucketId } ` ] [ 0 ] . scrollHeight
2020-09-05 20:35:52 +00:00
} )
} ,
createNewBucket ( ) {
if ( this . newBucketTitle === '' ) {
return
}
2020-04-25 23:11:34 +00:00
2020-09-05 20:35:52 +00:00
const newBucket = new BucketModel ( {
title : this . newBucketTitle ,
listId : parseInt ( this . $route . params . listId ) ,
} )
2020-04-25 23:11:34 +00:00
2020-09-05 20:35:52 +00:00
this . $store . dispatch ( 'kanban/createBucket' , newBucket )
. then ( ( ) => {
this . newBucketTitle = ''
this . showNewBucketInput = false
2020-04-25 23:11:34 +00:00
} )
2020-09-05 20:35:52 +00:00
. catch ( e => {
2021-06-22 20:07:57 +00:00
this . error ( e )
2020-04-25 23:11:34 +00:00
} )
2020-09-05 20:35:52 +00:00
} ,
deleteBucketModal ( bucketId ) {
if ( this . buckets . length <= 1 ) {
return
}
2020-04-25 23:11:34 +00:00
2020-09-05 20:35:52 +00:00
this . bucketToDelete = bucketId
this . showBucketDeleteModal = true
} ,
deleteBucket ( ) {
const bucket = new BucketModel ( {
id : this . bucketToDelete ,
listId : this . $route . params . listId ,
} )
2021-03-10 10:59:29 +00:00
this . $store . dispatch ( 'kanban/deleteBucket' , { bucket : bucket , params : this . params } )
2021-01-15 22:46:43 +00:00
. then ( ( ) => {
2021-06-23 23:24:57 +00:00
this . success ( { message : this . $t ( 'list.kanban.deleteBucketSuccess' ) } )
2021-01-15 22:46:43 +00:00
} )
2020-09-05 20:35:52 +00:00
. catch ( e => {
2021-06-22 20:07:57 +00:00
this . error ( e )
2020-09-05 20:35:52 +00:00
} )
. finally ( ( ) => {
this . showBucketDeleteModal = false
} )
} ,
saveBucketTitle ( bucketId ) {
2020-10-24 15:23:13 +00:00
const bucketTitleElement = this . $refs [ ` bucket ${ bucketId } title ` ] [ 0 ]
const bucketTitle = bucketTitleElement . textContent
2020-09-05 20:35:52 +00:00
const bucket = new BucketModel ( {
id : bucketId ,
title : bucketTitle ,
listId : Number ( this . $route . params . listId ) ,
} )
// Because the contenteditable does not have a change event,
// we're building it ourselves here and only updating the bucket
// if the title changed.
const realBucket = this . buckets [ filterObject ( this . buckets , b => b . id === bucketId ) ]
if ( realBucket . title === bucketTitle ) {
return
}
2020-04-25 23:11:34 +00:00
2020-09-05 20:35:52 +00:00
this . $store . dispatch ( 'kanban/updateBucket' , bucket )
. then ( r => {
realBucket . title = r . title
2020-10-24 15:23:13 +00:00
bucketTitleElement . blur ( )
2021-06-23 23:24:57 +00:00
this . success ( { message : this . $t ( 'list.kanban.bucketTitleSavedSuccess' ) } )
2020-09-05 20:35:52 +00:00
} )
. catch ( e => {
2021-06-22 20:07:57 +00:00
this . error ( e )
2020-09-05 20:35:52 +00:00
} )
} ,
updateBucket ( bucket ) {
bucket . limit = parseInt ( bucket . limit )
this . $store . dispatch ( 'kanban/updateBucket' , bucket )
2021-01-15 22:46:43 +00:00
. then ( ( ) => {
2021-06-23 23:24:57 +00:00
this . success ( { message : this . $t ( 'list.kanban.bucketLimitSavedSuccess' ) } )
2021-01-15 22:46:43 +00:00
} )
2020-09-05 20:35:52 +00:00
. catch ( e => {
2021-06-22 20:07:57 +00:00
this . error ( e )
2020-09-05 20:35:52 +00:00
} )
} ,
2021-04-15 14:58:48 +00:00
setBucketLimit ( bucket ) {
if ( bucket . limit < 0 ) {
return
}
this . updateBucket ( bucket )
} ,
2020-09-05 20:35:52 +00:00
shouldAcceptDrop ( bucket ) {
return bucket . id === this . sourceBucket || // When dragging from a bucket who has its limit reached, dragging should still be possible
bucket . limit === 0 || // If there is no limit set, dragging & dropping should always work
bucket . tasks . length < bucket . limit // Disallow dropping to buckets which have their limit reached
2020-04-25 23:11:34 +00:00
} ,
2021-03-24 20:16:56 +00:00
toggleDoneBucket ( bucket ) {
bucket . isDoneBucket = ! bucket . isDoneBucket
this . $store . dispatch ( 'kanban/updateBucket' , bucket )
. then ( ( ) => {
2021-06-23 23:24:57 +00:00
this . success ( { message : this . $t ( 'list.kanban.doneBucketSavedSuccess' ) } )
2021-03-24 20:16:56 +00:00
} )
. catch ( e => {
2021-06-22 20:07:57 +00:00
this . error ( e )
2021-03-24 20:16:56 +00:00
bucket . isDoneBucket = ! bucket . isDoneBucket
} )
} ,
2021-07-07 19:58:29 +00:00
collapseBucket ( bucket ) {
this . $set ( this . collapsedBuckets , bucket . id , true )
saveCollapsedBucketState ( this . $route . params . listId , this . collapsedBuckets )
} ,
unCollapseBucket ( bucket ) {
if ( ! this . collapsedBuckets [ bucket . id ] ) {
return
}
this . $set ( this . collapsedBuckets , bucket . id , false )
saveCollapsedBucketState ( this . $route . params . listId , this . collapsedBuckets )
} ,
2020-09-05 20:35:52 +00:00
} ,
}
2020-04-25 23:11:34 +00:00
< / script >