Virtual Keys: Filter by key alias (#10035) (#10085)

Co-authored-by: Christian Owusu <36159205+crisshaker@users.noreply.github.com>
This commit is contained in:
Ishaan Jaff 2025-04-16 19:46:05 -07:00 committed by GitHub
parent 2b14978d9d
commit 0ced13aec8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 84 additions and 12 deletions

View file

@ -30,6 +30,8 @@ interface AllKeysTableProps {
teams: Team[] | null; teams: Team[] | null;
selectedTeam: Team | null; selectedTeam: Team | null;
setSelectedTeam: (team: Team | null) => void; setSelectedTeam: (team: Team | null) => void;
selectedKeyAlias: string | null;
setSelectedKeyAlias: Setter<string | null>;
accessToken: string | null; accessToken: string | null;
userID: string | null; userID: string | null;
userRole: string | null; userRole: string | null;
@ -98,6 +100,8 @@ export function AllKeysTable({
teams, teams,
selectedTeam, selectedTeam,
setSelectedTeam, setSelectedTeam,
selectedKeyAlias,
setSelectedKeyAlias,
accessToken, accessToken,
userID, userID,
userRole, userRole,
@ -123,7 +127,8 @@ export function AllKeysTable({
organizations, organizations,
accessToken, accessToken,
setSelectedTeam, setSelectedTeam,
setCurrentOrg setCurrentOrg,
setSelectedKeyAlias
}); });
useEffect(() => { useEffect(() => {
@ -358,6 +363,23 @@ export function AllKeysTable({
})); }));
} }
}, },
{
name: "Key Alias",
label: "Key Alias",
isSearchable: true,
searchFn: async (searchText) => {
const filteredKeyAliases = allKeyAliases.filter(key => {
return key.toLowerCase().includes(searchText.toLowerCase())
});
return filteredKeyAliases.map((key) => {
return {
label: key,
value: key
}
});
}
}
]; ];

View file

@ -21,6 +21,7 @@ export const fetchAllKeyAliases = async (accessToken: string | null): Promise<st
accessToken, accessToken,
null, // organization_id null, // organization_id
"", // team_id "", // team_id
null, // selectedKeyAlias
currentPage, currentPage,
100 // larger page size to reduce number of requests 100 // larger page size to reduce number of requests
); );

View file

