Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Commit

Permalink
Merge 99ba3bc into a70b713
Browse files Browse the repository at this point in the history
  • Loading branch information
kuychaco committed Nov 30, 2018
2 parents a70b713 + 99ba3bc commit 2d9636a
Show file tree
Hide file tree
Showing 38 changed files with 1,876 additions and 98 deletions.
5 changes: 5 additions & 0 deletions keymaps/git.cson
Expand Up @@ -32,6 +32,11 @@
'tab': 'core:focus-next'
'shift-tab': 'core:focus-previous'

'.github-RecentCommitsView':
'up': 'github:recent-commit-up'
'down': 'github:recent-commit-down'
'enter': 'github:open-recent-commit'

'.github-StagingView.unstaged-changes-focused':
'cmd-backspace': 'github:discard-changes-in-selected-files'
'ctrl-backspace': 'github:discard-changes-in-selected-files'
Expand Down
44 changes: 44 additions & 0 deletions lib/containers/commit-detail-container.js
@@ -0,0 +1,44 @@
import React from 'react';
import PropTypes from 'prop-types';
import yubikiri from 'yubikiri';

import ObserveModel from '../views/observe-model';
import LoadingView from '../views/loading-view';
import CommitDetailController from '../controllers/commit-detail-controller';

export default class CommitDetailContainer extends React.Component {
static propTypes = {
repository: PropTypes.object.isRequired,
sha: PropTypes.string.isRequired,
}

fetchData = repository => {
return yubikiri({
commit: repository.getCommit(this.props.sha),
currentBranch: repository.getCurrentBranch(),
currentRemote: async query => repository.getRemoteForBranch((await query.currentBranch).getName()),
isCommitPushed: repository.isCommitPushed(this.props.sha),
});
}

render() {
return (
<ObserveModel model={this.props.repository} fetchData={this.fetchData}>
{this.renderResult}
</ObserveModel>
);
}

renderResult = data => {
if (this.props.repository.isLoading() || data === null || !data.commit.isPresent()) {
return <LoadingView />;
}

return (
<CommitDetailController
{...data}
{...this.props}
/>
);
}
}
38 changes: 38 additions & 0 deletions lib/controllers/commit-detail-controller.js
@@ -0,0 +1,38 @@
import React from 'react';
import PropTypes from 'prop-types';

import CommitDetailView from '../views/commit-detail-view';

export default class CommitDetailController extends React.Component {
static propTypes = {
...CommitDetailView.propTypes,

commit: PropTypes.object.isRequired,
}

constructor(props) {
super(props);

this.state = {
messageCollapsible: this.props.commit.isBodyLong(),
messageOpen: !this.props.commit.isBodyLong(),
};
}

render() {
return (
<CommitDetailView
messageCollapsible={this.state.messageCollapsible}
messageOpen={this.state.messageOpen}
toggleMessage={this.toggleMessage}
{...this.props}
/>
);
}

toggleMessage = () => {
return new Promise(resolve => {
this.setState(prevState => ({messageOpen: !prevState.messageOpen}), resolve);
});
}
}
11 changes: 11 additions & 0 deletions lib/controllers/git-tab-controller.js
Expand Up @@ -11,6 +11,7 @@ import {
CommitPropType, BranchPropType, FilePatchItemPropType, MergeConflictItemPropType, RefHolderPropType,
} from '../prop-types';
import {autobind} from '../helpers';
import CommitDetailItem from '../items/commit-detail-item';

