diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/api-keys/page-client.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/api-keys/page-client.tsx index cddf87128..046675583 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/api-keys/page-client.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/api-keys/page-client.tsx @@ -13,7 +13,7 @@ import { ActionDialog } from "@/components/action-dialog"; import Typography from "@/components/ui/typography"; -export default function ApiKeysDashboardClient() { +export default function PageClient() { const stackAdminApp = useAdminApp(); const apiKeySets = stackAdminApp.useApiKeySets(); @@ -100,6 +100,8 @@ function ShowKeyDialog(props: { apiKey?: ApiKeySetFirstView, onClose?: () => void, }) { + const stackAdminApp = useAdminApp(); + const project = stackAdminApp.useProject(); if (!props.apiKey) return null; return diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/api-keys/page.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/api-keys/page.tsx index cd1ef45fb..f8b59f27c 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/api-keys/page.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/api-keys/page.tsx @@ -1,11 +1,11 @@ -import ApiKeysDashboardClient from "./page-client"; +import PageClient from "./page-client"; export const metadata = { title: "API Keys", }; -export default function ApiKeysDashboard() { +export default function Page() { return ( - + ); } diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth-methods/page-client.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth-methods/page-client.tsx index 43331eed1..dfd136922 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth-methods/page-client.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth-methods/page-client.tsx @@ -5,7 +5,7 @@ import { OAuthProviderConfigJson } from "@stackframe/stack-shared"; import { PageLayout } from "../page-layout"; import { SettingCard, SettingSwitch } from "@/components/settings"; -export default function ProvidersClient() { +export default function PageClient() { const stackAdminApp = useAdminApp(); const project = stackAdminApp.useProjectAdmin(); const oauthProviders = project.evaluatedConfig.oauthProviders; diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth-methods/page.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth-methods/page.tsx index 0ecf67b85..8daa67826 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth-methods/page.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth-methods/page.tsx @@ -1,11 +1,11 @@ -import ProvidersClient from "./page-client"; +import PageClient from "./page-client"; export const metadata = { - title: "Providers", + title: "Auth Methods", }; -export default function Providers() { +export default function Page() { return ( - + ); } diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth-methods/providers.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth-methods/providers.tsx index b9932e30a..bed2b6161 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth-methods/providers.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth-methods/providers.tsx @@ -16,7 +16,7 @@ import { runAsynchronously } from "@stackframe/stack-shared/dist/utils/promises" import Typography from "@/components/ui/typography"; import { InputField, SwitchField } from "@/components/form-fields"; import { FormDialog } from "@/components/form-dialog"; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; +import { TextTooltip } from "@/components/text-tooltip"; /** * All the different types of OAuth providers that can be created. @@ -174,16 +174,9 @@ export function ProviderSettingSwitch(props: Props) {
{toTitle(props.id)} {isShared && enabled && - - - - Shared keys - - - Shared keys are created by the Stack team for easy development experience - - - + + Shared keys + }
} diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/urls-and-callbacks/page-client.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/domains/page-client.tsx similarity index 99% rename from packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/urls-and-callbacks/page-client.tsx rename to packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/domains/page-client.tsx index 1769ee2be..9db2b83a5 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/urls-and-callbacks/page-client.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/domains/page-client.tsx @@ -145,7 +145,7 @@ function DeleteDialog(props: { ); } -export default function UrlsAndCallbacksClient() { +export default function PageClient() { const stackAdminApp = useAdminApp(); const project = stackAdminApp.useProjectAdmin(); const domains = project.evaluatedConfig.domains; diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/domains/page.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/domains/page.tsx new file mode 100644 index 000000000..a6aeeb04d --- /dev/null +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/domains/page.tsx @@ -0,0 +1,11 @@ +import PageClient from "./page-client"; + +export const metadata = { + title: "Domains & Handlers", +}; + +export default function Page() { + return ( + + ); +} diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/environment/page.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/environment/page.tsx deleted file mode 100644 index 448747ac1..000000000 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/environment/page.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import EnvironmentClient from "./page-client"; - -export const metadata = { - title: "Environment", -}; - -export default function Environment() { - return ( - - ); -} diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/environment/page-client.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/project-settings/page-client.tsx similarity index 54% rename from packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/environment/page-client.tsx rename to packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/project-settings/page-client.tsx index ccdce7bb0..fa875acda 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/environment/page-client.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/project-settings/page-client.tsx @@ -1,19 +1,17 @@ "use client";; import { useAdminApp } from "../use-admin-app"; import { PageLayout } from "../page-layout"; -import { SettingCard, SettingSwitch } from "@/components/settings"; +import { SettingCard, SettingInput, SettingSwitch } from "@/components/settings"; import { Alert } from "@/components/ui/alert"; -import Typography from "@/components/ui/typography"; import { Link } from "@/components/link"; -export default function EnvironmentClient() { +export default function PageClient() { const stackAdminApp = useAdminApp(); const project = stackAdminApp.useProjectAdmin(); - const productionModeErrors = project.getProductionModeErrors(); return ( - + )} + + + project.update({ displayName: v })} + defaultValue={project.displayName}/> + project.update({ description: v })} + defaultValue={project.description} + /> + + + {/* +
+ Delete Project} + okButton={{ label: "Delete Project", onClick: async () => { + // await project.delete(); + // stackAdminApp.router.push("/projects"); + }}} + confirmText="I understand that all the users, teams, and data associated with this project will be permanently deleted. This action cannot be undone." + > + {`Are you sure that you want to delete the project "${project.displayName}" with the id of "${project.id}"?`} + +
+
*/}
); } diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/project-settings/page.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/project-settings/page.tsx new file mode 100644 index 000000000..79e1c346b --- /dev/null +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/project-settings/page.tsx @@ -0,0 +1,11 @@ +import PageClient from "./page-client"; + +export const metadata = { + title: "Project Settings", +}; + +export default function Page() { + return ( + + ); +} diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/settings/route.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/settings/route.tsx deleted file mode 100644 index 5495a81f9..000000000 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/settings/route.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { redirectHandler } from "@/route-handlers/redirect-handler"; - -export const GET = redirectHandler("api-keys"); diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/sidebar-layout.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/sidebar-layout.tsx index 7b3fcb273..783275b4e 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/sidebar-layout.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/sidebar-layout.tsx @@ -2,11 +2,12 @@ import Link from "next/link"; import { Book, - Globe, KeyRound, LockKeyhole, LucideIcon, + Mail, Menu, + Settings, Settings2, ShieldEllipsis, User, @@ -105,18 +106,11 @@ const navigationItems: (Label | Item | Hidden)[] = [ }, { name: "Domains & Handlers", - href: "/urls-and-callbacks", - regex: /^\/projects\/[^\/]+\/urls-and-callbacks$/, + href: "/domains", + regex: /^\/projects\/[^\/]+\/domains$/, icon: LinkIcon, type: 'item' }, - { - name: "Environment", - href: "/environment", - regex: /^\/projects\/[^\/]+\/environment$/, - icon: Globe, - type: 'item' - }, { name: "API Keys", href: "/api-keys", @@ -124,6 +118,13 @@ const navigationItems: (Label | Item | Hidden)[] = [ icon: KeyRound, type: 'item' }, + { + name: "Project Settings", + href: "/project-settings", + regex: /^\/projects\/[^\/]+\/project-settings$/, + icon: Settings, + type: 'item' + } ]; export function NavItem({ item, href, onClick }: { item: Item, href: string, onClick?: () => void}) { diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-permissions/page-client.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-permissions/page-client.tsx index de9eda3c5..dae2a44ae 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-permissions/page-client.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-permissions/page-client.tsx @@ -10,7 +10,7 @@ import { InputField } from "@/components/form-fields"; import { TeamPermissionTable } from "@/components/data-table/team-permission-table"; -export default function ClientPage() { +export default function PageClient() { const stackAdminApp = useAdminApp(); const permissions = stackAdminApp.usePermissionDefinitions(); const [createPermissionModalOpen, setCreatePermissionModalOpen] = React.useState(false); diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-permissions/page.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-permissions/page.tsx index d0b2b6e37..3ac293ea3 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-permissions/page.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-permissions/page.tsx @@ -1,11 +1,11 @@ -import ClientPage from "./page-client"; +import PageClient from "./page-client"; export const metadata = { title: "Team Permissions", }; -export default function TeamPermissions() { +export default function Page() { return ( - + ); } diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-settings/page-client.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-settings/page-client.tsx index 53212a3b4..20bc4ac5f 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-settings/page-client.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-settings/page-client.tsx @@ -3,7 +3,7 @@ import { useAdminApp } from "../use-admin-app"; import { PageLayout } from "../page-layout"; import { SettingCard, SettingSwitch } from "@/components/settings"; -export default function TeamSettingsClient() { +export default function PageClient() { const stackAdminApp = useAdminApp(); const project = stackAdminApp.useProjectAdmin(); diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-settings/page.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-settings/page.tsx index 11ed28314..f6adeabcc 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-settings/page.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/team-settings/page.tsx @@ -1,11 +1,11 @@ -import TeamSettingsClient from "./page-client"; +import PageClient from "./page-client"; export const metadata = { title: "Team Settings", }; -export default function TeamSettings() { +export default function Page() { return ( - + ); } diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/[teamId]/page-client.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/[teamId]/page-client.tsx index 31f975761..13a055816 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/[teamId]/page-client.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/[teamId]/page-client.tsx @@ -5,7 +5,7 @@ import { PageLayout } from '../../page-layout'; import { TeamMemberTable } from '@/components/data-table/team-member-table'; -export default function ClientPage(props: { teamId: string }) { +export default function PageClient(props: { teamId: string }) { const stackAdminApp = useAdminApp(); const team = stackAdminApp.useTeam(props.teamId); const users = team?.useMembers(); diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/[teamId]/page.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/[teamId]/page.tsx index d2d8ae9f0..6395eb6a9 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/[teamId]/page.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/[teamId]/page.tsx @@ -1,4 +1,4 @@ -import ClientPage from "./page-client"; +import PageClient from "./page-client"; export const metadata = { title: "Team Members", @@ -6,6 +6,6 @@ export const metadata = { export default function Page({ params }: { params: { teamId: string } }) { return ( - + ); } \ No newline at end of file diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/page-client.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/page-client.tsx index a85be8a22..ce261c3fa 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/page-client.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/page-client.tsx @@ -4,7 +4,7 @@ import { PageLayout } from "../page-layout"; import { TeamTable } from "@/components/data-table/team-table"; -export default function ClientPage() { +export default function PageClient() { const stackAdminApp = useAdminApp(); const teams = stackAdminApp.useTeams(); diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/page.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/page.tsx index 829c5d698..8a6c9adb3 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/page.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/teams/page.tsx @@ -1,11 +1,11 @@ -import ClientPage from "./page-client"; +import PageClient from "./page-client"; export const metadata = { title: "Teams", }; -export default function TeamDashboard() { +export default function Page() { return ( - + ); } diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/urls-and-callbacks/page.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/urls-and-callbacks/page.tsx deleted file mode 100644 index f6d1393d3..000000000 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/urls-and-callbacks/page.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import UrlsAndCallbacksClient from "./page-client"; - -export const metadata = { - title: "Domains & Handlers", -}; - -export default function UrlsAndCallbacks() { - return ( - - ); -} diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/users/page-client.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/users/page-client.tsx index 905fc2733..c33de6653 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/users/page-client.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/users/page-client.tsx @@ -7,7 +7,7 @@ import { Link } from "@/components/link"; import { UserTable } from "@/components/data-table/user-table"; -export default function UsersDashboardClient() { +export default function PageClient() { const stackAdminApp = useAdminApp(); const allUsers = stackAdminApp.useServerUsers(); diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/users/page.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/users/page.tsx index 2a020370b..d4723e930 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/users/page.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/users/page.tsx @@ -1,11 +1,11 @@ -import UsersDashboardClient from "./page-client"; +import PageClient from "./page-client"; export const metadata = { title: "Users", }; -export default function UsersDashboard() { +export default function Page() { return ( - + ); } diff --git a/packages/stack-server/src/components/data-table/user-table.tsx b/packages/stack-server/src/components/data-table/user-table.tsx index f47f96605..d400cca6e 100644 --- a/packages/stack-server/src/components/data-table/user-table.tsx +++ b/packages/stack-server/src/components/data-table/user-table.tsx @@ -15,7 +15,7 @@ import { ActionDialog } from "../action-dialog"; import Typography from "../ui/typography"; import { standardFilterFn } from "./elements/utils"; import { CircleAlert } from "lucide-react"; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip"; +import { TextTooltip } from "../text-tooltip"; export type ExtendedServerUser = ServerUser & { authType: string, @@ -155,17 +155,9 @@ export const commonUserColumns: ColumnDef[] = [ { accessorKey: "primaryEmail", header: ({ column }) => , - cell: ({ row }) => - - - - - - Email not verified - - - }> + cell: ({ row }) => }> {row.original.primaryEmail} , }, diff --git a/packages/stack-server/src/components/settings.tsx b/packages/stack-server/src/components/settings.tsx index 4b37e3799..84d6909a5 100644 --- a/packages/stack-server/src/components/settings.tsx +++ b/packages/stack-server/src/components/settings.tsx @@ -9,8 +9,12 @@ import { import { Switch } from "./ui/switch"; import { Settings } from "lucide-react"; import { Button } from "./ui/button"; -import { useId, useState } from "react"; +import React, { useEffect, useId, useRef, useState } from "react"; import { Label } from "./ui/label"; +import { DelayedInput, Input } from "./ui/input"; +import { runAsynchronously } from "@stackframe/stack-shared/dist/utils/promises"; +import { Accordion } from "@radix-ui/react-accordion"; +import { AccordionContent, AccordionItem, AccordionTrigger } from "./ui/accordion"; export function SettingCard(props: { @@ -18,6 +22,7 @@ export function SettingCard(props: { description?: string, actions?: React.ReactNode, children?: React.ReactNode, + accordion?: string, }) { return ( @@ -25,8 +30,19 @@ export function SettingCard(props: { {props.title} {props.description && {props.description}} + - {props.children} + {props.accordion ? + + + {props.accordion} + + {props.children} + + + : + props.children} + {props.actions &&
@@ -69,12 +85,33 @@ export function SettingSwitch(props: { ); } -export function SettingIconButton(props: { - onClick?: () => void | Promise, -}) { +export const SettingIconButton = React.forwardRef< + HTMLButtonElement, + React.ComponentProps +>((props, ref) => { return ( - ); -} \ No newline at end of file +}); +SettingIconButton.displayName = "SettingIconButton"; + +export function SettingInput(props: { + label: string, + defaultValue?: string, + onChange: (value: string) => void | Promise, + actions?: React.ReactNode, +}) { + return ( +
+ + runAsynchronously(props.onChange(e.target.value))} + /> + {props.actions} +
+ ); +} diff --git a/packages/stack-server/src/components/text-tooltip.tsx b/packages/stack-server/src/components/text-tooltip.tsx new file mode 100644 index 000000000..34e31fe38 --- /dev/null +++ b/packages/stack-server/src/components/text-tooltip.tsx @@ -0,0 +1,19 @@ +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./ui/tooltip"; + +export function TextTooltip(props: { + text: string, + children: React.ReactNode, +}) { + return ( + + + + {props.children} + + + {props.text} + + + + ); +} \ No newline at end of file diff --git a/packages/stack-server/src/components/ui/input.tsx b/packages/stack-server/src/components/ui/input.tsx index cf1956fa0..89b714305 100644 --- a/packages/stack-server/src/components/ui/input.tsx +++ b/packages/stack-server/src/components/ui/input.tsx @@ -23,3 +23,29 @@ const Input = React.forwardRef( Input.displayName = "Input"; export { Input }; + + +export interface DelayedInputProps extends InputProps { + delay?: number, +} + +export const DelayedInput = React.forwardRef( + ({ delay = 500, defaultValue, ...props }, ref) => { + const [value, setValue] = React.useState(defaultValue ?? ""); + + const timeout = React.useRef | null>(null); + + const onChange = (e: React.ChangeEvent) => { + setValue(e.target.value); + if (timeout.current) { + clearTimeout(timeout.current); + } + timeout.current = setTimeout(() => { + props.onChange?.(e); + }, delay); + }; + + return ; + } +); +DelayedInput.displayName = "DelayedInput"; \ No newline at end of file