Skip to content

Commit

Permalink
feature: add dataset ids and org ids to api key component
Browse files Browse the repository at this point in the history
  • Loading branch information
skeptrunedev committed Jun 14, 2024
1 parent f4fc110 commit 9be1c97
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 27 deletions.
4 changes: 2 additions & 2 deletions dashboard/src/components/ApiKeyGenerateModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
DisclosurePanel,
} from "terracotta";
import {
ApiKeyDTO,
ApiKeyRespBody,
DatasetAndUsage,
fromI32ToUserRole,
Organization,
Expand All @@ -40,7 +40,7 @@ export const ApiKeyGenerateModal = (props: {

refetch: (
info?: unknown,
) => ApiKeyDTO[] | Promise<ApiKeyDTO[]> | null | undefined;
) => ApiKeyRespBody[] | Promise<ApiKeyRespBody[]> | null | undefined;
}) => {
const api_host = import.meta.env.VITE_API_HOST as unknown as string;

Expand Down
82 changes: 74 additions & 8 deletions dashboard/src/components/ApiKeys.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { FaRegularTrashCan } from "solid-icons/fa";
import { ApiKeyGenerateModal } from "./ApiKeyGenerateModal";
import { UserContext } from "../contexts/UserContext";
import {
ApiKeyDTO,
ApiKeyRespBody,
fromI32ToApiKeyRole,
fromI32ToUserRole,
} from "../types/apiTypes";
Expand Down Expand Up @@ -46,7 +46,7 @@ export const ApiKeys = () => {
})
.then((res) => res.json())
.then((data) => {
return data as ApiKeyDTO[];
return data as ApiKeyRespBody[];
});
},
{ initialValue: [] },
Expand Down Expand Up @@ -108,11 +108,26 @@ export const ApiKeys = () => {
scope="col"
class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
>
Created At
</th>
<th class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
Perms
</th>
<th
scope="col"
class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
>
Datasets
</th>
<th
scope="col"
class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
>
Organizations
</th>
<th
scope="col"
class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
>
Created At
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 bg-white">
Expand All @@ -122,14 +137,65 @@ export const ApiKeys = () => {
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm text-gray-900 sm:pl-6 lg:pl-8">
{apiKey.name}
</td>
<td class="px-3 py-3.5 text-left text-sm text-gray-900">
{formatDate(new Date(apiKey.created_at))}
</td>
<td class="px-3 py-3.5 text-left text-sm text-gray-900">
{apiKey.role > 0
? fromI32ToUserRole(currentUserRole())
: fromI32ToApiKeyRole(apiKey.role).toString()}
</td>
<td class="px-3 py-3.5 text-left text-sm text-gray-900">
<Show when={apiKey.dataset_ids?.length}>[</Show>
<For each={apiKey.dataset_ids}>
{(dataset_id, index) => (
<>
<a
class="text-fuchsia-600 hover:underline"
href={`/dashboard/dataset/${dataset_id}/start`}
>
{dataset_id}
</a>
<Show
when={
index() <
(apiKey.dataset_ids?.length ?? 0) - 1
}
>
{", "}
</Show>
</>
)}
</For>
<Show when={apiKey.dataset_ids?.length}>]</Show>
</td>
<td class="px-3 py-3.5 text-left text-sm text-gray-900">
<Show when={apiKey.organization_ids?.length}>[</Show>
<For each={apiKey.organization_ids}>
{(org_id, index) => (
<>
<a
class="text-fuchsia-600 hover:underline"
href={`/dashboard/${org_id}/overview`}
onClick={() =>
userContext.setSelectedOrganizationId(org_id)
}
>
{org_id}
</a>
<Show
when={
index() <
(apiKey.organization_ids?.length ?? 0) - 1
}
>
{", "}
</Show>
</>
)}
</For>
<Show when={apiKey.organization_ids?.length}>]</Show>
</td>
<td class="px-3 py-3.5 text-left text-sm text-gray-900">
{formatDate(new Date(apiKey.created_at))}
</td>
<td class="px-3 py-3.5 text-center text-sm text-gray-900">
<div
onClick={(e) => {
Expand Down
90 changes: 89 additions & 1 deletion dashboard/src/pages/Dashboard/Dataset/DatasetStart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,19 @@ import { BiRegularInfoCircle, BiRegularLinkExternal } from "solid-icons/bi";
import CreateChunkRequest from "../../../components/CreateChunkRequest.md";
import HybridSearchReqeust from "../../../components/HybridSearchRequest.md";
import { BuildingSomething } from "../../../components/BuildingSomething";
import { BsMagic } from "solid-icons/bs";
import { createEffect, createMemo, createSignal, useContext } from "solid-js";
import { UserContext } from "../../../contexts/UserContext";
import { useLocation } from "@solidjs/router";
import { createToast } from "../../../components/ShowToasts";
import { Dataset } from "../../../types/apiTypes";
import { DatasetContext } from "../../../contexts/DatasetContext";
import { FaRegularClipboard } from "solid-icons/fa";
import { AddSampleDataModal } from "../../../components/DatasetExampleModal";
import { BsMagic } from "solid-icons/bs";

export const DatasetStart = () => {
const api_host = import.meta.env.VITE_API_HOST as unknown as string;
const location = useLocation();
const userContext = useContext(UserContext);
const datasetContext = useContext(DatasetContext);

Expand All @@ -24,6 +33,35 @@ export const DatasetStart = () => {
return dataset;
});

createEffect(() => {
const pathname = location.pathname;
const datasetId = pathname.split("/")[3];

void fetch(`${api_host}/dataset/${datasetId}`, {
method: "GET",
headers: {
"TR-Dataset": datasetId,
"Content-Type": "application/json",
},
credentials: "include",
}).then((resp) => {
if (!resp.ok) {
createToast({
title: "Error",
type: "error",
message:
"This dataset does not exist or do you not have permission to access it.",
timeout: 1000,
});
return;
}

void resp.json().then((data: Dataset) => {
userContext.setSelectedOrganizationId(data.organization_id);
});
});
});

return (
<div class="h-full">
<main class="mx-auto">
Expand Down Expand Up @@ -53,6 +91,56 @@ export const DatasetStart = () => {
</button>
</div>
<BuildingSomething />
<div class="flex flex-col gap-2">
<div class="flex items-center space-x-3">
<p class="block text-sm font-medium">
{curDataset()?.name} dataset id:{" "}
</p>
<p class="w-fit text-sm">{curDataset()?.id}</p>
<button
class="text-sm underline"
onClick={() => {
void navigator.clipboard.writeText(curDataset()?.id ?? "");
window.dispatchEvent(
new CustomEvent("show-toast", {
detail: {
type: "info",
title: "Copied",
message: "Dataset ID copied to clipboard",
},
}),
);
}}
>
<FaRegularClipboard />
</button>
</div>
<div class="flex items-center space-x-3">
<p class="block text-sm font-medium">
{selectedOrganization()?.name} org id:
</p>
<p class="w-fit text-sm">{selectedOrganization()?.id}</p>
<button
class="text-sm underline"
onClick={() => {
void navigator.clipboard.writeText(
selectedOrganization()?.id ?? "",
);
window.dispatchEvent(
new CustomEvent("show-toast", {
detail: {
type: "info",
title: "Copied",
message: "Organization ID copied to clipboard",
},
}),
);
}}
>
<FaRegularClipboard />
</button>
</div>
</div>
</section>
<section
class="flex-col gap-4 border bg-white px-4 py-6 shadow sm:overflow-hidden sm:rounded-md sm:p-6 lg:col-span-2"
Expand Down
6 changes: 3 additions & 3 deletions dashboard/src/pages/Dashboard/Overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ export const Overview = () => {
});

onCleanup(() => {
datasetAndUsageAbortController.abort();
orgSubPlanAbortController.abort();
orgUsageAbortController.abort();
datasetAndUsageAbortController.abort("cleanup");
orgSubPlanAbortController.abort("cleanup");
orgUsageAbortController.abort("cleanup");
});
});

Expand Down
4 changes: 3 additions & 1 deletion dashboard/src/types/apiTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,13 @@ export function stringToApiKeyRole(input: string): ApiKeyRole | undefined {
}
}

export interface ApiKeyDTO {
export interface ApiKeyRespBody {
id: string;
user_id: string;
name: string;
role: number;
dataset_ids: string[] | null;
organization_ids: string[] | null;
created_at: string;
updated_at: string;
}
Expand Down
16 changes: 13 additions & 3 deletions server/src/data/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2346,25 +2346,35 @@ impl UserApiKey {
"user_id": "e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3",
"name": "Trieve",
"role": 1,
"dataset_ids": ["d0d0d0d0-d0d0-d0d0-d0d0-d0d0d0d0d0d0"],
"organization_ids": ["o1o1o1o1-o1o1-o1o1-o1o1-o1o1o1o1o1o1"],
"created_at": "2021-01-01T00:00:00",
"updated_at": "2021-01-01T00:00:00",
}))]
pub struct ApiKeyDTO {
pub struct ApiKeyRespBody {
pub id: uuid::Uuid,
pub user_id: uuid::Uuid,
pub name: String,
pub role: i32,
pub dataset_ids: Option<Vec<String>>,
pub organization_ids: Option<Vec<String>>,
pub created_at: chrono::NaiveDateTime,
pub updated_at: chrono::NaiveDateTime,
}

impl From<UserApiKey> for ApiKeyDTO {
impl From<UserApiKey> for ApiKeyRespBody {
fn from(api_key: UserApiKey) -> Self {
ApiKeyDTO {
ApiKeyRespBody {
id: api_key.id,
user_id: api_key.user_id,
name: api_key.name,
role: api_key.role,
dataset_ids: api_key
.dataset_ids
.map(|ids| ids.into_iter().filter_map(|id| id).collect()),
organization_ids: api_key
.organization_ids
.map(|ids| ids.into_iter().filter_map(|id| id).collect()),
created_at: api_key.created_at,
updated_at: api_key.updated_at,
}
Expand Down
2 changes: 0 additions & 2 deletions server/src/handlers/dataset_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,6 @@ pub async fn delete_dataset_by_tracking_id(
(status = 404, description = "Dataset not found", body = ErrorResponseBody)
),
params(
("TR-Organization" = String, Header, description = "The organization id to use for the request"),
("TR-Dataset" = String, Header, description = "The dataset id to use for the request"),
("dataset_id" = uuid, Path, description = "The id of the dataset you want to retrieve."),
),
Expand Down Expand Up @@ -341,7 +340,6 @@ pub async fn get_dataset(
(status = 404, description = "Dataset not found", body = ErrorResponseBody)
),
params(
("TR-Organization" = String, Header, description = "The organization id to use for the request"),
("TR-Dataset" = String, Header, description = "The dataset id to use for the request"),
("tracking_id" = String, Path, description = "The tracking id of the dataset you want to retrieve."),
),
Expand Down
4 changes: 2 additions & 2 deletions server/src/handlers/user_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ pub async fn set_user_api_key(
context_path = "/api",
tag = "user",
responses(
(status = 200, description = "JSON body representing the api_key for the user", body = Vec<ApiKeyDTO>),
(status = 200, description = "JSON body representing the api_key for the user", body = Vec<ApiKeyRespBody>),
(status = 400, description = "Service error relating to creating api_key for the user", body = ErrorResponseBody),
),
security(
Expand Down Expand Up @@ -207,7 +207,7 @@ pub struct DeleteUserApiKeyRequest {
context_path = "/api",
tag = "user",
responses(
(status = 200, description = "JSON body representing the api_key for the user", body = Vec<ApiKeyDTO>),
(status = 204, description = "Confirmation that the api key was deleted"),
(status = 400, description = "Service error relating to creating api_key for the user", body = ErrorResponseBody),
),
params(
Expand Down
4 changes: 2 additions & 2 deletions server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ impl Modify for SecurityAddon {
name = "BSL",
url = "https://github.com/devflowinc/trieve/blob/main/LICENSE.txt",
),
version = "0.10.4",
version = "0.10.5",
),
servers(
(url = "https://api.trieve.ai",
Expand Down Expand Up @@ -277,7 +277,7 @@ impl Modify for SecurityAddon {
operators::search_operator::GroupScoreChunk,
handlers::dataset_handler::CreateDatasetRequest,
handlers::dataset_handler::UpdateDatasetRequest,
data::models::ApiKeyDTO,
data::models::ApiKeyRespBody,
data::models::SlimUser,
data::models::UserOrganization,
data::models::Topic,
Expand Down
6 changes: 3 additions & 3 deletions server/src/operators/user_operator.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::data::models::{
ApiKeyDTO, ApiKeyRole, Organization, RedisPool, SlimUser, UserApiKey, UserOrganization,
ApiKeyRespBody, ApiKeyRole, Organization, RedisPool, SlimUser, UserApiKey, UserOrganization,
UserRole,
};
use crate::{
Expand Down Expand Up @@ -349,7 +349,7 @@ pub async fn get_user_from_api_key_query(
pub async fn get_user_api_keys_query(
user_id: uuid::Uuid,
pool: web::Data<Pool>,
) -> Result<Vec<ApiKeyDTO>, ServiceError> {
) -> Result<Vec<ApiKeyRespBody>, ServiceError> {
use crate::data::schema::user_api_key::dsl as user_api_key_columns;

let mut conn = pool.get().await.unwrap();
Expand All @@ -364,7 +364,7 @@ pub async fn get_user_api_keys_query(
let api_keys = api_keys
.into_iter()
.map(|api_key| api_key.into())
.collect::<Vec<ApiKeyDTO>>();
.collect::<Vec<ApiKeyRespBody>>();
Ok(api_keys)
}

Expand Down

0 comments on commit 9be1c97

Please sign in to comment.