Skip to content

Commit c5b0c4f

Browse files
committed
basic functionality acheived for github-desktop-like simple staging
1 parent a0f3423 commit c5b0c4f

File tree

6 files changed

+70
-44
lines changed

6 files changed

+70
-44
lines changed

jupyterlab_git/git.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,10 @@ def add(self, filename, top_repo_path):
529529
"""
530530
Execute git add<filename> command & return the result.
531531
"""
532+
if not isinstance(filename, str):
533+
# assume filename is a sequence
534+
filename = ' '.join(filename)
535+
532536
my_output = subprocess.check_output(["git", "add", filename], cwd=top_repo_path)
533537
return my_output
534538

src/components/CommitBox.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export class CommitBox extends React.Component<
5555
};
5656

5757
/** Update state of commit message input box */
58-
checkReadyForSubmit = (hasStagedFiles: boolean) => {
58+
commitButtonStyle = (hasStagedFiles: boolean) => {
5959
if (hasStagedFiles) {
6060
if (this.state.value.length === 0) {
6161
return classes(stagedCommitButtonStyle, stagedCommitButtonReadyStyle);
@@ -85,7 +85,7 @@ export class CommitBox extends React.Component<
8585
onChange={this.handleChange}
8686
/>
8787
<input
88-
className={this.checkReadyForSubmit(this.props.hasFiles)}
88+
className={this.commitButtonStyle(this.props.hasFiles)}
8989
type="button"
9090
title="Commit"
9191
disabled={!(this.props.hasFiles && this.state.value)}

src/components/FileList.tsx

Lines changed: 54 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
44
import { JSONObject } from '@phosphor/coreutils';
55
import { Menu } from '@phosphor/widgets';
66
import * as React from 'react';
7-
import { GitExtension } from '../model';
7+
import { BranchMarker, GitExtension } from '../model';
88
import {
99
moveFileDownButtonSelectedStyle,
1010
moveFileDownButtonStyle,
@@ -56,6 +56,7 @@ export interface IFileListProps {
5656
stagedFiles: Git.IStatusFileResult[];
5757
unstagedFiles: Git.IStatusFileResult[];
5858
untrackedFiles: Git.IStatusFileResult[];
59+
marker: BranchMarker;
5960
model: GitExtension;
6061
renderMime: IRenderMimeRegistry;
6162
settings: ISettingRegistry.ISettings;
@@ -146,7 +147,7 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
146147
label: 'Stage',
147148
caption: 'Stage the changes of selected file',
148149
execute: () => {
149-
this.addUnstagedFile(this.state.contextMenuFile);
150+
this.addFile(this.state.contextMenuFile);
150151
}
151152
});
152153
}
@@ -156,7 +157,7 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
156157
label: 'Track',
157158
caption: 'Start tracking selected file',
158159
execute: () => {
159-
this.addUntrackedFile(this.state.contextMenuFile);
160+
this.addFile(this.state.contextMenuFile);
160161
}
161162
});
162163
}
@@ -341,8 +342,8 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
341342
};
342343

343344
/** Add a specific unstaged file */
344-
addUnstagedFile = async (file: string) => {
345-
await this.props.model.add(file);
345+
addFile = async (...file: string[]) => {
346+
await this.props.model.add(...file);
346347
};
347348

348349
/** Discard changes in a specific unstaged or staged file */
@@ -362,9 +363,8 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
362363
await this.props.model.addAllUntracked();
363364
};
364365

365-
/** Add a specific untracked file */
366-
addUntrackedFile = async (file: string) => {
367-
await this.props.model.add(file);
366+
addAllMarkedFiles = async () => {
367+
await this.addFile(...this.markedFiles.map(file => file.to));
368368
};
369369

370370
disableStagesForDiscardAll = () => {
@@ -404,6 +404,29 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
404404
}
405405
};
406406

