Skip to content

Commit

Permalink
Backport PR #629 on branch 0.11.x (show both staged and unstaged chan…
Browse files Browse the repository at this point in the history
…ges 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]>
  • Loading branch information
3 people authored Jun 21, 2020
1 parent d44e5e6 commit 1175534
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 25 deletions.
10 changes: 4 additions & 6 deletions src/components/FileItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ export class FileItem extends React.Component<IFileItemProps> {
}

render() {
const status =
this.getFileChangedLabel(this.props.file.y as any) ||
this.getFileChangedLabel(this.props.file.x as any);
const { file } = this.props;
const status_code = file.status === 'staged' ? file.x : file.y;
const status = this.getFileChangedLabel(status_code as any);

return (
<li
Expand Down Expand Up @@ -110,9 +110,7 @@ export class FileItem extends React.Component<IFileItemProps> {
/>
{this.props.actions}
<span className={this.getFileChangedLabelClass(this.props.file.y)}>
{this.props.file.y === '?'
? 'U'
: this.props.file.y.trim() || this.props.file.x}
{this.props.file.y === '?' ? 'U' : status_code}
</span>
</li>
);
Expand Down
91 changes: 77 additions & 14 deletions src/components/FileList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
this._contextMenuStaged = new Menu({ commands });
this._contextMenuUnstaged = new Menu({ commands });
this._contextMenuUntracked = new Menu({ commands });
this._contextMenuSimpleUntracked = new Menu({ commands });
this._contextMenuSimpleTracked = new Menu({ commands });

this.state = {
selectedFile: null
Expand Down Expand Up @@ -134,7 +136,7 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
label: 'Discard',
caption: 'Discard recent changes of selected file',
execute: () => {
this.discardChanges(this.state.selectedFile.to);
this.discardChanges(this.state.selectedFile);
}
});
}
Expand All @@ -159,6 +161,18 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
[CommandIDs.gitFileOpen, CommandIDs.gitFileTrack].forEach(command => {
this._contextMenuUntracked.addItem({ command });
});

[
CommandIDs.gitFileOpen,
CommandIDs.gitFileDiscard,
CommandIDs.gitFileDiffWorking
].forEach(command => {
this._contextMenuSimpleTracked.addItem({ command });
});

[CommandIDs.gitFileOpen].forEach(command => {
this._contextMenuSimpleUntracked.addItem({ command });
});
}

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

/** Handle right-click on an untracked file in Simple mode*/
contextMenuSimpleUntracked = (event: React.MouseEvent) => {
event.preventDefault();
this._contextMenuSimpleUntracked.open(event.clientX, event.clientY);
};

/** Handle right-click on an tracked file in Simple mode*/
contextMenuSimpleTracked = (event: React.MouseEvent) => {
event.preventDefault();
this._contextMenuSimpleTracked.open(event.clientX, event.clientY);
};

/** Reset all staged files */
resetAllStagedFiles = async () => {
await this.props.model.reset();
Expand Down Expand Up @@ -234,23 +260,31 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
};

