mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-19 00:01:29 +00:00
fix(ui): reset virtual keys sort on filter reset and wire key hash filter
Two follow-ups on top of the filter-persistence fix: - Reset Filters now also resets the column sort. The sort state lives in the table's local `sorting`, separate from `filters` — clicking Reset cleared the chips but left the column header arrow and the useKeys sort_by/sort_order untouched. Wrap onResetFilters to setSorting and call onSortChange with the defaults (created_at desc). - Wire the "Key Hash" filter end-to-end. The chip was rendered but handleFilterChange dropped the value and useKeys never received it, so typing into Key Hash did nothing. Add it to FilterState/ DEFAULT_FILTERS/handleFilterChange and forward debouncedFilters ["Key Hash"] into useKeys. - Drop the now-dead "Sort By"/"Sort Order" entries from FilterState — the sort handler no longer writes them and Reset's old behavior of resetting them was a no-op. - Tests: forward Key Hash assertion in VirtualKeysTable.test.tsx, Key Hash handleFilterChange test in filter_logic.test.tsx, and update mock filter shapes accordingly. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f301297125
commit
cb65102669
4 changed files with 54 additions and 32 deletions
|
|
@ -203,8 +203,7 @@ beforeEach(() => {
|
|||
"User ID": "user-1",
|
||||
"User Email": "user@example.com",
|
||||
"User Role": "user",
|
||||
"Sort By": "created_at",
|
||||
"Sort Order": "desc",
|
||||
"Key Hash": "",
|
||||
},
|
||||
allTeams: [mockTeam],
|
||||
allOrganizations: [mockOrganization],
|
||||
|
|
@ -322,8 +321,7 @@ it("should show 'No keys found' message when filteredKeys is empty", () => {
|
|||
"Organization ID": "",
|
||||
"Key Alias": "",
|
||||
"User ID": "",
|
||||
"Sort By": "created_at",
|
||||
"Sort Order": "desc",
|
||||
"Key Hash": "",
|
||||
},
|
||||
allTeams: [mockTeam],
|
||||
allOrganizations: [mockOrganization],
|
||||
|
|
@ -370,8 +368,7 @@ it("should handle models with more than 3 entries to trigger expansion UI", () =
|
|||
"Organization ID": "",
|
||||
"Key Alias": "",
|
||||
"User ID": "",
|
||||
"Sort By": "created_at",
|
||||
"Sort Order": "desc",
|
||||
"Key Hash": "",
|
||||
},
|
||||
allTeams: [mockTeam],
|
||||
allOrganizations: [mockOrganization],
|
||||
|
|
@ -518,8 +515,7 @@ it("should display 'Default Proxy Admin' for user_id when value is 'default_user
|
|||
"Organization ID": "",
|
||||
"Key Alias": "",
|
||||
"User ID": "",
|
||||
"Sort By": "created_at",
|
||||
"Sort Order": "desc",
|
||||
"Key Hash": "",
|
||||
},
|
||||
allTeams: [mockTeam],
|
||||
allOrganizations: [mockOrganization],
|
||||
|
|
@ -568,8 +564,7 @@ it("should display 'Default Proxy Admin' for created_by when value is 'default_u
|
|||
"Organization ID": "",
|
||||
"Key Alias": "",
|
||||
"User ID": "",
|
||||
"Sort By": "created_at",
|
||||
"Sort Order": "desc",
|
||||
"Key Hash": "",
|
||||
},
|
||||
allTeams: [mockTeam],
|
||||
allOrganizations: [mockOrganization],
|
||||
|
|
@ -626,8 +621,7 @@ it("should display created_by_user email in 'Created By' column when available",
|
|||
"Organization ID": "",
|
||||
"Key Alias": "",
|
||||
"User ID": "",
|
||||
"Sort By": "created_at",
|
||||
"Sort Order": "desc",
|
||||
"Key Hash": "",
|
||||
},
|
||||
allTeams: [mockTeam],
|
||||
allOrganizations: [mockOrganization],
|
||||
|
|
@ -681,8 +675,7 @@ it("should display created_by_user alias over email when both available", async
|
|||
"Organization ID": "",
|
||||
"Key Alias": "",
|
||||
"User ID": "",
|
||||
"Sort By": "created_at",
|
||||
"Sort Order": "desc",
|
||||
"Key Hash": "",
|
||||
},
|
||||
allTeams: [mockTeam],
|
||||
allOrganizations: [mockOrganization],
|
||||
|
|
@ -731,8 +724,7 @@ it("should render table without crashing when models is null", async () => {
|
|||
"Organization ID": "",
|
||||
"Key Alias": "",
|
||||
"User ID": "",
|
||||
"Sort By": "created_at",
|
||||
"Sort Order": "desc",
|
||||
"Key Hash": "",
|
||||
},
|
||||
allTeams: [mockTeam],
|
||||
allOrganizations: [mockOrganization],
|
||||
|
|
@ -782,8 +774,7 @@ it("should render table without crashing when models is undefined", async () =>
|
|||
"Organization ID": "",
|
||||
"Key Alias": "",
|
||||
"User ID": "",
|
||||
"Sort By": "created_at",
|
||||
"Sort Order": "desc",
|
||||
"Key Hash": "",
|
||||
},
|
||||
allTeams: [mockTeam],
|
||||
allOrganizations: [mockOrganization],
|
||||
|
|
@ -868,8 +859,7 @@ it("should display 'Unknown' for last_active when value is null", async () => {
|
|||
"Organization ID": "",
|
||||
"Key Alias": "",
|
||||
"User ID": "",
|
||||
"Sort By": "created_at",
|
||||
"Sort Order": "desc",
|
||||
"Key Hash": "",
|
||||
},
|
||||
allTeams: [mockTeam],
|
||||
allOrganizations: [mockOrganization],
|
||||
|
|
@ -916,7 +906,7 @@ describe("pagination display – total count and page count", () => {
|
|||
} as any);
|
||||
|
||||
mockUseFilterLogic.mockReturnValue({
|
||||
filters: { "Team ID": "", "Organization ID": "", "Key Alias": "", "User ID": "", "Sort By": "created_at", "Sort Order": "desc" },
|
||||
filters: { "Team ID": "", "Organization ID": "", "Key Alias": "", "User ID": "", "Key Hash": "" },
|
||||
allTeams: [mockTeam],
|
||||
allOrganizations: [mockOrganization],
|
||||
handleFilterChange: vi.fn(),
|
||||
|
|
@ -947,7 +937,7 @@ describe("pagination display – total count and page count", () => {
|
|||
} as any);
|
||||
|
||||
mockUseFilterLogic.mockReturnValue({
|
||||
filters: { "Team ID": "", "Organization ID": "", "Key Alias": "aaaaa", "User ID": "", "Sort By": "created_at", "Sort Order": "desc" },
|
||||
filters: { "Team ID": "", "Organization ID": "", "Key Alias": "aaaaa", "User ID": "", "Key Hash": "" },
|
||||
allTeams: [mockTeam],
|
||||
allOrganizations: [mockOrganization],
|
||||
handleFilterChange: vi.fn(),
|
||||
|
|
@ -964,7 +954,7 @@ describe("pagination display – total count and page count", () => {
|
|||
|
||||
it("should pass current filter values into useKeys so remount/refetch keeps the filter applied", async () => {
|
||||
mockUseFilterLogic.mockReturnValue({
|
||||
filters: { "Team ID": "", "Organization ID": "", "Key Alias": "aaaaa", "User ID": "", "Sort By": "created_at", "Sort Order": "desc" },
|
||||
filters: { "Team ID": "", "Organization ID": "", "Key Alias": "aaaaa", "User ID": "", "Key Hash": "" },
|
||||
allTeams: [mockTeam],
|
||||
allOrganizations: [mockOrganization],
|
||||
handleFilterChange: vi.fn(),
|
||||
|
|
@ -983,6 +973,26 @@ describe("pagination display – total count and page count", () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("should forward the Key Hash filter into useKeys", async () => {
|
||||
mockUseFilterLogic.mockReturnValue({
|
||||
filters: { "Team ID": "", "Organization ID": "", "Key Alias": "", "User ID": "", "Key Hash": "hash-xyz" },
|
||||
allTeams: [mockTeam],
|
||||
allOrganizations: [mockOrganization],
|
||||
handleFilterChange: vi.fn(),
|
||||
handleFilterReset: vi.fn(),
|
||||
});
|
||||
|
||||
renderWithProviders(<VirtualKeysTable {...defaultMockProps} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockUseKeys).toHaveBeenCalledWith(
|
||||
expect.any(Number),
|
||||
expect.any(Number),
|
||||
expect.objectContaining({ keyHash: "hash-xyz" }),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("refetch button", () => {
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ export function VirtualKeysTable({ teams, organizations, onSortChange, currentSo
|
|||
debouncedFilters["Organization ID"],
|
||||
debouncedFilters["Key Alias"],
|
||||
debouncedFilters["User ID"],
|
||||
debouncedFilters["Key Hash"],
|
||||
]);
|
||||
|
||||
const {
|
||||
|
|
@ -121,6 +122,7 @@ export function VirtualKeysTable({ teams, organizations, onSortChange, currentSo
|
|||
organizationID: debouncedFilters["Organization ID"] || undefined,
|
||||
selectedKeyAlias: debouncedFilters["Key Alias"] || undefined,
|
||||
userID: debouncedFilters["User ID"] || undefined,
|
||||
keyHash: debouncedFilters["Key Hash"] || undefined,
|
||||
});
|
||||
const [expandedAccordions, setExpandedAccordions] = useState<Record<string, boolean>>({});
|
||||
|
||||
|
|
@ -700,7 +702,11 @@ export function VirtualKeysTable({ teams, organizations, onSortChange, currentSo
|
|||
options={filterOptions}
|
||||
onApplyFilters={handleFilterChange}
|
||||
initialValues={filters}
|
||||
onResetFilters={handleFilterReset}
|
||||
onResetFilters={() => {
|
||||
handleFilterReset();
|
||||
setSorting([{ id: "created_at", desc: true }]);
|
||||
onSortChange?.("created_at", "desc");
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@ const DEFAULT_FILTERS = {
|
|||
"Organization ID": "",
|
||||
"Key Alias": "",
|
||||
"User ID": "",
|
||||
"Sort By": "created_at",
|
||||
"Sort Order": "desc",
|
||||
"Key Hash": "",
|
||||
};
|
||||
|
||||
describe("useFilterLogic – filter state management", () => {
|
||||
|
|
@ -42,6 +41,16 @@ describe("useFilterLogic – filter state management", () => {
|
|||
expect(result.current.filters["Key Alias"]).toBe("my-alias");
|
||||
});
|
||||
|
||||
it("records the Key Hash filter when handleFilterChange is called", () => {
|
||||
const { result } = renderHook(() => useFilterLogic(defaultProps));
|
||||
|
||||
act(() => {
|
||||
result.current.handleFilterChange({ "Key Hash": "abc123" });
|
||||
});
|
||||
|
||||
expect(result.current.filters["Key Hash"]).toBe("abc123");
|
||||
});
|
||||
|
||||
it("preserves filter state across re-renders (regression: bug where results reset on remount)", () => {
|
||||
const { result, rerender } = renderHook(() => useFilterLogic(defaultProps));
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ export interface FilterState {
|
|||
"Key Alias": string;
|
||||
[key: string]: string;
|
||||
"User ID": string;
|
||||
"Sort By": string;
|
||||
"Sort Order": string;
|
||||
"Key Hash": string;
|
||||
}
|
||||
|
||||
const DEFAULT_FILTERS: FilterState = {
|
||||
|
|
@ -19,8 +18,7 @@ const DEFAULT_FILTERS: FilterState = {
|
|||
"Organization ID": "",
|
||||
"Key Alias": "",
|
||||
"User ID": "",
|
||||
"Sort By": "created_at",
|
||||
"Sort Order": "desc",
|
||||
"Key Hash": "",
|
||||
};
|
||||
|
||||
export function useFilterLogic({
|
||||
|
|
@ -71,8 +69,7 @@ export function useFilterLogic({
|
|||
"Organization ID": newFilters["Organization ID"] || "",
|
||||
"Key Alias": newFilters["Key Alias"] || "",
|
||||
"User ID": newFilters["User ID"] || "",
|
||||
"Sort By": newFilters["Sort By"] || "created_at",
|
||||
"Sort Order": newFilters["Sort Order"] || "desc",
|
||||
"Key Hash": newFilters["Key Hash"] || "",
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue