Move Project Keys into sidebar

This commit is contained in:
Konstantin Wohlwend 2025-10-28 00:03:48 -07:00
parent 1aa8352318
commit 09a9686878
8 changed files with 115 additions and 34 deletions

View File

@ -77,6 +77,8 @@ To see all development ports, refer to the index.html of `apps/dev-launchpad/pub
- Whenever you learn something new, or at the latest right before you call the `Stop` tool, write whatever you learned into the ./claude/CLAUDE-KNOWLEDGE.md file, in the Q&A format in there. You will later be able to look up knowledge from there (based on the question you asked).
- Animations: Keep hover/click transitions snappy and fast. Don't delay the action with a pre-transition (e.g. no fade-in when hovering a button) — it makes the UI feel sluggish. Instead, apply transitions after the action, like a smooth fade-out when the hover ends.
- Whenever you make changes in the dashboard, provide the user with a deep link to the dashboard page that you've just changed. Usually, this takes the form of `http://localhost:<whatever-is-in-$NEXT_PUBLIC_STACK_PORT_PREFIX>01/projects/-selector-/...`, although sometimes it's different. If $NEXT_PUBLIC_STACK_PORT_PREFIX is set to 91, 92, or 93, use `a.localhost`, `b.localhost`, and `c.localhost` for the domains, respectively.
- To update the list of apps available, edit `apps-frontend.tsx` and `apps-config.tsx`. When you're tasked to implement a new app or a new page, always check existing apps for inspiration on how you could implement the new app or page.
- NEVER use Next.js dynamic functions if you can avoid them. Instead, prefer using a client component to make sure the page remains static (eg. prefer `usePathname` instead of `await params`).
### Code-related
- Use ES6 maps instead of records wherever you can.

View File

@ -0,0 +1,52 @@
"use client";
import { SettingCard, SettingSwitch } from "@/components/settings";
import { Typography } from "@stackframe/stack-ui";
import { AppEnabledGuard } from "../app-enabled-guard";
import { PageLayout } from "../page-layout";
import { useAdminApp } from "../use-admin-app";
export default function PageClient() {
const stackAdminApp = useAdminApp();
const project = stackAdminApp.useProject();
return (
<AppEnabledGuard appId="api-keys">
<PageLayout title="API Keys" description="Configure API key settings for your project">
<SettingCard
title="API Key Settings"
description="Configure which types of API keys are allowed in your project."
>
<SettingSwitch
label="Allow User API Keys"
checked={project.config.allowUserApiKeys}
onCheckedChange={async (checked) => {
await project.update({
config: {
allowUserApiKeys: checked
}
});
}}
/>
<Typography variant="secondary" type="footnote">
Enable to allow users to create API keys for their accounts. Enables user-api-keys backend routes.
</Typography>
<SettingSwitch
label="Allow Team API Keys"
checked={project.config.allowTeamApiKeys}
onCheckedChange={async (checked) => {
await project.update({
config: {
allowTeamApiKeys: checked
}
});
}}
/>
<Typography variant="secondary" type="footnote">
Enable to allow users to create API keys for their teams. Enables team-api-keys backend routes.
</Typography>
</SettingCard>
</PageLayout>
</AppEnabledGuard>
);
}

View File

@ -0,0 +1,11 @@
import PageClient from "./page-client";
export const metadata = {
title: "API Keys",
};
export default function Page() {
return (
<PageClient />
);
}

View File

@ -1,11 +1,11 @@
import PageClient from "./page-client";
// This page used to be the location of Project Keys before it was moved to /project-keys
// Redirecting to the new location
import { redirect } from 'next/navigation';
export const metadata = {
title: "API Keys",
};
export default function Page() {
return (
<PageClient />
);
export default function Page({
params,
}: {
params: { projectId: string },
}) {
redirect(`/projects/${params.projectId}/project-keys`);
}

View File

@ -23,29 +23,27 @@ export default function PageClient() {
const [returnedApiKey, setReturnedApiKey] = useState<InternalApiKeyFirstView | null>(null);
return (
<AppEnabledGuard appId="api-keys">
<PageLayout
title="Stack Auth Keys"
actions={
<Button onClick={() => setIsNewApiKeyDialogOpen(true)}>
Create Stack Auth Keys
</Button>
}
>
<InternalApiKeyTable apiKeys={apiKeySets} />
<PageLayout
title="Project Keys"
actions={
<Button onClick={() => setIsNewApiKeyDialogOpen(true)}>
Create Project Keys
</Button>
}
>
<InternalApiKeyTable apiKeys={apiKeySets} />
<CreateDialog
open={isNewApiKeyDialogOpen}
onOpenChange={setIsNewApiKeyDialogOpen}
onKeyCreated={setReturnedApiKey}
/>
<ShowKeyDialog
apiKey={returnedApiKey || undefined}
onClose={() => setReturnedApiKey(null)}
/>
<CreateDialog
open={isNewApiKeyDialogOpen}
onOpenChange={setIsNewApiKeyDialogOpen}
onKeyCreated={setReturnedApiKey}
/>
<ShowKeyDialog
apiKey={returnedApiKey || undefined}
onClose={() => setReturnedApiKey(null)}
/>
</PageLayout>
</AppEnabledGuard>
</PageLayout>
);
}
@ -80,7 +78,7 @@ function CreateDialog(props: {
return <SmartFormDialog
open={props.open}
onOpenChange={props.onOpenChange}
title="Create Stack Auth Keys"
title="Create Project Keys"
formSchema={formSchema}
okButton={{ label: "Create" }}
onSubmit={async (values) => {
@ -110,7 +108,7 @@ function ShowKeyDialog(props: {
return (
<ActionDialog
open={!!props.apiKey}
title="Stack Auth Keys"
title="Project Keys"
okButton={{ label: "Close" }}
onClose={props.onClose}
preventClose
@ -118,7 +116,7 @@ function ShowKeyDialog(props: {
>
<div className="flex flex-col gap-4">
<Typography>
Here are your Stack Auth keys.{" "}
Here are your project keys.{" "}
<span className="font-bold">
Copy them to a safe place. You will not be able to view them again.
</span>

View File

@ -0,0 +1,11 @@
import PageClient from "./page-client";
export const metadata = {
title: "Project Keys",
};
export default function Page() {
return (
<PageClient />
);
}

View File

@ -28,6 +28,7 @@ import {
ChevronDown,
ChevronRight,
Globe,
KeyRound,
LucideIcon,
Menu,
Settings,
@ -79,6 +80,12 @@ const bottomItems: BottomItem[] = [
icon: Blocks,
regex: /^\/projects\/[^\/]+\/apps(\/.*)?$/,
},
{
name: 'Project Keys',
href: '/project-keys',
icon: KeyRound,
regex: /^\/projects\/[^\/]+\/project-keys(\/.*)?$/,
},
{
name: 'Project Settings',
href: '/project-settings',

View File

@ -97,7 +97,7 @@ export const ALL_APPS_FRONTEND = {
},
"api-keys": {
icon: KeyRound,
href: "api-keys",
href: "api-keys-app",
navigationItems: [
{ displayName: "API Keys", href: "." },
],