feat: move select filters to dedicated components
This commit is contained in:
parent
4bad685f39
commit
bb58dba8e0
63
src/components/input/SelectList.vue
Normal file
63
src/components/input/SelectList.vue
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<multiselect
|
||||||
|
v-model="selectedLists"
|
||||||
|
:search-results="foundLists"
|
||||||
|
:loading="listService.loading"
|
||||||
|
:multiple="true"
|
||||||
|
:placeholder="$t('list.search')"
|
||||||
|
label="title"
|
||||||
|
@search="findLists"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {computed, ref, shallowReactive, watchEffect, type PropType} from 'vue'
|
||||||
|
|
||||||
|
import Multiselect from '@/components/input/multiselect.vue'
|
||||||
|
|
||||||
|
import type {IList} from '@/modelTypes/IList'
|
||||||
|
|
||||||
|
import ListService from '@/services/list'
|
||||||
|
import {includesById} from '@/helpers/utils'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Array as PropType<IList[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:modelValue', value: IList[]): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const lists = ref<IList[]>([])
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
lists.value = props.modelValue
|
||||||
|
})
|
||||||
|
|
||||||
|
const selectedLists = computed({
|
||||||
|
get() {
|
||||||
|
return lists.value
|
||||||
|
},
|
||||||
|
set: (value) => {
|
||||||
|
lists.value = value
|
||||||
|
emit('update:modelValue', value)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const listService = shallowReactive(new ListService())
|
||||||
|
const foundLists = ref<IList[]>([])
|
||||||
|
|
||||||
|
async function findLists(query: string) {
|
||||||
|
if (query === '') {
|
||||||
|
foundLists.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await listService.getAll({}, {s: query}) as IList[]
|
||||||
|
|
||||||
|
// Filter selected items from the results
|
||||||
|
foundLists.value = response.filter(({id}) => !includesById(lists.value, id))
|
||||||
|
}
|
||||||
|
</script>
|
63
src/components/input/SelectNamespace.vue
Normal file
63
src/components/input/SelectNamespace.vue
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<multiselect
|
||||||
|
v-model="selectedNamespaces"
|
||||||
|
:search-results="foundNamespaces"
|
||||||
|
:loading="namespaceService.loading"
|
||||||
|
:multiple="true"
|
||||||
|
:placeholder="$t('namespace.search')"
|
||||||
|
label="namespace"
|
||||||
|
@search="findNamespaces"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {computed, ref, shallowReactive, watchEffect, type PropType} from 'vue'
|
||||||
|
|
||||||
|
import Multiselect from '@/components/input/multiselect.vue'
|
||||||
|
|
||||||
|
import type {INamespace} from '@/modelTypes/INamespace'
|
||||||
|
|
||||||
|
import NamespaceService from '@/services/namespace'
|
||||||
|
import {includesById} from '@/helpers/utils'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Array as PropType<INamespace[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:modelValue', value: INamespace[]): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const namespaces = ref<INamespace[]>([])
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
namespaces.value = props.modelValue
|
||||||
|
})
|
||||||
|
|
||||||
|
const selectedNamespaces = computed({
|
||||||
|
get() {
|
||||||
|
return namespaces.value
|
||||||
|
},
|
||||||
|
set: (value) => {
|
||||||
|
namespaces.value = value
|
||||||
|
emit('update:modelValue', value)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const namespaceService = shallowReactive(new NamespaceService())
|
||||||
|
const foundNamespaces = ref<INamespace[]>([])
|
||||||
|
|
||||||
|
async function findNamespaces(query: string) {
|
||||||
|
if (query === '') {
|
||||||
|
foundNamespaces.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await namespaceService.getAll({}, {s: query}) as INamespace[]
|
||||||
|
|
||||||
|
// Filter selected items from the results
|
||||||
|
foundNamespaces.value = response.filter(({id}) => !includesById(namespaces.value, id))
|
||||||
|
}
|
||||||
|
</script>
|
63
src/components/input/SelectUser.vue
Normal file
63
src/components/input/SelectUser.vue
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<multiselect
|
||||||
|
v-model="selectedUsers"
|
||||||
|
:search-results="foundUsers"
|
||||||
|
:loading="userService.loading"
|
||||||
|
:multiple="true"
|
||||||
|
:placeholder="$t('team.edit.search')"
|
||||||
|
label="username"
|
||||||
|
@search="findUsers"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {computed, ref, shallowReactive, watchEffect, type PropType} from 'vue'
|
||||||
|
|
||||||
|
import Multiselect from '@/components/input/multiselect.vue'
|
||||||
|
|
||||||
|
import type {IUser} from '@/modelTypes/IUser'
|
||||||
|
|
||||||
|
import UserService from '@/services/user'
|
||||||
|
import {includesById} from '@/helpers/utils'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Array as PropType<IUser[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:modelValue', value: IUser[]): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const users = ref<IUser[]>([])
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
users.value = props.modelValue
|
||||||
|
})
|
||||||
|
|
||||||
|
const selectedUsers = computed({
|
||||||
|
get() {
|
||||||
|
return users.value
|
||||||
|
},
|
||||||
|
set: (value) => {
|
||||||
|
users.value = value
|
||||||
|
emit('update:modelValue', value)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const userService = shallowReactive(new UserService())
|
||||||
|
const foundUsers = ref<IUser[]>([])
|
||||||
|
|
||||||
|
async function findUsers(query: string) {
|
||||||
|
if (query === '') {
|
||||||
|
foundUsers.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await userService.getAll({}, {s: query}) as IUser[]
|
||||||
|
|
||||||
|
// Filter selected items from the results
|
||||||
|
foundUsers.value = response.filter(({id}) => !includesById(users.value, id))
|
||||||
|
}
|
||||||
|
</script>
|
@ -135,16 +135,10 @@
|
|||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">{{ $t('task.attributes.assignees') }}</label>
|
<label class="label">{{ $t('task.attributes.assignees') }}</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<multiselect
|
<SelectUser
|
||||||
:loading="services.users.loading"
|
|
||||||
:placeholder="$t('team.edit.search')"
|
|
||||||
@search="(query: string) => find('users', query)"
|
|
||||||
:search-results="foundEntities.users"
|
|
||||||
@select="() => add('users', 'assignees')"
|
|
||||||
label="username"
|
|
||||||
:multiple="true"
|
|
||||||
@remove="() => remove('users', 'assignees')"
|
|
||||||
v-model="entities.users"
|
v-model="entities.users"
|
||||||
|
@select="changeMultiselectFilter('users', 'assignees')"
|
||||||
|
@remove="changeMultiselectFilter('users', 'assignees')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -152,7 +146,10 @@
|
|||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">{{ $t('task.attributes.labels') }}</label>
|
<label class="label">{{ $t('task.attributes.labels') }}</label>
|
||||||
<div class="control labels-list">
|
<div class="control labels-list">
|
||||||
<edit-labels v-model="entities.labels" @update:model-value="changeLabelFilter"/>
|
<edit-labels
|
||||||
|
v-model="entities.labels"
|
||||||
|
@update:model-value="changeLabelFilter"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -161,32 +158,20 @@
|
|||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">{{ $t('list.lists') }}</label>
|
<label class="label">{{ $t('list.lists') }}</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<multiselect
|
<SelectList
|
||||||
:loading="services.lists.loading"
|
|
||||||
:placeholder="$t('list.search')"
|
|
||||||
@search="(query: string) => find('lists', query)"
|
|
||||||
:search-results="foundEntities.lists"
|
|
||||||
@select="() => add('lists', 'list_id')"
|
|
||||||
label="title"
|
|
||||||
@remove="() => remove('lists', 'list_id')"
|
|
||||||
:multiple="true"
|
|
||||||
v-model="entities.lists"
|
v-model="entities.lists"
|
||||||
|
@select="changeMultiselectFilter('lists', 'list_id')"
|
||||||
|
@remove="changeMultiselectFilter('lists', 'list_id')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">{{ $t('namespace.namespaces') }}</label>
|
<label class="label">{{ $t('namespace.namespaces') }}</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<multiselect
|
<SelectNamespace
|
||||||
:loading="services.namespace.loading"
|
|
||||||
:placeholder="$t('namespace.search')"
|
|
||||||
@search="(query: string) => find('namespace', query)"
|
|
||||||
:search-results="foundEntities.namespace"
|
|
||||||
@select="() => add('namespace', 'namespace')"
|
|
||||||
label="title"
|
|
||||||
@remove="() => remove('namespace', 'namespace')"
|
|
||||||
:multiple="true"
|
|
||||||
v-model="entities.namespace"
|
v-model="entities.namespace"
|
||||||
|
@select="changeMultiselectFilter('namespace', 'namespace')"
|
||||||
|
@remove="changeMultiselectFilter('namespace', 'namespace')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -214,10 +199,11 @@ import PrioritySelect from '@/components/tasks/partials/prioritySelect.vue'
|
|||||||
import PercentDoneSelect from '@/components/tasks/partials/percentDoneSelect.vue'
|
import PercentDoneSelect from '@/components/tasks/partials/percentDoneSelect.vue'
|
||||||
import EditLabels from '@/components/tasks/partials/editLabels.vue'
|
import EditLabels from '@/components/tasks/partials/editLabels.vue'
|
||||||
import Fancycheckbox from '@/components/input/fancycheckbox.vue'
|
import Fancycheckbox from '@/components/input/fancycheckbox.vue'
|
||||||
import Multiselect from '@/components/input/multiselect.vue'
|
import SelectUser from '@/components/input/SelectUser.vue'
|
||||||
|
import SelectList from '@/components/input/SelectList.vue'
|
||||||
|
import SelectNamespace from '@/components/input/SelectNamespace.vue'
|
||||||
|
|
||||||
import {parseDateOrString} from '@/helpers/time/parseDateOrString'
|
import {parseDateOrString} from '@/helpers/time/parseDateOrString'
|
||||||
import {includesById} from '@/helpers/utils'
|
|
||||||
import {dateIsValid, formatISO} from '@/helpers/time/formatDate'
|
import {dateIsValid, formatISO} from '@/helpers/time/formatDate'
|
||||||
import {objectToSnakeCase} from '@/helpers/case'
|
import {objectToSnakeCase} from '@/helpers/case'
|
||||||
|
|
||||||
@ -298,12 +284,6 @@ const entities: Entities = reactive({
|
|||||||
namespace: [],
|
namespace: [],
|
||||||
})
|
})
|
||||||
|
|
||||||
const foundEntities: Omit<Entities, 'labels'> = reactive({
|
|
||||||
users: [],
|
|
||||||
lists: [],
|
|
||||||
namespace: [],
|
|
||||||
})
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
filters.value.requireAllFilters = params.value.filter_concat === 'and'
|
filters.value.requireAllFilters = params.value.filter_concat === 'and'
|
||||||
})
|
})
|
||||||
@ -579,31 +559,9 @@ function setPercentDoneFilter() {
|
|||||||
setSingleValueFilter('percent_done', 'percentDone', 'usePercentDone')
|
setSingleValueFilter('percent_done', 'percentDone', 'usePercentDone')
|
||||||
}
|
}
|
||||||
|
|
||||||
async function find(kind: Omit<EntityType, 'labels'>, query: string) {
|
async function changeMultiselectFilter(kind: EntityType, filterName) {
|
||||||
if (query === '') {
|
await nextTick()
|
||||||
foundEntities[kind] = []
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await services[kind].getAll({}, {s: query})
|
|
||||||
|
|
||||||
// Filter users from the results who are already assigned
|
|
||||||
foundEntities[kind] = response.filter(({id}) => !includesById(entities[kind], id))
|
|
||||||
}
|
|
||||||
|
|
||||||
function add(kind, filterName) {
|
|
||||||
nextTick(() => {
|
|
||||||
changeMultiselectFilter(kind, filterName)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function remove(kind, filterName) {
|
|
||||||
nextTick(() => {
|
|
||||||
changeMultiselectFilter(kind, filterName)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeMultiselectFilter(kind: EntityType, filterName) {
|
|
||||||
if (entities[kind].length === 0) {
|
if (entities[kind].length === 0) {
|
||||||
removePropertyFromFilter(filterName)
|
removePropertyFromFilter(filterName)
|
||||||
change()
|
change()
|
||||||
|
@ -6,7 +6,7 @@ export function findById<T extends {id: string | number}>(array : T[], id : stri
|
|||||||
return array.find(({id: currentId}) => currentId === id)
|
return array.find(({id: currentId}) => currentId === id)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function includesById(array: [], id: string | number) {
|
export function includesById(array: any[], id: string | number) {
|
||||||
return array.some(({id: currentId}) => currentId === id)
|
return array.some(({id: currentId}) => currentId === id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user