@@ -13,32 +13,39 @@ import { ExpandItemsContext } from './Contexts/ExpandedItemsProvider'
1313import { useTreeLoading } from './Contexts/TreeLoadingProvider'
1414import StyledTreeItemProps from './Props/StyledTreeItemProps'
1515
16- export const StyledTreeItem = ( props : StyledTreeItemProps ) => {
16+ export const StyledTreeItem = ( {
17+ contentvalue,
18+ activeitempath,
19+ navigate,
20+ editMode,
21+ ...restProps
22+ } : StyledTreeItemProps ) => {
1723 const { setIsTreeLoading, enabledPath } = useTreeLoading ( )
18- const [ hasChildren , setHasChildren ] = useState < boolean > ( true )
1924 const [ innerElements , setInnerElements ] = useState < React . JSX . Element [ ] > ( )
20- const expContext = useContext ( ExpandItemsContext )
21- const currentPath = useQuery ( ) . get ( 'path' )
22- if ( ! expContext ) {
23- throw new Error ( 'MyComponent must be used within a ExpandItemsProvider' )
24- }
25- const [ expandItems , setExpandItems , _expandOriginalItems , _setExpandOriginalItems , loadChildren ] = expContext
2625 const [ contextMenuItem , setContextMenuItem ] = useState < GenericContent | null > ( null )
2726 const [ isContextMenuOpened , setIsContextMenuOpened ] = useState ( false )
2827 const [ contextMenuAnchorPos , setContextMenuAnchorPos ] = useState < { top : number ; left : number } > ( {
2928 top : 0 ,
3029 left : 0 ,
3130 } )
32- const path = props . contentvalue . Path
33- const isDisabled = ! path . includes ( enabledPath )
31+
32+ const expContext = useContext ( ExpandItemsContext )
33+ if ( ! expContext ) throw new Error ( 'StyledTreeItem must be used within ExpandItemsProvider' )
34+
35+ const [ expandItems , setExpandItems , , , loadChildren ] = expContext
3436 const history = useHistory ( )
3537 const repository = useRepository ( )
36- const { location } = history
3738 const snRoute = useSnRoute ( )
3839 const uiSettings = useContext ( ResponsivePersonalSettings )
39- const { navigate, editMode, ...restProps } = props
40+
41+ const currentPath = useQuery ( ) . get ( 'path' )
4042 const mountedRef = useRef ( true )
4143
44+ const path = contentvalue . Path
45+ const isDisabled = ! path . includes ( enabledPath )
46+ const itemId = String ( contentvalue . Id )
47+
48+ // Track mount state
4249 useEffect ( ( ) => {
4350 mountedRef . current = true
4451 return ( ) => {
@@ -47,162 +54,151 @@ export const StyledTreeItem = (props: StyledTreeItemProps) => {
4754 } , [ ] )
4855
4956 const loadCollectionCB = useCallback (
50- async ( contentPath : string ) : Promise < void > => {
57+ async ( contentPath : string ) => {
5158 try {
5259 const children = await loadChildren ( contentPath )
53- if ( ! mountedRef . current ) {
54- return
55- }
56- children ?. sort ( ( a , b ) => {
60+ if ( ! mountedRef . current ) return
61+
62+ const sorted = children ?. sort ( ( a , b ) => {
5763 const isAFolder = a . Type . toLowerCase ( ) . includes ( 'folder' ) ? 0 : 1
5864 const isBFolder = b . Type . toLowerCase ( ) . includes ( 'folder' ) ? 0 : 1
59- if ( isAFolder !== isBFolder ) {
60- return isAFolder - isBFolder
61- }
62- return a . Name . localeCompare ( b . Name )
65+ return isAFolder - isBFolder || a . Name . localeCompare ( b . Name )
6366 } )
6467
65- const elements = children ?. map ( ( innerChild : GenericContent ) => (
68+ const elements = sorted ?. map ( ( child ) => (
6669 < StyledTreeItem
67- id = { String ( innerChild . Id ) }
68- key = { innerChild . Id }
69- data-id = { innerChild . Id }
70- activeitempath = { props . activeitempath }
71- nodeId = { innerChild . Id . toString ( ) }
72- contentvalue = { innerChild }
73- navigate = { props . navigate }
70+ key = { child . Id }
71+ id = { String ( child . Id ) }
72+ data-id = { child . Id }
73+ activeitempath = { activeitempath }
74+ nodeId = { child . Id . toString ( ) }
75+ contentvalue = { child }
76+ navigate = { navigate }
7477 editMode = { editMode }
7578 onContextMenu = { ( event ) => {
7679 event . preventDefault ( )
7780 event . stopPropagation ( )
7881 } }
7982 />
8083 ) )
81-
82- if ( elements ) {
83- setHasChildren ( elements . length > 0 )
84- setInnerElements ( elements )
85- }
84+ setInnerElements ( elements )
8685 } finally {
8786 //
8887 }
8988 } ,
90- [ loadChildren , props . activeitempath , props . navigate , editMode ] ,
89+ [ loadChildren , activeitempath , navigate , editMode ] ,
9190 )
9291
92+ // Load children if expanded
9393 useEffect ( ( ) => {
94- const itemId = String ( props . contentvalue . Id )
9594 if ( expandItems . has ( itemId ) ) {
96- loadCollectionCB ( props . contentvalue . Path )
95+ loadCollectionCB ( contentvalue . Path )
9796 }
98- } , [ props , expandItems , loadCollectionCB , currentPath ] )
97+ } , [ expandItems , itemId , contentvalue . Path , currentPath , loadCollectionCB ] )
9998
99+ // Collapse if outside enabledPath
100100 useEffect ( ( ) => {
101- const itemId = String ( props . contentvalue . Id )
102- const itemPath = props . contentvalue . Path
103-
101+ const itemPath = contentvalue . Path
104102 if ( ! enabledPath . startsWith ( itemPath ) && ! itemPath . startsWith ( enabledPath ) && expandItems . has ( itemId ) ) {
105103 setExpandItems ( ( prev ) => {
106104 const updated = new Set ( prev )
107105 updated . delete ( itemId )
108106 return updated
109107 } )
110108 }
111- } , [ enabledPath , expandItems , props . contentvalue . Id , props . contentvalue . Path , setExpandItems ] )
112-
113- const getLabel = ( ) => {
114- return (
115- < >
116- < ListItemIcon key = { props . contentvalue . Id } >
117- < Icon item = { props . contentvalue } />
118- </ ListItemIcon >
119- < ListItemText
120- style = { { fontSize : '11px!important' , color : isDisabled ? 'grey' : '' } }
121- primary = { `${ props . contentvalue . Name } ` }
122- />
123- </ >
124- )
125- }
109+ } , [ enabledPath , expandItems , itemId , contentvalue . Path , setExpandItems ] )
110+
111+ const getLabel = ( ) => (
112+ < >
113+ < ListItemIcon >
114+ < Icon item = { contentvalue } style = { { height : 20 , width : 20 , fontSize : 18 } } />
115+ </ ListItemIcon >
116+ < ListItemText style = { { fontSize : '11px' , color : isDisabled ? 'grey' : undefined } } primary = { contentvalue . Name } />
117+ </ >
118+ )
126119
127120 const onIconClick : MouseEventHandler = ( event ) => {
128121 if ( isDisabled ) return
129122 event . preventDefault ( )
130123 event . stopPropagation ( )
131- setExpandItems ( ( eItems ) => {
132- const updatedItems = new Set ( eItems )
133- const itemId = props . contentvalue . Id . toString ( )
134- if ( updatedItems . has ( itemId ) ) {
135- if ( document . activeElement ) {
136- ; ( document . activeElement as HTMLElement ) . blur ( )
137- }
138- updatedItems . delete ( itemId )
124+
125+ setExpandItems ( ( items ) => {
126+ const updated = new Set ( items )
127+ if ( updated . has ( itemId ) ) {
128+ ; ( document . activeElement as HTMLElement | null ) ?. blur ( )
129+ updated . delete ( itemId )
139130 } else {
140131 setIsTreeLoading ( true )
141- updatedItems . add ( itemId )
142- loadCollectionCB ( props . contentvalue . Path ) . finally ( ( ) => setIsTreeLoading ( false ) )
132+ updated . add ( itemId )
133+ loadCollectionCB ( contentvalue . Path ) . finally ( ( ) => setIsTreeLoading ( false ) )
143134 }
144- return updatedItems
135+ return updated
145136 } )
146137 }
147138
148139 const onLabelClick : MouseEventHandler = ( event ) => {
149140 if ( isDisabled ) return
150- const displayName = props . contentvalue . DisplayName
141+ const displayName = contentvalue . DisplayName
142+
151143 if ( displayName ?. endsWith ( '.settings' ) || displayName ?. endsWith ( '.xml' ) ) {
152- history . push ( getPrimaryActionUrl ( { content : props . contentvalue , repository, uiSettings, location, snRoute } ) )
144+ history . push (
145+ getPrimaryActionUrl ( { content : contentvalue , repository, uiSettings, location : history . location , snRoute } ) ,
146+ )
153147 return
154148 }
149+
155150 if ( editMode ) {
156151 navigateToAction ( {
157152 history,
158153 routeMatch : snRoute . match ! ,
159154 action : 'edit' ,
160- queryParams : { content : props . contentvalue . Path . replace ( snRoute . path , '' ) } ,
155+ queryParams : { content : contentvalue . Path . replace ( snRoute . path , '' ) } ,
161156 } )
162157 } else {
163158 const itemPath = ( event . target as HTMLElement ) . closest ( '[data-path]' ) ?. getAttribute ( 'data-path' )
164- const itemId = props . contentvalue . Id . toString ( )
165- setExpandItems ( ( prevItems ) => {
166- const updatedItems = new Set ( prevItems )
159+ setExpandItems ( ( prev ) => {
160+ const updated = new Set ( prev )
167161 if ( ! expandItems . has ( itemId ) ) {
168162 setIsTreeLoading ( true )
169- updatedItems . add ( itemId )
170- loadCollectionCB ( props . contentvalue . Path ) . finally ( ( ) => setIsTreeLoading ( false ) )
171- } else {
172- if ( itemPath === props . activeitempath ) {
173- updatedItems . delete ( itemId )
174- }
163+ updated . add ( itemId )
164+ loadCollectionCB ( contentvalue . Path ) . finally ( ( ) => setIsTreeLoading ( false ) )
165+ } else if ( itemPath === activeitempath ) {
166+ updated . delete ( itemId )
175167 }
176- return updatedItems
168+ return updated
177169 } )
178- props . navigate ( props . contentvalue )
170+ navigate ( contentvalue )
179171 }
180172 }
181173
182- const onContextMenu = ( event : React . MouseEvent , data : GenericContent ) => {
183- if ( isDisabled ) return
184- event . preventDefault ( )
185- event . stopPropagation ( )
186- setContextMenuItem ( data )
187- setContextMenuAnchorPos ( { top : event . clientY , left : event . clientX } )
188- setIsContextMenuOpened ( true )
189- }
174+ const onContextMenu = useCallback (
175+ ( event : React . MouseEvent ) => {
176+ if ( isDisabled ) return
177+ event . preventDefault ( )
178+ event . stopPropagation ( )
179+ setContextMenuItem ( contentvalue )
180+ setContextMenuAnchorPos ( { top : event . clientY , left : event . clientX } )
181+ setIsContextMenuOpened ( true )
182+ } ,
183+ [ contentvalue , isDisabled ] ,
184+ )
190185
191186 return (
192187 < >
193188 < TreeItem
194189 { ...restProps }
195190 label = { getLabel ( ) }
196- id = { props . contentvalue . Id . toString ( ) }
197- data-path = { props . contentvalue . Path }
191+ id = { itemId }
192+ data-path = { path }
198193 onIconClick = { onIconClick }
199194 onLabelClick = { onLabelClick }
200- onContextMenu = { ( event ) => onContextMenu ( event , props . contentvalue ) }
195+ onContextMenu = { onContextMenu }
201196 expandIcon = { isDisabled ? < > </ > : undefined }
202- collapseIcon = { ( ! hasChildren || isDisabled ) && < > </ > } >
197+ collapseIcon = { ( ! innerElements ?. length || isDisabled ) && < > </ > } >
203198 { innerElements }
204199 < > </ >
205200 </ TreeItem >
201+
206202 { contextMenuItem && (
207203 < ContentContextMenu
208204 isOpened = { isContextMenuOpened }
0 commit comments