1+ import { apiServerProxy } from "@/actions/proxies" ;
2+ import type { Project } from "@/api/projects" ;
13import { CopyTextButton } from "@/components/ui/CopyTextButton" ;
24import { DynamicHeight } from "@/components/ui/DynamicHeight" ;
35import { Spinner } from "@/components/ui/Spinner/Spinner" ;
@@ -23,17 +25,18 @@ import {
2325} from "@/components/ui/form" ;
2426import { Input } from "@/components/ui/input" ;
2527import { Textarea } from "@/components/ui/textarea" ;
28+ import { useDashboardRouter } from "@/lib/DashboardRouter" ;
2629import {
2730 type ApiKey ,
2831 type CreateKeyInput ,
2932 useCreateApiKey ,
3033} from "@3rdweb-sdk/react/hooks/useApi" ;
3134import { zodResolver } from "@hookform/resolvers/zod" ;
3235import { DialogDescription } from "@radix-ui/react-dialog" ;
33- import type { UseMutationResult } from "@tanstack/react-query" ;
36+ import { type UseMutationResult , useQuery } from "@tanstack/react-query" ;
3437import { SERVICES } from "@thirdweb-dev/service-utils" ;
3538import { useTrack } from "hooks/analytics/useTrack" ;
36- import { ArrowLeftIcon } from "lucide-react" ;
39+ import { ArrowLeftIcon , ExternalLinkIcon } from "lucide-react" ;
3740import { useState } from "react" ;
3841import { useForm } from "react-hook-form" ;
3942import { toast } from "sonner" ;
@@ -54,6 +57,7 @@ export type CreateAPIKeyDialogProps = {
5457 onCreateAndComplete ?: ( ) => void ;
5558 prefill ?: CreateAPIKeyPrefillOptions ;
5659 enableNebulaServiceByDefault : boolean ;
60+ teamSlug : string | undefined ;
5761} ;
5862
5963const CreateAPIKeyDialog = ( props : CreateAPIKeyDialogProps ) => {
@@ -78,6 +82,7 @@ export const CreateAPIKeyDialogUI = (props: {
7882 > ;
7983 prefill ?: CreateAPIKeyPrefillOptions ;
8084 enableNebulaServiceByDefault : boolean ;
85+ teamSlug : string | undefined ;
8186} ) => {
8287 const [ screen , setScreen ] = useState <
8388 { id : "create" } | { id : "api-details" ; key : ApiKey }
@@ -97,7 +102,7 @@ export const CreateAPIKeyDialogUI = (props: {
97102 } }
98103 >
99104 < DialogContent
100- className = "z-[10001] p-0"
105+ className = "z-[10001] overflow-hidden p-0"
101106 dialogOverlayClassName = "z-[10000]"
102107 dialogCloseClassName = { screen . id === "api-details" ? "hidden" : "" }
103108 >
@@ -116,6 +121,7 @@ export const CreateAPIKeyDialogUI = (props: {
116121 { screen . id === "api-details" && (
117122 < APIKeyDetails
118123 apiKey = { screen . key }
124+ teamSlug = { props . teamSlug }
119125 onComplete = { ( ) => {
120126 onOpenChange ( false ) ;
121127 setScreen ( { id : "create" } ) ;
@@ -402,9 +408,35 @@ function DomainsAlert(props: {
402408function APIKeyDetails ( props : {
403409 apiKey : ApiKey ;
404410 onComplete : ( ) => void ;
411+ teamSlug : string | undefined ;
405412} ) {
406413 const { apiKey } = props ;
407414 const [ secretStored , setSecretStored ] = useState ( false ) ;
415+ const router = useDashboardRouter ( ) ;
416+
417+ // get the project.slug for the apiKey to render "View Project" button
418+ const projectQuery = useQuery ( {
419+ queryKey : [ "project" , props . teamSlug , apiKey . id ] ,
420+ queryFn : async ( ) => {
421+ const res = await apiServerProxy < {
422+ result : Project [ ] ;
423+ } > ( {
424+ method : "GET" ,
425+ pathname : `/v1/teams/${ props . teamSlug } /projects` ,
426+ } ) ;
427+
428+ if ( ! res . ok ) {
429+ throw new Error ( res . error ) ;
430+ }
431+
432+ const projects = res . data . result ;
433+ const project = projects . find ( ( p ) => p . publishableKey === apiKey . key ) ;
434+ return project || null ;
435+ } ,
436+ enabled : ! ! props . teamSlug ,
437+ } ) ;
438+
439+ const projectSlug = projectQuery . data ?. slug ;
408440
409441 return (
410442 < div >
@@ -474,10 +506,31 @@ function APIKeyDetails(props: {
474506 type = "button"
475507 onClick = { props . onComplete }
476508 disabled = { ! secretStored }
509+ variant = "outline"
477510 className = "min-w-28 gap-2"
478511 >
479- Complete
512+ { props . teamSlug ? "Close" : " Complete" }
480513 </ Button >
514+
515+ { props . teamSlug && (
516+ < Button
517+ onClick = { ( ) => {
518+ if ( ! projectSlug ) {
519+ return ;
520+ }
521+ router . push ( `/team/${ props . teamSlug } /${ projectSlug } ` ) ;
522+ } }
523+ disabled = { ! secretStored || ! projectSlug }
524+ className = "min-w-28 gap-2"
525+ >
526+ View Project
527+ { projectQuery . isPending ? (
528+ < Spinner className = "size-4" />
529+ ) : (
530+ < ExternalLinkIcon className = "size-4" />
531+ ) }
532+ </ Button >
533+ ) }
481534 </ DialogFooter >
482535 </ div >
483536 ) ;
0 commit comments