feat: improve kanban implementation
This commit is contained in:
parent
43b22360a5
commit
d66ad12f5c
11 changed files with 230 additions and 127 deletions
|
@ -25,6 +25,7 @@
|
|||
"easymde": "^2.15.0",
|
||||
"highlight.js": "11.2.0",
|
||||
"is-touch-device": "1.0.1",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"marked": "3.0.4",
|
||||
"register-service-worker": "1.7.2",
|
||||
"snake-case": "3.0.4",
|
||||
|
|
|
@ -93,7 +93,11 @@ app.mixin({
|
|||
})
|
||||
|
||||
app.config.errorHandler = (err, vm, info) => {
|
||||
error(err)
|
||||
// if (import.meta.env.PROD) {
|
||||
// error(err)
|
||||
// } else {
|
||||
console.error(err, vm, info)
|
||||
// }
|
||||
}
|
||||
|
||||
app.config.globalProperties.$message = {
|
||||
|
|
|
@ -18,7 +18,7 @@ export default class BucketService extends AbstractService {
|
|||
|
||||
beforeUpdate(model) {
|
||||
const taskService = new TaskService()
|
||||
model.tasks = model.tasks.map(t => taskService.processModel(t))
|
||||
model.tasks = model.tasks?.map(t => taskService.processModel(t))
|
||||
return model
|
||||
}
|
||||
}
|
|
@ -37,7 +37,8 @@ export default class TaskService extends AbstractService {
|
|||
return this.processModel(model)
|
||||
}
|
||||
|
||||
processModel(model) {
|
||||
processModel(updatedModel) {
|
||||
const model = { ...updatedModel }
|
||||
|
||||
model.title = model.title?.trim()
|
||||
|
||||
|
|
|
@ -56,7 +56,10 @@ export const store = createStore({
|
|||
state.errorMessage = error
|
||||
},
|
||||
[ONLINE](state, online) {
|
||||
state.online = import.meta.env.VITE_IS_ONLINE || online
|
||||
if (import.meta.env.VITE_IS_ONLINE) {
|
||||
console.log('Setting fake online state', import.meta.env.VITE_IS_ONLINE)
|
||||
}
|
||||
state.online = !!import.meta.env.VITE_IS_ONLINE || online
|
||||
},
|
||||
[CURRENT_LIST](state, currentList) {
|
||||
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
import cloneDeep from 'lodash.clonedeep'
|
||||
|
||||
import {findById, findIndexById} from '@/helpers/utils'
|
||||
import {i18n} from '@/i18n'
|
||||
import {success} from '@/message'
|
||||
|
||||
import BucketService from '../../services/bucket'
|
||||
import {setLoading} from '../helper'
|
||||
import TaskCollectionService from '@/services/taskCollection'
|
||||
|
||||
const TASKS_PER_BUCKET = 25
|
||||
|
||||
function getTaskPosition(state, task) {
|
||||
function getTaskIndices(state, task) {
|
||||
const bucketIndex = findIndexById(state.buckets, task.bucketId)
|
||||
|
||||
if (!bucketIndex) {
|
||||
|
@ -167,7 +172,7 @@ export default {
|
|||
return
|
||||
}
|
||||
|
||||
const { bucketIndex, taskIndex } = getTaskPosition(state, task)
|
||||
const { bucketIndex, taskIndex } = getTaskIndices(state, task)
|
||||
|
||||
state.buckets[bucketIndex].tasks.splice(taskIndex, 1)
|
||||
},
|
||||
|
@ -189,23 +194,21 @@ export default {
|
|||
getBucketById(state) {
|
||||
return (bucketId) => findById(state.buckets, bucketId)
|
||||
},
|
||||
getTaskById: state => id => {
|
||||
for (const b in state.buckets) {
|
||||
for (const t in state.buckets[b].tasks) {
|
||||
if (state.buckets[b].tasks[t].id === id) {
|
||||
return {
|
||||
bucketIndex: b,
|
||||
taskIndex: t,
|
||||
task: state.buckets[b].tasks[t],
|
||||
}
|
||||
}
|
||||
|
||||
getTaskById(state) {
|
||||
return (id) => {
|
||||
let taskIndex
|
||||
const bucketIndex = state.buckets.findIndex(({ tasks }) => {
|
||||
taskIndex = findIndexById(tasks, id)
|
||||
return taskIndex !== undefined
|
||||
})
|
||||
|
||||
return {
|
||||
bucketIndex: taskIndex || null,
|
||||
taskIndex: taskIndex || null,
|
||||
task: state.buckets?.[bucketIndex].tasks?.[taskIndex] || null,
|
||||
}
|
||||
}
|
||||
return {
|
||||
bucketIndex: null,
|
||||
taskIndex: null,
|
||||
task: null,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -256,6 +259,15 @@ export default {
|
|||
params.sort_by = 'kanban_position'
|
||||
params.order_by = 'asc'
|
||||
|
||||
// const hasBucketFilter = Object.entries(params.filter_by).some(([key, value]) => {
|
||||
// const condition = value === 'bucket_id'
|
||||
// if (condition) {
|
||||
// if (value !== bucketId) {
|
||||
// params.filter_value[key] = bucketId
|
||||
// }
|
||||
// }
|
||||
// return condition
|
||||
// })
|
||||
let hasBucketFilter = false
|
||||
for (const f in params.filter_by) {
|
||||
if (params.filter_by[f] === 'bucket_id') {
|
||||
|
@ -293,6 +305,7 @@ export default {
|
|||
ctx.commit('setBucketLoading', {bucketId: bucketId, loading: false})
|
||||
})
|
||||
},
|
||||
|
||||
createBucket(ctx, bucket) {
|
||||
const cancel = setLoading(ctx, 'kanban')
|
||||
|
||||
|
@ -309,6 +322,7 @@ export default {
|
|||
cancel()
|
||||
})
|
||||
},
|
||||
|
||||
deleteBucket(ctx, {bucket, params}) {
|
||||
const cancel = setLoading(ctx, 'kanban')
|
||||
|
||||
|
@ -327,24 +341,96 @@ export default {
|
|||
cancel()
|
||||
})
|
||||
},
|
||||
updateBucket(ctx, bucket) {
|
||||
|
||||
updateBucket(ctx, updatedBucketData) {
|
||||
const cancel = setLoading(ctx, 'kanban')
|
||||
|
||||
const bucketIndex = findIndexById(ctx.state.buckets, updatedBucketData.id)
|
||||
const oldBucket = cloneDeep(ctx.state.buckets[bucketIndex])
|
||||
|
||||
const bucket = ctx.state.buckets[bucketIndex]
|
||||
|
||||
const requestData = {
|
||||
id: updatedBucketData.id,
|
||||
listId: updatedBucketData.listId || oldBucket.listId,
|
||||
title: oldBucket.title, // can't be empty in request
|
||||
// ...bucket,
|
||||
...updatedBucketData,
|
||||
}
|
||||
|
||||
const updatedBucket = {
|
||||
...bucket,
|
||||
...requestData,
|
||||
}
|
||||
ctx.commit('setBucketByIndex', {bucketIndex, bucket: updatedBucket})
|
||||
|
||||
const bucketService = new BucketService()
|
||||
return bucketService.update(bucket)
|
||||
return bucketService.update(updatedBucket)
|
||||
.then(r => {
|
||||
const bi = findById(ctx.state.buckets, r.id)
|
||||
const bucket = r
|
||||
bucket.tasks = ctx.state.buckets[bi].tasks
|
||||
ctx.commit('setBucketByIndex', {bucketIndex: bi, bucket})
|
||||
return Promise.resolve(r)
|
||||
Promise.resolve(r)
|
||||
})
|
||||
.catch(e => {
|
||||
// restore original state
|
||||
ctx.commit('setBucketByIndex', {bucketIndex, bucket: oldBucket})
|
||||
|
||||
return Promise.reject(e)
|
||||
})
|
||||
.finally(() => {
|
||||
cancel()
|
||||
.finally(() => cancel())
|
||||
},
|
||||
|
||||
updateBuckets(ctx, updatedBucketsData) {
|
||||
const cancel = setLoading(ctx, 'kanban')
|
||||
|
||||
const oldBuckets = []
|
||||
const updatedBuckets = updatedBucketsData.map((updatedBucketData) => {
|
||||
const bucketIndex = findIndexById(ctx.state.buckets, updatedBucketData.id)
|
||||
const bucket = ctx.state.buckets[bucketIndex]
|
||||
|
||||
const oldBucket = cloneDeep(bucket)
|
||||
oldBuckets.push(oldBucket)
|
||||
|
||||
const newBucket = {
|
||||
// FIXME: maybe optional to set the original value as well
|
||||
...bucket,
|
||||
id: updatedBucketData.id,
|
||||
listId: updatedBucketData.listId || oldBucket.listId,
|
||||
...updatedBucketData,
|
||||
}
|
||||
ctx.commit('setBucketByIndex', {bucketIndex, bucket: newBucket})
|
||||
|
||||
const bucketService = new BucketService()
|
||||
return bucketService.update(newBucket)
|
||||
})
|
||||
|
||||
return Promise.all(updatedBuckets)
|
||||
.then(r => {
|
||||
Promise.resolve(r)
|
||||
})
|
||||
.catch(e => {
|
||||
// restore original state
|
||||
Object.values(updatedBuckets).forEach((oldBucket) => ctx.commit('setBucketById', oldBucket))
|
||||
|
||||
return Promise.reject(e)
|
||||
})
|
||||
.finally(() => cancel())
|
||||
},
|
||||
|
||||
updateBucketTitle(ctx, { id, title }) {
|
||||
const bucket = findById(ctx.state.buckets, id)
|
||||
|
||||
if (bucket.title === title) {
|
||||
// bucket title has not changed
|
||||
return
|
||||
}
|
||||
|
||||
const updatedBucketData = {
|
||||
id,
|
||||
title,
|
||||
}
|
||||
|
||||
ctx.dispatch('updateBucket', updatedBucketData).then(() => {
|
||||
success({message: i18n.global.t('list.kanban.bucketTitleSavedSuccess')})
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
|
@ -117,14 +117,24 @@ export default {
|
|||
addTaskAttachment(ctx, {taskId, attachment}) {
|
||||
const t = ctx.rootGetters['kanban/getTaskById'](taskId)
|
||||
if (t.task !== null) {
|
||||
const newTask = { ...t }
|
||||
newTask.task.attachments.push(attachment)
|
||||
const attachments = [
|
||||
...t.task.attachments,
|
||||
attachment,
|
||||
]
|
||||
|
||||
const newTask = {
|
||||
...t,
|
||||
task: {
|
||||
...t.task,
|
||||
attachments,
|
||||
},
|
||||
}
|
||||
ctx.commit('kanban/setTaskInBucketByIndex', newTask, {root: true})
|
||||
}
|
||||
ctx.commit('attachments/add', attachment, {root: true})
|
||||
},
|
||||
addAssignee(ctx, {user, taskId}) {
|
||||
|
||||
addAssignee(ctx, {user, taskId}) {
|
||||
const taskAssignee = new TaskAssigneeModel({userId: user.id, taskId: taskId})
|
||||
|
||||
const taskAssigneeService = new TaskAssigneeService()
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<div class="kanban-view">
|
||||
<div class="filter-container" v-if="list.isSavedFilter && !list.isSavedFilter()">
|
||||
<div class="filter-container" v-if="isSavedFilter">
|
||||
<div class="items">
|
||||
<x-button
|
||||
@click.prevent.stop="showFilters = !showFilters"
|
||||
@click.prevent.stop="toggleFilterPopup"
|
||||
icon="filter"
|
||||
type="secondary"
|
||||
>
|
||||
|
@ -11,19 +11,20 @@
|
|||
</x-button>
|
||||
</div>
|
||||
<filter-popup
|
||||
@update:modelValue="() => {filtersChanged = true; loadBuckets()}"
|
||||
:visible="showFilters"
|
||||
v-model="params"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
:class="{ 'is-loading': loading && !oneTaskUpdating}"
|
||||
class="kanban kanban-bucket-container loader-container">
|
||||
class="kanban kanban-bucket-container loader-container"
|
||||
>
|
||||
<!-- @end="updateBucketPosition" -->
|
||||
<draggable
|
||||
v-bind="dragOptions"
|
||||
v-model="buckets"
|
||||
:modelValue="buckets"
|
||||
@update:modelValue="updateBucketPositions"
|
||||
@start="() => dragBucket = true"
|
||||
@end="updateBucketPosition"
|
||||
group="buckets"
|
||||
:disabled="!canWrite"
|
||||
tag="transition-group"
|
||||
|
@ -70,14 +71,14 @@
|
|||
<div class="field has-addons" v-if="showSetLimitInput">
|
||||
<div class="control">
|
||||
<input
|
||||
@change="() => setBucketLimit(bucket)"
|
||||
@keyup.enter="() => setBucketLimit(bucket)"
|
||||
@keyup.esc="() => showSetLimitInput = false"
|
||||
@keyup.enter="() => showSetLimitInput = false"
|
||||
:value="bucket.limit"
|
||||
@input="(event) => setBucketLimit(bucket.id, parseInt(event.target.value))"
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
v-focus.always
|
||||
v-model="bucket.limit"
|
||||
/>
|
||||
</div>
|
||||
<div class="control">
|
||||
|
@ -130,7 +131,8 @@
|
|||
>
|
||||
<draggable
|
||||
v-bind="dragOptions"
|
||||
v-model="bucket.tasks"
|
||||
:modelValue="bucket.tasks"
|
||||
@update:modelValue="(tasks) => updateTasks(bucket.id, tasks)"
|
||||
@start="() => dragstart(bucket)"
|
||||
@end="updateTaskPosition"
|
||||
:group="{name: 'tasks', put: shouldAcceptDrop(bucket) && !dragBucket}"
|
||||
|
@ -236,7 +238,6 @@
|
|||
import draggable from 'vuedraggable'
|
||||
|
||||
import BucketModel from '../../../models/bucket'
|
||||
import {findById} from '@/helpers/utils'
|
||||
import {mapState} from 'vuex'
|
||||
import {saveListView} from '@/helpers/saveListView'
|
||||
import Rights from '../../../models/constants/rights.json'
|
||||
|
@ -245,7 +246,7 @@ import FilterPopup from '@/components/list/partials/filter-popup.vue'
|
|||
import Dropdown from '@/components/misc/dropdown.vue'
|
||||
import {getCollapsedBucketState, saveCollapsedBucketState} from '@/helpers/saveCollapsedBucketState'
|
||||
import {calculateItemPosition} from '../../../helpers/calculateItemPosition'
|
||||
import KanbanCard from '../../../components/tasks/partials/kanban-card'
|
||||
import KanbanCard from '@/components/tasks/partials/kanban-card'
|
||||
|
||||
const DRAG_OPTIONS = {
|
||||
// sortable options
|
||||
|
@ -299,20 +300,29 @@ export default {
|
|||
filter_concat: 'and',
|
||||
},
|
||||
showFilters: false,
|
||||
filtersChanged: false, // To trigger a reload of the board
|
||||
}
|
||||
},
|
||||
created() {
|
||||
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',
|
||||
loadBucketParameter: {
|
||||
handler: 'loadBuckets',
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isSavedFilter() {
|
||||
return this.list.isSavedFilter && !this.list.isSavedFilter()
|
||||
},
|
||||
loadBucketParameter() {
|
||||
return {
|
||||
listId: this.$route.params.listId,
|
||||
params: this.params,
|
||||
}
|
||||
},
|
||||
bucketDraggableComponentData() {
|
||||
return {
|
||||
type: 'transition',
|
||||
|
@ -340,6 +350,7 @@ export default {
|
|||
return this.$store.state.kanban.buckets
|
||||
},
|
||||
set(value) {
|
||||
console.log('should not set buckets', value)
|
||||
this.$store.commit('kanban/setBuckets', value)
|
||||
},
|
||||
},
|
||||
|
@ -351,29 +362,25 @@ export default {
|
|||
list: state => state.currentList,
|
||||
}),
|
||||
},
|
||||
|
||||
methods: {
|
||||
loadBuckets() {
|
||||
toggleFilterPopup() {
|
||||
this.showFilters = !this.showFilters
|
||||
},
|
||||
|
||||
loadBuckets() {
|
||||
// Prevent trying to load buckets if the task popup view is active
|
||||
if (this.$route.name !== 'list.kanban') {
|
||||
return
|
||||
}
|
||||
|
||||
// Only load buckets if we don't already loaded them
|
||||
if (
|
||||
!this.filtersChanged && (
|
||||
this.loadedListId === this.$route.params.listId ||
|
||||
this.loadedListId === parseInt(this.$route.params.listId))
|
||||
) {
|
||||
return
|
||||
}
|
||||
const { listId, params } = this.loadBucketParameter
|
||||
|
||||
this.collapsedBuckets = getCollapsedBucketState(this.$route.params.listId)
|
||||
this.collapsedBuckets = getCollapsedBucketState(listId)
|
||||
|
||||
console.debug(`Loading buckets, loadedListId = ${this.loadedListId}, $route.params =`, this.$route.params)
|
||||
this.filtersChanged = false
|
||||
|
||||
this.$store.dispatch('kanban/loadBucketsForList', {listId: this.$route.params.listId, params: this.params})
|
||||
this.$store.dispatch('kanban/loadBucketsForList', {listId, params})
|
||||
},
|
||||
|
||||
setTaskContainerRef(id, el) {
|
||||
|
@ -394,6 +401,16 @@ export default {
|
|||
bucketId: id,
|
||||
})
|
||||
},
|
||||
|
||||
updateTasks(bucketId, tasks) {
|
||||
const newBucket = {
|
||||
...this.$store.getters['kanban/getBucketById'](bucketId),
|
||||
tasks,
|
||||
}
|
||||
|
||||
this.$store.dispatch('kanban/updateBucket', newBucket)
|
||||
},
|
||||
|
||||
updateTaskPosition(e) {
|
||||
this.drag = false
|
||||
|
||||
|
@ -407,20 +424,23 @@ export default {
|
|||
const taskBefore = newBucket.tasks[e.newIndex - 1] ?? null
|
||||
const taskAfter = newBucket.tasks[e.newIndex + 1] ?? null
|
||||
|
||||
task.kanbanPosition = calculateItemPosition(taskBefore !== null ? taskBefore.kanbanPosition : null, taskAfter !== null ? taskAfter.kanbanPosition : null)
|
||||
task.bucketId = newBucket.id
|
||||
// task.kanbanPosition = calculateItemPosition(taskBefore !== null ? taskBefore.kanbanPosition : null, taskAfter !== null ? taskAfter.kanbanPosition : null)
|
||||
// task.bucketId = newBucket.id
|
||||
|
||||
this.$store.dispatch('tasks/update', task)
|
||||
.catch(e => {
|
||||
this.$message.error(e)
|
||||
})
|
||||
.finally(() => {
|
||||
const newTask = {
|
||||
...task,
|
||||
bucketId: newBucket.id,
|
||||
kanbanPosition: calculateItemPosition(taskBefore !== null ? taskBefore.kanbanPosition : null, taskAfter !== null ? taskAfter.kanbanPosition : null),
|
||||
}
|
||||
|
||||
this.$store.dispatch('tasks/update', newTask)
|
||||
// .finally(() => {
|
||||
this.taskUpdating[task.id] = false
|
||||
this.oneTaskUpdating = false
|
||||
})
|
||||
// })
|
||||
},
|
||||
toggleShowNewTaskInput(bucket) {
|
||||
this.showNewTaskInput[bucket] = !this.showNewTaskInput[bucket]
|
||||
toggleShowNewTaskInput(bucketId) {
|
||||
this.showNewTaskInput[bucketId] = !this.showNewTaskInput[bucketId]
|
||||
},
|
||||
addTaskToBucket(bucketId) {
|
||||
|
||||
|
@ -463,9 +483,6 @@ export default {
|
|||
this.newBucketTitle = ''
|
||||
this.showNewBucketInput = false
|
||||
})
|
||||
.catch(e => {
|
||||
this.$message.error(e)
|
||||
})
|
||||
},
|
||||
deleteBucketModal(bucketId) {
|
||||
if (this.buckets.length <= 1) {
|
||||
|
@ -478,16 +495,10 @@ export default {
|
|||
deleteBucket() {
|
||||
const bucket = new BucketModel({
|
||||
id: this.bucketToDelete,
|
||||
listId: this.$route.params.listId,
|
||||
})
|
||||
|
||||
this.$store.dispatch('kanban/deleteBucket', {bucket: bucket, params: this.params})
|
||||
.then(() => {
|
||||
this.$message.success({message: this.$t('list.kanban.deleteBucketSuccess')})
|
||||
})
|
||||
.catch(e => {
|
||||
this.$message.error(e)
|
||||
})
|
||||
.then(() => this.$message.success({message: this.$t('list.kanban.deleteBucketSuccess')}))
|
||||
.finally(() => {
|
||||
this.showBucketDeleteModal = false
|
||||
})
|
||||
|
@ -497,40 +508,22 @@ export default {
|
|||
this.bucketTitleEditable = true
|
||||
this.$nextTick(() => e.target.focus())
|
||||
},
|
||||
|
||||
saveBucketTitle(bucketId, bucketTitle) {
|
||||
this.bucketTitleEditable = false
|
||||
const bucket = new BucketModel({
|
||||
const updatedBucketData = {
|
||||
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 = findById(this.buckets, bucketId)
|
||||
if (realBucket.title === bucketTitle) {
|
||||
return
|
||||
}
|
||||
|
||||
this.$store.dispatch('kanban/updateBucket', bucket)
|
||||
.then(r => {
|
||||
realBucket.title = r.title
|
||||
this.$store.dispatch('kanban/updateBucketTitle', updatedBucketData)
|
||||
.then(() => {
|
||||
this.bucketTitleEditable = false
|
||||
this.$message.success({message: this.$t('list.kanban.bucketTitleSavedSuccess')})
|
||||
})
|
||||
.catch(e => {
|
||||
this.$message.error(e)
|
||||
})
|
||||
},
|
||||
updateBucket(bucket) {
|
||||
bucket.limit = parseInt(bucket.limit)
|
||||
this.$store.dispatch('kanban/updateBucket', bucket)
|
||||
.then(() => {
|
||||
this.$message.success({message: this.$t('list.kanban.bucketLimitSavedSuccess')})
|
||||
})
|
||||
.catch(e => {
|
||||
this.$message.error(e)
|
||||
})
|
||||
|
||||
updateBucketPositions(buckets) {
|
||||
this.$store.dispatch('kanban/updateBuckets', buckets)
|
||||
},
|
||||
updateBucketPosition(e) {
|
||||
this.dragBucket = false
|
||||
|
@ -539,19 +532,26 @@ export default {
|
|||
const bucketBefore = this.buckets[e.newIndex - 1] ?? null
|
||||
const bucketAfter = this.buckets[e.newIndex + 1] ?? null
|
||||
|
||||
bucket.position = calculateItemPosition(bucketBefore !== null ? bucketBefore.position : null, bucketAfter !== null ? bucketAfter.position : null)
|
||||
const updatedData = {
|
||||
id: bucket.id,
|
||||
position: calculateItemPosition(bucketBefore !== null ? bucketBefore.position : null, bucketAfter !== null ? bucketAfter.position : null),
|
||||
}
|
||||
|
||||
this.$store.dispatch('kanban/updateBucket', bucket)
|
||||
.catch(e => {
|
||||
this.$message.error(e)
|
||||
})
|
||||
this.$store.dispatch('kanban/updateBucket', updatedData)
|
||||
},
|
||||
setBucketLimit(bucket) {
|
||||
if (bucket.limit < 0) {
|
||||
setBucketLimit(bucketId, limit) {
|
||||
if (limit < 0) {
|
||||
return
|
||||
}
|
||||
|
||||
this.updateBucket(bucket)
|
||||
const newBucket = {
|
||||
...this.$store.getters['kanban/getBucketById'](bucketId),
|
||||
limit,
|
||||
}
|
||||
|
||||
this.$store.dispatch('kanban/updateBucket', newBucket)
|
||||
.then(() => this.$message.success({message: this.$t('list.kanban.bucketLimitSavedSuccess')}))
|
||||
|
||||
},
|
||||
shouldAcceptDrop(bucket) {
|
||||
return bucket.id === this.sourceBucket || // When dragging from a bucket who has its limit reached, dragging should still be possible
|
||||
|
@ -563,15 +563,13 @@ export default {
|
|||
this.sourceBucket = bucket.id
|
||||
},
|
||||
toggleDoneBucket(bucket) {
|
||||
bucket.isDoneBucket = !bucket.isDoneBucket
|
||||
this.$store.dispatch('kanban/updateBucket', bucket)
|
||||
.then(() => {
|
||||
this.$message.success({message: this.$t('list.kanban.doneBucketSavedSuccess')})
|
||||
})
|
||||
.catch(e => {
|
||||
this.$message.error(e)
|
||||
bucket.isDoneBucket = !bucket.isDoneBucket
|
||||
})
|
||||
const newBucket = {
|
||||
...bucket,
|
||||
isDoneBucket: !bucket.isDoneBucket,
|
||||
}
|
||||
this.$store.dispatch('kanban/updateBucket', newBucket)
|
||||
.then(() => this.$message.success({message: this.$t('list.kanban.doneBucketSavedSuccess')}))
|
||||
.catch(e => this.$message.error(e))
|
||||
},
|
||||
collapseBucket(bucket) {
|
||||
this.collapsedBuckets[bucket.id] = true
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
<filter-popup
|
||||
:visible="showTaskFilter"
|
||||
v-model="params"
|
||||
@update:modelValue="loadTasks(1)"
|
||||
@update:modelValue="loadTasks()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
<filter-popup
|
||||
:visible="showTaskFilter"
|
||||
v-model="params"
|
||||
@update:modelValue="loadTasks(1)"
|
||||
@update:modelValue="loadTasks()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ module.exports = {
|
|||
template: {
|
||||
compilerOptions: {
|
||||
compatConfig: {
|
||||
MODE: 2,
|
||||
MODE: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue