Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: api keys API #2652

Merged
merged 11 commits into from
Jul 29, 2024
2 changes: 2 additions & 0 deletions src/frontend/src/controllers/API/queries/api-keys/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from "./use-delete-api-key";
export * from "./use-get-api-keys";
export * from "./use-post-add-api-key";
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useMutationFunctionType } from "@/types/api";
import { api } from "../../api";
import { getURL } from "../../helpers/constants";
import { UseRequestProcessor } from "../../services/request-processor";

interface IDeleteApiKey {
keyId: string;
}

// add types for error handling and success
export const useDeleteApiKey: useMutationFunctionType<IDeleteApiKey> = (
options,
) => {
const { mutate } = UseRequestProcessor();

const deleteApiKeyFn = async (payload: IDeleteApiKey): Promise<any> => {
const res = await api.delete(`${getURL("API_KEY")}/${payload.keyId}`);
return res.data;
};

const mutation = mutate(["useDeleteApiKey"], deleteApiKeyFn, options);

return mutation;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useDarkStore } from "@/stores/darkStore";
import { useQueryFunctionType } from "@/types/api";
import { api } from "../../api";
import { getURL } from "../../helpers/constants";
import { UseRequestProcessor } from "../../services/request-processor";

export interface IApiKeysDataArray {
name: string;
last_used_at: string | null;
total_uses: number;
is_active: boolean;
id: string;
api_key: string;
user_id: string;
created_at: string;
}

interface IApiQueryResponse {
total_count: number;
user_id: string;
api_keys: Array<IApiKeysDataArray>;
}

export const useGetApiKeysQuery: useQueryFunctionType<
undefined,
IApiQueryResponse
> = (_, options) => {
const { query } = UseRequestProcessor();

const getApiKeysFn = async () => {
return await api.get<IApiQueryResponse>(`${getURL("API_KEY")}/`);
};

const responseFn = async () => {
const { data } = await getApiKeysFn();
return data;
};

const queryResult = query(["useGetApiKeysQuery"], responseFn, { ...options });

return queryResult;
};

This file was deleted.

This file was deleted.

83 changes: 62 additions & 21 deletions src/frontend/src/pages/SettingsPage/pages/ApiKeysPage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import {
DEL_KEY_ERROR_ALERT,
DEL_KEY_ERROR_ALERT_PLURAL,
DEL_KEY_SUCCESS_ALERT,
DEL_KEY_SUCCESS_ALERT_PLURAL,
} from "@/constants/alerts_constants";
import {
IApiKeysDataArray,
useDeleteApiKey,
useGetApiKeysQuery,
} from "@/controllers/API/queries/api-keys";
import { SelectionChangedEvent } from "ag-grid-community";
import { useContext, useEffect, useRef, useState } from "react";
import TableComponent from "../../../../components/tableComponent";
import { AuthContext } from "../../../../contexts/authContext";
import useAlertStore from "../../../../stores/alertStore";
import ApiKeyHeaderComponent from "./components/ApiKeyHeader";
import { getColumnDefs } from "./helpers/column-defs";
import useApiKeys from "./hooks/use-api-keys";
import useDeleteApiKeys from "./hooks/use-handle-delete-key";

