1+ import { useState } from 'react'
2+ import { useForm } from 'react-hook-form'
3+ import { useQuery } from '@tanstack/react-query'
4+ import log from 'electron-log/renderer'
15import { Form } from '@/common/components/ui/form'
26import {
37 getFormSchemaRunMcpCommand ,
48 type FormSchemaRunMcpCommand ,
59} from '../lib/form-schema-run-mcp-server-with-command'
6- import { useForm } from 'react-hook-form'
7-
810import { FormFieldsRunMcpCommand } from './form-fields-run-mcp-command'
11+ import { getApiV1BetaWorkloadsOptions } from '@/common/api/generated/@tanstack/react-query.gen'
912import {
1013 Dialog ,
1114 DialogContent ,
@@ -18,18 +21,43 @@ import { Button } from '@/common/components/ui/button'
1821import { zodV4Resolver } from '@/common/lib/zod-v4-resolver'
1922import { FormFieldsArrayCustomEnvVars } from './form-fields-array-custom-env-vars'
2023import { FormFieldsArrayCustomSecrets } from './form-fields-array-custom-secrets'
21- import { useQuery } from '@tanstack/react-query'
22- import { getApiV1BetaWorkloadsOptions } from '@/common/api/generated/@tanstack/react-query.gen'
24+ import { useRunCustomServer } from '../hooks/use-run-custom-server'
25+ import { LoadingStateAlert } from '@/common/components/secrets/loading-state-alert'
26+ import { AlertErrorFormSubmission } from '@/common/components/workloads/alert-error-form-submission'
2327
2428export function DialogFormRunMcpServerWithCommand ( {
25- onSubmit,
2629 isOpen,
2730 onOpenChange,
2831} : {
29- onSubmit : ( data : FormSchemaRunMcpCommand ) => void
3032 isOpen : boolean
3133 onOpenChange : ( open : boolean ) => void
3234} ) {
35+ const [ error , setError ] = useState < string | null > ( null )
36+ const [ isSubmitting , setIsSubmitting ] = useState ( false )
37+ const [ loadingSecrets , setLoadingSecrets ] = useState < {
38+ text : string
39+ completedCount : number
40+ secretsCount : number
41+ } | null > ( null )
42+ const {
43+ installServerMutation,
44+ checkServerStatus,
45+ isErrorSecrets,
46+ isPendingSecrets,
47+ } = useRunCustomServer ( {
48+ onSecretSuccess : ( completedCount , secretsCount ) => {
49+ setLoadingSecrets ( ( prev ) => ( {
50+ ...prev ,
51+ text : `Encrypting secrets (${ completedCount } of ${ secretsCount } )...` ,
52+ completedCount,
53+ secretsCount,
54+ } ) )
55+ } ,
56+ onSecretError : ( error , variables ) => {
57+ log . error ( 'onSecretError' , error , variables )
58+ } ,
59+ } )
60+
3361 const { data } = useQuery ( {
3462 ...getApiV1BetaWorkloadsOptions ( { query : { all : true } } ) ,
3563 } )
@@ -44,6 +72,32 @@ export function DialogFormRunMcpServerWithCommand({
4472 } ,
4573 } )
4674
75+ const onSubmitForm = ( data : FormSchemaRunMcpCommand ) => {
76+ setIsSubmitting ( true )
77+ if ( error ) {
78+ setError ( null )
79+ }
80+
81+ installServerMutation (
82+ { data } ,
83+ {
84+ onSuccess : ( ) => {
85+ checkServerStatus ( data )
86+ onOpenChange ( false )
87+ } ,
88+ onSettled : ( _ , error ) => {
89+ setIsSubmitting ( false )
90+ if ( ! error ) {
91+ form . reset ( )
92+ }
93+ } ,
94+ onError : ( error ) => {
95+ setError ( typeof error === 'string' ? error : error . message )
96+ } ,
97+ }
98+ )
99+ }
100+
47101 return (
48102 < Dialog open = { isOpen } onOpenChange = { onOpenChange } >
49103 < DialogContent
@@ -54,31 +108,52 @@ export function DialogFormRunMcpServerWithCommand({
54108 } }
55109 >
56110 < Form { ...form } >
57- < form
58- onSubmit = { form . handleSubmit ( ( data ) => {
59- onSubmit ( data )
60- form . reset ( )
61- onOpenChange ( false )
62- } ) }
63- >
111+ < form onSubmit = { form . handleSubmit ( onSubmitForm ) } >
64112 < DialogHeader className = "mb-4 p-6" >
65113 < DialogTitle > Custom MCP server</ DialogTitle >
66114 < DialogDescription >
67115 ToolHive allows you to securely run a custom MCP server from a
68116 Docker image or a package manager command.
69117 </ DialogDescription >
70118 </ DialogHeader >
71-
72- < div
73- className = "relative max-h-[65dvh] space-y-4 overflow-y-auto px-6"
74- >
75- < FormFieldsRunMcpCommand form = { form } />
76- < FormFieldsArrayCustomSecrets form = { form } />
77- < FormFieldsArrayCustomEnvVars form = { form } />
78- </ div >
119+ { isSubmitting && (
120+ < LoadingStateAlert
121+ isPendingSecrets = { isPendingSecrets }
122+ loadingSecrets = { loadingSecrets }
123+ />
124+ ) }
125+ { ! isSubmitting && (
126+ < div
127+ className = "relative max-h-[65dvh] space-y-4 overflow-y-auto
128+ px-6"
129+ >
130+ { error && (
131+ < AlertErrorFormSubmission
132+ error = { error }
133+ isErrorSecrets = { isErrorSecrets }
134+ onDismiss = { ( ) => setError ( null ) }
135+ />
136+ ) }
137+ < FormFieldsRunMcpCommand form = { form } />
138+ < FormFieldsArrayCustomSecrets form = { form } />
139+ < FormFieldsArrayCustomEnvVars form = { form } />
140+ </ div >
141+ ) }
79142
80143 < DialogFooter className = "p-6" >
81- < Button type = "submit" > Install server</ Button >
144+ < Button
145+ type = "button"
146+ variant = "outline"
147+ disabled = { isSubmitting }
148+ onClick = { ( ) => {
149+ onOpenChange ( false )
150+ } }
151+ >
152+ Cancel
153+ </ Button >
154+ < Button disabled = { isSubmitting } type = "submit" >
155+ Install server
156+ </ Button >
82157 </ DialogFooter >
83158 </ form >
84159 </ Form >
0 commit comments