Skip to content

Commit 1175534

Browse files
meeseeksmachineianhifcollonval
authored
Backport PR #629 on branch 0.11.x (show both staged and unstaged changes for a file) (#679)
* Backport PR #629: show both staged and unstaged changes for a file * Correction for JLab 1 * Forget to update jest mock package Co-authored-by: Ian Hunt-Isaak <[email protected]> Co-authored-by: Frédéric Collonval <[email protected]>
1 parent d44e5e6 commit 1175534

File tree

6 files changed

+241
-25
lines changed

6 files changed

+241
-25
lines changed

src/components/FileItem.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ export class FileItem extends React.Component<IFileItemProps> {
7474
}
7575

7676
render() {
77-
const status =
78-
this.getFileChangedLabel(this.props.file.y as any) ||
79-
this.getFileChangedLabel(this.props.file.x as any);
77+
const { file } = this.props;
78+
const status_code = file.status === 'staged' ? file.x : file.y;
79+
const status = this.getFileChangedLabel(status_code as any);
8080

8181
return (
8282
<li
@@ -110,9 +110,7 @@ export class FileItem extends React.Component<IFileItemProps> {
110110
/>
111111
{this.props.actions}
112112
<span className={this.getFileChangedLabelClass(this.props.file.y)}>
113-
{this.props.file.y === '?'
114-
? 'U'
115-
: this.props.file.y.trim() || this.props.file.x}
113+
{this.props.file.y === '?' ? 'U' : status_code}
116114
</span>
117115
</li>
118116
);

src/components/FileList.tsx

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
4444
this._contextMenuStaged = new Menu({ commands });
4545
this._contextMenuUnstaged = new Menu({ commands });
4646
this._contextMenuUntracked = new Menu({ commands });
47+
this._contextMenuSimpleUntracked = new Menu({ commands });
48+
this._contextMenuSimpleTracked = new Menu({ commands });
4749

4850
this.state = {
4951
selectedFile: null
@@ -134,7 +136,7 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
134136
label: 'Discard',
135137
caption: 'Discard recent changes of selected file',
136138
execute: () => {
137-
this.discardChanges(this.state.selectedFile.to);
139+
this.discardChanges(this.state.selectedFile);
138140
}
139141
});
140142
}
@@ -159,6 +161,18 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
159161
[CommandIDs.gitFileOpen, CommandIDs.gitFileTrack].forEach(command => {
160162
this._contextMenuUntracked.addItem({ command });
161163
});
164+
165+
[
166+
CommandIDs.gitFileOpen,
167+
CommandIDs.gitFileDiscard,
168+
CommandIDs.gitFileDiffWorking
169+
].forEach(command => {
170+
this._contextMenuSimpleTracked.addItem({ command });
171+
});
172+
173+
[CommandIDs.gitFileOpen].forEach(command => {
174+
this._contextMenuSimpleUntracked.addItem({ command });
175+
});
162176
}
163177

164178
/** Handle right-click on a staged file */
@@ -179,6 +193,18 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
179193
this._contextMenuUntracked.open(event.clientX, event.clientY);
180194
};
181195

196+
/** Handle right-click on an untracked file in Simple mode*/
197+
contextMenuSimpleUntracked = (event: React.MouseEvent) => {
198+
event.preventDefault();
199+
this._contextMenuSimpleUntracked.open(event.clientX, event.clientY);
200+
};
201+
202+
/** Handle right-click on an tracked file in Simple mode*/
203+
contextMenuSimpleTracked = (event: React.MouseEvent) => {
204+
event.preventDefault();
205+
this._contextMenuSimpleTracked.open(event.clientX, event.clientY);
206+
};
207+
182208
/** Reset all staged files */
183209
resetAllStagedFiles = async () => {
184210
await this.props.model.reset();
@@ -234,23 +260,31 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
234260
};
235261

