1
1
import React , { useEffect , useState } from 'react'
2
2
import cx from 'classnames'
3
+ import { diff } from 'deep-diff'
3
4
5
+ import { useShallow } from 'zustand/react/shallow'
4
6
import { Spinner } from 'uiSrc/ui'
5
7
8
+ import { checkExistingPath } from './tbd'
9
+ import ReJSONConfirmDialog from './RejsonConfirmDialog'
6
10
import { RejsonDynamicTypes } from '../rejson-dynamic-types'
7
11
import { JSONObjectProps , ObjectTypes } from '../interfaces'
8
12
import { generatePath , getBrackets , wrapPath } from '../utils'
@@ -13,10 +17,18 @@ import {
13
17
EditItemFieldAction ,
14
18
} from '../components'
15
19
20
+ import { useRejsonStore } from '../hooks/useRejsonStore'
16
21
import styles from '../styles.module.scss'
17
22
18
23
const defaultValue : [ ] = [ ]
19
24
25
+ const JSONParse = ( value : string ) => JSON . parse ( value )
26
+
27
+ const hasModifications = ( oldObj : any , newObj : any ) => {
28
+ const differences = diff ( oldObj , newObj )
29
+ return differences ?. some ( ( d : any ) => d . kind === 'E' )
30
+ }
31
+
20
32
export const RejsonObject = React . memo ( ( props : JSONObjectProps ) => {
21
33
const {
22
34
type,
@@ -38,14 +50,24 @@ export const RejsonObject = React.memo((props: JSONObjectProps) => {
38
50
value : currentValue ,
39
51
} = props
40
52
41
- const [ path ] = useState < string > ( currentFullPath || generatePath ( parentPath , keyName ) )
53
+ const [ path ] = useState < string > (
54
+ currentFullPath || generatePath ( parentPath , keyName ) ,
55
+ )
42
56
const [ value , setValue ] = useState < any > ( defaultValue )
43
57
const [ downloaded , setDownloaded ] = useState < boolean > ( isDownloaded )
44
58
const [ editEntireObject , setEditEntireObject ] = useState < boolean > ( false )
45
59
const [ valueOfEntireObject , setValueOfEntireObject ] = useState < any > ( '' )
46
60
const [ addNewKeyValuePair , setAddNewKeyValuePair ] = useState < boolean > ( false )
47
61
const [ loading , setLoading ] = useState < boolean > ( false )
48
62
const [ isExpanded , setIsExpanded ] = useState < boolean > ( false )
63
+ const [ isConfirmVisible , setIsConfirmVisible ] = useState < boolean > ( false )
64
+ const [ confirmDialogAction , setConfirmDialogAction ] = useState < any > ( ( ) => { } )
65
+
66
+ const { fullValue } = useRejsonStore (
67
+ useShallow ( ( state ) => ( {
68
+ fullValue : state . data . data ,
69
+ } ) ) ,
70
+ )
49
71
50
72
useEffect ( ( ) => {
51
73
if ( ! expandedRows ?. has ( path ) ) {
@@ -62,34 +84,71 @@ export const RejsonObject = React.memo((props: JSONObjectProps) => {
62
84
fetchObject ( )
63
85
} , [ ] )
64
86
65
- const handleFormSubmit = ( { key, value } : { key ?: string , value : string } ) => {
66
- setAddNewKeyValuePair ( false )
67
-
87
+ const handleFormSubmit = ( {
88
+ key,
89
+ value : updatedValue ,
90
+ } : {
91
+ key ?: string
92
+ value : string
93
+ } ) => {
68
94
if ( type === ObjectTypes . Array ) {
69
95
handleAppendRejsonObjectItemAction ( selectedKey , path , value )
70
96
return
71
97
}
72
98
73
99
const updatedPath = wrapPath ( key as string , path )
100
+ const isKeyExisting = fullValue
101
+ ? checkExistingPath ( updatedPath || '' , JSONParse ( fullValue as string ) )
102
+ : false
103
+
104
+ if ( isKeyExisting ) {
105
+ setConfirmDialogAction ( ( ) => ( ) => {
106
+ setAddNewKeyValuePair ( false )
107
+
108
+ if ( updatedPath ) {
109
+ handleSetRejsonDataAction ( selectedKey , updatedPath , updatedValue )
110
+ }
111
+ } )
112
+
113
+ setIsConfirmVisible ( true )
114
+ return
115
+ }
116
+
117
+ setAddNewKeyValuePair ( false )
74
118
if ( updatedPath ) {
75
- handleSetRejsonDataAction ( selectedKey , updatedPath , value )
119
+ handleSetRejsonDataAction ( selectedKey , updatedPath , updatedValue )
76
120
}
77
121
}
78
122
79
- const handleUpdateValueFormSubmit = ( value : string ) => {
123
+ const handleUpdateValueFormSubmit = ( updatedValue : string ) => {
124
+ if ( hasModifications ( value , updatedValue ) ) {
125
+ setConfirmDialogAction ( ( ) => ( ) => {
126
+ setEditEntireObject ( false )
127
+ handleSetRejsonDataAction ( selectedKey , path , updatedValue as string )
128
+ } )
129
+
130
+ setIsConfirmVisible ( true )
131
+ return
132
+ }
133
+
80
134
setEditEntireObject ( false )
81
- handleSetRejsonDataAction ( selectedKey , path , value as string )
135
+ handleSetRejsonDataAction ( selectedKey , path , updatedValue as string )
82
136
}
83
137
84
138
const onClickEditEntireObject = async ( ) => {
85
139
const data = await handleFetchVisualisationResults ( selectedKey , path , true )
86
140
87
141
setEditEntireObject ( true )
88
- setValueOfEntireObject ( typeof data . data === 'object' ? JSON . stringify ( data . data , ( _key , value ) => (
89
- typeof value === 'bigint'
90
- ? value . toString ( )
91
- : value
92
- ) , 4 ) : data . data )
142
+ setValueOfEntireObject (
143
+ typeof data . data === 'object'
144
+ ? JSON . stringify (
145
+ data . data ,
146
+ ( _key , value ) =>
147
+ ( typeof value === 'bigint' ? value . toString ( ) : value ) ,
148
+ 4 ,
149
+ )
150
+ : data . data ,
151
+ )
93
152
}
94
153
95
154
const onClickExpandCollapse = ( path : string ) => {
@@ -116,7 +175,10 @@ export const RejsonObject = React.memo((props: JSONObjectProps) => {
116
175
const spinnerDelay = setTimeout ( ( ) => setLoading ( true ) , 300 )
117
176
118
177
try {
119
- const { data, downloaded } = await handleFetchVisualisationResults ( selectedKey , path )
178
+ const { data, downloaded } = await handleFetchVisualisationResults (
179
+ selectedKey ,
180
+ path ,
181
+ )
120
182
121
183
setValue ( data )
122
184
onJsonKeyExpandAndCollapse ( true , path )
@@ -134,7 +196,15 @@ export const RejsonObject = React.memo((props: JSONObjectProps) => {
134
196
< >
135
197
< div className = { styles . row } key = { keyName + parentPath } >
136
198
< div className = { styles . rowContainer } >
137
- < div className = { styles . quotedKeyName } style = { { paddingLeft : `${ leftPadding } em` } } >
199
+ < ReJSONConfirmDialog
200
+ open = { isConfirmVisible }
201
+ onClose = { ( ) => setIsConfirmVisible ( false ) }
202
+ onConfirm = { confirmDialogAction }
203
+ />
204
+ < div
205
+ className = { styles . quotedKeyName }
206
+ style = { { paddingLeft : `${ leftPadding } em` } }
207
+ >
138
208
< span
139
209
className = { cx ( styles . quoted , styles . keyName ) }
140
210
onClick = { ( ) => onClickExpandCollapse ( path ) }
@@ -155,7 +225,11 @@ export const RejsonObject = React.memo((props: JSONObjectProps) => {
155
225
{ getBrackets ( type , 'end' ) }
156
226
</ div >
157
227
) }
158
- { isExpanded && ! editEntireObject && < span className = { styles . defaultFontOpenIndex } > { getBrackets ( type , 'start' ) } </ span > }
228
+ { isExpanded && ! editEntireObject && (
229
+ < span className = { styles . defaultFontOpenIndex } >
230
+ { getBrackets ( type , 'start' ) }
231
+ </ span >
232
+ ) }
159
233
</ div >
160
234
{ ! editEntireObject && ! loading && (
161
235
< EditItemFieldAction
@@ -193,7 +267,9 @@ export const RejsonObject = React.memo((props: JSONObjectProps) => {
193
267
onJsonKeyExpandAndCollapse = { onJsonKeyExpandAndCollapse }
194
268
handleSubmitUpdateValue = { handleSubmitUpdateValue }
195
269
handleFetchVisualisationResults = { handleFetchVisualisationResults }
196
- handleAppendRejsonObjectItemAction = { handleAppendRejsonObjectItemAction }
270
+ handleAppendRejsonObjectItemAction = {
271
+ handleAppendRejsonObjectItemAction
272
+ }
197
273
handleSetRejsonDataAction = { handleSetRejsonDataAction }
198
274
/>
199
275
) }
@@ -203,6 +279,7 @@ export const RejsonObject = React.memo((props: JSONObjectProps) => {
203
279
onCancel = { ( ) => setAddNewKeyValuePair ( false ) }
204
280
onSubmit = { handleFormSubmit }
205
281
leftPadding = { leftPadding }
282
+ shouldCloseOnOutsideClick = { false }
206
283
/>
207
284
) }
208
285
{ isExpanded && ! editEntireObject && (
0 commit comments