1
- import { Button , Dialog , TextInput , Dropdown , Banner , Dropzone , Typography , TextLink } from '@neo4j-ndl/react' ;
1
+ import { Button , Dialog , TextInput , Dropdown , Banner , Dropzone , Typography , TextLink , Flex } from '@neo4j-ndl/react' ;
2
2
import { Dispatch , SetStateAction , useCallback , useEffect , useMemo , useState } from 'react' ;
3
3
import connectAPI from '../../../services/ConnectAPI' ;
4
4
import { useCredentials } from '../../../context/UserCredentials' ;
5
5
import { useSearchParams } from 'react-router-dom' ;
6
6
import { buttonCaptions } from '../../../utils/Constants' ;
7
+ import { createVectorIndex } from '../../../services/vectorIndexCreation' ;
8
+ import { connectionState , UserCredentials } from '../../../types' ;
9
+ import VectorIndexMisMatchAlert from './VectorIndexMisMatchAlert' ;
7
10
8
11
interface Message {
9
12
type : 'success' | 'info' | 'warning' | 'danger' | 'unknown' ;
10
- content : string ;
13
+ content : string | React . ReactNode ;
11
14
}
12
15
13
16
interface ConnectionModalProps {
14
17
open : boolean ;
15
- setOpenConnection : Dispatch < SetStateAction < boolean > > ;
18
+ setOpenConnection : Dispatch < SetStateAction < connectionState > > ;
16
19
setConnectionStatus : Dispatch < SetStateAction < boolean > > ;
20
+ isVectorIndexMatch : boolean ;
21
+ noVectorIndexFound : boolean ;
17
22
}
18
23
19
- export default function ConnectionModal ( { open, setOpenConnection, setConnectionStatus } : ConnectionModalProps ) {
24
+ export default function ConnectionModal ( {
25
+ open,
26
+ setOpenConnection,
27
+ setConnectionStatus,
28
+ isVectorIndexMatch,
29
+ noVectorIndexFound,
30
+ } : ConnectionModalProps ) {
20
31
let prefilledconnection = localStorage . getItem ( 'neo4j.connection' ) ;
21
32
let initialuri ;
22
33
let initialdb ;
23
34
let initialusername ;
24
35
let initialport ;
25
36
let initialprotocol ;
37
+ let initialuserdbvectorindex ;
26
38
if ( prefilledconnection ) {
27
39
let parsedcontent = JSON . parse ( prefilledconnection ) ;
40
+ initialuserdbvectorindex = parsedcontent . userDbVectorIndex ;
28
41
let urisplit = parsedcontent ?. uri ?. split ( '://' ) ;
29
42
initialuri = urisplit [ 1 ] ;
30
43
initialdb = parsedcontent ?. database ;
@@ -40,9 +53,11 @@ export default function ConnectionModal({ open, setOpenConnection, setConnection
40
53
const [ username , setUsername ] = useState < string > ( initialusername ?? 'neo4j' ) ;
41
54
const [ password , setPassword ] = useState < string > ( '' ) ;
42
55
const [ connectionMessage , setMessage ] = useState < Message | null > ( { type : 'unknown' , content : '' } ) ;
43
- const { setUserCredentials } = useCredentials ( ) ;
56
+ const { setUserCredentials, userCredentials } = useCredentials ( ) ;
44
57
const [ isLoading , setIsLoading ] = useState < boolean > ( false ) ;
45
58
const [ searchParams , setSearchParams ] = useSearchParams ( ) ;
59
+ const [ userDbVectorIndex , setUserDbVectorIndex ] = useState < number | undefined > ( initialuserdbvectorindex ?? undefined ) ;
60
+ const [ vectorIndexLoading , setVectorIndexLoading ] = useState < boolean > ( false ) ;
46
61
47
62
useEffect ( ( ) => {
48
63
if ( searchParams . has ( 'connectURL' ) ) {
@@ -51,8 +66,66 @@ export default function ConnectionModal({ open, setOpenConnection, setConnection
51
66
searchParams . delete ( 'connectURL' ) ;
52
67
setSearchParams ( searchParams ) ;
53
68
}
69
+ return ( ) => {
70
+ setUserDbVectorIndex ( undefined ) ;
71
+ } ;
54
72
} , [ open ] ) ;
55
73
74
+ const recreateVectorIndex = useCallback (
75
+ async ( isNewVectorIndex : boolean ) => {
76
+ try {
77
+ setVectorIndexLoading ( true ) ;
78
+ const response = await createVectorIndex ( userCredentials as UserCredentials , isNewVectorIndex ) ;
79
+ setVectorIndexLoading ( false ) ;
80
+ if ( response . data . status === 'Failed' ) {
81
+ throw new Error ( response . data . error ) ;
82
+ } else {
83
+ setMessage ( {
84
+ type : 'success' ,
85
+ content : 'Successfully created the vector index' ,
86
+ } ) ;
87
+ setConnectionStatus ( true ) ;
88
+ localStorage . setItem (
89
+ 'neo4j.connection' ,
90
+ JSON . stringify ( {
91
+ uri : userCredentials ?. uri ,
92
+ user : userCredentials ?. userName ,
93
+ password : userCredentials ?. password ,
94
+ database : userCredentials ?. database ,
95
+ userDbVectorIndex : 384 ,
96
+ } )
97
+ ) ;
98
+ }
99
+ } catch ( error ) {
100
+ setVectorIndexLoading ( false ) ;
101
+ if ( error instanceof Error ) {
102
+ console . log ( 'Error in recreating the vector index' , error . message ) ;
103
+ setMessage ( { type : 'danger' , content : error . message } ) ;
104
+ }
105
+ }
106
+ setTimeout ( ( ) => {
107
+ setMessage ( { type : 'unknown' , content : '' } ) ;
108
+ setOpenConnection ( ( prev ) => ( { ...prev , openPopUp : false } ) ) ;
109
+ } , 3000 ) ;
110
+ } ,
111
+ [ userCredentials , userDbVectorIndex ]
112
+ ) ;
113
+ useEffect ( ( ) => {
114
+ if ( ! isVectorIndexMatch ) {
115
+ setMessage ( {
116
+ type : 'danger' ,
117
+ content : (
118
+ < VectorIndexMisMatchAlert
119
+ vectorIndexLoading = { vectorIndexLoading }
120
+ recreateVectorIndex = { ( ) => recreateVectorIndex ( ! noVectorIndexFound ) }
121
+ isVectorIndexAlreadyExists = { ! noVectorIndexFound }
122
+ userVectorIndexDimension = { JSON . parse ( localStorage . getItem ( 'neo4j.connection' ) ?? 'null' ) . userDbVectorIndex }
123
+ />
124
+ ) ,
125
+ } ) ;
126
+ }
127
+ } , [ isVectorIndexMatch , vectorIndexLoading , noVectorIndexFound ] ) ;
128
+
56
129
const parseAndSetURI = ( uri : string , urlparams = false ) => {
57
130
const uriParts : string [ ] = uri . split ( '://' ) ;
58
131
let uriHost : string [ ] | string ;
@@ -131,27 +204,47 @@ export default function ConnectionModal({ open, setOpenConnection, setConnection
131
204
setIsLoading ( true ) ;
132
205
const response = await connectAPI ( connectionURI , username , password , database ) ;
133
206
if ( response ?. data ?. status === 'Success' ) {
207
+ setUserDbVectorIndex ( response . data . data . db_vector_dimension ) ;
208
+ if ( response . data . data . db_vector_dimension === response . data . data . application_dimension ) {
209
+ setConnectionStatus ( true ) ;
210
+ setOpenConnection ( ( prev ) => ( { ...prev , openPopUp : false } ) ) ;
211
+ setMessage ( {
212
+ type : 'success' ,
213
+ content : response . data . data . message ,
214
+ } ) ;
215
+ } else {
216
+ setMessage ( {
217
+ type : 'danger' ,
218
+ content : (
219
+ < VectorIndexMisMatchAlert
220
+ vectorIndexLoading = { vectorIndexLoading }
221
+ recreateVectorIndex = { ( ) => recreateVectorIndex ( response . data . data . db_vector_dimension === 0 ) }
222
+ isVectorIndexAlreadyExists = { response . data . data . db_vector_dimension != 0 }
223
+ userVectorIndexDimension = { response . data . data . db_vector_dimension }
224
+ />
225
+ ) ,
226
+ } ) ;
227
+ }
134
228
localStorage . setItem (
135
229
'neo4j.connection' ,
136
- JSON . stringify ( { uri : connectionURI , user : username , password : password , database : database } )
230
+ JSON . stringify ( {
231
+ uri : connectionURI ,
232
+ user : username ,
233
+ password : password ,
234
+ database : database ,
235
+ userDbVectorIndex,
236
+ } )
137
237
) ;
138
- setConnectionStatus ( true ) ;
139
- setMessage ( {
140
- type : 'success' ,
141
- content : response . data . message ,
142
- } ) ;
143
- setOpenConnection ( false ) ;
144
238
} else {
145
239
setMessage ( { type : 'danger' , content : response . data . error } ) ;
146
- setOpenConnection ( true ) ;
240
+ setOpenConnection ( ( prev ) => ( { ... prev , openPopUp : true } ) ) ;
147
241
setPassword ( '' ) ;
148
242
setConnectionStatus ( false ) ;
149
243
}
150
244
setIsLoading ( false ) ;
151
245
setTimeout ( ( ) => {
152
- setMessage ( { type : 'unknown' , content : '' } ) ;
153
246
setPassword ( '' ) ;
154
- } , 3000 ) ;
247
+ } , 10000 ) ;
155
248
} ;
156
249
157
250
const onClose = useCallback ( ( ) => {
@@ -167,7 +260,7 @@ export default function ConnectionModal({ open, setOpenConnection, setConnection
167
260
open = { open }
168
261
aria-labelledby = 'form-dialog-title'
169
262
onClose = { ( ) => {
170
- setOpenConnection ( false ) ;
263
+ setOpenConnection ( ( prev ) => ( { ... prev , openPopUp : false } ) ) ;
171
264
setMessage ( { type : 'unknown' , content : '' } ) ;
172
265
} }
173
266
>
@@ -269,9 +362,11 @@ export default function ConnectionModal({ open, setOpenConnection, setConnection
269
362
/>
270
363
</ div >
271
364
</ div >
272
- < Button loading = { isLoading } disabled = { isDisabled } onClick = { ( ) => submitConnection ( ) } >
273
- { buttonCaptions . connect }
274
- </ Button >
365
+ < Flex flexDirection = 'row' justifyContent = 'flex-end' >
366
+ < Button loading = { isLoading } disabled = { isDisabled } onClick = { ( ) => submitConnection ( ) } >
367
+ { buttonCaptions . connect }
368
+ </ Button >
369
+ </ Flex >
275
370
</ Dialog . Content >
276
371
</ Dialog >
277
372
</ >
0 commit comments