mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-12 08:42:18 +00:00
fix(logs): preserve exact alias exclusions when editing filters
This commit is contained in:
parent
c875836ed5
commit
333fd5b773
6 changed files with 48 additions and 9 deletions
|
|
@ -47,8 +47,8 @@ function renderFilters(filters: Record<string, string> = {}) {
|
|||
return { set };
|
||||
}
|
||||
|
||||
function StatefulFilters() {
|
||||
const [filters, setFilters] = useState<Record<string, string | undefined>>({});
|
||||
function StatefulFilters({ initialFilters = {} }: { initialFilters?: Record<string, string | undefined> }) {
|
||||
const [filters, setFilters] = useState<Record<string, string | undefined>>(initialFilters);
|
||||
return (
|
||||
<RequestLogsFilters
|
||||
get={(id: string) => filters[id]}
|
||||
|
|
@ -213,6 +213,22 @@ describe("RequestLogsFilters", () => {
|
|||
expect(set).toHaveBeenCalledWith(LOG_FILTER_IDS.EXCLUDE_KEY_ALIAS, "noisy");
|
||||
});
|
||||
|
||||
it("keeps a restored is not operator when clearing the alias to choose another", async () => {
|
||||
vi.mocked(useInfiniteKeyAliases).mockReturnValue({
|
||||
...emptyInfiniteQuery,
|
||||
data: { pages: [{ aliases: ["noisy", "quiet"] }], pageParams: [1] },
|
||||
} as unknown as ReturnType<typeof useInfiniteKeyAliases>);
|
||||
const user = userEvent.setup();
|
||||
renderWithProviders(<StatefulFilters initialFilters={{ [LOG_FILTER_IDS.EXCLUDE_KEY_ALIAS]: "noisy" }} />);
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "Clear", hidden: true }));
|
||||
|
||||
expect(screen.getByRole("combobox", { name: "Key Alias operator" })).toHaveTextContent("is not");
|
||||
await chooseSelectOption(user, screen.getByPlaceholderText("Search a key alias"), "quiet");
|
||||
expect(screen.getByRole("combobox", { name: "Key Alias operator" })).toHaveTextContent("is not");
|
||||
expect(screen.getByPlaceholderText("Search a key alias")).toHaveValue("quiet");
|
||||
});
|
||||
|
||||
it("does not leak the team scope into the Model lookup", async () => {
|
||||
renderFilters({ [LOG_FILTER_IDS.TEAM_ID]: "team-42" });
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ function KeyAliasFilterField({
|
|||
teamId: string;
|
||||
}) {
|
||||
const [search, setSearch] = useState("");
|
||||
const [operator, setOperator] = useState<KeyAliasOperator>("is");
|
||||
const [operator, setOperator] = useState<KeyAliasOperator>(excludeValue !== "" ? "is not" : "is");
|
||||
let activeOperator: KeyAliasOperator = operator;
|
||||
if (excludeValue !== "") {
|
||||
activeOperator = "is not";
|
||||
|
|
|
|||
|
|
@ -566,6 +566,21 @@ describe("RequestLogsPanel", () => {
|
|||
await waitFor(() => expect(lastCall()?.params?.exclude_key_alias).toBeUndefined());
|
||||
});
|
||||
|
||||
it.each([" noisy ", " "])(
|
||||
"preserves the exact excluded alias %j when reapplying bookmarked filters",
|
||||
async (alias) => {
|
||||
const user = userEvent.setup();
|
||||
renderPanel(new URLSearchParams({ exclude_key_alias: alias }).toString());
|
||||
|
||||
await waitFor(() => expect(lastCall()?.params?.exclude_key_alias).toBe(alias));
|
||||
await user.click(screen.getByTestId("datatable-filters-trigger"));
|
||||
await user.click(screen.getByTestId("filter-drawer-apply"));
|
||||
|
||||
await waitFor(() => expect(urlParams().get("exclude_key_alias")).toBe(alias));
|
||||
expect(lastCall()?.params?.exclude_key_alias).toBe(alias);
|
||||
},
|
||||
);
|
||||
|
||||
it("treats conflicting Key Alias URL parameters as one mutually exclusive filter", async () => {
|
||||
renderPanel("key_alias=quiet&exclude_key_alias=noisy");
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import type { LogEntry } from "../types";
|
|||
import {
|
||||
DEFAULT_LOGS_SORTING,
|
||||
formatLogsWindow,
|
||||
getExactFilterValue,
|
||||
getFilterValue,
|
||||
getLogsWindowEndBound,
|
||||
LOG_FILTER_IDS,
|
||||
|
|
@ -224,7 +225,7 @@ export default function RequestLogsPanel({ accessToken, token, userRole, userID,
|
|||
(updaterOrValue) => {
|
||||
const next = typeof updaterOrValue === "function" ? updaterOrValue(columnFiltersRef.current) : updaterOrValue;
|
||||
const nextKeyAlias = getFilterValue(next, LOG_FILTER_IDS.KEY_ALIAS);
|
||||
const nextExcludeKeyAlias = getFilterValue(next, LOG_FILTER_IDS.EXCLUDE_KEY_ALIAS);
|
||||
const nextExcludeKeyAlias = getExactFilterValue(next, LOG_FILTER_IDS.EXCLUDE_KEY_ALIAS);
|
||||
const normalizedNext = next.filter(
|
||||
(filter) => filter.id !== LOG_FILTER_IDS.KEY_ALIAS && filter.id !== LOG_FILTER_IDS.EXCLUDE_KEY_ALIAS,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -92,7 +92,9 @@ describe("useLogFilterLogic", () => {
|
|||
{ id: LOG_FILTER_IDS.MODEL_ID, value: "model-uuid-1", param: "model_id" },
|
||||
{ id: LOG_FILTER_IDS.PUBLIC_MODEL_OR_SEARCH_TOOL, value: "gpt-4o", param: "model" },
|
||||
{ id: LOG_FILTER_IDS.KEY_ALIAS, value: "alias-1", param: "key_alias" },
|
||||
{ id: "exclude_key_alias", value: "alias-1", param: "exclude_key_alias" },
|
||||
{ id: LOG_FILTER_IDS.EXCLUDE_KEY_ALIAS, value: "alias-1", param: "exclude_key_alias" },
|
||||
{ id: LOG_FILTER_IDS.EXCLUDE_KEY_ALIAS, value: " alias-1 ", param: "exclude_key_alias" },
|
||||
{ id: LOG_FILTER_IDS.EXCLUDE_KEY_ALIAS, value: " ", param: "exclude_key_alias" },
|
||||
{ id: LOG_FILTER_IDS.ERROR_CODE, value: "429", param: "error_code" },
|
||||
{ id: LOG_FILTER_IDS.ERROR_MESSAGE, value: "rate limited", param: "error_message" },
|
||||
{ id: LOG_FILTER_IDS.USER_ID, value: "user-9", param: "user_id" },
|
||||
|
|
@ -111,6 +113,7 @@ describe("useLogFilterLogic", () => {
|
|||
columnFilters: [
|
||||
{ id: LOG_FILTER_IDS.TEAM_ID, value: " " },
|
||||
{ id: LOG_FILTER_IDS.KEY_HASH, value: "" },
|
||||
{ id: LOG_FILTER_IDS.EXCLUDE_KEY_ALIAS, value: "" },
|
||||
],
|
||||
});
|
||||
|
||||
|
|
@ -118,6 +121,7 @@ describe("useLogFilterLogic", () => {
|
|||
const params = lastCallParams()?.params;
|
||||
expect(params?.team_id).toBeUndefined();
|
||||
expect(params?.api_key).toBeUndefined();
|
||||
expect(params?.exclude_key_alias).toBeUndefined();
|
||||
expect(params?.error_code).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -98,10 +98,13 @@ export const DEFAULT_LOGS_SORTING: SortingState = [{ id: "startTime", desc: true
|
|||
|
||||
const isSortField = (id: string): id is LogsSortField => Object.hasOwn(LOGS_SORT_FIELD_MAP, id);
|
||||
|
||||
export const getFilterValue = (columnFilters: ColumnFiltersState, columnId: string): string | undefined => {
|
||||
export const getExactFilterValue = (columnFilters: ColumnFiltersState, columnId: string): string | undefined => {
|
||||
const entry = columnFilters.find((filter) => filter.id === columnId);
|
||||
if (typeof entry?.value !== "string") return undefined;
|
||||
const trimmed = entry.value.trim();
|
||||
return typeof entry?.value === "string" && entry.value !== "" ? entry.value : undefined;
|
||||
};
|
||||
|
||||
export const getFilterValue = (columnFilters: ColumnFiltersState, columnId: string): string | undefined => {
|
||||
const trimmed = getExactFilterValue(columnFilters, columnId)?.trim();
|
||||
return trimmed === "" ? undefined : trimmed;
|
||||
};
|
||||
|
||||
|
|
@ -194,7 +197,7 @@ export function useLogFilterLogic({
|
|||
model_id: getFilterValue(columnFilters, LOG_FILTER_IDS.MODEL_ID),
|
||||
model: getFilterValue(columnFilters, LOG_FILTER_IDS.PUBLIC_MODEL_OR_SEARCH_TOOL),
|
||||
key_alias: getFilterValue(columnFilters, LOG_FILTER_IDS.KEY_ALIAS),
|
||||
exclude_key_alias: getFilterValue(columnFilters, LOG_FILTER_IDS.EXCLUDE_KEY_ALIAS),
|
||||
exclude_key_alias: getExactFilterValue(columnFilters, LOG_FILTER_IDS.EXCLUDE_KEY_ALIAS),
|
||||
error_code: getFilterValue(columnFilters, LOG_FILTER_IDS.ERROR_CODE),
|
||||
error_message: getFilterValue(columnFilters, LOG_FILTER_IDS.ERROR_MESSAGE),
|
||||
sort_by: sortBy,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue