@@ -9,11 +9,13 @@ import {
99 Checkbox ,
1010 CircularProgress ,
1111 FormHelperText ,
12+ Alert ,
1213} from "@mui/material" ;
1314import { useState } from "react" ;
1415import { Form , Formik } from "formik" ;
1516import * as Yup from "yup" ;
1617import useSWRMutation from "swr/mutation" ;
18+ import { mutate } from "swr" ;
1719import Link from "next/link" ;
1820import { ChevronLeft } from "@mui/icons-material" ;
1921import { useRouter } from "next/navigation" ;
@@ -51,133 +53,159 @@ import {
5153 getPostgresInitialValues ,
5254} from "@/app/components/forms/connection-details/PostgresConnectionDetails" ;
5355
54- const AddDestination = ( ) => {
55- const Status = Object . freeze ( {
56- NOT_STARTED : 0 ,
57- LOADING : 1 ,
58- SUCCESS : 2 ,
59- FAILED : 3 ,
60- } ) ;
61-
62- // state of the connection test
63- const [ testConnectionStatus , setTestConnectionStatus ] = useState (
64- Status . NOT_STARTED
65- ) ;
66-
67- // state for the source being created
68- const [ destinationCreated , setDestinationCreated ] = useState ( false ) ;
69- const [ destinationId , setDestinationId ] = useState ( "" ) ;
70-
71- const router = useRouter ( ) ;
72-
73- const createDestination = ( params ) => {
74- return postRequest ( "/destinations" , { arg : params } ) ;
75- } ;
76-
77- const updateDestination = ( destinationId , params ) => {
78- return putRequest ( `/destinations/${ destinationId } ` , { arg : params } ) ;
79- } ;
80-
81- const startDestinationCheck = ( destinationId ) => {
82- return postRequest ( `/destinations/${ destinationId } /check` , { arg : { } } ) ;
56+ const testConnection = async ( key , { arg : values , destinationId } ) => {
57+ const params = {
58+ destination_name : values . destination_name ,
59+ vendor_type : values . vendor_type ,
60+ recipient_id : values . recipient_id ,
61+ schedule : {
62+ type : "INCREMENTAL" ,
63+ frequency : values . schedule_frequency ,
64+ day : values . schedule_day ,
65+ hour : values . schedule_hour ,
66+ minute : 0 ,
67+ } ,
68+ models : values . selectedModels ,
69+ connection_info : {
70+ vendor_type : values . vendor_type ,
71+ ...values [ values . vendor_type ] ,
72+ } ,
8373 } ;
8474
85- const waitForDestinationCheck = ( destinationId , taskId ) => {
86- return pollTaskStatus ( `/destinations/${ destinationId } /check/${ taskId } ` ) ;
87- } ;
75+ try {
76+ if ( ! destinationId ) {
77+ console . log ( "Creating destination" ) ;
78+ const result = await postRequest ( "/destinations" , { arg : params } ) ;
79+ const check = await postRequest (
80+ `/destinations/${ result . destination_id } /check` ,
81+ {
82+ arg : { } ,
83+ }
84+ ) ;
85+ const status = await pollTaskStatus (
86+ `/destinations/${ result . destination_id } /check/${ check . task_id } `
87+ ) ;
88+
89+ if (
90+ status . success === undefined ||
91+ status . success === null ||
92+ status . success === false
93+ ) {
94+ throw new Error ( status . cause ) ;
95+ }
8896
89- const updateCheckState = ( result ) => {
90- if ( ! result . success || result . success === false ) {
91- setTestConnectionStatus ( Status . FAILED ) ;
97+ return {
98+ destination_id : result . destination_id ,
99+ success : status . success ,
100+ } ;
92101 } else {
93- setTestConnectionStatus ( Status . SUCCESS ) ;
102+ console . log ( "Updating destination" ) ;
103+ const result = await putRequest ( `/destinations/${ destinationId } ` , {
104+ arg : params ,
105+ } ) ;
106+ const check = await postRequest ( `/destinations/${ destinationId } /check` , {
107+ arg : { } ,
108+ } ) ;
109+ const status = await pollTaskStatus (
110+ `/destinations/${ destinationId } /check/${ check . task_id } `
111+ ) ;
112+
113+ if (
114+ status . success === undefined ||
115+ status . success === null ||
116+ status . success === false
117+ ) {
118+ throw new Error ( status . cause ) ;
119+ }
120+
121+ return {
122+ destination_id : result . destination_id ,
123+ success : status . success ,
124+ } ;
94125 }
95- } ;
126+ } catch ( e ) {
127+ console . warn ( "Error testing connection: " , e ) ;
128+ throw e ;
129+ }
130+ } ;
131+
132+ const enableDestination = async ( key , { arg : destinationId } ) => {
133+ try {
134+ const result = await putRequest ( `/destinations/${ destinationId } ` , {
135+ arg : { is_enabled : true , state : "CREATED" } ,
136+ } ) ;
137+ // Invalidate the destinations cache since there's a new destination
138+ mutate ( "/destinations" ) ;
139+ return result ;
140+ } catch ( e ) {
141+ console . warn ( "Error enabling destination: " , e ) ;
142+ throw e ;
143+ }
144+ } ;
96145
146+ const AddDestination = ( ) => {
97147 const {
98- data : recipients ,
99- error : recipientsError ,
100- isLoading : recipientsLoading ,
101- } = useSWR ( "/recipients" , getRequest ) ;
148+ trigger : testConnectionTrigger ,
149+ data : testConnectionResult ,
150+ error : testConnectionError ,
151+ isMutating : isTestConnectionMutating ,
152+ } = useSWRMutation ( "/destinations/test_connection" , testConnection ) ;
153+ const destinationId = testConnectionResult ?. destination_id ;
102154
103155 const {
104- data : models ,
105- error : modelsError ,
106- isLoading : modelsLoading ,
107- } = useSWR ( "/models" , getRequest ) ;
108- const modelIds = models ?. map ( ( m ) => m . model_id ) ;
156+ trigger : enableDestinationTrigger ,
157+ data : enableDestinationResult ,
158+ error : enableDestinationError ,
159+ isMutating : isEnableDestinationMutating ,
160+ } = useSWRMutation (
161+ ( destinationId ) => `/destinations/${ destinationId } ` ,
162+ enableDestination
163+ ) ;
164+
165+ const router = useRouter ( ) ;
109166
110167 // form submission handler
111168 const handleCreateAndCheckDestination = async ( values , validateForm ) => {
112- setTestConnectionStatus ( Status . LOADING ) ;
113169 const errors = await validateForm ( values ) ;
114170 if ( Object . keys ( errors ) . length > 0 ) {
115171 console . log ( errors ) ;
116- setTestConnectionStatus ( Status . FAILED ) ;
117172 return ;
118173 }
119- const params = {
120- destination_name : values . destination_name ,
121- vendor_type : values . vendor_type ,
122- recipient_id : values . recipient_id ,
123- schedule : {
124- type : "INCREMENTAL" ,
125- frequency : values . schedule_frequency ,
126- day : values . schedule_day ,
127- hour : values . schedule_hour ,
128- minute : 0 ,
129- } ,
130- models : values . selectedModels ,
131- connection_info : {
132- vendor_type : values . vendor_type ,
133- ...values [ values . vendor_type ] ,
134- } ,
135- } ;
136174
137175 try {
138- if ( ! destinationCreated ) {
139- console . log ( "Creating destination" ) ;
140- const result = await createDestination ( params ) ;
141- const check = await startDestinationCheck ( result . destination_id ) ;
142- const status = await waitForDestinationCheck (
143- result . destination_id ,
144- check . task_id
145- ) ;
146-
147- setDestinationCreated ( true ) ;
148- setDestinationId ( result . destination_id ) ;
149- updateCheckState ( status ) ;
150- } else {
151- console . log ( "Updating destination" ) ;
152- await updateDestination ( destinationId , params ) ;
153- const check = await startDestinationCheck ( destinationId ) ;
154- const status = await waitForDestinationCheck (
155- destinationId ,
156- check . task_id
157- ) ;
158- updateCheckState ( status ) ;
159- }
176+ const result = await testConnectionTrigger ( values , destinationId ) ;
160177 } catch ( e ) {
161- setTestConnectionStatus ( Status . FAILED ) ;
162- } finally {
178+ console . warn ( "Error testing connection: " , e ) ;
179+ return ;
163180 }
164181 } ;
165182
166183 // when the create button is clicked
167- const handleEnableDestination = async ( ) => {
168- if ( destinationCreated ) {
184+ const handleEnableDestination = async ( values ) => {
185+ console . log ( "Submitting form" ) ;
186+ if ( destinationId ) {
169187 try {
170- await updateDestination ( destinationId , {
171- is_enabled : true ,
172- state : "CREATED" ,
173- } ) ;
188+ await enableDestinationTrigger ( destinationId ) ;
174189 router . push ( "/destinations" ) ;
175190 } catch ( e ) {
176191 console . log ( "Enabling destination failed: " , e ) ;
177192 }
178193 }
179194 } ;
180195
196+ const {
197+ data : recipients ,
198+ error : recipientsError ,
199+ isLoading : recipientsLoading ,
200+ } = useSWR ( "/recipients" , getRequest ) ;
201+
202+ const {
203+ data : models ,
204+ error : modelsError ,
205+ isLoading : modelsLoading ,
206+ } = useSWR ( "/models" , getRequest ) ;
207+ const modelIds = models ?. map ( ( m ) => m . model_id ) ;
208+
181209 if ( recipientsError || modelsError ) {
182210 return < Typography > Error with API</ Typography > ;
183211 }
@@ -389,7 +417,8 @@ const AddDestination = () => {
389417 variant = "contained"
390418 disabled = {
391419 isValidating ||
392- testConnectionStatus == Status . LOADING ||
420+ isTestConnectionMutating ||
421+ isEnableDestinationMutating ||
393422 ! isValid ||
394423 ! dirty
395424 }
@@ -399,31 +428,50 @@ const AddDestination = () => {
399428 >
400429 Test Connection
401430 </ Button >
402- { testConnectionStatus == Status . LOADING ? (
403- < CircularProgress size = { 28 } />
404- ) : null }
405- { testConnectionStatus == Status . SUCCESS ? (
406- < Typography fontSize = { 26 } > ✅</ Typography >
407- ) : null }
408- { testConnectionStatus == Status . FAILED ? (
409- < Typography fontSize = { 26 } > ❌</ Typography >
410- ) : null }
431+ { renderTestConnectionStatus (
432+ testConnectionResult ,
433+ testConnectionError ,
434+ isTestConnectionMutating
435+ ) }
411436 </ Stack >
412437 < FormHelperText >
413438 Testing the connection may take a few minutes.
414439 </ FormHelperText >
440+ { testConnectionError ? (
441+ < Alert severity = "error" >
442+ < Typography > { testConnectionError . message } </ Typography >
443+ </ Alert >
444+ ) : null }
445+ { enableDestinationError ? (
446+ < Alert severity = "error" >
447+ < Typography >
448+ { enableDestinationError . message }
449+ </ Typography >
450+ </ Alert >
451+ ) : null }
415452 </ Stack >
416453
417- < Button
418- type = "submit"
419- variant = "contained"
420- disabled = {
421- isSubmitting || ! ( testConnectionStatus == Status . SUCCESS )
422- }
423- sx = { { width : "fit-content" } }
424- >
425- Create
426- </ Button >
454+ < Stack direction = "row" alignItems = "center" spacing = { 1.5 } >
455+ < Button
456+ type = "submit"
457+ variant = "contained"
458+ disabled = {
459+ isValidating ||
460+ isTestConnectionMutating ||
461+ isEnableDestinationMutating ||
462+ testConnectionError ||
463+ testConnectionResult ?. success === false ||
464+ ! isValid ||
465+ ! dirty
466+ }
467+ sx = { { width : "fit-content" } }
468+ >
469+ Create
470+ </ Button >
471+ { isEnableDestinationMutating ? (
472+ < CircularProgress size = { 28 } />
473+ ) : null }
474+ </ Stack >
427475 </ Stack >
428476 </ Form >
429477 ) ;
@@ -449,6 +497,23 @@ const renderConnectionDetails = (vendor_type, setFieldValue, values) => {
449497 }
450498} ;
451499
500+ const renderTestConnectionStatus = (
501+ testConnectionResult ,
502+ testConnectionError ,
503+ isTestConnectionMutating
504+ ) => {
505+ if ( isTestConnectionMutating ) {
506+ return < CircularProgress size = { 28 } /> ;
507+ }
508+ if ( testConnectionError ) {
509+ return < Typography fontSize = { 26 } > ❌</ Typography > ;
510+ }
511+ if ( testConnectionResult ?. success === true ) {
512+ return < Typography fontSize = { 26 } > ✅</ Typography > ;
513+ }
514+ return null ;
515+ } ;
516+
452517const renderScheduleDetails = ( schedule_frequency ) => {
453518 return (
454519 < >
0 commit comments