git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
4.0 KiB
4.0 KiB
Filter Builder - Quick Start Guide
🚀 3 Steps to Integrate
Step 1: Import (Line ~92)
import FilterBuilder from './FilterBuilder';
Step 2: Add Helpers (Line ~545, after addLog)
// Filter condition helpers
const addFilterCondition = useCallback(() => {
const newCondition: FilterCondition = {
id: `condition_${Date.now()}`,
field: '',
operator: 'eq',
value: '',
};
setFilterConditions(prev => [...prev, newCondition]);
}, []);
const updateFilterCondition = useCallback((id: string, updates: Partial<FilterCondition>) => {
setFilterConditions(prev =>
prev.map(cond => cond.id === id ? { ...cond, ...updates } : cond)
);
}, []);
const removeFilterCondition = useCallback((id: string) => {
setFilterConditions(prev => prev.filter(cond => cond.id !== id));
}, []);
const conditionsToFilterJson = useCallback((conditions: FilterCondition[]): string => {
if (conditions.length === 0) return '{}';
const filter: Record<string, any> = {};
conditions.forEach(cond => {
if (!cond.field.trim()) return;
const fieldName = cond.field.trim();
switch (cond.operator) {
case 'eq':
filter[fieldName] = cond.value;
break;
case 'ne':
filter[fieldName] = { $ne: cond.value };
break;
case 'gt':
filter[fieldName] = { ...(filter[fieldName] || {}), $gt: cond.value };
break;
case 'lt':
filter[fieldName] = { ...(filter[fieldName] || {}), $lt: cond.value };
break;
case 'gte':
filter[fieldName] = { ...(filter[fieldName] || {}), $gte: cond.value };
break;
case 'lte':
filter[fieldName] = { ...(filter[fieldName] || {}), $lte: cond.value };
break;
case 'contains':
filter[fieldName] = { $contains: cond.value };
break;
case 'exists':
filter[fieldName] = { $exists: cond.value === 'true' || cond.value === true };
break;
}
});
return JSON.stringify(filter, null, 2);
}, []);
useEffect(() => {
if (useFilter && filterConditions.length > 0) {
const jsonStr = conditionsToFilterJson(filterConditions);
setFilterJson(jsonStr);
}
}, [filterConditions, useFilter, conditionsToFilterJson]);
Step 3: Replace UI (Line ~1190, search for "Use metadata filter")
Find this:
{/* Filter option */}
<div className="flex items-center gap-4">
<Switch size="sm" isSelected={useFilter} onValueChange={setUseFilter}>
Use metadata filter
</Switch>
{useFilter && (
<Input
size="sm"
placeholder='{"category": "ML"}'
value={filterJson}
onChange={(e) => setFilterJson(e.target.value)}
...
/>
)}
</div>
Replace with:
{/* Filter option */}
<div className="space-y-3">
<Switch size="sm" isSelected={useFilter} onValueChange={setUseFilter}>
Use metadata filter
</Switch>
{useFilter && (
<FilterBuilder
conditions={filterConditions}
onAddCondition={addFilterCondition}
onUpdateCondition={updateFilterCondition}
onRemoveCondition={removeFilterCondition}
generatedJson={filterJson}
showJson={showFilterJson}
onToggleJson={() => setShowFilterJson(!showFilterJson)}
/>
)}
</div>
✅ Test
npm run dev
- Toggle "Use metadata filter" ON
- Click "+ Add Condition"
- Add filter:
category=ML - Click "Show JSON"
- Perform search
📚 Full Documentation
- Implementation Guide:
src/IMPLEMENTATION_GUIDE.md - Code Snippets:
src/CODE_SNIPPETS.md - Visual Demo:
src/FILTER_BUILDER_DEMO.md - README:
README_FILTER_BUILDER.md
📁 Files
- ✓
src/FilterBuilder.tsx(component) - ✓
src/App.tsx(modify this)
⚡ Already Done
- ✓ State variables added (lines 531-534)
- ✓ FilterCondition interface (lines 100-105)
- ✓ HeroUI components imported
- ✓ Lucide icons imported
Time to integrate: ~10 minutes