frontend/src/components/tasks/partials/editLabels.vue

156 lines
3.6 KiB
Vue
Raw Normal View History

2019-11-24 13:16:24 +00:00
<template>
<Multiselect
:loading="loading"
:placeholder="$t('task.label.placeholder')"
:multiple="true"
@search="findLabel"
:search-results="foundLabels"
@select="addLabel"
label="title"
:creatable="true"
@create="createAndAddLabel"
:create-placeholder="$t('task.label.createPlaceholder')"
v-model="labels"
:search-delay="10"
:close-after-select="false"
2019-11-24 13:16:24 +00:00
>
<template #tag="{item: label}">
<span
:style="{'background': label.hexColor, 'color': label.textColor}"
2021-01-17 09:55:04 +00:00
class="tag">
<span>{{ label.title }}</span>
<BaseButton v-cy="'taskDetail.removeLabel'" @click="removeLabel(label)" class="delete is-small" />
</span>
2019-11-24 13:16:24 +00:00
</template>
<template #searchResult="{option}">
<span
v-if="typeof option === 'string'"
2022-01-18 21:22:32 +00:00
class="tag search-result">
<span>{{ option }}</span>
</span>
<span
v-else
:style="{'background': option.hexColor, 'color': option.textColor}"
2022-01-18 21:22:32 +00:00
class="tag search-result">
<span>{{ option.title }}</span>
</span>
</template>
</Multiselect>
2019-11-24 13:16:24 +00:00
</template>
<script setup lang="ts">
2022-06-23 01:08:35 +00:00
import {type PropType, ref, computed, shallowReactive, watch} from 'vue'
import {useI18n} from 'vue-i18n'
2022-09-05 16:32:42 +00:00
import LabelModel from '@/models/label'
import LabelTaskService from '@/services/labelTask'
import {success} from '@/message'
import BaseButton from '@/components/base/BaseButton.vue'
import Multiselect from '@/components/input/multiselect.vue'
2022-09-23 10:55:53 +00:00
import type {ILabel} from '@/modelTypes/ILabel'
import {useLabelStore} from '@/stores/labels'
import {useTaskStore} from '@/stores/tasks'
const props = defineProps({
modelValue: {
2022-07-20 22:42:36 +00:00
type: Array as PropType<ILabel[]>,
default: () => [],
},
taskId: {
type: Number,
required: false,
default: 0,
},
disabled: {
default: false,
},
})
const emit = defineEmits(['update:modelValue'])
const {t} = useI18n({useScope: 'global'})
const labelTaskService = shallowReactive(new LabelTaskService())
2022-07-20 22:42:36 +00:00
const labels = ref<ILabel[]>([])
const query = ref('')
watch(
() => props.modelValue,
(value) => {
labels.value = value
},
{
immediate: true,
deep: true,
},
)
2022-09-23 10:55:53 +00:00
const taskStore = useTaskStore()
const labelStore = useLabelStore()
const foundLabels = computed(() => labelStore.filterLabelsByQuery(labels.value, query.value))
const loading = computed(() => labelTaskService.loading || labelStore.isLoading)
function findLabel(newQuery: string) {
query.value = newQuery
}
2022-07-20 22:42:36 +00:00
async function addLabel(label: ILabel, showNotification = true) {
if (props.taskId === 0) {
2022-09-23 10:55:53 +00:00
emit('update:modelValue', labels.value)
return
}
2022-09-23 10:55:53 +00:00
await taskStore.addLabel({label, taskId: props.taskId})
emit('update:modelValue', labels.value)
if (showNotification) {
success({message: t('task.label.addSuccess')})
}
}
2022-07-20 22:42:36 +00:00
async function removeLabel(label: ILabel) {
if (props.taskId !== 0) {
2022-09-23 10:55:53 +00:00
await taskStore.removeLabel({label, taskId: props.taskId})
}
for (const l in labels.value) {
if (labels.value[l].id === label.id) {
2022-07-20 19:15:35 +00:00
labels.value.splice(l, 1) // FIXME: l should be index
}
}
emit('update:modelValue', labels.value)
success({message: t('task.label.removeSuccess')})
}
async function createAndAddLabel(title: string) {
if (props.taskId === 0) {
return
}
const labelStore = useLabelStore()
const newLabel = await labelStore.createLabel(new LabelModel({title}))
addLabel(newLabel, false)
labels.value.push(newLabel)
success({message: t('task.label.addCreateSuccess')})
}
2019-11-24 13:16:24 +00:00
</script>
<style lang="scss" scoped>
.tag {
2022-01-18 21:22:32 +00:00
margin: .25rem !important;
}
.tag.search-result {
margin: 0 !important;
}
:deep(.input-wrapper) {
padding: .25rem !important;
}
:deep(input.input) {
padding: 0 .5rem;
}
</style>