export default class GitTabController extends React.Component {
static focus = {
Expand Down Expand Up @@ -277,6 +278,16 @@ export default class GitTabController extends React.Component {
new Author(author.email, author.name));

this.updateSelectedCoAuthors(coAuthors);

// close corresponding commit item pane, if opened
const uri = CommitDetailItem.buildURI(this.props.repository.getWorkingDirectoryPath(), lastCommit.getSha());
const pane = this.props.workspace.paneForURI(uri);
if (pane) {
const item = pane.itemForURI(uri);
if (item) {
await pane.destroyItem(item);
}
}
return null;
}

Expand Down
6 changes: 3 additions & 3 deletions lib/controllers/multi-file-patch-controller.js
Expand Up @@ -22,9 +22,9 @@ export default class MultiFilePatchController extends React.Component {
config: PropTypes.object.isRequired,

destroy: PropTypes.func.isRequired,
discardLines: PropTypes.func.isRequired,
undoLastDiscard: PropTypes.func.isRequired,
surface: PropTypes.func.isRequired,
discardLines: PropTypes.func,
undoLastDiscard: PropTypes.func,
surface: PropTypes.func,
}

constructor(props) {
Expand Down
48 changes: 48 additions & 0 deletions lib/controllers/recent-commits-controller.js
@@ -1,13 +1,50 @@
import React from 'react';
import PropTypes from 'prop-types';
import {autobind} from '../helpers';
import {addEvent} from '../reporter-proxy';

import CommitDetailItem from '../items/commit-detail-item';
import URIPattern from '../atom/uri-pattern';
import RecentCommitsView from '../views/recent-commits-view';
import {CompositeDisposable} from 'event-kit';

export default class RecentCommitsController extends React.Component {
static propTypes = {
commits: PropTypes.arrayOf(PropTypes.object).isRequired,
isLoading: PropTypes.bool.isRequired,
undoLastCommit: PropTypes.func.isRequired,
workspace: PropTypes.object.isRequired,
repository: PropTypes.object.isRequired,
commandRegistry: PropTypes.object.isRequired,
}

constructor(props, context) {
super(props, context);
autobind(this, 'openCommit', 'updateSelectedCommit');

this.subscriptions = new CompositeDisposable(
this.props.workspace.onDidChangeActivePaneItem(this.updateSelectedCommit),
);
this.state = {selectedCommitSha: ''};
}

updateSelectedCommit() {
const activeItem = this.props.workspace.getActivePaneItem();

const pattern = new URIPattern(decodeURIComponent(
CommitDetailItem.buildURI(
this.props.repository.getWorkingDirectoryPath(),
'{sha}'),
));

if (activeItem && activeItem.getURI) {
const match = pattern.matches(activeItem.getURI());
const {sha} = match.getParams();
if (match.ok() && sha && sha !== this.state.selectedCommitSha) {
return new Promise(resolve => this.setState({selectedCommitSha: sha}, resolve));
}
}
return Promise.resolve();
}

render() {
Expand All @@ -16,7 +53,18 @@ export default class RecentCommitsController extends React.Component {
commits={this.props.commits}
isLoading={this.props.isLoading}
undoLastCommit={this.props.undoLastCommit}
openCommit={this.openCommit}
selectedCommitSha={this.state.selectedCommitSha}
commandRegistry={this.props.commandRegistry}
/>
);
}

openCommit({sha}) {
const workdir = this.props.repository.getWorkingDirectoryPath();
const uri = CommitDetailItem.buildURI(workdir, sha);
this.props.workspace.open(uri).then(() => {
addEvent('open-commit-in-pane', {package: 'github', from: 'recent commit'});
});
}
}
57 changes: 57 additions & 0 deletions lib/controllers/root-controller.js
Expand Up @@ -11,12 +11,14 @@ import Panel from '../atom/panel';
import PaneItem from '../atom/pane-item';
import CloneDialog from '../views/clone-dialog';
import OpenIssueishDialog from '../views/open-issueish-dialog';
import OpenCommitDialog from '../views/open-commit-dialog';
import InitDialog from '../views/init-dialog';
import CredentialDialog from '../views/credential-dialog';
import Commands, {Command} from '../atom/commands';
import GitTimingsView from '../views/git-timings-view';
import ChangedFileItem from '../items/changed-file-item';
import IssueishDetailItem from '../items/issueish-detail-item';
import CommitDetailItem from '../items/commit-detail-item';
import CommitPreviewItem from '../items/commit-preview-item';
import GitTabItem from '../items/git-tab-item';
import GitHubTabItem from '../items/github-tab-item';
Expand Down Expand Up @@ -139,6 +141,7 @@ export default class RootController extends React.Component {
<Command command="github:toggle-github-tab" callback={this.githubTabTracker.toggle} />
<Command command="github:toggle-github-tab-focus" callback={this.githubTabTracker.toggleFocus} />
<Command command="github:clone" callback={this.openCloneDialog} />
<Command command="github:open-commit" callback={this.showOpenCommitDialog} />
<Command
command="github:view-unstaged-changes-for-current-file"
callback={this.viewUnstagedChangesForCurrentFile}
Expand Down Expand Up @@ -188,6 +191,7 @@ export default class RootController extends React.Component {
{this.renderCloneDialog()}
{this.renderCredentialDialog()}
{this.renderOpenIssueishDialog()}
{this.renderOpenCommitDialog()}
</Fragment>
);
}
Expand Down Expand Up @@ -244,6 +248,22 @@ export default class RootController extends React.Component {
);
}

renderOpenCommitDialog() {
if (!this.state.openCommitDialogActive) {
return null;
}

return (
<Panel workspace={this.props.workspace} location="modal">
<OpenCommitDialog
commandRegistry={this.props.commandRegistry}
didAccept={this.acceptOpenCommit}
didCancel={this.cancelOpenCommit}
/>
</Panel>
);
}

renderCredentialDialog() {
if (this.state.credentialDialogQuery === null) {
return null;
Expand Down Expand Up @@ -362,6 +382,26 @@ export default class RootController extends React.Component {
/>
)}
</PaneItem>
<PaneItem
workspace={this.props.workspace}
uriPattern={CommitDetailItem.uriPattern}
className="github-CommitDetail-root">
{({itemHolder, params}) => (
<CommitDetailItem
ref={itemHolder.setter}

workdirContextPool={this.props.workdirContextPool}
workingDirectory={params.workingDirectory}
workspace={this.props.workspace}
commands={this.props.commandRegistry}
keymaps={this.props.keymaps}
tooltips={this.props.tooltips}
config={this.props.config}

sha={params.sha}
/>
)}
</PaneItem>
<PaneItem workspace={this.props.workspace} uriPattern={IssueishDetailItem.uriPattern}>
{({itemHolder, params}) => (
<IssueishDetailItem
Expand Down Expand Up @@ -490,6 +530,10 @@ export default class RootController extends React.Component {
this.setState({openIssueishDialogActive: true});
}

showOpenCommitDialog = () => {
this.setState({openCommitDialogActive: true});
}

showWaterfallDiagnostics() {
this.props.workspace.open(GitTimingsView.buildURI());
}
Expand Down Expand Up @@ -548,6 +592,19 @@ export default class RootController extends React.Component {
this.setState({openIssueishDialogActive: false});
}

acceptOpenCommit = ({sha}) => {
const workdir = this.props.repository.getWorkingDirectoryPath();
const uri = CommitDetailItem.buildURI(workdir, sha);
this.setState({openCommitDialogActive: false});
this.props.workspace.open(uri).then(() => {
addEvent('open-commit-in-pane', {package: 'github', from: 'dialog'});
});
}

cancelOpenCommit = () => {
this.setState({openCommitDialogActive: false});
}

surfaceFromFileAtPath = (filePath, stagingStatus) => {
const gitTab = this.gitTabTracker.getComponent();
return gitTab && gitTab.focusAndSelectStagingItem(filePath, stagingStatus);
Expand Down
18 changes: 18 additions & 0 deletions lib/git-shell-out-strategy.js
Expand Up @@ -687,6 +687,14 @@ export default class GitShellOutStrategy {
return headCommit;
}

async getDiffsForCommit(sha) {
const output = await this.exec([
'diff', '--no-prefix', '--no-ext-diff', '--no-renames', `${sha}~`, sha,
]);

return parseDiff(output);
}

async getCommits(options = {}) {
const {max, ref, includeUnborn} = {max: 1, ref: 'HEAD', includeUnborn: false, ...options};

Expand Down Expand Up @@ -926,6 +934,16 @@ export default class GitShellOutStrategy {
});
}

async getBranchesWithCommit(sha, option = {}) {
const args = ['branch', '--format=%(refname)', '--contains', sha];
if (option.showLocal && option.showRemote) {
args.splice(1, 0, '--all');
} else if (option.showRemote) {
args.splice(1, 0, '--remotes');
}
return (await this.exec(args)).trim().split(LINE_ENDING_REGEX);
}

checkoutFiles(paths, revision) {
if (paths.length === 0) { return null; }
const args = ['checkout'];
Expand Down
10 changes: 10 additions & 0 deletions lib/github-package.js
Expand Up @@ -389,6 +389,16 @@ export default class GithubPackage {
return item;
}

createCommitDetailStub({uri}) {
const item = StubItem.create('git-commit-detail', {
title: 'Commit',
}, uri);
if (this.controller) {
this.rerender();
}
return item;
}

destroyGitTabItem() {
if (this.gitTabStubItem) {
this.gitTabStubItem.destroy();
Expand Down

0 comments on commit 2d9636a

Please sign in to comment.