/** Discard changes in a specific unstaged or staged file */
discardChanges = async (file: string) => {
discardChanges = async (file: Git.IStatusFile) => {
const result = await showDialog({
title: 'Discard changes',
body: (
<span>
Are you sure you want to permanently discard changes to <b>{file}</b>?
This action cannot be undone.
Are you sure you want to permanently discard changes to{' '}
<b>{file.to}</b>? This action cannot be undone.
</span>
),
buttons: [Dialog.cancelButton(), Dialog.warnButton({ label: 'Discard' })]
});
if (result.button.accept) {
try {
await this.props.model.reset(file);
await this.props.model.checkout({ filename: file });
if (file.status === 'staged' || file.status === 'partially-staged') {
await this.props.model.reset(file.to);
}
if (
file.status === 'unstaged' ||
(file.status === 'partially-staged' && file.x !== 'A')
) {
// resetting an added file moves it to untracked category => checkout will fail
await this.props.model.checkout({ filename: file.to });
}
} catch (reason) {
showErrorMessage(`Discard changes for ${file} failed.`, reason, [
showErrorMessage(`Discard changes for ${file.to} failed.`, reason, [
Dialog.warnButton({ label: 'DISMISS' })
]);
}
Expand Down Expand Up @@ -297,6 +331,16 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
case 'untracked':
untrackedFiles.push(file);
break;
case 'partially-staged':
stagedFiles.push({
...file,
status: 'staged'
});
unstagedFiles.push({
...file,
status: 'unstaged'
});
break;

default:
break;
Expand Down Expand Up @@ -325,7 +369,8 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
this.state.selectedFile.x === candidate.x &&
this.state.selectedFile.y === candidate.y &&
this.state.selectedFile.from === candidate.from &&
this.state.selectedFile.to === candidate.to
this.state.selectedFile.to === candidate.to &&
this.state.selectedFile.status === candidate.status
);
}

Expand Down Expand Up @@ -443,7 +488,7 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
iconName={'git-discard'}
title={'Discard changes'}
onClick={() => {
this.discardChanges(file.to);
this.discardChanges(file);
}}
/>
<ActionButton
Expand Down Expand Up @@ -569,9 +614,13 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
? (): void => undefined
: openFile;

let diffButton: JSX.Element;
if (file.status === 'unstaged') {
diffButton = this._createDiffButton(file, 'WORKING');
let contextMenu = this.contextMenuSimpleUntracked;

if (
file.status === 'unstaged' ||
file.status === 'partially-staged'
) {
const diffButton = this._createDiffButton(file, 'WORKING');
actions = (
<React.Fragment>
<ActionButton
Expand All @@ -586,7 +635,7 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
iconName={'git-discard'}
title={'Discard changes'}
onClick={() => {
this.discardChanges(file.to);
this.discardChanges(file);
}}
/>
</React.Fragment>
Expand All @@ -596,8 +645,9 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
? () => this._openDiffView(file, 'WORKING')
: () => undefined
: openFile;
contextMenu = this.contextMenuSimpleTracked;
} else if (file.status === 'staged') {
diffButton = this._createDiffButton(file, 'INDEX');
const diffButton = this._createDiffButton(file, 'INDEX');
actions = (
<React.Fragment>
<ActionButton
Expand All @@ -607,13 +657,22 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
onClick={openFile}
/>
{diffButton}
<ActionButton
className={hiddenButtonStyle}
iconName={'git-discard'}
title={'Discard changes'}
onClick={() => {
this.discardChanges(file);
}}
/>
</React.Fragment>
);
onDoubleClick = doubleClickDiff
? diffButton
? () => this._openDiffView(file, 'INDEX')
: () => undefined
: openFile;
contextMenu = this.contextMenuSimpleTracked;
}

return (
Expand All @@ -624,6 +683,8 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
markBox={true}
model={this.props.model}
onDoubleClick={onDoubleClick}
contextMenu={contextMenu}
selectFile={this.updateSelectedFile}
/>
);
})}
Expand Down Expand Up @@ -683,4 +744,6 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
private _contextMenuStaged: Menu;
private _contextMenuUnstaged: Menu;
private _contextMenuUntracked: Menu;
private _contextMenuSimpleTracked: Menu;
private _contextMenuSimpleUntracked: Menu;
}
8 changes: 6 additions & 2 deletions src/components/GitPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -417,11 +417,15 @@ export class GitPanel extends React.Component<
}

private _hasStagedFile(): boolean {
return this.state.files.some(file => file.status === 'staged');
return this.state.files.some(
file => file.status === 'staged' || file.status === 'partially-staged'
);
}

private _hasUnStagedFile(): boolean {
return this.state.files.some(file => file.status === 'unstaged');
return this.state.files.some(
file => file.status === 'unstaged' || file.status === 'partially-staged'
);
}

/**
Expand Down
7 changes: 6 additions & 1 deletion src/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -493,5 +493,10 @@ export namespace Git {
toggle(fname: string): void;
}

export type Status = 'untracked' | 'staged' | 'unstaged' | null;
export type Status =
| 'untracked'
| 'staged'
| 'unstaged'
| 'partially-staged'
| null;
}
4 changes: 2 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export function decodeStage(x: string, y: string): Git.Status {
return 'untracked';
} else {
// If file is staged
if (x !== ' ' && y !== 'D') {
return 'staged';
if (x !== ' ') {
return y !== ' ' ? 'partially-staged' : 'staged';
}
// If file is unstaged but tracked
if (y !== ' ') {
Expand Down
Loading

0 comments on commit 1175534

Please sign in to comment.