Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
fc43d11
feat(api-keys): create table to list created keys
kworathur Feb 18, 2026
ee3ebd4
feat(api-keys): implement three-card grid layout on api keys page
kworathur Feb 19, 2026
ea8f57f
styles(api-keys): ensure consistency of table with design
kworathur Feb 19, 2026
b3b2b96
feat(api-keys): make api key reveal UI look like editor'
kworathur Feb 19, 2026
849c7f4
feat(api-keys): reveal api key with mocked data
kworathur Feb 20, 2026
2b01fae
feat(api-keys): refactor cards to use generic dark-card component
kworathur Feb 20, 2026
54245c0
fix: remove redundant ui component dark-card
kworathur Feb 20, 2026
badf431
chore: move reveal card to forms
kworathur Feb 20, 2026
eea5a6a
styles: ensure styling consistency across cards used in juno-dashboard
kworathur Feb 20, 2026
f57e20c
chore: fix lint errors
kworathur Feb 20, 2026
f627b30
chore: fix lint errors
kworathur Feb 20, 2026
e8d5306
styles: fix code style errors
kworathur Feb 20, 2026
6c2914b
remove debug statements from actions
kworathur Feb 20, 2026
29f068d
styles: align descriptions with column headers
kworathur Feb 20, 2026
a7f129d
styles: fix code style issues
kworathur Feb 20, 2026
4883fec
fix: remove console.error from catch block
kworathur Feb 20, 2026
4e79d58
fix unused error var
kworathur Feb 20, 2026
f93c60e
Update src/components/forms/CreateAPIKeyForm.tsx
kworathur Feb 20, 2026
8e56cf1
fix: missing curly bracket
kworathur Feb 20, 2026
f578c74
fix: touch up styling
llam36 Feb 23, 2026
753877a
Merge branch 'main' into 69-spring-2026-api-key-creation-page
llam36 Feb 23, 2026
d96a3b5
Akash/top bar and user page revamp (#75)
asarode06 Feb 24, 2026
1925374
New Request Account and Login Page (#76)
nyccreator Feb 27, 2026
0a94a46
fix: styling
llam36 Feb 27, 2026
a4bbae8
fix: update logo
llam36 Feb 27, 2026
01529bf
fix: styling
llam36 Feb 27, 2026
6ec27b7
feat(api-keys): implement three-card grid layout on api keys page
kworathur Feb 19, 2026
75c7009
fix: dup imports
kworathur Mar 7, 2026
da9eab3
feat: populate api keys table with data from backend
kworathur Mar 16, 2026
d1037b8
styles: fix lint errors
kworathur Mar 16, 2026
c115c6f
fix: styling
llam36 Feb 27, 2026
58faeed
feat: edit layout
llam36 Mar 9, 2026
092416d
Davidgu/fetch migration (#78)
shaply Mar 10, 2026
b2ec987
fix: use juno-sdk 0.0.10
llam36 Mar 10, 2026
65ed7ce
feat(api-keys): implement three-card grid layout on api keys page
kworathur Feb 19, 2026
b464b8b
fix: styling
llam36 Feb 27, 2026
a1b0cf6
styles: fix lint errors
kworathur Mar 16, 2026
63cf2bf
fix: lint errors
kworathur Mar 16, 2026
6cd348f
Merge branch 'main' into 69-spring-2026-api-key-creation-page
kworathur Mar 16, 2026
736fe49
fix: build errors
kworathur Mar 16, 2026
fe99695
fix: linter errors
kworathur Mar 16, 2026
632a234
fix: netlify build errors
kworathur Mar 21, 2026
edddb89
fix: build errors on local machine
kworathur Mar 21, 2026
8d38241
fix: lint and format errors
kworathur Mar 21, 2026
8198735
feat(auth): replace email/password auth with jwt auth
kworathur Mar 27, 2026
f9056fe
fix: lint errors
kworathur Mar 27, 2026
1606ff2
styles: make api key layout use same padding as other pages
kworathur Mar 28, 2026
ee277a7
styles: remove 'Request' from sdk function names
kworathur Mar 28, 2026
87b3bb3
fix: invalid import in usertable
kworathur Mar 31, 2026
7ab7095
fix: improperly formatted files
kworathur Apr 3, 2026
48298f2
Merge branch 'main' into 69-spring-2026-api-key-creation-page
kworathur Apr 3, 2026
d648732
chore: fix formatting issues
kworathur Apr 3, 2026
5a9ad3c
fix: only reset table row selection after all deletes succeed
kworathur Apr 3, 2026
ad8b575
fix pagination, clean up formatting, use badge ui for consistency
aakashg00 Apr 12, 2026
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
132 changes: 126 additions & 6 deletions src/app/(dashboard)/admin/keys/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,96 @@ import {
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import { useCallback, useEffect, useState } from "react";
import { toast } from "sonner";
import { ApiKeyDataTable } from "@/components/apiKeyTable/apiKey-table";
import { ApiKeyColumn } from "@/components/apiKeyTable/columns";
import ApiKeyRevealCard from "@/components/forms/ApiKeyRevealForm";
import { getApiKeysAction, deleteApiKeyByIdAction } from "@/lib/actions";
import { getProjects } from "@/lib/sdkActions";

type CreatedKeyInfo = {
value: string;
description: string;
environment: string;
project: string;
dateCreated: string;
};

export default function KeyPage() {
const [apiKeys, setApiKeys] = useState<ApiKeyColumn[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [createdKey, setCreatedKey] = useState<CreatedKeyInfo | null>(null);
const [projectNames, setProjectNames] = useState<Record<string, string>>({});
const [pageIndex, setPageIndex] = useState(0);
const [pageSize, setPageSize] = useState(10);
const [paginationLinks, setPaginationLinks] = useState({
first: "",
prev: "",
next: "",
last: "",
});
const [keysLoadTrigger, setKeysLoadTrigger] = useState(0);

useEffect(() => {
async function fetchProjects() {
const result = await getProjects();
if (result.success) {
setProjectNames(
Object.fromEntries(
result.projects.map((p) => [String(p.id), String(p.name ?? "")]),
),
);
}
}
fetchProjects();
}, []);

const fetchApiKeys = useCallback(async () => {
setIsLoading(true);
try {
const result = await getApiKeysAction({
offset: pageIndex * pageSize,
limit: pageSize,
});
if (result.success) {
const mapped: ApiKeyColumn[] = (result.keys ?? []).map((key) => ({
id: Number(key.id),
description: key.description ?? "",
dateCreated: key.createdAt
? new Date(key.createdAt).toISOString().split("T")[0]
: "N/A",
linkedProject: projectNames[String(key.project)] ?? "Unknown",
environment: key.environment ?? "N/A",
}));
setApiKeys(mapped);
setPaginationLinks(result.links);
} else {
toast.error(result.error ?? "Failed to fetch API keys");
}
} catch {
toast.error("Failed to fetch API keys");
} finally {
setIsLoading(false);
}
}, [pageIndex, pageSize, projectNames]);

useEffect(() => {
fetchApiKeys();
}, [fetchApiKeys, keysLoadTrigger]);

const handleDelete = async (key: ApiKeyColumn) => {
const result = await deleteApiKeyByIdAction(String(key.id));
if (result.success) {
setApiKeys((prev) => prev.filter((k) => k.id !== key.id));
toast.success("API key deleted successfully.");
} else {
toast.error(result.error ?? "Failed to delete API key");
}
};

return (
<div className="flex flex-col">
<div className="flex flex-col gap-[18px]">
<Breadcrumb className="mb-4">
<BreadcrumbList>
<BreadcrumbItem>
Expand All @@ -25,12 +110,47 @@ export default function KeyPage() {
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
<div className="flex flex-col gap-8">
<div className="grid grid-cols-1 xl:grid-cols-2 gap-8 items-start">
<CreateAPIKeyForm
projects={Object.values(projectNames)}
onKeyAdd={(newKey) => {
setCreatedKey({
value: newKey.value,
description: newKey.description,
environment: newKey.environment,
project: newKey.project.name,
dateCreated: new Date().toISOString().split("T")[0],
});
toast.success("Successfully created API key");
setKeysLoadTrigger((t) => t + 1);
}}
/>

<ApiKeyRevealCard
keyValue={createdKey?.value ?? null}
description={createdKey?.description ?? ""}
environment={createdKey?.environment ?? ""}
project={createdKey?.project ?? ""}
dateCreated={createdKey?.dateCreated ?? ""}
/>
</div>

<CreateAPIKeyForm
onKeyAdd={() => {
toast.success("Successfully created API key");
}}
/>
<ApiKeyDataTable
data={apiKeys}
isLoading={isLoading}
pageIndex={pageIndex}
pageSize={pageSize}
paginationLinks={paginationLinks}
onPageIndexChange={setPageIndex}
onPageSizeChange={setPageSize}
onKeyAction={async (key, action) => {
if (action === "delete") {
await handleDelete(key);
}
}}
/>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion src/app/(dashboard)/admin/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function AdminLayout({
<SidebarProvider>
<TopBar />
<AdminSidebar />
<div className="flex flex-col w-screen mt-12">
<div className="flex flex-col w-screen mt-11">
<main className="m-7">{children}</main>
</div>
</SidebarProvider>
Expand Down
2 changes: 1 addition & 1 deletion src/app/(dashboard)/admin/users/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
import { Separator } from "@/components/ui/separator";
import { getProjects, getUsers } from "@/lib/sdkActions";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { ProjectResponse } from "juno-sdk/build/main/internal/index";
import type { ProjectResponse } from "juno-sdk/build/main/internal/index";
import { toast } from "sonner";
import { UserColumn } from "../../../../components/usertable/columns";
import { UserDataTable } from "../../../../components/usertable/data-table";
Expand Down
2 changes: 1 addition & 1 deletion src/app/(dashboard)/projects/[projectId]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default async function ProjectLayout({
currProjName={project.name}
projectId={Number(projectId)}
/>
<div className="flex flex-col w-screen mt-12">
<div className="flex flex-col w-screen mt-11">
<main className="m-7">{children}</main>
</div>
</SidebarProvider>
Expand Down
19 changes: 14 additions & 5 deletions src/app/(dashboard)/projects/[projectId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
getCustomEventTypes,
} from "@/lib/settings";
import { useQuery } from "@tanstack/react-query";
import { ProjectResponse } from "juno-sdk/build/main/internal/index";
import type { ProjectResponse } from "juno-sdk/build/main/internal/index";
import { BarChart3, Settings } from "lucide-react";
import Link from "next/link";
import { useParams } from "next/navigation";
Expand Down Expand Up @@ -209,9 +209,18 @@ const DashboardPage = () => {
refetchOnWindowFocus: true,
});

const clickData: Event[] = clickEventsResponse?.events?.events || [];
const inputData: Event[] = inputEventsResponse?.events?.events || [];
const visitData: Event[] = visitEventsResponse?.events?.events || [];
const clickData: Event[] = useMemo(
() => clickEventsResponse?.events?.events || [],
[clickEventsResponse],
);
const inputData: Event[] = useMemo(
() => inputEventsResponse?.events?.events || [],
[inputEventsResponse],
);
const visitData: Event[] = useMemo(
() => visitEventsResponse?.events?.events || [],
[visitEventsResponse],
);

const customEventTypes: CustomEventType[] = (() => {
const types = customEventTypesResponse?.eventTypes;
Expand Down Expand Up @@ -289,7 +298,7 @@ const DashboardPage = () => {
};

fetchAllCustomEvents();
}, [projectName, customEventTypesJson]);
}, [projectName, projectId, customEventTypesJson]);

const customEventTypesById = useMemo(
() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { Skeleton } from "@/components/ui/skeleton";
import { getProjectById } from "@/lib/project";
import { getEmailAnalytics, getEmailConfig } from "@/lib/settings";
import { useQuery } from "@tanstack/react-query";
import { ProjectResponse } from "juno-sdk/build/main/internal/index";
import type { ProjectResponse } from "juno-sdk/build/main/internal/index";
import { Mail, Settings } from "lucide-react";
import Link from "next/link";
import { useParams } from "next/navigation";
Expand Down
2 changes: 1 addition & 1 deletion src/app/(dashboard)/projects/[projectId]/users/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { UserColumn } from "@/components/usertable/columns";
import { UserDataTable } from "@/components/usertable/data-table";
import { getProjectUsers } from "@/lib/actions";
import { getProjects } from "@/lib/sdkActions";
import { ProjectResponse } from "juno-sdk/build/main/internal/index";
import type { ProjectResponse } from "juno-sdk/build/main/internal/index";
import { useParams } from "next/navigation";
import { useEffect, useState } from "react";
import { toast } from "sonner";
Expand Down
Loading
Loading