Add a "done" option to kanban buckets (#440)
Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/440 Co-authored-by: konrad <konrad@kola-entertainments.de> Co-committed-by: konrad <konrad@kola-entertainments.de>
This commit is contained in:
parent
f1115c2338
commit
2435bd68a0
4 changed files with 65 additions and 7 deletions
|
@ -20,6 +20,7 @@ export default class BucketModel extends AbstractModel {
|
||||||
listId: 0,
|
listId: 0,
|
||||||
limit: 0,
|
limit: 0,
|
||||||
tasks: [],
|
tasks: [],
|
||||||
|
isDoneBucket: false,
|
||||||
|
|
||||||
createdBy: null,
|
createdBy: null,
|
||||||
created: null,
|
created: null,
|
||||||
|
|
|
@ -8,6 +8,12 @@ import TaskCollectionService from '@/services/taskCollection'
|
||||||
|
|
||||||
const tasksPerBucket = 25
|
const tasksPerBucket = 25
|
||||||
|
|
||||||
|
const addTaskToBucketAndSort = (state, task) => {
|
||||||
|
const bi = filterObject(state.buckets, b => b.id === task.bucketId)
|
||||||
|
state.buckets[bi].tasks.push(task)
|
||||||
|
state.buckets[bi].tasks.sort((a, b) => a.position > b.position ? 1 : -1)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This store is intended to hold the currently active kanban view.
|
* This store is intended to hold the currently active kanban view.
|
||||||
* It should hold only the current buckets.
|
* It should hold only the current buckets.
|
||||||
|
@ -64,16 +70,38 @@ export default {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const b in state.buckets) {
|
let found = false
|
||||||
if (state.buckets[b].id === task.bucketId) {
|
|
||||||
|
const findAndUpdate = b => {
|
||||||
for (const t in state.buckets[b].tasks) {
|
for (const t in state.buckets[b].tasks) {
|
||||||
if (state.buckets[b].tasks[t].id === task.id) {
|
if (state.buckets[b].tasks[t].id === task.id) {
|
||||||
const bucket = state.buckets[b]
|
const bucket = state.buckets[b]
|
||||||
bucket.tasks[t] = task
|
bucket.tasks[t] = task
|
||||||
|
|
||||||
|
if (bucket.id !== task.bucketId) {
|
||||||
|
bucket.tasks.splice(t, 1)
|
||||||
|
addTaskToBucketAndSort(state, task)
|
||||||
|
}
|
||||||
|
|
||||||
Vue.set(state.buckets, b, bucket)
|
Vue.set(state.buckets, b, bucket)
|
||||||
|
found = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const b in state.buckets) {
|
||||||
|
if (state.buckets[b].id === task.bucketId) {
|
||||||
|
findAndUpdate(b)
|
||||||
|
if (found) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const b in state.buckets) {
|
||||||
|
findAndUpdate(b)
|
||||||
|
if (found) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,9 @@ button.table {
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
padding-right: .5rem;
|
padding-right: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon:not(.has-text-success) {
|
||||||
color: $grey-300 !important;
|
color: $grey-300 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,13 @@
|
||||||
<div :class="{ 'is-loading': loading && !oneTaskUpdating}" class="kanban loader-container">
|
<div :class="{ 'is-loading': loading && !oneTaskUpdating}" class="kanban loader-container">
|
||||||
<div :key="`bucket${bucket.id}`" class="bucket" v-for="bucket in buckets">
|
<div :key="`bucket${bucket.id}`" class="bucket" v-for="bucket in buckets">
|
||||||
<div class="bucket-header">
|
<div class="bucket-header">
|
||||||
|
<span
|
||||||
|
v-if="bucket.isDoneBucket"
|
||||||
|
class="icon is-small has-text-success mr-2"
|
||||||
|
v-tooltip="'All tasks moved into this bucket will automatically marked as done.'"
|
||||||
|
>
|
||||||
|
<icon icon="check-double"/>
|
||||||
|
</span>
|
||||||
<h2
|
<h2
|
||||||
:ref="`bucket${bucket.id}title`"
|
:ref="`bucket${bucket.id}title`"
|
||||||
@focusout="() => saveBucketTitle(bucket.id)"
|
@focusout="() => saveBucketTitle(bucket.id)"
|
||||||
|
@ -63,6 +70,14 @@
|
||||||
Limit: {{ bucket.limit > 0 ? bucket.limit : 'Not set' }}
|
Limit: {{ bucket.limit > 0 ? bucket.limit : 'Not set' }}
|
||||||
</template>
|
</template>
|
||||||
</a>
|
</a>
|
||||||
|
<a
|
||||||
|
@click="toggleDoneBucket(bucket)"
|
||||||
|
class="dropdown-item"
|
||||||
|
v-tooltip="'All tasks moved into the done bucket will be marked as done automatically. All tasks marked as done from elsewhere will be moved as well.'"
|
||||||
|
>
|
||||||
|
<span class="icon is-small" :class="{'has-text-success': bucket.isDoneBucket}"><icon icon="check-double"/></span>
|
||||||
|
Done bucket
|
||||||
|
</a>
|
||||||
<a
|
<a
|
||||||
:class="{'is-disabled': buckets.length <= 1}"
|
:class="{'is-disabled': buckets.length <= 1}"
|
||||||
@click="() => deleteBucketModal(bucket.id)"
|
@click="() => deleteBucketModal(bucket.id)"
|
||||||
|
@ -591,6 +606,17 @@ export default {
|
||||||
bucket.limit === 0 || // If there is no limit set, dragging & dropping should always work
|
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
|
bucket.tasks.length < bucket.limit // Disallow dropping to buckets which have their limit reached
|
||||||
},
|
},
|
||||||
|
toggleDoneBucket(bucket) {
|
||||||
|
bucket.isDoneBucket = !bucket.isDoneBucket
|
||||||
|
this.$store.dispatch('kanban/updateBucket', bucket)
|
||||||
|
.then(() => {
|
||||||
|
this.success({message: 'The done bucket has been saved successfully.'}, this)
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
this.error(e, this)
|
||||||
|
bucket.isDoneBucket = !bucket.isDoneBucket
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in a new issue