Skip to content

Commit 692bbc2

Browse files
authored
Merge pull request #321 from traceroot-ai/feat/service_name_contain_modify_selected
feat: service name contain and modify selected search
2 parents ad085b9 + 2350b7f commit 692bbc2

File tree

1 file changed

+112
-22
lines changed

1 file changed

+112
-22
lines changed

ui/src/components/explore/SearchBar.tsx

Lines changed: 112 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ const SearchBar: React.FC<SearchBarProps> = ({
7373
const [metadataCategoryValue, setMetadataCategoryValue] = useState("");
7474
const [metadataValue, setMetadataValue] = useState("");
7575
const [logSearchValue, setLogSearchValue] = useState("");
76+
const [editingCriterionId, setEditingCriterionId] = useState<string | null>(
77+
null,
78+
);
7679
const searchBarRef = useRef<HTMLDivElement>(null);
7780

7881
// Memoize extracted search terms to prevent unnecessary re-renders
@@ -106,11 +109,20 @@ const SearchBar: React.FC<SearchBarProps> = ({
106109
// Click-outside detection to collapse search
107110
useEffect(() => {
108111
const handleClickOutside = (event: MouseEvent) => {
109-
if (
110-
searchBarRef.current &&
111-
!searchBarRef.current.contains(event.target as Node) &&
112-
isSearchExpanded
113-
) {
112+
const target = event.target as Node;
113+
114+
// Check if click is inside the search bar
115+
if (searchBarRef.current && searchBarRef.current.contains(target)) {
116+
return;
117+
}
118+
119+
// Check if click is inside a dropdown menu portal
120+
// Radix UI portals have data-radix-popper-content-wrapper attribute
121+
const isInsideDropdown = (target as Element).closest?.(
122+
'[role="menu"], [data-radix-popper-content-wrapper]',
123+
);
124+
125+
if (isSearchExpanded && !isInsideDropdown) {
114126
setIsSearchExpanded(false);
115127
}
116128
};
@@ -140,6 +152,40 @@ const SearchBar: React.FC<SearchBarProps> = ({
140152
}
141153
}, [metadataSearchTerms, onMetadataSearchTermsChange]);
142154

155+
const handleEditCriterion = (criterion: SearchCriterion) => {
156+
if (disabled) return;
157+
158+
// Load the criterion into the input fields
159+
setEditingCriterionId(criterion.id);
160+
setCurrentCriterion({
161+
category: criterion.category,
162+
operation: criterion.operation,
163+
});
164+
165+
// Set the appropriate input value based on category
166+
if (
167+
criterion.category !== "metadata" &&
168+
criterion.category !== "log" &&
169+
criterion.category !== "service_name" &&
170+
criterion.category !== "service_environment"
171+
) {
172+
// For metadata categories, split category and value
173+
setMetadataCategoryValue(criterion.category);
174+
setMetadataValue(criterion.value);
175+
setCurrentCriterion({
176+
category: "metadata",
177+
operation: criterion.operation,
178+
});
179+
} else if (criterion.category === "log") {
180+
setLogSearchValue(criterion.value);
181+
} else {
182+
setInputValue(criterion.value);
183+
}
184+
185+
// Ensure search bar is expanded
186+
setIsSearchExpanded(true);
187+
};
188+
143189
const handleAddCriterion = () => {
144190
if (disabled) return;
145191

@@ -154,24 +200,42 @@ const SearchBar: React.FC<SearchBarProps> = ({
154200
}
155201

156202
if (categoryValue && currentCriterion.operation && searchValue) {
157-
const newCriterion: SearchCriterion = {
158-
id: Date.now().toString(),
159-
category: categoryValue,
160-
operation: currentCriterion.operation,
161-
value: searchValue,
162-
logicalOperator: criteria.length > 0 ? "AND" : undefined,
163-
};
164-
165-
const newCriteria = [...criteria, newCriterion];
203+
let newCriteria: SearchCriterion[];
204+
const operation = currentCriterion.operation; // Guaranteed to be string due to the if condition
205+
206+
if (editingCriterionId) {
207+
// Update existing criterion
208+
newCriteria = criteria.map((c) =>
209+
c.id === editingCriterionId
210+
? {
211+
...c,
212+
category: categoryValue,
213+
operation: operation,
214+
value: searchValue,
215+
}
216+
: c,
217+
);
218+
setEditingCriterionId(null);
219+
} else {
220+
// Add new criterion
221+
const newCriterion: SearchCriterion = {
222+
id: Date.now().toString(),
223+
category: categoryValue,
224+
operation: operation,
225+
value: searchValue,
226+
logicalOperator: criteria.length > 0 ? "AND" : undefined,
227+
};
228+
newCriteria = [...criteria, newCriterion];
229+
}
230+
166231
setCriteria(newCriteria);
167232
setCurrentCriterion({ category: "log", operation: "contains" });
168233
setInputValue("");
169234
setMetadataCategoryValue("");
170235
setMetadataValue("");
171-
// Clear logSearchValue when adding a criterion
172236
setLogSearchValue("");
173237
onSearch(newCriteria);
174-
// Collapse search after adding criterion
238+
// Collapse search after adding/updating criterion
175239
setIsSearchExpanded(false);
176240
}
177241
};
@@ -181,6 +245,17 @@ const SearchBar: React.FC<SearchBarProps> = ({
181245

182246
const newCriteria = criteria.filter((c) => c.id !== id);
183247
setCriteria(newCriteria);
248+
249+
// If we're editing the criterion being removed, clear the edit state
250+
if (editingCriterionId === id) {
251+
setEditingCriterionId(null);
252+
setCurrentCriterion({ category: "log", operation: "contains" });
253+
setInputValue("");
254+
setMetadataCategoryValue("");
255+
setMetadataValue("");
256+
setLogSearchValue("");
257+
}
258+
184259
// If no criteria left, default back to log category
185260
if (newCriteria.length === 0) {
186261
setCurrentCriterion({ category: "log", operation: "contains" });
@@ -237,7 +312,10 @@ const SearchBar: React.FC<SearchBarProps> = ({
237312
{criterion.logicalOperator}
238313
</span>
239314
)}
240-
<div className="flex items-center space-x-1 bg-gray-100 dark:bg-gray-700 rounded-md px-2 py-1">
315+
<div
316+
className="flex items-center space-x-1 rounded-md px-2 py-1 cursor-pointer transition-all bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600"
317+
onClick={() => handleEditCriterion(criterion)}
318+
>
241319
<span className="text-xs font-medium text-gray-700 dark:text-gray-300">
242320
{getCategoryLabel(criterion.category)}
243321
</span>
@@ -250,7 +328,10 @@ const SearchBar: React.FC<SearchBarProps> = ({
250328
<Button
251329
variant="ghost"
252330
size="icon"
253-
onClick={() => handleRemoveCriterion(criterion.id)}
331+
onClick={(e) => {
332+
e.stopPropagation();
333+
handleRemoveCriterion(criterion.id);
334+
}}
254335
className="ml-0.5 h-4 w-4 p-0 opacity-70 transition-opacity hover:opacity-100 flex-shrink-0"
255336
disabled={disabled}
256337
>
@@ -427,7 +508,14 @@ const SearchBar: React.FC<SearchBarProps> = ({
427508
if (currentCriterion.category === "log") {
428509
return operation.value === "contains";
429510
}
430-
// For other categories, show '=' operation
511+
// For service_name and service_environment, show both operations
512+
if (
513+
currentCriterion.category === "service_name" ||
514+
currentCriterion.category === "service_environment"
515+
) {
516+
return true; // Show both '=' and 'contains'
517+
}
518+
// For other categories (metadata), show '=' operation only
431519
return operation.value === "=";
432520
}).map((operation) => (
433521
<DropdownMenuRadioItem
@@ -460,7 +548,7 @@ const SearchBar: React.FC<SearchBarProps> = ({
460548
<div className="flex items-center gap-1">
461549
<span>Press</span>
462550
<Kbd>Enter</Kbd>
463-
<span>to add</span>
551+
<span>to {editingCriterionId ? "update" : "add"}</span>
464552
</div>
465553
</TooltipContent>
466554
</Tooltip>
@@ -484,7 +572,7 @@ const SearchBar: React.FC<SearchBarProps> = ({
484572
<div className="flex items-center gap-1">
485573
<span>Press</span>
486574
<Kbd>Enter</Kbd>
487-
<span>to add</span>
575+
<span>to {editingCriterionId ? "update" : "add"}</span>
488576
</div>
489577
</TooltipContent>
490578
</Tooltip>
@@ -509,7 +597,7 @@ const SearchBar: React.FC<SearchBarProps> = ({
509597
<div className="flex items-center gap-1">
510598
<span>Press</span>
511599
<Kbd>Enter</Kbd>
512-
<span>to add</span>
600+
<span>to {editingCriterionId ? "update" : "add"}</span>
513601
</div>
514602
</TooltipContent>
515603
</Tooltip>
@@ -522,6 +610,8 @@ const SearchBar: React.FC<SearchBarProps> = ({
522610
onClick={() => {
523611
// Clear all completed criteria
524612
setCriteria([]);
613+
// Clear editing state
614+
setEditingCriterionId(null);
525615
// Clear current criterion being built and reset to default
526616
setCurrentCriterion({ category: "log", operation: "contains" });
527617
// Clear input value

0 commit comments

Comments
 (0)