1- import React , { useState , useEffect } from 'react' ;
1+ import React from 'react' ;
22import PropTypes from 'prop-types' ;
3- import { Tree , ActionTypes } from 'react-wooden-tree' ;
3+ import { Tree , ActionTypes } from 'react-wooden-tree' ;
44import {
55 ControlLabel , FieldLevelHelp , FormGroup , HelpBlock ,
66} from 'patternfly-react' ;
7+ import { useFieldApi , useFormApi } from '@data-driven-forms/react-form-renderer' ;
78
89import RequiredLabel from '../../forms/required-label' ;
9- import { convert , flatten } from './helpers' ;
10- import { useFieldApi , useFormApi } from '@@ddf' ;
10+ import TreeViewBase from './base' ;
1111
12- const setChecked = ( keys = [ ] ) => ( { state, ...node } ) => ( { ...node , state : { ...state , checked : keys . includes ( node . attr . key ) } } ) ;
13-
14- const TreeViewField = ( { loadData, lazyLoadData, ...props } ) => {
15- const [ { nodes } , setState ] = useState ( { } ) ;
16-
17- const { input : { value } , meta } = useFieldApi ( props ) ;
12+ const TreeViewField = ( {
13+ loadData, lazyLoadData, helperText, isRequired, label, identifier, ...props
14+ } ) => {
15+ const { input : { value = [ ] , name } , meta } = useFieldApi ( props ) ;
1816 const formOptions = useFormApi ( ) ;
1917
20- useEffect ( ( ) => {
21- loadData ( ) . then ( ( values ) => {
22- setState ( state => ( { ...state , nodes : flatten ( convert ( values , setChecked ( value ) ) ) } ) ) ;
23- } ) ;
24- } , [ loadData ] ) ;
25-
2618 const actionMapper = {
27- [ ActionTypes . EXPANDED ] : Tree . nodeExpanded ,
28- [ ActionTypes . CHECKED ] : Tree . nodeChecked ,
29- [ ActionTypes . DISABLED ] : Tree . nodeDisabled ,
30- [ ActionTypes . SELECTED ] : Tree . nodeSelected ,
31- [ ActionTypes . LOADING ] : Tree . nodeLoading ,
32- [ ActionTypes . CHILD_NODES ] : ( node , value ) => {
33- // There's a bug in the react-wooden-tree, the passed value here contains all the child
34- // nodes and that would force the tree to mount nested children to the parent node twice.
35- // For now we're filtering out the child nodes manually by counting the number of dots in
36- // their identifier.
37- const min = value . reduce ( ( min , key ) => {
38- const nl = key . split ( '.' ) . length ;
39- return nl > min ? min : nl ;
40- } , undefined ) ;
41-
42- return Tree . nodeChildren ( node , value . filter ( key => key . split ( '.' ) . length === min ) ) ;
43- } ,
4419 [ ActionTypes . CHECKED_DIRECTLY ] : ( node , value ) => {
45- const values = formOptions . getFieldState ( props . name ) . value ;
46- formOptions . change ( props . name , value ? [ ...values , node . attr . key ] : values . filter ( item => item !== node . attr . key ) ) ;
47-
20+ const { value : values = [ ] } = formOptions . getFieldState ( name ) ;
21+ formOptions . change ( name , value ? [ ...values , identifier ( node ) ] : values . filter ( item => item !== identifier ( node ) ) ) ;
4822 return Tree . nodeChecked ( node , value ) ;
4923 } ,
5024 } ;
5125
52- const lazyLoad = node => lazyLoadData ( node ) . then ( ( result ) => {
53- const data = flatten ( convert ( result , setChecked ( value ) ) ) ;
54-
55- let subtree = { } ;
56- Object . keys ( data ) . forEach ( ( key ) => {
57- if ( key !== '' ) {
58- // Creating the node id from the parent id.
59- const nodeId = `${ node . nodeId } .${ key } ` ;
60- // Updating the children ids, so it does not point to something else.
61- const element = { ...data [ key ] , nodeId, nodes : data [ key ] . nodes . map ( child => `${ node . nodeId } .${ child } ` ) } ;
62- subtree = { ...subtree , [ nodeId ] : element } ;
63- }
64- } ) ;
65- return subtree ;
66- } ) ;
67-
68- const onDataChange = commands => setState ( state => ( {
69- ...state ,
70- nodes : commands . reduce (
71- ( nodes , { type, value, nodeId } ) => (
72- type === ActionTypes . ADD_NODES
73- ? Tree . addNodes ( nodes , value )
74- : Tree . nodeUpdater ( nodes , actionMapper [ type ] ( Tree . nodeSelector ( nodes , nodeId ) , value ) )
75- ) , nodes ,
76- ) ,
77- } ) ) ;
78-
7926 return (
8027 < FormGroup validationState = { meta . error ? 'error' : null } >
8128 < ControlLabel >
82- { props . isRequired ? < RequiredLabel label = { props . label } /> : props . label }
83- { props . helperText && < FieldLevelHelp content = { props . helperText } /> }
29+ { isRequired ? < RequiredLabel label = { label } /> : label }
30+ { helperText && < FieldLevelHelp content = { helperText } /> }
8431 </ ControlLabel >
85- < Tree
86- data = { nodes }
87- nodeIcon = ""
88- expandIcon = "fa fa-fw fa-angle-right"
89- collapseIcon = "fa fa-fw fa-angle-down"
90- loadingIcon = "fa fa-fw fa-spinner fa-pulse"
91- checkedIcon = "fa fa-fw fa-check-square-o"
92- uncheckedIcon = "fa fa-fw fa-square-o"
93- selectedIcon = ""
94- partiallyCheckedIcon = "fa fa-fw fa-check-square"
95- preventDeselect
96- showCheckbox
97- callbacks = { { onDataChange, lazyLoad } }
32+ < TreeViewBase
33+ loadData = { loadData }
34+ lazyLoadData = { lazyLoadData }
35+ actionMapper = { actionMapper }
36+ check = { node => value . includes ( identifier ( node ) ) }
37+ isMulti
9838 { ...props }
9939 />
10040 { meta . error && < HelpBlock > { meta . error } </ HelpBlock > }
@@ -103,8 +43,20 @@ const TreeViewField = ({ loadData, lazyLoadData, ...props }) => {
10343} ;
10444
10545TreeViewField . propTypes = {
106- loadData : PropTypes . func ,
46+ loadData : PropTypes . func . isRequired ,
10747 lazyLoadData : PropTypes . func ,
48+ helperText : PropTypes . string ,
49+ isRequired : PropTypes . bool ,
50+ label : PropTypes . string ,
51+ identifier : PropTypes . func ,
52+ } ;
53+
54+ TreeViewField . defaultProps = {
55+ lazyLoadData : ( ) => undefined ,
56+ helperText : undefined ,
57+ isRequired : false ,
58+ label : undefined ,
59+ identifier : node => node . attr . key ,
10860} ;
10961
11062export default TreeViewField ;
0 commit comments