Files
opencode-krates-connector/client/src/hooks/useSpotlight.ts
Hermes Agent f55f31a6d9 feat: implement Spotlight Krate Creation workflow
- Add type-to-trigger Spotlight with keyboard (any character)
- Add canvas click to open Spotlight
- Implement keyboard navigation (↑↓ Enter Esc)
- Add keyboard shortcut handlers and spotlight store
- Create useSpotlight hook with fuzzy search
- Create mock Kubernetes resources for initial testing
- Implement krate creation with collision detection
- Add Quick Actions (all pods, services, deployments, namespaces)
- Create Spotlight with filter chips and result rendering
- Add Spotlight state management with setQuery, setFilter, setSel
- Include design specs (Krates.dc.html, server.js, support.js)
2026-06-16 12:27:47 -04:00

136 lines
3.5 KiB
TypeScript

import { useMemo } from 'react'
import { fuzzySearch } from '../utils/fuzzy'
import { MOCK_NAMESPACES, MOCK_PODS, MOCK_DEPLOYMENTS, MOCK_SERVICES } from '../data/mockResources'
export interface SpotlightResource {
id: string
type: string
name: string
namespace?: string
status?: string
color: string
}
export const useSpotlight = () => {
const executeSearch = (query: string, filterType: string | null): SpotlightResource[] => {
if (!query || query.trim() === '') {
return []
}
const resources: SpotlightResource[] = []
const addIfExists = (items: any[], type: string) => {
items.forEach((item, index) => {
const name = item.name || item.metadata?.name
const ns = item.namespace || item.metadata?.namespace || 'default'
const color = getNamespaceColor(ns)
const score = fuzzySearch(query, name)
if (score > 0.3) {
if (!filterType || filterType === 'all' || filterType === type) {
resources.push({
id: `${type}-${index}-${name}`,
type,
name,
namespace: ns,
color: color,
})
}
}
})
}
if (!filterType || filterType === 'all' || filterType === 'namespace') {
MOCK_NAMESPACES.forEach((ns, index) => {
if (fuzzySearch(query, ns.name) > 0.3) {
resources.push({
id: `namespace-${index}-${ns.name}`,
type: 'namespace',
name: ns.name,
color: getNamespaceColor(ns.name),
})
}
})
}
if (!filterType || filterType === 'all' || filterType === 'pod') {
addIfExists(MOCK_PODS, 'pod')
}
if (!filterType || filterType === 'all' || filterType === 'deployment') {
addIfExists(MOCK_DEPLOYMENTS, 'deployment')
}
if (!filterType || filterType === 'all' || filterType === 'service') {
addIfExists(MOCK_SERVICES, 'service')
}
return resources.sort((a, b) => fuzzySearch(query, b.name) - fuzzySearch(query, a.name))
}
const getQuickActions = (query: string): SpotlightResource[] => {
const actions: SpotlightResource[] = []
const namespaces = Array.from(new Set([...MOCK_NAMESPACES.map((ns) => ns.name)]))
namespaces.forEach((ns, index) => {
actions.push({
id: `quick-${index}-${ns}`,
type: 'quick_create',
name: `Create krate for ns/${ns}`,
namespace: ns,
color: getNamespaceColor(ns),
})
})
actions.push({
id: 'quick-pods',
type: 'quick_create',
name: 'All pods',
color: '#6fb1ff',
})
actions.push({
id: 'quick-svcs',
type: 'quick_create',
name: 'All services',
color: '#6fb1ff',
})
actions.push({
id: 'quick-deployments',
type: 'quick_create',
name: 'All deployments',
color: '#6fb1ff',
})
if (query.trim()) {
actions.push({
id: 'quick-search',
type: 'quick_create',
name: `Search again for "${query}"`,
color: '#4dd6e8',
})
}
return actions
}
const getNamespaceColor = (namespace: string): string => {
if (namespace === 'default') return '#6fb1ff'
if (namespace === 'kube-system') return '#9c88ff'
if (namespace === 'kube-public') return '#4dd6e8'
if (namespace === 'production') return '#6fb1ff'
if (namespace === 'staging') return '#4dd6e8'
return '#6fb1ff'
}
return useMemo(
() => ({
executeSearch,
getQuickActions,
getNamespaceColor,
}),
[]
)
}