feat: add setting for default bucket
Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/3735
This commit is contained in:
commit
04ba1011cc
@ -2,6 +2,7 @@ import {library} from '@fortawesome/fontawesome-svg-core'
|
|||||||
import {
|
import {
|
||||||
faAlignLeft,
|
faAlignLeft,
|
||||||
faAngleRight,
|
faAngleRight,
|
||||||
|
faAnglesUp,
|
||||||
faArchive,
|
faArchive,
|
||||||
faArrowLeft,
|
faArrowLeft,
|
||||||
faArrowUpFromBracket,
|
faArrowUpFromBracket,
|
||||||
@ -142,6 +143,7 @@ library.add(faUser)
|
|||||||
library.add(faUsers)
|
library.add(faUsers)
|
||||||
library.add(faArrowUpFromBracket)
|
library.add(faArrowUpFromBracket)
|
||||||
library.add(faX)
|
library.add(faX)
|
||||||
|
library.add(faAnglesUp)
|
||||||
|
|
||||||
// overwriting the wrong types
|
// overwriting the wrong types
|
||||||
export default FontAwesomeIcon as unknown as FontAwesomeIconFixedTypes
|
export default FontAwesomeIcon as unknown as FontAwesomeIconFixedTypes
|
@ -1,21 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<BaseButton class="dropdown-item">
|
<BaseButton class="dropdown-item">
|
||||||
<span class="icon" v-if="icon">
|
<span
|
||||||
|
v-if="icon"
|
||||||
|
class="icon is-small"
|
||||||
|
:class="iconClass"
|
||||||
|
>
|
||||||
<Icon :icon="icon"/>
|
<Icon :icon="icon"/>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<slot />
|
<slot/>
|
||||||
</span>
|
</span>
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import BaseButton, { type BaseButtonProps } from '@/components/base//BaseButton.vue'
|
import BaseButton, {type BaseButtonProps} from '@/components/base//BaseButton.vue'
|
||||||
import Icon from '@/components/misc/Icon'
|
import Icon from '@/components/misc/Icon'
|
||||||
import type { IconProp } from '@fortawesome/fontawesome-svg-core'
|
import type {IconProp} from '@fortawesome/fontawesome-svg-core'
|
||||||
|
|
||||||
export interface DropDownItemProps extends /* @vue-ignore */ BaseButtonProps {
|
export interface DropDownItemProps extends /* @vue-ignore */ BaseButtonProps {
|
||||||
icon?: IconProp,
|
icon?: IconProp,
|
||||||
|
iconClass?: object | string,
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<DropDownItemProps>()
|
defineProps<DropDownItemProps>()
|
||||||
@ -24,7 +29,6 @@ defineProps<DropDownItemProps>()
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.dropdown-item {
|
.dropdown-item {
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
display: block;
|
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
padding: $item-padding;
|
padding: $item-padding;
|
||||||
@ -52,10 +56,7 @@ defineProps<DropDownItemProps>()
|
|||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
padding-right: .5rem;
|
padding-right: .5rem;
|
||||||
|
color: var(--grey-300);
|
||||||
&:not(.has-text-success) {
|
|
||||||
color: var(--grey-300) !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-text-danger .icon {
|
.has-text-danger .icon {
|
||||||
|
@ -334,6 +334,9 @@
|
|||||||
"doneBucketHint": "All tasks moved into this bucket will automatically marked as done.",
|
"doneBucketHint": "All tasks moved into this bucket will automatically marked as done.",
|
||||||
"doneBucketHintExtended": "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.",
|
"doneBucketHintExtended": "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.",
|
||||||
"doneBucketSavedSuccess": "The done bucket has been saved successfully.",
|
"doneBucketSavedSuccess": "The done bucket has been saved successfully.",
|
||||||
|
"defaultBucket": "Default bucket",
|
||||||
|
"defaultBucketHint": "When creating tasks without specifying a bucket, they will be added to this bucket.",
|
||||||
|
"defaultBucketSavedSuccess": "The default bucket has been saved successfully.",
|
||||||
"deleteLast": "You cannot remove the last bucket.",
|
"deleteLast": "You cannot remove the last bucket.",
|
||||||
"addTaskPlaceholder": "Enter the new task title…",
|
"addTaskPlaceholder": "Enter the new task title…",
|
||||||
"addTask": "Add a task",
|
"addTask": "Add a task",
|
||||||
|
@ -8,7 +8,6 @@ export interface IBucket extends IAbstract {
|
|||||||
projectId: number
|
projectId: number
|
||||||
limit: number
|
limit: number
|
||||||
tasks: ITask[]
|
tasks: ITask[]
|
||||||
isDoneBucket: boolean
|
|
||||||
position: number
|
position: number
|
||||||
count: number
|
count: number
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ export interface IProject extends IAbstract {
|
|||||||
position: number
|
position: number
|
||||||
backgroundBlurHash: string
|
backgroundBlurHash: string
|
||||||
parentProjectId: number
|
parentProjectId: number
|
||||||
|
doneBucketId: number
|
||||||
|
defaultBucketId: number
|
||||||
|
|
||||||
created: Date
|
created: Date
|
||||||
updated: Date
|
updated: Date
|
||||||
|
@ -12,7 +12,6 @@ export default class BucketModel extends AbstractModel<IBucket> implements IBuck
|
|||||||
projectId = ''
|
projectId = ''
|
||||||
limit = 0
|
limit = 0
|
||||||
tasks: ITask[] = []
|
tasks: ITask[] = []
|
||||||
isDoneBucket = false
|
|
||||||
position = 0
|
position = 0
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ export default class ProjectModel extends AbstractModel<IProject> implements IPr
|
|||||||
position = 0
|
position = 0
|
||||||
backgroundBlurHash = ''
|
backgroundBlurHash = ''
|
||||||
parentProjectId = 0
|
parentProjectId = 0
|
||||||
|
doneBucketId = 0
|
||||||
|
defaultBucketId = 0
|
||||||
|
|
||||||
created: Date = null
|
created: Date = null
|
||||||
updated: Date = null
|
updated: Date = null
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
>
|
>
|
||||||
<div class="bucket-header" @click="() => unCollapseBucket(bucket)">
|
<div class="bucket-header" @click="() => unCollapseBucket(bucket)">
|
||||||
<span
|
<span
|
||||||
v-if="bucket.isDoneBucket"
|
v-if="project.doneBucketId === bucket.id"
|
||||||
class="icon is-small has-text-success mr-2"
|
class="icon is-small has-text-success mr-2"
|
||||||
v-tooltip="$t('project.kanban.doneBucketHint')"
|
v-tooltip="$t('project.kanban.doneBucketHint')"
|
||||||
>
|
>
|
||||||
@ -97,26 +97,32 @@
|
|||||||
<dropdown-item
|
<dropdown-item
|
||||||
@click.stop="toggleDoneBucket(bucket)"
|
@click.stop="toggleDoneBucket(bucket)"
|
||||||
v-tooltip="$t('project.kanban.doneBucketHintExtended')"
|
v-tooltip="$t('project.kanban.doneBucketHintExtended')"
|
||||||
|
:icon-class="{'has-text-success': bucket.id === project.doneBucketId}"
|
||||||
|
icon="check-double"
|
||||||
>
|
>
|
||||||
<span class="icon is-small" :class="{'has-text-success': bucket.isDoneBucket}">
|
|
||||||
<icon icon="check-double"/>
|
|
||||||
</span>
|
|
||||||
{{ $t('project.kanban.doneBucket') }}
|
{{ $t('project.kanban.doneBucket') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
|
<dropdown-item
|
||||||
|
@click.stop="toggleDefaultBucket(bucket)"
|
||||||
|
v-tooltip="$t('project.kanban.defaultBucketHint')"
|
||||||
|
:icon-class="{'has-text-primary': bucket.id === project.defaultBucketId}"
|
||||||
|
icon="th"
|
||||||
|
>
|
||||||
|
{{ $t('project.kanban.defaultBucket') }}
|
||||||
|
</dropdown-item>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
@click.stop="() => collapseBucket(bucket)"
|
@click.stop="() => collapseBucket(bucket)"
|
||||||
|
icon="angles-up"
|
||||||
>
|
>
|
||||||
{{ $t('project.kanban.collapse') }}
|
{{ $t('project.kanban.collapse') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:class="{'is-disabled': buckets.length <= 1}"
|
:class="{'is-disabled': buckets.length <= 1}"
|
||||||
@click.stop="() => deleteBucketModal(bucket.id)"
|
@click.stop="() => deleteBucketModal(bucket.id)"
|
||||||
class="has-text-danger"
|
|
||||||
v-tooltip="buckets.length <= 1 ? $t('project.kanban.deleteLast') : ''"
|
v-tooltip="buckets.length <= 1 ? $t('project.kanban.deleteLast') : ''"
|
||||||
|
icon-class="has-text-danger"
|
||||||
|
icon="trash-alt"
|
||||||
>
|
>
|
||||||
<span class="icon is-small">
|
|
||||||
<icon icon="trash-alt"/>
|
|
||||||
</span>
|
|
||||||
{{ $t('misc.delete') }}
|
{{ $t('misc.delete') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
</dropdown>
|
</dropdown>
|
||||||
@ -251,6 +257,7 @@ import {calculateItemPosition} from '@/helpers/calculateItemPosition'
|
|||||||
|
|
||||||
import {isSavedFilter} from '@/services/savedFilter'
|
import {isSavedFilter} from '@/services/savedFilter'
|
||||||
import {success} from '@/message'
|
import {success} from '@/message'
|
||||||
|
import {useProjectStore} from '@/stores/projects'
|
||||||
|
|
||||||
const DRAG_OPTIONS = {
|
const DRAG_OPTIONS = {
|
||||||
// sortable options
|
// sortable options
|
||||||
@ -268,6 +275,7 @@ const {t} = useI18n({useScope: 'global'})
|
|||||||
const baseStore = useBaseStore()
|
const baseStore = useBaseStore()
|
||||||
const kanbanStore = useKanbanStore()
|
const kanbanStore = useKanbanStore()
|
||||||
const taskStore = useTaskStore()
|
const taskStore = useTaskStore()
|
||||||
|
const projectStore = useProjectStore()
|
||||||
|
|
||||||
const taskContainerRefs = ref<{[id: IBucket['id']]: HTMLElement}>({})
|
const taskContainerRefs = ref<{[id: IBucket['id']]: HTMLElement}>({})
|
||||||
|
|
||||||
@ -422,10 +430,9 @@ async function updateTaskPosition(e) {
|
|||||||
)
|
)
|
||||||
if (
|
if (
|
||||||
oldBucket !== undefined && // This shouldn't actually be `undefined`, but let's play it safe.
|
oldBucket !== undefined && // This shouldn't actually be `undefined`, but let's play it safe.
|
||||||
newBucket.id !== oldBucket.id &&
|
newBucket.id !== oldBucket.id
|
||||||
newBucket.isDoneBucket !== oldBucket.isDoneBucket
|
|
||||||
) {
|
) {
|
||||||
newTask.done = newBucket.isDoneBucket
|
newTask.done = project.value.doneBucketId === newBucket.id
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
oldBucket !== undefined && // This shouldn't actually be `undefined`, but let's play it safe.
|
oldBucket !== undefined && // This shouldn't actually be `undefined`, but let's play it safe.
|
||||||
@ -596,10 +603,26 @@ function dragstart(bucket: IBucket) {
|
|||||||
sourceBucket.value = bucket.id
|
sourceBucket.value = bucket.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function toggleDefaultBucket(bucket: IBucket) {
|
||||||
|
const defaultBucketId = project.value.defaultBucketId === bucket.id
|
||||||
|
? 0
|
||||||
|
: bucket.id
|
||||||
|
|
||||||
|
await projectStore.updateProject({
|
||||||
|
...project.value,
|
||||||
|
defaultBucketId,
|
||||||
|
})
|
||||||
|
success({message: t('project.kanban.defaultBucketSavedSuccess')})
|
||||||
|
}
|
||||||
|
|
||||||
async function toggleDoneBucket(bucket: IBucket) {
|
async function toggleDoneBucket(bucket: IBucket) {
|
||||||
await kanbanStore.updateBucket({
|
const doneBucketId = project.value.doneBucketId === bucket.id
|
||||||
...bucket,
|
? 0
|
||||||
isDoneBucket: !bucket.isDoneBucket,
|
: bucket.id
|
||||||
|
|
||||||
|
await projectStore.updateProject({
|
||||||
|
...project.value,
|
||||||
|
doneBucketId,
|
||||||
})
|
})
|
||||||
success({message: t('project.kanban.doneBucketSavedSuccess')})
|
success({message: t('project.kanban.doneBucketSavedSuccess')})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user