1
- import { IFile , IStatus , RendererEvents , RepositoryInfo } from "common_library" ;
1
+ import { IChanges , IFile , IStatus , RendererEvents , RepositoryInfo } from "common_library" ;
2
2
import React , { Fragment , useEffect , useMemo , useRef } from "react" ;
3
3
import { FaAngleDown , FaAngleRight , FaMinus } from "react-icons/fa" ;
4
4
import { EnumChangesType , UiUtils , useMultiState } from "../../../../lib" ;
5
5
6
+ interface ISingleFileProps {
7
+ fileName :string ;
8
+ filePath :string ;
9
+ handleSelect :( path :string ) => void ;
10
+ isSelected :boolean ;
11
+ handleUnstage :( ) => void ;
12
+ changeType :"M" | "A" | "D" ;
13
+ }
14
+
15
+ function SingleFile ( props :ISingleFileProps ) {
16
+ const [ state , setState ] = useMultiState ( { isHovered :false } )
17
+ return (
18
+ < div key = { props . filePath } className = { `row g-0 align-items-center flex-nowrap hover w-100 ${ props . isSelected ? "selected" :"" } ` }
19
+ title = { props . fileName } onMouseEnter = { ( ) => setState ( { isHovered :true } ) } onMouseLeave = { _ => setState ( { isHovered :false } ) }
20
+ onClick = { _ => props . handleSelect ( props . filePath ) } >
21
+ < div className = "col-auto overflow-hidden flex-shrink-1" style = { { textOverflow :'ellipsis' } } >
22
+ < span className = { `pe-1 flex-shrink-0 ${ props . changeType === "D" ?"text-decoration-line-through" :"" } ` } > { props . fileName } </ span >
23
+ < span className = "small text-secondary" > { props . filePath } </ span >
24
+ </ div >
25
+
26
+ < div className = "col-auto align-items-center flex-nowrap overflow-hidden flex-grow-1 text-end pe-1" >
27
+ { state . isHovered && < Fragment >
28
+ < span className = "hover" title = "Unstage" onClick = { _ => props . handleUnstage ( ) } > < FaMinus /> </ span >
29
+ </ Fragment > }
30
+ < span >
31
+ < span className = "ps-1 text-success fw-bold" > { props . changeType } </ span >
32
+ </ span >
33
+ </ div >
34
+ </ div >
35
+ )
36
+ }
6
37
7
38
interface IStagedChangesProps {
8
- stagedChanges ?: IFile [ ] ;
39
+ changes : IChanges ;
9
40
repoInfoInfo ?:RepositoryInfo ;
10
41
onStatusChange :( status :IStatus ) => void ;
11
42
handleSelect :( path :string ) => void ;
@@ -42,13 +73,21 @@ function StagedChangesComponent(props:IStagedChangesProps){
42
73
return props . height - headerRef . current . clientHeight ;
43
74
} , [ headerRef . current ?. clientHeight , props . height ] ) ;
44
75
76
+ const totalItemCount = useMemo ( ( ) => {
77
+ const length = props . changes . created . length + props . changes . deleted . length
78
+ + props . changes . modified . length ;
79
+ return length ;
80
+ } , [ props . changes ] )
81
+
45
82
const handleUnstageItem = ( item :IFile ) => {
46
83
window . ipcRenderer . send ( RendererEvents . unStageItem ( ) . channel , [ item . path ] , props . repoInfoInfo )
47
84
}
48
85
49
86
const unStageAll = ( ) => {
50
- if ( ! props . stagedChanges ?. length ) return ;
51
- window . ipcRenderer . send ( RendererEvents . unStageItem ( ) . channel , props . stagedChanges . map ( x => x . path ) , props . repoInfoInfo )
87
+ if ( ! totalItemCount ) return ;
88
+ const paths = [ ...props . changes . created . map ( _ => _ . path ) , ...props . changes . deleted . map ( _ => _ . path ) ,
89
+ ...props . changes . modified . map ( _ => _ . path ) ] ;
90
+ window . ipcRenderer . send ( RendererEvents . unStageItem ( ) . channel , paths , props . repoInfoInfo )
52
91
}
53
92
54
93
return < div style = { { maxHeight :props . height } } >
@@ -57,7 +96,7 @@ function StagedChangesComponent(props:IStagedChangesProps){
57
96
< div className = "d-flex flex-grow-1" onClick = { props . hanldeExpand } >
58
97
< span > { props . isExpanded ? < FaAngleDown /> : < FaAngleRight /> } </ span >
59
98
< span > Staged Changes</ span >
60
- { ! ! props . stagedChanges ?. length && < span className = "text-info" > ({ props . stagedChanges . length } )</ span > }
99
+ { ! ! totalItemCount && < span className = "text-info" > ({ totalItemCount } )</ span > }
61
100
</ div >
62
101
{ state . isHeadHover && < div className = "d-flex" >
63
102
< span className = "hover" title = "UnStage all" onClick = { _ => unStageAll ( ) } > < FaMinus /> </ span >
@@ -67,24 +106,27 @@ function StagedChangesComponent(props:IStagedChangesProps){
67
106
{ props . isExpanded &&
68
107
< div className = "container ps-2 border" onMouseLeave = { _ => setState ( { hoveredFile :undefined } ) }
69
108
style = { { maxHeight :`${ fileListPanelHeight } px` , overflowX :'hidden' , overflowY :'auto' } } >
70
- { props . stagedChanges ?. map ( f => (
71
- < div key = { f . path } className = { `row g-0 align-items-center flex-nowrap hover w-100 ${ props . selectedMode === EnumChangesType . STAGED && f . path === props . selectedFilePath ?"selected" :"" } ` }
72
- title = { f . path } onMouseEnter = { ( ) => setState ( { hoveredFile :f } ) } onClick = { _ => props . handleSelect ( f . path ) } >
73
- < div className = "col-auto overflow-hidden flex-shrink-1" style = { { textOverflow :'ellipsis' } } >
74
- < span className = "pe-1 flex-shrink-0" > { f . fileName } </ span >
75
- < span className = "small text-secondary" > { f . path } </ span >
76
- </ div >
77
-
78
- < div className = "col-auto align-items-center flex-nowrap overflow-hidden flex-grow-1 text-end pe-1" >
79
- { state . hoveredFile ?. path === f . path && < Fragment >
80
- < span className = "hover" title = "Unstage" onClick = { _ => handleUnstageItem ( f ) } > < FaMinus /> </ span >
81
- </ Fragment > }
82
- < span >
83
- < span className = "ps-1 text-success fw-bold" > { "M" } </ span >
84
- </ span >
85
- </ div >
86
- </ div >
87
- ) ) }
109
+ { props . changes ?. modified ?. map ( f => (
110
+ < SingleFile key = { f . path } fileName = { f . fileName } filePath = { f .
111
+ path } handleSelect = { _ => props . handleSelect ( f . path ) }
112
+ handleUnstage = { ( ) => handleUnstageItem ( f ) }
113
+ isSelected = { props . selectedMode === EnumChangesType . STAGED && f . path === props . selectedFilePath }
114
+ changeType = "M" />
115
+ ) ) }
116
+ { props . changes ?. created ?. map ( f => (
117
+ < SingleFile key = { f . path } fileName = { f . fileName } filePath = { f .
118
+ path } handleSelect = { _ => props . handleSelect ( f . path ) }
119
+ handleUnstage = { ( ) => handleUnstageItem ( f ) }
120
+ isSelected = { props . selectedMode === EnumChangesType . STAGED && f . path === props . selectedFilePath }
121
+ changeType = "A" />
122
+ ) ) }
123
+ { props . changes ?. deleted ?. map ( f => (
124
+ < SingleFile key = { f . path } fileName = { f . fileName } filePath = { f .
125
+ path } handleSelect = { _ => props . handleSelect ( f . path ) }
126
+ handleUnstage = { ( ) => handleUnstageItem ( f ) }
127
+ isSelected = { props . selectedMode === EnumChangesType . STAGED && f . path === props . selectedFilePath }
128
+ changeType = "D" />
129
+ ) ) }
88
130
</ div >
89
131
}
90
132
</ div >
0 commit comments