Files
cameleer-server/ui/src/components/command-palette/PaletteInput.tsx

73 lines
2.1 KiB
TypeScript
Raw Normal View History

import { useRef, useEffect } from 'react';
import { useCommandPalette } from './use-command-palette';
import { parseFilterPrefix, checkTrailingFilter } from './utils';
import styles from './CommandPalette.module.css';
export function PaletteInput() {
const { query, filters, setQuery, addFilter, removeLastFilter, removeFilter } =
useCommandPalette();
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
inputRef.current?.focus();
}, []);
function handleChange(value: string) {
// Check if user typed a filter prefix like "status:failed "
const parsed = parseFilterPrefix(value);
if (parsed) {
addFilter(parsed.filter);
setQuery(parsed.remaining);
return;
}
const trailing = checkTrailingFilter(value);
if (trailing) {
addFilter(trailing);
setQuery('');
return;
}
setQuery(value);
}
function handleKeyDown(e: React.KeyboardEvent) {
if (e.key === 'Backspace' && query === '' && filters.length > 0) {
e.preventDefault();
removeLastFilter();
}
}
return (
<div className={styles.inputWrap}>
<svg className={styles.searchIcon} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<circle cx="11" cy="11" r="8" />
<path d="m21 21-4.35-4.35" />
</svg>
{filters.length > 0 && (
<div className={styles.chipList}>
{filters.map((f, i) => (
<span key={f.key} className={styles.chip}>
<span className={styles.chipKey}>{f.key}:</span>
{f.value}
<button className={styles.chipRemove} onClick={() => removeFilter(i)}>
&times;
</button>
</span>
))}
</div>
)}
<input
ref={inputRef}
className={styles.input}
type="text"
value={query}
onChange={(e) => handleChange(e.target.value)}
onKeyDown={handleKeyDown}
placeholder={filters.length > 0 ? 'Refine search...' : 'Search executions, agents...'}
/>
<div className={styles.inputHint}>
<kbd className={styles.kbd}>esc</kbd> close
</div>
</div>
);
}