407+
/** Commit all marked files */
408+
commitAllMarkedFiles = async (message: string): Promise<void> => {
409+
await this.resetAllStagedFiles();
410+
await this.addAllMarkedFiles();
411+
await this.commitAllStagedFiles(message);
412+
};
413+
414+
get markedFiles() {
415+
return this.allFilesExcludingUnmodified.filter(file =>
416+
this.props.marker.get(file.to)
417+
);
418+
}
419+
420+
get allFilesExcludingUnmodified() {
421+
let files = this.props.untrackedFiles.concat(
422+
this.props.unstagedFiles,
423+
this.props.stagedFiles
424+
);
425+
426+
files.sort((a, b) => a.to.localeCompare(b.to));
427+
return files;
428+
}
429+
407430
render() {
408431
const sharedProps = {
409432
model: this.props.model,
@@ -449,7 +472,7 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
449472
moveAllFiles={this.addAllUnstagedFiles}
450473
discardAllFiles={this.discardAllUnstagedFiles}
451474
discardFile={this.discardChanges}
452-
moveFile={this.addUnstagedFile}
475+
moveFile={this.addFile}
453476
moveFileIconClass={moveFileUpButtonStyle}
454477
moveFileIconSelectedClass={moveFileUpButtonSelectedStyle}
455478
moveAllFilesTitle={'Stage all changes'}
@@ -471,7 +494,7 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
471494
moveAllFiles={this.addAllUntrackedFiles}
472495
discardAllFiles={null}
473496
discardFile={null}
474-
moveFile={this.addUntrackedFile}
497+
moveFile={this.addFile}
475498
moveFileIconClass={moveFileUpButtonStyle}
476499
moveFileIconSelectedClass={moveFileUpButtonSelectedStyle}
477500
moveAllFilesTitle={'Track all untracked files'}
@@ -484,46 +507,41 @@ export class FileList extends React.Component<IFileListProps, IFileListState> {
484507
/>
485508
);
486509

487-
const allFilesExcludingUnmodified = () => {
488-
let files = this.props.untrackedFiles.concat(
489-
this.props.unstagedFiles,
490-
this.props.stagedFiles
491-
);
492-
493-
files.sort((a, b) => a.to.localeCompare(b.to));
494-
return files;
495-
};
496-
497-
return (
498-
<div onContextMenu={event => event.preventDefault()}>
499-
<CommitBox
500-
hasFiles={this.props.stagedFiles.length > 0}
501-
commitFunc={this.commitAllStagedFiles}
502-
/>
503-
{this.props.settings.composite['simpleStaging'] ? (
510+
if (this.props.settings.composite['simpleStaging']) {
511+
return (
512+
<div>
513+
<CommitBox
514+
hasFiles={this.markedFiles.length > 0}
515+
commitFunc={this.commitAllMarkedFiles}
516+
/>
504517
<div>
505518
<GitStageSimple
506519
heading={'Changed'}
507-
files={allFilesExcludingUnmodified()}
508-
marker={this.props.model.getMarker(
509-
this.props.model.pathRepository,
510-
''
511-
)}
520+
files={this.allFilesExcludingUnmodified}
521+
marker={this.props.marker}
512522
model={this.props.model}
513523
discardAllFiles={this.discardAllChanges}
514524
discardFile={this.discardChanges}
515525
renderMime={this.props.renderMime}
516526
/>
517527
</div>
518-
) : (
528+
</div>
529+
);
530+
} else {
531+
return (
532+
<div onContextMenu={event => event.preventDefault()}>
533+
<CommitBox
534+
hasFiles={this.props.stagedFiles.length > 0}
535+
commitFunc={this.commitAllStagedFiles}
536+
/>
519537
<div>
520538
<Staged />
521539
<Changed />
522540
<Untracked />
523541
</div>
524-
)}
525-
</div>
526-
);
542+
</div>
543+
);
544+
}
527545
}
528546

529547
/**

src/components/GitPanel.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,10 @@ export class GitPanel extends React.Component<
208208
stagedFiles={this.state.stagedFiles}
209209
unstagedFiles={this.state.unstagedFiles}
210210
untrackedFiles={this.state.untrackedFiles}
211+
marker={this.props.model.getMarker(
212+
this.props.model.pathRepository,
213+
this.state.currentBranch
214+
)}
211215
model={this.props.model}
212216
renderMime={this.props.renderMime}
213217
settings={this.props.settings}

src/model.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ export class GitExtension implements IGitExtension, IDisposable {
439439
/** Make request to add one or all files into
440440
* the staging area in repository
441441
*/
442-
async add(filename?: string): Promise<Response> {
442+
async add(...filename: string[]): Promise<Response> {
443443
await this.ready;
444444
const path = this.pathRepository;
445445

@@ -455,8 +455,8 @@ export class GitExtension implements IGitExtension, IDisposable {
455455
}
456456

457457
const response = await httpGitRequest('/git/add', 'POST', {
458-
add_all: filename === undefined,
459-
filename: filename === undefined ? null : filename,
458+
add_all: !filename,
459+
filename: filename || '',
460460
top_repo_path: path
461461
});
462462

tests/test-components/CommitBox.spec.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ describe('CommitBox', () => {
1515
hasFiles: true
1616
});
1717

18-
let actual = box.checkReadyForSubmit(true);
18+
let actual = box.commitButtonStyle(true);
1919

2020
let expected = classes(
2121
stagedCommitButtonStyle,
@@ -30,7 +30,7 @@ describe('CommitBox', () => {
3030
hasFiles: true
3131
});
3232

33-
let actual = box.checkReadyForSubmit(false);
33+
let actual = box.commitButtonStyle(false);
3434
let expected = classes(
3535
stagedCommitButtonStyle,
3636
stagedCommitButtonDisabledStyle
@@ -48,7 +48,7 @@ describe('CommitBox', () => {
4848
value: 'message'
4949
},
5050
() => {
51-
let actual = box.checkReadyForSubmit(true);
51+
let actual = box.commitButtonStyle(true);
5252

5353
let expected = stagedCommitButtonStyle;
5454
expect(actual).toEqual(expected);

0 commit comments

Comments
 (0)