| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143 |
2x
2x
2x
2x
2x
4x
16x
16x
16x
12x
12x
12x
12x
12x
16x
4x
8x
12x
12x
12x
12x
24x
| import React from 'react';
import { style } from 'app/styles';
import { CaretDownIcon } from 'app/components/CaretDownIcon';
import { CaretRightIcon } from 'app/components/CaretRightIcon';
import { FileIcon } from 'app/components/FileIcon';
import { CommaNumber } from 'app/components/CommaNumber';
export interface DirectoryTreeProps {
fileTree: object;
expandedNodes: string[];
onExpandNode: (fullPath: string) => void;
onFileClick: (fullPath: string) => void;
// only show commits that DON't have .status of this value
filterCommitStatus?: 'added' | 'deleted' | 'modified';
style?: object | string;
}
const outerStyle = {
transition: 'all 1s ease',
flexGrow: 1,
};
const directoryNodeStyle = {
display: 'block',
marginLeft: 20,
};
const treeNodeStyle = {
_extends: 'normalText',
marginLeft: 10,
};
const fileNameStyle = {
_extends: 'normalText',
textDecoration: 'underline',
cursor: 'pointer',
};
const deltaStyle = {
_extends: 'smallerText',
float: 'right',
};
// const iconSize = 12;
// const iconStyle = {
// display: 'inline-block',
// height: iconSize,
// width: iconSize,
// textAlign: 'center'
// }
export class DirectoryTree extends React.Component<DirectoryTreeProps> {
render() {
return (
<div
style={style(outerStyle, this.props.style)}
data-testid="directoryTree"
>
{this.renderTree(this.props.fileTree)}
</div>
);
}
renderTree(treeNode, key = 0) {
let renderedTreeNodes = [];
const index = 0;
for (const nodeName in treeNode) {
const childNode = treeNode[nodeName];
const isExpanded =
this.props.expandedNodes.includes(childNode.fullPath) ||
Object.keys(childNode.nodes).length <= 1 ||
Object.keys(treeNode).length <= 1;
renderedTreeNodes.push(
this.isFile(childNode)
? this.renderFileTreeNode(childNode, nodeName, key + index)
: this.renderDirectoryTreeNode(
childNode,
nodeName,
isExpanded,
key + index
)
);
Eif (isExpanded) {
renderedTreeNodes = renderedTreeNodes.concat(
this.renderTree(childNode.nodes, key + index)
);
}
}
return (
<div style={directoryNodeStyle} key={key + index + 1}>
{renderedTreeNodes}
</div>
);
}
renderFileTreeNode(childNode, nodeName, key) {
return this.renderTreeNode(childNode, nodeName, FileIcon, key, () => {
this.props.onFileClick(childNode.fullPath);
});
}
renderDirectoryTreeNode(childNode, nodeName, isExpanded, key) {
return this.renderTreeNode(
childNode,
nodeName,
isExpanded ? CaretDownIcon : CaretRightIcon,
key,
() => {
this.props.onExpandNode(childNode.fullPath);
}
);
}
renderTreeNode(childNode, nodeName, Icon, key, onClick) {
const nodeStyle = Object.assign({}, treeNodeStyle) as any;
nodeStyle.color = `@colors.${childNode.status}`;
const nameStyle = this.isFile(childNode) ? fileNameStyle : {};
return (
<div
key={key}
style={style(nodeStyle)}
onClick={onClick}
data-testid="directoryTreeNode"
>
<Icon height={14} width={14} />
{' '}
<span
style={style(nameStyle, { color: nodeStyle.color })}
title="click to filter"
>
{nodeName}
</span>
{' '}
<div style={style(deltaStyle)}>
<CommaNumber value={childNode.delta || 0} />
𝚫
</div>
</div>
);
}
isFile(childNode) {
return !childNode.nodes || Object.keys(childNode.nodes).length === 0;
}
}
|