Поиск и фильтры
Поиск и группы фильтров сужают один набор вместе: сущность совпадает, если прошла текстовый запрос и группу типов и группу состояний и каждую группу, объявленную потребителем, и пользовательский предикат.
Показать исходник
<script setup lang="ts">
import { ref } from 'vue'
import { AssetMap, emptyFilterState } from 'vue-asset-map'
import type { FilterState } from 'vue-asset-map'
import { useSiteTheme } from '../theme/useSiteTheme'
import { useSiteLocale } from '../theme/useSiteLocale'
import { entities, links, views, filterGroups, statusColors, kindIcons } from './fixture'
const theme = useSiteTheme()
const locale = useSiteLocale()
const filters = ref<FilterState>(emptyFilterState())
const openFilterGroups = ref<string[]>(['subnet'])
// Try `10.38.24.*` or `10.38.24.0/24` in the search field.
function preset(query: string): void {
filters.value = { ...filters.value, query }
}
</script>
<template>
<AssetMap
v-model:filters="filters"
v-model:open-filter-groups="openFilterGroups"
class="demo-map"
view="physical"
:entities="entities"
:links="links"
:views="views"
:filter-options="{ groups: filterGroups, neighborDepth: 1 }"
:theme="theme"
:locale="locale"
:theme-config="{ statusColors, kindIcons }"
:layout="{ engine: 'radial', options: { rootId: 'internet' } }"
auto-fit-view
>
<template #toolbar-right>
<button type="button" class="demo-toolbar-button" @click="preset('10.38.24.0/24')">
CIDR 10.38.24.0/24
</button>
<button type="button" class="demo-toolbar-button" @click="preset('')">Reset</button>
</template>
</AssetMap>
</template>
Режимы поиска
Режим выбирает сам запрос:
| Запрос | Режим |
|---|---|
10.38.24.0/24 | CIDR — адреса внутри подписей сравниваются с диапазоном |
10.38.24.*, 10.38.*.*, 10.38.24.7* | Маска — сравнение по строковому виду, поэтому .7* найдёт и .7, и .70 |
beelink | Регистронезависимая подстрока |
База CIDR может быть любым адресом внутри сети: 10.38.24.5/24 — тот же диапазон, что и 10.38.24.0/24.
Какие поля искать — решаете вы:
const filterOptions = {
searchFields: (entity) => [entity.label, entity.meta?.fqdn ?? '', ...(entity.sublabels ?? [])],
}По умолчанию — название плюс все подписи.
Совпадения и видимая область
applyFilters возвращает два множества:
matchedIds— прямые совпадения, их подсвечивает рендер;visibleIds— всё, что остаётся на карте: совпадения плюс соседи наneighborDepthшагов плюс цепочки предков, если не выключенkeepPathToRoot.
Соседи и путь до корня сохраняют граф связным вокруг совпадений. Узел вне области видимости не показывается и не служит мостиком на следующий шаг обхода.
const filterOptions = {
neighborDepth: 2,
keepPathToRoot: true,
layers: ['physical'],
}Пока не активен ни один критерий, matchedIds пуст, а виден весь граф: подсвечивать пока нечего.
Свои группы фильтров
Пакет не знает, что такое «подсеть» или «критичность». Объявите группы и то, как читать их значения с сущности:
import type { FilterGroupDef } from 'vue-asset-map'
const filterGroups: FilterGroupDef[] = [
{
id: 'subnet',
label: 'Подсеть',
valuesOf: (entity) => (entity.meta?.subnet ? [entity.meta.subnet] : []),
options: [
{ value: 'internet', label: 'Интернет' },
{ value: 'vpn', label: 'VPN' },
{ value: 'docker', label: 'Docker bridge' },
],
},
{
id: 'severity',
label: 'Критичность',
valuesOf: (entity) => (entity.meta?.severity ? [entity.meta.severity] : []),
options: [
{ value: 'critical', label: 'Критический' },
{ value: 'high', label: 'Высокий' },
{ value: 'medium', label: 'Средний' },
{ value: 'low', label: 'Низкий' },
],
defaultOpen: false,
},
]<AssetMap :entities="entities" :links="links" :filter-options="{ groups: filterGroups }" />options фиксирует порядок и подписи — здесь критичность идёт по убыванию, а не по алфавиту. Без него значения собираются из самих данных.
Значения внутри одной группы соединяются по ИЛИ: выбор «критический» и «высокий» показывает оба. Группы между собой соединяются по И.
Счётчики групп фильтров
Счётчики считаются по текущей проекции, а не по результату фильтра. Иначе выбор offline обнулил бы все остальные счётчики, и вернуться было бы некуда.
Значения, объявленные в options явно, показываются даже с нулём, поэтому список не прыгает, пока по нему кликают.
Управление состоянием
<AssetMap
v-model:filters="filters"
v-model:open-filter-groups="openFilterGroups"
:entities="entities"
:links="links"
:filter-options="{ groups: filterGroups }"
/>import { emptyFilterState } from 'vue-asset-map'
const filters = ref(emptyFilterState())
const openFilterGroups = ref<string[]>(['subnet'])Какие группы раскрыты — это состояние компонента, а не localStorage: пакет не пишет в хранилище браузера. Сохранять его между сессиями решает приложение, и v-model:open-filter-groups — то, как оно выходит наружу.
Задержка перед применением
Текстовый запрос откладывается на searchDebounce (200 мс по умолчанию). Клик по значению группы фильтров применяется сразу: это осознанное единичное действие, и задерживать его не нужно. Очистка поля тоже применяется сразу.
Раскладка не зависит от фильтра: поиск скрывает и подсвечивает узлы, но не перестраивает карту. Иначе граф прыгал бы на каждой набранной букве.