@ -2,10 +2,15 @@ import { useEffect, useState } from "react";
import { KeyResponse } from "../key_team_helpers/key_list"; import { KeyResponse } from "../key_team_helpers/key_list";
import { Organization } from "../networking"; import { Organization } from "../networking";
import { Team } from "../key_team_helpers/key_list"; import { Team } from "../key_team_helpers/key_list";
import { useQuery } from "@tanstack/react-query";
import { fetchAllKeyAliases, fetchAllOrganizations, fetchAllTeams } from "./filter_helpers";
import { Setter } from "@/types";
export interface FilterState { export interface FilterState {
'Team ID': string; 'Team ID': string;
'Organization ID': string; 'Organization ID': string;
'Key Alias': string;
[key: string]: string; [key: string]: string;
} }
@ -15,7 +20,8 @@ export function useFilterLogic({
organizations, organizations,
accessToken, accessToken,
setSelectedTeam, setSelectedTeam,
setCurrentOrg setCurrentOrg,
setSelectedKeyAlias
}: { }: {
keys: KeyResponse[]; keys: KeyResponse[];
teams: Team[] | null; teams: Team[] | null;
@ -23,12 +29,13 @@ export function useFilterLogic({
accessToken: string | null; accessToken: string | null;
setSelectedTeam: (team: Team | null) => void; setSelectedTeam: (team: Team | null) => void;
setCurrentOrg: React.Dispatch<React.SetStateAction<Organization | null>>; setCurrentOrg: React.Dispatch<React.SetStateAction<Organization | null>>;
setSelectedKeyAlias: Setter<string | null>
}) { }) {
const [filters, setFilters] = useState<FilterState>({ const [filters, setFilters] = useState<FilterState>({
'Team ID': '', 'Team ID': '',
'Organization ID': '', 'Organization ID': '',
'Key Alias': ''
}); });
const [allKeyAliases, setAllKeyAliases] = useState<string[]>([]);
const [allTeams, setAllTeams] = useState<Team[]>(teams || []); const [allTeams, setAllTeams] = useState<Team[]>(teams || []);
const [allOrganizations, setAllOrganizations] = useState<Organization[]>(organizations || []); const [allOrganizations, setAllOrganizations] = useState<Organization[]>(organizations || []);
const [filteredKeys, setFilteredKeys] = useState<KeyResponse[]>(keys); const [filteredKeys, setFilteredKeys] = useState<KeyResponse[]>(keys);
@ -79,6 +86,16 @@ export function useFilterLogic({
} }
}, [accessToken]); }, [accessToken]);
const queryAllKeysQuery = useQuery({
queryKey: ['allKeys'],
queryFn: async () => {
if (!accessToken) throw new Error('Access token required');
return await fetchAllKeyAliases(accessToken);
},
enabled: !!accessToken
});
const allKeyAliases = queryAllKeysQuery.data || []
// Update teams and organizations when props change // Update teams and organizations when props change
useEffect(() => { useEffect(() => {
if (teams && teams.length > 0) { if (teams && teams.length > 0) {
@ -103,6 +120,7 @@ export function useFilterLogic({
setFilters({ setFilters({
'Team ID': newFilters['Team ID'] || '', 'Team ID': newFilters['Team ID'] || '',
'Organization ID': newFilters['Organization ID'] || '', 'Organization ID': newFilters['Organization ID'] || '',
'Key Alias': newFilters['Key Alias'] || ''
}); });
// Handle Team change // Handle Team change
@ -120,6 +138,12 @@ export function useFilterLogic({
setCurrentOrg(selectedOrg); setCurrentOrg(selectedOrg);
} }
} }
const keyAlias = newFilters['Key Alias'];
const selectedKeyAlias = keyAlias
? allKeyAliases.find((k) => k === keyAlias) || null
: null;
setSelectedKeyAlias(selectedKeyAlias)
}; };
const handleFilterReset = () => { const handleFilterReset = () => {
@ -127,6 +151,7 @@ export function useFilterLogic({
setFilters({ setFilters({
'Team ID': '', 'Team ID': '',
'Organization ID': '', 'Organization ID': '',
'Key Alias': ''
}); });
// Reset team and org selections // Reset team and org selections
@ -144,6 +169,3 @@ export function useFilterLogic({
handleFilterReset handleFilterReset
}; };
} }
// These functions are imported from key_team_helpers/filter_helpers.ts
import { fetchAllKeyAliases, fetchAllTeams, fetchAllOrganizations } from './filter_helpers';

View file

@ -85,6 +85,7 @@ total_pages: number;
interface UseKeyListProps { interface UseKeyListProps {
selectedTeam?: Team; selectedTeam?: Team;
currentOrg: Organization | null; currentOrg: Organization | null;
selectedKeyAlias: string | null;
accessToken: string; accessToken: string;
currentPage?: number; currentPage?: number;
} }
@ -108,9 +109,9 @@ setKeys: Setter<KeyResponse[]>;
const useKeyList = ({ const useKeyList = ({
selectedTeam, selectedTeam,
currentOrg, currentOrg,
selectedKeyAlias,
accessToken, accessToken,
currentPage = 1, currentPage = 1,
}: UseKeyListProps): UseKeyListReturn => { }: UseKeyListProps): UseKeyListReturn => {
const [keyData, setKeyData] = useState<KeyListResponse>({ const [keyData, setKeyData] = useState<KeyListResponse>({
keys: [], keys: [],
@ -134,8 +135,9 @@ const useKeyList = ({
accessToken, accessToken,
currentOrg?.organization_id || null, currentOrg?.organization_id || null,
selectedTeam?.team_id || "", selectedTeam?.team_id || "",
selectedKeyAlias,
params.page as number || 1, params.page as number || 1,
50 50,
); );
console.log("data", data); console.log("data", data);
setKeyData(data); setKeyData(data);
@ -149,8 +151,17 @@ const useKeyList = ({
useEffect(() => { useEffect(() => {
fetchKeys(); fetchKeys();
console.log("selectedTeam", selectedTeam, "currentOrg", currentOrg, "accessToken", accessToken); console.log(
}, [selectedTeam, currentOrg, accessToken]); 'selectedTeam',
selectedTeam,
'currentOrg',
currentOrg,
'accessToken',
accessToken,
'selectedKeyAlias',
selectedKeyAlias
);
}, [selectedTeam, currentOrg, accessToken, selectedKeyAlias]);
const setKeys = (newKeysOrUpdater: KeyResponse[] | ((prevKeys: KeyResponse[]) => KeyResponse[])) => { const setKeys = (newKeysOrUpdater: KeyResponse[] | ((prevKeys: KeyResponse[]) => KeyResponse[])) => {
setKeyData(prevData => { setKeyData(prevData => {

View file

@ -2569,8 +2569,9 @@ export const keyListCall = async (
accessToken: String, accessToken: String,
organizationID: string | null, organizationID: string | null,
teamID: string | null, teamID: string | null,
selectedKeyAlias: string | null,
page: number, page: number,
pageSize: number pageSize: number,
) => { ) => {
/** /**
* Get all available teams on proxy * Get all available teams on proxy
@ -2588,6 +2589,10 @@ export const keyListCall = async (
queryParams.append('organization_id', organizationID.toString()); queryParams.append('organization_id', organizationID.toString());
} }
if (selectedKeyAlias) {
queryParams.append('key_alias', selectedKeyAlias)
}
if (page) { if (page) {
queryParams.append('page', page.toString()); queryParams.append('page', page.toString());
} }

View file

@ -108,6 +108,7 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
team_id: null, team_id: null,
}; };
const [selectedTeam, setSelectedTeam] = useState<any | null>(null); const [selectedTeam, setSelectedTeam] = useState<any | null>(null);
const [selectedKeyAlias, setSelectedKeyAlias] = useState<string | null>(null);
// check if window is not undefined // check if window is not undefined
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
window.addEventListener("beforeunload", function () { window.addEventListener("beforeunload", function () {
@ -350,6 +351,8 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
accessToken={accessToken} accessToken={accessToken}
selectedTeam={selectedTeam ? selectedTeam : null} selectedTeam={selectedTeam ? selectedTeam : null}
setSelectedTeam={setSelectedTeam} setSelectedTeam={setSelectedTeam}
selectedKeyAlias={selectedKeyAlias}
setSelectedKeyAlias={setSelectedKeyAlias}
data={keys} data={keys}
setData={setKeys} setData={setKeys}
premiumUser={premiumUser} premiumUser={premiumUser}

View file

@ -71,6 +71,7 @@ import useKeyList from "./key_team_helpers/key_list";
import { KeyResponse } from "./key_team_helpers/key_list"; import { KeyResponse } from "./key_team_helpers/key_list";
import { AllKeysTable } from "./all_keys_table"; import { AllKeysTable } from "./all_keys_table";
import { Team } from "./key_team_helpers/key_list"; import { Team } from "./key_team_helpers/key_list";
import { Setter } from "@/types";
const isLocal = process.env.NODE_ENV === "development"; const isLocal = process.env.NODE_ENV === "development";
const proxyBaseUrl = isLocal ? "http://localhost:4000" : null; const proxyBaseUrl = isLocal ? "http://localhost:4000" : null;
@ -107,6 +108,8 @@ interface ViewKeyTableProps {
currentOrg: Organization | null; currentOrg: Organization | null;
organizations: Organization[] | null; organizations: Organization[] | null;
setCurrentOrg: React.Dispatch<React.SetStateAction<Organization | null>>; setCurrentOrg: React.Dispatch<React.SetStateAction<Organization | null>>;
selectedKeyAlias: string | null;
setSelectedKeyAlias: Setter<string | null>;
} }
interface ItemData { interface ItemData {
@ -154,7 +157,9 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
premiumUser, premiumUser,
currentOrg, currentOrg,
organizations, organizations,
setCurrentOrg setCurrentOrg,
selectedKeyAlias,
setSelectedKeyAlias
}) => { }) => {
const [isButtonClicked, setIsButtonClicked] = useState(false); const [isButtonClicked, setIsButtonClicked] = useState(false);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
@ -179,6 +184,7 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
const { keys, isLoading, error, pagination, refresh, setKeys } = useKeyList({ const { keys, isLoading, error, pagination, refresh, setKeys } = useKeyList({
selectedTeam, selectedTeam,
currentOrg, currentOrg,
selectedKeyAlias,
accessToken, accessToken,
}); });
@ -432,6 +438,8 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
organizations={organizations} organizations={organizations}
setCurrentOrg={setCurrentOrg} setCurrentOrg={setCurrentOrg}
refresh={refresh} refresh={refresh}
selectedKeyAlias={selectedKeyAlias}
setSelectedKeyAlias={setSelectedKeyAlias}
/> />
{isDeleteModalOpen && ( {isDeleteModalOpen && (