236262
/** Discard changes in a specific unstaged or staged file */
237-
discardChanges = async (file: string) => {
263+
discardChanges = async (file: Git.IStatusFile) => {
238264
const result = await showDialog({
239265
title: 'Discard changes',
240266
body: (
241267
<span>
242-
Are you sure you want to permanently discard changes to <b>{file}</b>?
243-
This action cannot be undone.
268+
Are you sure you want to permanently discard changes to{' '}
269+
<b>{file.to}</b>? This action cannot be undone.
244270
</span>
245271
),
246272
buttons: [Dialog.cancelButton(), Dialog.warnButton({ label: 'Discard' })]
247273
});
248274
if (result.button.accept) {
249275
try {
250-
await this.props.model.reset(file);
251-
await this.props.model.checkout({ filename: file });
276+
if (file.status === 'staged' || file.status === 'partially-staged') {
277+
await this.props.model.reset(file.to);
278+
}
279+
if (
280+
file.status === 'unstaged' ||
281+
(file.status === 'partially-staged' && file.x !== 'A')
282+
) {
283+
// resetting an added file moves it to untracked category => checkout will fail
284+
await this.props.model.checkout({ filename: file.to });
285+
}
252286
} catch (reason) {
253-
showErrorMessage(`Discard changes for ${file} failed.`, reason, [
287+
showErrorMessage(`Discard changes for ${file.to} failed.`, reason, [
254288
Dialog.warnButton({ label: 'DISMISS' })
255289
]);
256290
}
@@ -297,6 +331,16 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
297331
case 'untracked':
298332
untrackedFiles.push(file);
299333
break;
334+
case 'partially-staged':
335+
stagedFiles.push({
336+
...file,
337+
status: 'staged'
338+
});
339+
unstagedFiles.push({
340+
...file,
341+
status: 'unstaged'
342+
});
343+
break;
300344

301345
default:
302346
break;
@@ -325,7 +369,8 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
325369
this.state.selectedFile.x === candidate.x &&
326370
this.state.selectedFile.y === candidate.y &&
327371
this.state.selectedFile.from === candidate.from &&
328-
this.state.selectedFile.to === candidate.to
372+
this.state.selectedFile.to === candidate.to &&
373+
this.state.selectedFile.status === candidate.status
329374
);
330375
}
331376

@@ -443,7 +488,7 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
443488
iconName={'git-discard'}
444489
title={'Discard changes'}
445490
onClick={() => {
446-
this.discardChanges(file.to);
491+
this.discardChanges(file);
447492
}}
448493
/>
449494
<ActionButton
@@ -569,9 +614,13 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
569614
? (): void => undefined
570615
: openFile;
571616

572-
let diffButton: JSX.Element;
573-
if (file.status === 'unstaged') {
574-
diffButton = this._createDiffButton(file, 'WORKING');
617+
let contextMenu = this.contextMenuSimpleUntracked;
618+
619+
if (
620+
file.status === 'unstaged' ||
621+
file.status === 'partially-staged'
622+
) {
623+
const diffButton = this._createDiffButton(file, 'WORKING');
575624
actions = (
576625
<React.Fragment>
577626
<ActionButton
@@ -586,7 +635,7 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
586635
iconName={'git-discard'}
587636
title={'Discard changes'}
588637
onClick={() => {
589-
this.discardChanges(file.to);
638+
this.discardChanges(file);
590639
}}
591640
/>
592641
</React.Fragment>
@@ -596,8 +645,9 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
596645
? () => this._openDiffView(file, 'WORKING')
597646
: () => undefined
598647
: openFile;
648+
contextMenu = this.contextMenuSimpleTracked;
599649
} else if (file.status === 'staged') {
600-
diffButton = this._createDiffButton(file, 'INDEX');
650+
const diffButton = this._createDiffButton(file, 'INDEX');
601651
actions = (
602652
<React.Fragment>
603653
<ActionButton
@@ -607,13 +657,22 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
607657
onClick={openFile}
608658
/>
609659
{diffButton}
660+
<ActionButton
661+
className={hiddenButtonStyle}
662+
iconName={'git-discard'}
663+
title={'Discard changes'}
664+
onClick={() => {
665+
this.discardChanges(file);
666+
}}
667+
/>
610668
</React.Fragment>
611669
);
612670
onDoubleClick = doubleClickDiff
613671
? diffButton
614672
? () => this._openDiffView(file, 'INDEX')
615673
: () => undefined
616674
: openFile;
675+
contextMenu = this.contextMenuSimpleTracked;
617676
}
618677

619678
return (
@@ -624,6 +683,8 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
624683
markBox={true}
625684
model={this.props.model}
626685
onDoubleClick={onDoubleClick}
686+
contextMenu={contextMenu}
687+
selectFile={this.updateSelectedFile}
627688
/>
628689
);
629690
})}
@@ -683,4 +744,6 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
683744
private _contextMenuStaged: Menu;
684745
private _contextMenuUnstaged: Menu;
685746
private _contextMenuUntracked: Menu;
747+
private _contextMenuSimpleTracked: Menu;
748+
private _contextMenuSimpleUntracked: Menu;
686749
}

src/components/GitPanel.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -417,11 +417,15 @@ export class GitPanel extends React.Component<
417417
}
418418

419419
private _hasStagedFile(): boolean {
420-
return this.state.files.some(file => file.status === 'staged');
420+
return this.state.files.some(
421+
file => file.status === 'staged' || file.status === 'partially-staged'
422+
);
421423
}
422424

423425
private _hasUnStagedFile(): boolean {
424-
return this.state.files.some(file => file.status === 'unstaged');
426+
return this.state.files.some(
427+
file => file.status === 'unstaged' || file.status === 'partially-staged'
428+
);
425429
}
426430

427431
/**

src/tokens.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,5 +493,10 @@ export namespace Git {
493493
toggle(fname: string): void;
494494
}
495495

496-
export type Status = 'untracked' | 'staged' | 'unstaged' | null;
496+
export type Status =
497+
| 'untracked'
498+
| 'staged'
499+
| 'unstaged'
500+
| 'partially-staged'
501+
| null;
497502
}

src/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ export function decodeStage(x: string, y: string): Git.Status {
4040
return 'untracked';
4141
} else {
4242
// If file is staged
43-
if (x !== ' ' && y !== 'D') {
44-
return 'staged';
43+
if (x !== ' ') {
44+
return y !== ' ' ? 'partially-staged' : 'staged';
4545
}
4646
// If file is unstaged but tracked
4747
if (y !== ' ') {

0 commit comments

Comments
 (0)