feat: move select filters to dedicated components
continuous-integration/drone/pr Build is passing Details

This commit is contained in:
Dominik Pschenitschni 2022-11-06 21:49:28 +01:00
parent 4bad685f39
commit bb58dba8e0
Signed by: dpschen
GPG Key ID: B257AC0149F43A77
5 changed files with 208 additions and 61 deletions

View 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>

View 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>

View 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>

View File

@ -135,16 +135,10 @@
<div class="field">
<label class="label">{{ $t('task.attributes.assignees') }}</label>
<div class="control">
<multiselect
: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')"
<SelectUser
v-model="entities.users"
@select="changeMultiselectFilter('users', 'assignees')"
@remove="changeMultiselectFilter('users', 'assignees')"
/>
</div>
</div>
@ -152,7 +146,10 @@
<div class="field">
<label class="label">{{ $t('task.attributes.labels') }}</label>
<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>
@ -161,32 +158,20 @@
<div class="field">
<label class="label">{{ $t('list.lists') }}</label>
<div class="control">
<multiselect
: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"
<SelectList
v-model="entities.lists"
@select="changeMultiselectFilter('lists', 'list_id')"
@remove="changeMultiselectFilter('lists', 'list_id')"
/>
</div>
</div>
<div class="field">
<label class="label">{{ $t('namespace.namespaces') }}</label>
<div class="control">
<multiselect
: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"
<SelectNamespace
v-model="entities.namespace"
@select="changeMultiselectFilter('namespace', 'namespace')"
@remove="changeMultiselectFilter('namespace', 'namespace')"
/>
</div>
</div>
@ -214,10 +199,11 @@ import PrioritySelect from '@/components/tasks/partials/prioritySelect.vue'
import PercentDoneSelect from '@/components/tasks/partials/percentDoneSelect.vue'
import EditLabels from '@/components/tasks/partials/editLabels.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 {includesById} from '@/helpers/utils'
import {dateIsValid, formatISO} from '@/helpers/time/formatDate'
import {objectToSnakeCase} from '@/helpers/case'
@ -298,12 +284,6 @@ const entities: Entities = reactive({
namespace: [],
})
const foundEntities: Omit<Entities, 'labels'> = reactive({
users: [],
lists: [],
namespace: [],
})
onMounted(() => {
filters.value.requireAllFilters = params.value.filter_concat === 'and'
})
@ -579,31 +559,9 @@ function setPercentDoneFilter() {
setSingleValueFilter('percent_done', 'percentDone', 'usePercentDone')
}
async function find(kind: Omit<EntityType, 'labels'>, query: string) {
if (query === '') {
foundEntities[kind] = []
return
}
async function changeMultiselectFilter(kind: EntityType, filterName) {
await nextTick()
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) {
removePropertyFromFilter(filterName)
change()

View File

@ -6,7 +6,7 @@ export function findById<T extends {id: string | number}>(array : T[], id : stri
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)
}