73 lines
2.1 KiB
TypeScript
73 lines
2.1 KiB
TypeScript
|
|
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)}>
|
||
|
|
×
|
||
|
|
</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>
|
||
|
|
);
|
||
|
|
}
|