1
- import React , { useEffect , useState } from 'react' ;
1
+ import React , { useEffect , useState , useRef } from 'react' ;
2
2
import PropTypes from 'prop-types' ;
3
3
import styles from '../styles/Design_Style.module.css' ;
4
4
@@ -8,6 +8,7 @@ const DataDictionary = ({ dataset, resourceId, config }) => {
8
8
const [ isDictionaryOpen , setIsDictionaryOpen ] = useState ( false ) ;
9
9
const [ geoJsonStructure , setGeoJsonStructure ] = useState ( null ) ;
10
10
const [ expandedRows , setExpandedRows ] = useState ( { } ) ;
11
+ const accordionLabelRef = useRef ( null ) ;
11
12
12
13
useEffect ( ( ) => {
13
14
if ( ! dataset || dataDictionary . length > 0 ) return ;
@@ -87,7 +88,7 @@ const DataDictionary = ({ dataset, resourceId, config }) => {
87
88
} ;
88
89
89
90
const parseJsonStructure = ( jsonData ) => {
90
- const parseObject = ( obj ) => {
91
+ const parseObject = ( obj , level = 0 ) => {
91
92
return Object . keys ( obj ) . map ( ( key ) => {
92
93
const value = obj [ key ] ;
93
94
const isArray = Array . isArray ( value ) ;
@@ -97,7 +98,8 @@ const DataDictionary = ({ dataset, resourceId, config }) => {
97
98
name : key ,
98
99
type : isArray ? 'Array' : isObject ? 'Object' : typeof value ,
99
100
description : isArray ? 'Array' : isObject ? 'Object' : 'Primitive' ,
100
- children : isObject ? parseObject ( value ) : null ,
101
+ children : isObject ? parseObject ( value , level + 1 ) : null ,
102
+ level,
101
103
} ;
102
104
} ) ;
103
105
} ;
@@ -109,6 +111,7 @@ const DataDictionary = ({ dataset, resourceId, config }) => {
109
111
type : 'Array' ,
110
112
description : 'Array' ,
111
113
children : jsonData . length > 0 ? parseObject ( jsonData [ 0 ] ) : null ,
114
+ level : 0 ,
112
115
} ,
113
116
] ;
114
117
} else if ( typeof jsonData === 'object' && jsonData !== null ) {
@@ -125,15 +128,48 @@ const DataDictionary = ({ dataset, resourceId, config }) => {
125
128
setIsDictionaryOpen ( ! isDictionaryOpen ) ;
126
129
} ;
127
130
131
+ const handleKeyDown = ( event ) => {
132
+ if ( event . key === 'Enter' ) {
133
+ handleToggleDictionary ( ) ;
134
+ }
135
+ } ;
136
+
128
137
const toggleRow = ( index ) => {
129
138
setExpandedRows ( ( prev ) => ( {
130
139
...prev ,
131
140
[ index ] : ! prev [ index ] ,
132
141
} ) ) ;
133
142
} ;
134
143
144
+ const renderRows = ( items ) => {
145
+ return items . map ( ( item , index ) => (
146
+ < React . Fragment key = { index } >
147
+ < tr
148
+ className = { `${ index % 2 === 0 ? styles . evenRow : styles . oddRow } ${
149
+ expandedRows [ index ] ? styles . expandedRow : ''
150
+ } `}
151
+ onClick = { ( ) => toggleRow ( index ) }
152
+ >
153
+ < td style = { { wordBreak : 'break-word' , paddingLeft : `${ item . level * 20 } px` } } >
154
+ < span className = { styles . fieldName } >
155
+ { item . name } { item . children && < span className = { styles . toggleIcon } > ▶</ span > }
156
+ </ span >
157
+ </ td >
158
+ < td style = { { wordBreak : 'break-word' } } >
159
+ < span className = { styles . typeBadge } > { item . type } </ span >
160
+ </ td >
161
+ < td style = { { wordBreak : 'break-word' } } > { item . description } </ td >
162
+ </ tr >
163
+ { expandedRows [ index ] && item . children && renderRows ( item . children ) }
164
+ </ React . Fragment >
165
+ ) ) ;
166
+ } ;
167
+
135
168
return (
136
- < div className = "ds_accordion" style = { { width : '100%' , marginTop : '2rem' } } >
169
+ < div
170
+ className = "ds_accordion"
171
+ style = { { width : '100%' , maxWidth : '100%' , marginTop : '2rem' , boxSizing : 'border-box' } }
172
+ >
137
173
< div className = "ds_accordion-item" >
138
174
< input
139
175
type = "checkbox"
@@ -153,81 +189,77 @@ const DataDictionary = ({ dataset, resourceId, config }) => {
153
189
) }
154
190
</ h3 >
155
191
< span className = { styles . accordionIndicator } > </ span >
156
- < label className = "ds_accordion-item__label" htmlFor = "data-dictionary-accordion" >
157
- < span className = "visually-hidden" > Show this section</ span >
192
+ < label
193
+ className = "ds_accordion-item__label"
194
+ htmlFor = "data-dictionary-accordion"
195
+ ref = { accordionLabelRef }
196
+ tabIndex = { 0 }
197
+ onKeyDown = { handleKeyDown }
198
+ role = "button"
199
+ aria-expanded = { isDictionaryOpen }
200
+ aria-controls = "data-dictionary-body"
201
+ >
202
+ < span className = "visually-hidden" > Toggle data dictionary</ span >
158
203
</ label >
159
204
</ div >
160
- < div className = "ds_accordion-item__body" >
161
- < div className = { styles . tableWrapper } >
205
+ < div className = "ds_accordion-item__body" id = "data-dictionary-body" >
206
+ < div
207
+ className = { styles . tableWrapper }
208
+ style = { { width : '100%' , maxWidth : '100%' , overflowX : 'auto' , boxSizing : 'border-box' } }
209
+ >
162
210
{ geoJsonStructure ? (
163
211
< div >
164
212
< h4 > JSON Structure</ h4 >
165
- < table className = { styles . tableModern } >
213
+ < table
214
+ className = { `${ styles . tableModern } ${ styles . smallFont } ` }
215
+ style = { {
216
+ width : '100%' ,
217
+ maxWidth : '100%' ,
218
+ borderRadius : 0 ,
219
+ tableLayout : 'auto' ,
220
+ boxSizing : 'border-box' ,
221
+ } }
222
+ >
166
223
< thead >
167
224
< tr >
168
- < th > Field Name</ th >
169
- < th > Type</ th >
170
- < th > Description</ th >
225
+ < th style = { { wordBreak : 'break-word' } } > Field Name</ th >
226
+ < th style = { { wordBreak : 'break-word' } } > Type</ th >
227
+ < th style = { { wordBreak : 'break-word' } } > Description</ th >
171
228
</ tr >
172
229
</ thead >
173
- < tbody >
174
- { geoJsonStructure . map ( ( item , index ) => (
175
- < React . Fragment key = { index } >
176
- < tr
177
- className = { `${ index % 2 === 0 ? styles . evenRow : styles . oddRow } ${
178
- expandedRows [ index ] ? styles . expandedRow : ''
179
- } `}
180
- onClick = { ( ) => toggleRow ( index ) }
181
- >
182
- < td >
183
- < span className = { styles . fieldName } >
184
- { item . name } { item . children && < span className = { styles . toggleIcon } > ▶</ span > }
185
- </ span >
186
- </ td >
187
- < td >
188
- < span className = { styles . typeBadge } > { item . type } </ span >
189
- </ td >
190
- < td > { item . description } </ td >
191
- </ tr >
192
- { expandedRows [ index ] &&
193
- item . children &&
194
- item . children . map ( ( child , idx ) => (
195
- < tr key = { idx } className = { index % 2 === 0 ? styles . evenRow : styles . oddRow } >
196
- < td style = { { paddingLeft : '20px' } } >
197
- < span className = { styles . fieldName } > { child . name } </ span >
198
- </ td >
199
- < td >
200
- < span className = { styles . typeBadge } > { child . type } </ span >
201
- </ td >
202
- < td > { child . description } </ td >
203
- </ tr >
204
- ) ) }
205
- </ React . Fragment >
206
- ) ) }
207
- </ tbody >
230
+ < tbody > { renderRows ( geoJsonStructure ) } </ tbody >
208
231
</ table >
209
232
</ div >
210
233
) : dataDictionary . length > 0 ? (
211
- < table className = { styles . tableModern } >
234
+ < table
235
+ className = { `${ styles . tableModern } ${ styles . smallFont } ` }
236
+ style = { {
237
+ width : '100%' ,
238
+ maxWidth : '100%' ,
239
+ borderRadius : 0 ,
240
+ tableLayout : 'auto' ,
241
+ boxSizing : 'border-box' ,
242
+ } }
243
+ >
212
244
< thead >
213
245
< tr >
214
- < th > Field Name</ th >
215
- < th > Type</ th >
216
- < th > Description</ th >
246
+ < th style = { { wordBreak : 'break-word' } } > Field Name</ th >
247
+ < th style = { { wordBreak : 'break-word' } } > Type</ th >
248
+ < th style = { { wordBreak : 'break-word' } } > Description</ th >
217
249
</ tr >
218
250
</ thead >
219
251
< tbody >
220
252
{ dataDictionary
221
253
. filter ( ( field ) => field . name !== '_id' )
222
254
. map ( ( field , index ) => (
223
255
< tr key = { index } className = { index % 2 === 0 ? styles . evenRow : styles . oddRow } >
224
- < td >
256
+ < td style = { { wordBreak : 'break-word' } } >
225
257
< span className = { styles . fieldName } > { field . name } </ span >
226
258
</ td >
227
- < td >
259
+ < td style = { { wordBreak : 'break-word' } } >
228
260
< span className = { styles . typeBadge } > { field . type } </ span >
229
261
</ td >
230
- < td > { field . description } </ td >
262
+ < td style = { { wordBreak : 'break-word' } } > { field . description } </ td >
231
263
</ tr >
232
264
) ) }
233
265
</ tbody >
@@ -248,4 +280,4 @@ DataDictionary.propTypes = {
248
280
config : PropTypes . object . isRequired ,
249
281
} ;
250
282
251
- export default DataDictionary ;
283
+ export default DataDictionary ;
0 commit comments