export default function ApiKeysPage() {
const [loadingKeys, setLoadingKeys] = useState(true);
Expand All @@ -15,44 +24,76 @@ export default function ApiKeysPage() {
const setErrorData = useAlertStore((state) => state.setErrorData);
const { userData } = useContext(AuthContext);
const [userId, setUserId] = useState("");
const keysList = useRef([]);
const [keysList, setKeysList] = useState<IApiKeysDataArray[]>([]);
const { refetch } = useGetApiKeysQuery();

async function getApiKeysQuery() {
const { data } = await refetch();
if (data !== undefined) {
const updatedKeysList = data["api_keys"].map((apikey) => ({
...apikey,
name: apikey.name && apikey.name !== "" ? apikey.name : "Untitled",
last_used_at: apikey.last_used_at ?? "Never",
}));
setKeysList(updatedKeysList);
setUserId(data["user_id"]);
}
}

useEffect(() => {
fetchApiKeys();
if (userData) {
getApiKeysQuery();
}
}, [userData]);

const { fetchApiKeys } = useApiKeys(
userData,
setLoadingKeys,
keysList,
setUserId,
);

function resetFilter() {
fetchApiKeys();
getApiKeysQuery();
}

const { handleDeleteKey } = useDeleteApiKeys(
selectedRows,
resetFilter,
setSuccessData,
setErrorData,
);
const { mutate } = useDeleteApiKey();

function handleDeleteApi() {
for (let i = 0; i < selectedRows.length; i++) {
mutate(
{ keyId: selectedRows[i] },
{
onSuccess: () => {
resetFilter();
setSuccessData({
title:
selectedRows.length === 1
? DEL_KEY_SUCCESS_ALERT
: DEL_KEY_SUCCESS_ALERT_PLURAL,
});
},
onError: (error) => {
setErrorData({
title:
selectedRows.length === 1
? DEL_KEY_ERROR_ALERT
: DEL_KEY_ERROR_ALERT_PLURAL,
list: [error?.response?.data?.detail],
});
},
},
);
}
}

const columnDefs = getColumnDefs();

return (
<div className="flex h-full w-full flex-col justify-between gap-6">
<ApiKeyHeaderComponent
selectedRows={selectedRows}
fetchApiKeys={fetchApiKeys}
fetchApiKeys={getApiKeysQuery}
userId={userId}
/>

<div className="flex h-full w-full flex-col justify-between">
<TableComponent
key={"apiKeys"}
onDelete={handleDeleteKey}
onDelete={handleDeleteApi}
overlayNoRowsTemplate="No data available"
onSelectionChanged={(event: SelectionChangedEvent) => {
setSelectedRows(event.api.getSelectedRows().map((row) => row.id));
Expand All @@ -61,7 +102,7 @@ export default function ApiKeysPage() {
suppressRowClickSelection={true}
pagination={true}
columnDefs={columnDefs}
rowData={keysList.current}
rowData={keysList}
/>
</div>
</div>
Expand Down
14 changes: 6 additions & 8 deletions src/frontend/tests/end-to-end/promptModalComponent.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,8 @@ test("PromptTemplateComponent", async ({ page }) => {
}

value =
(await page
.locator('//*[@id="textarea_str_edit_prompt1"]')
.inputValue()) ?? "";
(await page.locator('//*[@id="textarea_str_edit_prompt1"]').inputValue()) ??
"";

if (value != "prompt_name_test_123123!@#!@#") {
expect(false).toBeTruthy();
Expand All @@ -126,14 +125,14 @@ test("PromptTemplateComponent", async ({ page }) => {
expect(false).toBeTruthy();
}

await page.getByTestId('textarea_str_edit_prompt1-ExternalLink').click();
await page.getByTestId("textarea_str_edit_prompt1-ExternalLink").click();
await page
.getByTestId("text-area-modal")
.fill("prompt_edit_test_12312312321!@#$");

await page.getByText("Finish Editing", { exact: true }).click();

await page.getByTestId('textarea_str_edit_prompt-ExternalLink').click();
await page.getByTestId("textarea_str_edit_prompt-ExternalLink").click();
await page
.getByTestId("text-area-modal")
.fill("prompt_edit_test_44444444444!@#$");
Expand Down Expand Up @@ -194,9 +193,8 @@ test("PromptTemplateComponent", async ({ page }) => {
}

value =
(await page
.locator('//*[@id="textarea_str_edit_prompt1"]')
.inputValue()) ?? "";
(await page.locator('//*[@id="textarea_str_edit_prompt1"]').inputValue()) ??
"";

if (value != "prompt_edit_test_12312312321!@#$") {
expect(false).toBeTruthy();
Expand Down