mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
refactor: rework useSearch and ViewSearch to no longer use ViewBase and expect defined data
This commit is contained in:
parent
da02692d93
commit
1f1dac1792
2 changed files with 43 additions and 49 deletions
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts" generic="T extends Obj | AnyTreeNode">
|
<script setup lang="ts" generic="T extends Obj | AnyTreeNode">
|
||||||
import { computed, type Component } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
import type { AnyTreeNode } from '@/helpers/data/tree'
|
import type { AnyTreeNode } from '@/helpers/data/tree'
|
||||||
|
@ -10,12 +10,10 @@ const props = withDefaults(
|
||||||
items?: T[] | null
|
items?: T[] | null
|
||||||
itemsName: string | null
|
itemsName: string | null
|
||||||
modelValue?: string
|
modelValue?: string
|
||||||
skeleton?: string | Component
|
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
items: undefined,
|
items: undefined,
|
||||||
modelValue: undefined,
|
modelValue: undefined,
|
||||||
skeleton: 'ListGroupSkeleton',
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,6 +22,7 @@ const slots = defineSlots<{
|
||||||
'top-bar-buttons': any
|
'top-bar-buttons': any
|
||||||
top: any
|
top: any
|
||||||
'alert-message': any
|
'alert-message': any
|
||||||
|
'forced-default'?: any
|
||||||
default: any
|
default: any
|
||||||
bot: any
|
bot: any
|
||||||
skeleton: any
|
skeleton: any
|
||||||
|
@ -47,11 +46,10 @@ const noItemsMessage = computed(() => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ViewBase :skeleton="skeleton">
|
<div>
|
||||||
<template v-if="slots['top-bar']" #top-bar>
|
<slot v-if="slots['top-bar']" name="top-bar" />
|
||||||
<slot name="top-bar" />
|
<TopBar v-else>
|
||||||
</template>
|
<template #group-left>
|
||||||
<template v-if="!slots['top-bar']" #top-bar-group-left>
|
|
||||||
<BInputGroup class="w-100">
|
<BInputGroup class="w-100">
|
||||||
<BInputGroupText>
|
<BInputGroupText>
|
||||||
<YIcon iname="search" />
|
<YIcon iname="search" />
|
||||||
|
@ -60,36 +58,30 @@ const noItemsMessage = computed(() => {
|
||||||
<BFormInput
|
<BFormInput
|
||||||
id="top-bar-search"
|
id="top-bar-search"
|
||||||
v-model="model"
|
v-model="model"
|
||||||
:placeholder="t('search.for', { items: t('items.' + itemsName, 2) })"
|
:placeholder="
|
||||||
:disabled="!items"
|
t('search.for', { items: t('items.' + itemsName, 2) })
|
||||||
|
"
|
||||||
|
:disabled="items === undefined"
|
||||||
/>
|
/>
|
||||||
</BInputGroup>
|
</BInputGroup>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="!slots['top-bar']" #top-bar-group-right>
|
<template #group-right>
|
||||||
<slot name="top-bar-buttons" />
|
<slot name="top-bar-buttons" />
|
||||||
</template>
|
</template>
|
||||||
|
</TopBar>
|
||||||
|
|
||||||
<template #top>
|
|
||||||
<slot name="top" />
|
<slot name="top" />
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default>
|
<slot name="forced-default">
|
||||||
<BAlert v-if="noItemsMessage" :model-value="true" variant="warning">
|
<BAlert v-if="noItemsMessage" :model-value="true" variant="warning">
|
||||||
<slot name="alert-message">
|
<slot name="alert-message">
|
||||||
<YIcon iname="exclamation-triangle" />
|
<YIcon iname="exclamation-triangle" />
|
||||||
{{ noItemsMessage }}
|
{{ noItemsMessage }}
|
||||||
</slot>
|
</slot>
|
||||||
</BAlert>
|
</BAlert>
|
||||||
|
|
||||||
<slot v-else name="default" />
|
<slot v-else name="default" />
|
||||||
</template>
|
</slot>
|
||||||
|
|
||||||
<template #bot>
|
|
||||||
<slot name="bot" />
|
<slot name="bot" />
|
||||||
</template>
|
</div>
|
||||||
|
|
||||||
<template #skeleton>
|
|
||||||
<slot name="skeleton" />
|
|
||||||
</template>
|
|
||||||
</ViewBase>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
import type { ComputedRef, MaybeRefOrGetter, Ref } from 'vue'
|
import type {
|
||||||
import { computed, ref, toValue, watch } from 'vue'
|
ComputedRef,
|
||||||
|
MaybeRefOrGetter,
|
||||||
|
Ref,
|
||||||
|
WritableComputedRef,
|
||||||
|
} from 'vue'
|
||||||
|
import { computed, isRef, ref, toValue } from 'vue'
|
||||||
|
|
||||||
import type { AnyTreeNode, TreeRootNode } from '@/helpers/data/tree'
|
import type { AnyTreeNode, TreeRootNode } from '@/helpers/data/tree'
|
||||||
|
|
||||||
|
// Returns `undefined` when there's no items and `null` when there's no match
|
||||||
export function useSearch<
|
export function useSearch<
|
||||||
T extends any[] | TreeRootNode,
|
T extends any[] | TreeRootNode,
|
||||||
V extends T extends (infer V)[] ? V : AnyTreeNode,
|
V extends T extends (infer V)[] ? V : AnyTreeNode,
|
||||||
>(
|
>(
|
||||||
items:
|
items: MaybeRefOrGetter<T> | ComputedRef<T>,
|
||||||
| MaybeRefOrGetter<T | null | undefined>
|
|
||||||
| ComputedRef<T | null | undefined>,
|
|
||||||
filterFn: (search: string, item: V, index: number, arr: T) => boolean,
|
filterFn: (search: string, item: V, index: number, arr: T) => boolean,
|
||||||
{
|
{
|
||||||
externalSearch,
|
externalSearch,
|
||||||
|
@ -18,19 +22,17 @@ export function useSearch<
|
||||||
}: {
|
}: {
|
||||||
filterAllFn?: (search: string, items: T) => boolean | undefined
|
filterAllFn?: (search: string, items: T) => boolean | undefined
|
||||||
filterIfNoSearch?: boolean
|
filterIfNoSearch?: boolean
|
||||||
externalSearch?: MaybeRefOrGetter<string>
|
externalSearch?: Ref<string> | WritableComputedRef<string>
|
||||||
} = {},
|
} = {},
|
||||||
): [search: Ref<string>, filteredItems: ComputedRef<T | undefined | null>] {
|
): [search: Ref<string>, filteredItems: ComputedRef<T | undefined | null>] {
|
||||||
const search = ref(toValue(externalSearch) ?? '')
|
const search = isRef(externalSearch)
|
||||||
watch(
|
? externalSearch
|
||||||
() => toValue(externalSearch),
|
: ref(toValue(externalSearch) ?? '')
|
||||||
(s) => (search.value = s ?? ''),
|
|
||||||
)
|
|
||||||
|
|
||||||
const filteredItems = computed(() => {
|
const filteredItems = computed(() => {
|
||||||
const items_ = toValue(items)
|
const items_ = toValue(items)
|
||||||
const s = toValue(search.value).toLowerCase()
|
const s = toValue(search.value).toLowerCase()
|
||||||
if (!items_) return undefined
|
if (!items_.length) return undefined
|
||||||
if (filterAllFn) {
|
if (filterAllFn) {
|
||||||
const returnAll = filterAllFn(s, items_)
|
const returnAll = filterAllFn(s, items_)
|
||||||
if (returnAll !== undefined) {
|
if (returnAll !== undefined) {
|
||||||
|
|
Loading…
Reference in a new issue