@@ -5,114 +5,90 @@ import TreeView from "@material-ui/lab/TreeView"
5
5
import TreeItem from "@material-ui/lab/TreeItem"
6
6
import Menu from "@material-ui/core/Menu"
7
7
import MenuItem from "@material-ui/core/MenuItem"
8
- import { FC , useMemo , useState } from "react"
9
- import { TemplateVersionFiles } from "util/templateVersion "
8
+ import { FC , useState } from "react"
9
+ import { FileTree } from "util/filetree "
10
10
import { DockerIcon } from "components/Icons/DockerIcon"
11
11
12
- export interface File {
12
+ const sortFileTree = ( fileTree : FileTree ) => ( a : string , b : string ) => {
13
+ const contentA = fileTree [ a ]
14
+ const contentB = fileTree [ b ]
15
+ if ( typeof contentA === "object" ) {
16
+ return - 1
17
+ }
18
+ if ( typeof contentB === "object" ) {
19
+ return 1
20
+ }
21
+ return a . localeCompare ( b )
22
+ }
23
+
24
+ type ContextMenu = {
13
25
path : string
14
- content ?: string
15
- children : Record < string , File >
26
+ clientX : number
27
+ clientY : number
16
28
}
17
29
18
- export const FileTree : FC < {
19
- onSelect : ( file : File ) => void
20
- onDelete : ( file : File ) => void
21
- onRename : ( file : File ) => void
22
- files : TemplateVersionFiles
23
- activeFile ?: File
24
- } > = ( { activeFile , files , onDelete, onRename, onSelect } ) => {
30
+ export const FileTreeView : FC < {
31
+ onSelect : ( path : string ) => void
32
+ onDelete : ( path : string ) => void
33
+ onRename : ( path : string ) => void
34
+ fileTree : FileTree
35
+ activePath ?: string
36
+ } > = ( { fileTree , activePath , onDelete, onRename, onSelect } ) => {
25
37
const styles = useStyles ( )
26
- const fileTree = useMemo < Record < string , File > > ( ( ) => {
27
- const paths = Object . keys ( files )
28
- const roots : Record < string , File > = { }
29
- paths . forEach ( ( path ) => {
30
- const pathParts = path . split ( "/" )
31
- const firstPart = pathParts . shift ( )
32
- if ( ! firstPart ) {
33
- // Not possible!
34
- return
35
- }
36
- let activeFile = roots [ firstPart ]
37
- if ( ! activeFile ) {
38
- activeFile = {
39
- path : firstPart ,
40
- children : { } ,
41
- }
42
- roots [ firstPart ] = activeFile
43
- }
44
- while ( pathParts . length > 0 ) {
45
- const pathPart = pathParts . shift ( )
46
- if ( ! pathPart ) {
47
- continue
48
- }
49
- if ( ! activeFile . children [ pathPart ] ) {
50
- activeFile . children [ pathPart ] = {
51
- path : activeFile . path + "/" + pathPart ,
52
- children : { } ,
53
- }
54
- }
55
- activeFile = activeFile . children [ pathPart ]
56
- }
57
- activeFile . content = files [ path ]
58
- activeFile . path = path
59
- } )
60
- return roots
61
- } , [ files ] )
62
- const [ contextMenu , setContextMenu ] = useState <
63
- | {
64
- file : File
65
- clientX : number
66
- clientY : number
67
- }
68
- | undefined
69
- > ( )
70
-
71
- const buildTreeItems = ( name : string , file : File ) : JSX . Element => {
38
+ const [ contextMenu , setContextMenu ] = useState < ContextMenu | undefined > ( )
39
+
40
+ const buildTreeItems = (
41
+ filename : string ,
42
+ content ?: FileTree | string ,
43
+ parentPath ?: string ,
44
+ ) : JSX . Element => {
45
+ const currentPath = parentPath ? `${ parentPath } /${ filename } ` : filename
72
46
let icon : JSX . Element | null = null
73
- if ( file . path . endsWith ( ".tf" ) ) {
47
+ if ( filename . endsWith ( ".tf" ) ) {
74
48
icon = < FileTypeTerraform />
75
49
}
76
- if ( file . path . endsWith ( ".md" ) ) {
50
+ if ( filename . endsWith ( ".md" ) ) {
77
51
icon = < FileTypeMarkdown />
78
52
}
79
- if ( file . path . endsWith ( "Dockerfile" ) ) {
53
+ if ( filename . endsWith ( "Dockerfile" ) ) {
80
54
icon = < FileTypeDockerfile />
81
55
}
82
56
83
57
return (
84
58
< TreeItem
85
- nodeId = { file . path }
86
- key = { file . path }
87
- label = { name }
59
+ nodeId = { currentPath }
60
+ key = { currentPath }
61
+ label = { filename }
88
62
className = { `${ styles . fileTreeItem } ${
89
- file . path === activeFile ?. path ? "active" : ""
63
+ currentPath === activePath ? "active" : ""
90
64
} `}
91
65
onClick = { ( ) => {
92
- if ( file . content ) {
93
- onSelect ( file )
94
- }
66
+ onSelect ( currentPath )
95
67
} }
96
68
onContextMenu = { ( event ) => {
97
69
event . preventDefault ( )
98
- if ( ! file . content ) {
99
- return
100
- }
101
70
setContextMenu (
102
71
contextMenu
103
72
? undefined
104
73
: {
105
- file : file ,
74
+ path : currentPath ,
106
75
clientY : event . clientY ,
107
76
clientX : event . clientX ,
108
77
} ,
109
78
)
110
79
} }
111
80
icon = { icon }
112
81
>
113
- { Object . entries ( file . children || { } ) . map ( ( [ name , file ] ) => {
114
- return buildTreeItems ( name , file )
115
- } ) }
82
+ { typeof content === "object" ? (
83
+ Object . keys ( content )
84
+ . sort ( sortFileTree ( content ) )
85
+ . map ( ( filename ) => {
86
+ const child = content [ filename ]
87
+ return buildTreeItems ( filename , child , currentPath )
88
+ } )
89
+ ) : (
90
+ < > </ >
91
+ ) }
116
92
</ TreeItem >
117
93
)
118
94
}
@@ -124,9 +100,12 @@ export const FileTree: FC<{
124
100
aria-label = "Files"
125
101
className = { styles . fileTree }
126
102
>
127
- { Object . entries ( fileTree ) . map ( ( [ name , file ] ) => {
128
- return buildTreeItems ( name , file )
129
- } ) }
103
+ { Object . keys ( fileTree )
104
+ . sort ( sortFileTree ( fileTree ) )
105
+ . map ( ( filename ) => {
106
+ const child = fileTree [ filename ]
107
+ return buildTreeItems ( filename , child )
108
+ } ) }
130
109
131
110
< Menu
132
111
onClose = { ( ) => setContextMenu ( undefined ) }
@@ -154,7 +133,7 @@ export const FileTree: FC<{
154
133
if ( ! contextMenu ) {
155
134
return
156
135
}
157
- onRename ( contextMenu . file )
136
+ onRename ( contextMenu . path )
158
137
setContextMenu ( undefined )
159
138
} }
160
139
>
@@ -165,7 +144,7 @@ export const FileTree: FC<{
165
144
if ( ! contextMenu ) {
166
145
return
167
146
}
168
- onDelete ( contextMenu . file )
147
+ onDelete ( contextMenu . path )
169
148
setContextMenu ( undefined )
170
149
} }
171
150
>
0 commit comments