Download frontend/src/ui/tools/useToolsInventory.js from ruslanmv/HomePilot: direct link, hf CLI and curl.
- Browser
- Download file 3.41 kB
-
https://huggingface.co/spaces/ruslanmv/HomePilot/resolve/main/frontend/src/ui/tools/useToolsInventory.js
- Command line
-
hf download hf://spaces/ruslanmv/HomePilot/frontend/src/ui/tools/useToolsInventory.js
-
curl -L -o useToolsInventory.js https://huggingface.co/spaces/ruslanmv/HomePilot/resolve/main/frontend/src/ui/tools/useToolsInventory.js
3.41 kB
| /** | |
| * Hook that wraps useAgenticCatalog and provides a unified capabilities view. | |
| * | |
| * Merges catalog.tools + catalog.a2a_agents into a single CapabilityItem[] | |
| * list with search, status, and type filtering. | |
| */ | |
| import { useMemo, useState } from 'react'; | |
| import { useAgenticCatalog } from '../../agentic/useAgenticCatalog'; | |
| import { deriveStatus } from './ToolStatusBadge'; | |
| export function useToolsInventory({ backendUrl, apiKey }) { | |
| const { catalog, loading, error, refresh } = useAgenticCatalog({ | |
| backendUrl, | |
| apiKey, | |
| enabled: true, | |
| }); | |
| const [search, setSearch] = useState(''); | |
| const [statusFilter, setStatusFilter] = useState('all'); | |
| const [typeFilter, setTypeFilter] = useState('all'); | |
| /* Build unified list from both sources */ | |
| const allItems = useMemo(() => { | |
| const toolItems = (catalog?.tools || []) | |
| .filter((t) => t.id && t.name) | |
| .map((t) => ({ kind: 'tool', data: t })); | |
| const a2aItems = (catalog?.a2a_agents || []) | |
| .filter((a) => a.id && a.name) | |
| .map((a) => ({ kind: 'a2a_agent', data: a })); | |
| return [...toolItems, ...a2aItems]; | |
| }, [catalog?.tools, catalog?.a2a_agents]); | |
| /* Filtered list */ | |
| const items = useMemo(() => { | |
| let filtered = allItems; | |
| // Type filter | |
| if (typeFilter !== 'all') { | |
| const kind = typeFilter === 'a2a' ? 'a2a_agent' : 'tool'; | |
| filtered = filtered.filter((item) => item.kind === kind); | |
| } | |
| // Search filter | |
| if (search.trim()) { | |
| const q = search.toLowerCase(); | |
| filtered = filtered.filter((item) => { | |
| const d = item.data; | |
| const searchable = `${d.name} ${d.description || ''} ${d.id} ${item.kind === 'a2a_agent' && 'endpoint_url' in d ? d.endpoint_url || '' : ''}`; | |
| return searchable.toLowerCase().includes(q); | |
| }); | |
| } | |
| // Status filter | |
| if (statusFilter !== 'all') { | |
| filtered = filtered.filter((item) => deriveStatus(item.data.enabled) === statusFilter); | |
| } | |
| return filtered; | |
| }, [allItems, search, statusFilter, typeFilter]); | |
| /* Counts */ | |
| const counts = useMemo(() => { | |
| const tools = (catalog?.tools || []); | |
| const a2a = (catalog?.a2a_agents || []); | |
| return { | |
| total: tools.length + a2a.length, | |
| tools: { | |
| total: tools.length, | |
| active: tools.filter((t) => t.enabled === true).length, | |
| inactive: tools.filter((t) => t.enabled === false).length, | |
| }, | |
| a2a: { | |
| total: a2a.length, | |
| active: a2a.filter((a) => a.enabled === true).length, | |
| inactive: a2a.filter((a) => a.enabled === false).length, | |
| }, | |
| active: tools.filter((t) => t.enabled === true).length + a2a.filter((a) => a.enabled === true).length, | |
| inactive: tools.filter((t) => t.enabled === false).length + a2a.filter((a) => a.enabled === false).length, | |
| }; | |
| }, [catalog?.tools, catalog?.a2a_agents]); | |
| return { | |
| items, | |
| counts, | |
| loading, | |
| error, | |
| refresh, | |
| search, | |
| setSearch, | |
| statusFilter, | |
| setStatusFilter, | |
| typeFilter, | |
| setTypeFilter, | |
| forgeHealthy: catalog?.forge?.healthy ?? null, | |
| }; | |
| } | |