Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
BACKEND_URL=http://localhost:8000
BACKEND_URL=http://localhost:8000
NEXT_PUBLIC_GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
28 changes: 9 additions & 19 deletions app/(main)/configurations/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export default function ConfigLibraryPage() {
Record<string, number>
>({});
const { sidebarCollapsed } = useApp();
const { activeKey } = useAuth();
const apiKey = activeKey?.key;
const { activeKey, isAuthenticated } = useAuth();
const apiKey = activeKey?.key ?? "";
const [searchInput, setSearchInput] = useState("");
const [debouncedQuery, setDebouncedQuery] = useState("");
const [columnCount, setColumnCount] = useState(3);
Expand Down Expand Up @@ -100,11 +100,11 @@ export default function ConfigLibraryPage() {

useEffect(() => {
const fetchEvaluationCounts = async () => {
if (!activeKey) return;
if (!isAuthenticated) return;
try {
const data = await apiFetch<EvalJob[] | { data: EvalJob[] }>(
"/api/evaluations",
activeKey.key,
apiKey,
);
const jobs: EvalJob[] = Array.isArray(data) ? data : data.data || [];
const counts: Record<string, number> = {};
Expand All @@ -129,7 +129,7 @@ export default function ConfigLibraryPage() {
await existing;
return;
}
if (!apiKey) return;
if (!isAuthenticated) return;

const loadPromise = (async () => {
const res = await apiFetch<{
Expand All @@ -144,15 +144,15 @@ export default function ConfigLibraryPage() {
pendingVersionLoads.set(configId, loadPromise);
await loadPromise;
},
[apiKey],
[apiKey, isAuthenticated],
);

const loadSingleVersion = useCallback(
async (configId: string, version: number): Promise<SavedConfig | null> => {
const key = `${configId}:${version}`;
const existing = pendingSingleVersionLoads.get(key);
if (existing) return existing;
if (!apiKey) return null;
if (!isAuthenticated) return null;

const configPublic =
configs.find((c) => c.id === configId) ??
Expand All @@ -179,7 +179,7 @@ export default function ConfigLibraryPage() {
pendingSingleVersionLoads.set(key, loadPromise);
return loadPromise;
},
[apiKey, configs],
[apiKey, configs, isAuthenticated],
);

const handleCreateNew = () => {
Expand Down Expand Up @@ -277,17 +277,7 @@ export default function ConfigLibraryPage() {
) : error ? (
<div className="rounded-lg p-6 text-center bg-[#fef2f2] border border-[#fecaca]">
<WarningTriangleIcon className="w-12 h-12 mx-auto mb-3 text-[#dc2626]" />
<p className="text-sm font-medium text-[#dc2626]">{error}</p>
<button
onClick={() => router.push("/keystore")}
className="mt-4 px-4 py-2 rounded-md text-sm font-medium transition-colors"
style={{
backgroundColor: colors.accent.primary,
color: colors.bg.primary,
}}
>
Go to Keystore
</button>
<p className="text-sm font-medium text-status-error">{error}</p>
</div>
) : configs.length === 0 ? (
<div
Expand Down
8 changes: 4 additions & 4 deletions app/(main)/configurations/prompt-editor/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function PromptEditorContent() {
const toast = useToast();
const searchParams = useSearchParams();
const { sidebarCollapsed } = useApp();
const { activeKey } = useAuth();
const { activeKey, isAuthenticated } = useAuth();
const urlConfigId = searchParams.get("config");
const urlVersion = searchParams.get("version");
const showHistory = searchParams.get("history") === "true";
Expand Down Expand Up @@ -265,9 +265,9 @@ function PromptEditorContent() {
return;
}

const apiKey = activeKey?.key;
if (!apiKey) {
toast.error("No API key found. Please add an API key in the Keystore.");
const apiKey = activeKey?.key ?? "";
if (!isAuthenticated) {
toast.error("Please log in to save configurations.");
return;
}

Expand Down
134 changes: 24 additions & 110 deletions app/(main)/datasets/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useState, useEffect } from "react";

import { useAuth } from "@/app/lib/context/AuthContext";
import { useApp } from "@/app/lib/context/AppContext";
import { apiFetch } from "@/app/lib/apiClient";
import { APIKey } from "@/app/lib/types/credentials";
import Sidebar from "@/app/components/Sidebar";
import PageHeader from "@/app/components/PageHeader";
Expand Down Expand Up @@ -41,7 +42,7 @@ export default function Datasets() {
const [isUploading, setIsUploading] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const { activeKey: apiKey } = useAuth();
const { activeKey: apiKey, isAuthenticated } = useAuth();

// Pagination state
const [currentPage, setCurrentPage] = useState(1);
Expand All @@ -52,36 +53,22 @@ export default function Datasets() {
if (apiKey) {
fetchDatasets();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [apiKey]);

const fetchDatasets = async () => {
if (!apiKey) {
setError("No API key found. Please add an API key in the Keystore.");
if (!isAuthenticated) {
setError("Please log in to continue.");
return;
}

setIsLoading(true);
setError(null);

try {
const response = await fetch("/api/evaluations/datasets", {
method: "GET",
headers: {
"X-API-KEY": apiKey.key,
},
});

if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(
errorData.error ||
errorData.message ||
`Failed to fetch datasets: ${response.status}`,
);
}

const data = await response.json();
const data = await apiFetch<Dataset[] | { data: Dataset[] }>(
"/api/evaluations/datasets",
apiKey?.key ?? "",
);
const datasetList = Array.isArray(data) ? data : data.data || [];
setDatasets(datasetList);
} catch (err: unknown) {
Expand Down Expand Up @@ -119,49 +106,29 @@ export default function Datasets() {
return;
}

if (!apiKey) {
toast.error("No API key found. Please add an API key in the Keystore.");
if (!isAuthenticated) {
toast.error("Please log in to continue.");
return;
}

setIsUploading(true);

try {
// Prepare FormData for upload
const formData = new FormData();
formData.append("file", selectedFile);
formData.append("dataset_name", datasetName.trim());

formData.append("duplication_factor", duplicationFactor || "1");

// Upload to backend
const response = await fetch("/api/evaluations/datasets", {
await apiFetch<Dataset>("/api/evaluations/datasets", apiKey?.key ?? "", {
method: "POST",
body: formData,
headers: {
"X-API-KEY": apiKey.key,
},
});

if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(
errorData.error ||
errorData.message ||
`Upload failed with status ${response.status}`,
);
}

await response.json();
// Refresh datasets list
await fetchDatasets();

// Reset form
setSelectedFile(null);
setDatasetName("");
setDuplicationFactor("1");

// Close modal
setIsModalOpen(false);

toast.success("Dataset uploaded successfully!");
Expand All @@ -176,8 +143,8 @@ export default function Datasets() {
};

const handleDeleteDataset = async (datasetId: number) => {
if (!apiKey) {
toast.error("No API key found");
if (!isAuthenticated) {
toast.error("Please log in to continue");
return;
}

Expand All @@ -187,23 +154,14 @@ export default function Datasets() {
}

try {
const response = await fetch(`/api/evaluations/datasets/${datasetId}`, {
method: "DELETE",
headers: {
"X-API-KEY": apiKey.key,
await apiFetch(
`/api/evaluations/datasets/${datasetId}`,
apiKey?.key ?? "",
{
method: "DELETE",
},
});

if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(
errorData.error ||
errorData.message ||
`Delete failed with status ${response.status}`,
);
}
);

// Refresh datasets list
await fetchDatasets();
toast.success("Dataset deleted successfully");
} catch (error) {
Expand All @@ -214,7 +172,6 @@ export default function Datasets() {
}
};

// Pagination calculations
const indexOfLastItem = currentPage * itemsPerPage;
const indexOfFirstItem = indexOfLastItem - itemsPerPage;
const currentDatasets = datasets.slice(indexOfFirstItem, indexOfLastItem);
Expand All @@ -223,26 +180,17 @@ export default function Datasets() {
const paginate = (pageNumber: number) => setCurrentPage(pageNumber);

return (
<div
className="w-full h-screen flex flex-col"
style={{ backgroundColor: "#fafafa" }}
>
<div className="w-full h-screen flex flex-col bg-bg-secondary">
<div className="flex flex-1 overflow-hidden">
{/* Sidebar */}
<Sidebar collapsed={sidebarCollapsed} activeRoute="/datasets" />

{/* Main Content */}
<div className="flex-1 flex flex-col overflow-hidden">
<PageHeader
title="Datasets"
subtitle="Manage your evaluation datasets"
/>

{/* Content Area */}
<div
className="flex-1 overflow-auto p-6"
style={{ backgroundColor: "#fafafa" }}
>
<div className="flex-1 overflow-auto p-6 bg-bg-secondary">
<div className="max-w-6xl mx-auto space-y-6">
<DatasetListing
datasets={currentDatasets}
Expand All @@ -260,7 +208,6 @@ export default function Datasets() {
</div>
</div>

{/* Upload Dataset Modal */}
{isModalOpen && (
<UploadDatasetModal
selectedFile={selectedFile}
Expand Down Expand Up @@ -365,42 +312,9 @@ function DatasetListing({
<p className="text-sm">Loading datasets...</p>
</div>
) : !apiKey ? (
<div
className="text-center py-12"
style={{ color: "hsl(330, 3%, 49%)" }}
>
<svg
className="mx-auto h-12 w-12 mb-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"
/>
</svg>
<p
className="font-medium mb-2"
style={{ color: "hsl(330, 3%, 19%)" }}
>
No API key found
</p>
<p className="text-sm mb-4">
Please add an API key in the Keystore to manage datasets
</p>
<a
href="/keystore"
className="inline-block px-6 py-2 rounded-md text-sm font-medium transition-colors"
style={{
backgroundColor: "#171717",
color: "hsl(0, 0%, 100%)",
}}
>
Go to Keystore
</a>
<div className="text-center py-12 text-text-secondary">
<p className="font-medium mb-2 text-text-primary">Login required</p>
<p className="text-sm">Please log in to manage datasets</p>
</div>
) : error ? (
<div
Expand Down
Loading
Loading