Skip to content
This repository was archived by the owner on Dec 15, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
0853912
add tab for changed files
Dec 7, 2018
66e485c
Making fetch happen
Dec 8, 2018
686cf43
make patch URL actually valid
Dec 8, 2018
9f378a5
drill them props
Dec 8, 2018
4d2098d
drill these props too
Dec 8, 2018
e3fb672
[wip] actually build the file patch
Dec 8, 2018
58f00d0
hacky fix for height problem
Dec 11, 2018
66c0398
pass `itemType` to all the components that need it
Dec 11, 2018
2a22816
jeez, you want more props? so needy.
Dec 11, 2018
acd9626
smell ya later unnecessary div
Dec 11, 2018
5041b71
add some tests for `PullRequestChangedFilesoContainer`
Dec 11, 2018
f344abb
love too commit .only and console logging
Dec 11, 2018
edd2b07
moar tests! moar!
Dec 11, 2018
8733b9b
Document and reorganize PropTypes a bit
smashwilson Dec 12, 2018
ddea33e
Pass the host and token through IssueishDetail components
smashwilson Dec 12, 2018
314439e
Shuffle a bunch of stuff in PrChangedFilesContainer because I'm me
smashwilson Dec 12, 2018
4401f8b
I'm calling that prop "diff" now
smashwilson Dec 12, 2018
081264b
Pass pull request attributes directly rather than parsing them from t…
smashwilson Dec 12, 2018
39bb8b9
Capital TODO to trigger TODO bot
smashwilson Dec 12, 2018
61920e0
Drill that Repository down to the MultiFilePatch components
smashwilson Dec 12, 2018
6390955
Overkill custom PropType validator for itemType
smashwilson Dec 12, 2018
8d5a845
Use itemType within the IssueishDetail item
smashwilson Dec 12, 2018
99daac3
move diff parsing into `PrChangedFilesContainer`
Dec 12, 2018
63e3cfa
fix derp merge
Dec 12, 2018
bb2ab96
PrDetailView tests :white_check_mark: and :100:
smashwilson Dec 12, 2018
ae98c0e
add tests for `PullRequestChangedFilesController`
Dec 12, 2018
db3f189
wip -- why diff fixture no worky?
Dec 12, 2018
d4e2dca
Dedent patch fixture
kuychaco Dec 12, 2018
3df90c5
Don't JSON stringify stubbed response
kuychaco Dec 12, 2018
9c69216
naming things is hard, let's go shopping
Dec 12, 2018
206c352
`itemType` test is now unnecessary
Dec 12, 2018
924113b
rename `patch` to `multiFilePatch`
Dec 12, 2018
5aa73c1
fix multiFilePatch prop test in PullRequestChangedFilesController
Dec 13, 2018
31c744c
pluralization is hard ok
Dec 13, 2018
f149919
fix missing prop errors in test
Dec 13, 2018
44f5fd1
move `destroy` method to `IssueishDetailItem`
Dec 13, 2018
00232d1
:fire: PullRequestChangedFiles controller and view
Dec 13, 2018
df729f9
Make header and nav full-width
simurai Dec 13, 2018
8a3ddd8
Add scrolling
simurai Dec 13, 2018
ac5de8e
refetch diff on refresh
vanessayuenn Dec 13, 2018
6b2590b
Endpoint model to derive GitHub API endpoints from a domain
smashwilson Dec 13, 2018
f639ddb
Access an Endpoint from a Remote
smashwilson Dec 13, 2018
3589080
Access a login model key for an Endpoint
smashwilson Dec 13, 2018
abca1f5
Access an Endpoint's host, the user-facing GitHub domain
smashwilson Dec 13, 2018
792ee9a
Pass Endpoints instead of host strings
smashwilson Dec 13, 2018
27a411c
Count PrDetailView tab openings
smashwilson Dec 13, 2018
0ba6c63
somewhat better error handling
vanessayuenn Dec 13, 2018
ef27922
Yep that was totally me
smashwilson Dec 13, 2018
3080420
Missed a getEnvironmentForHost() call
smashwilson Dec 13, 2018
439de1f
Spelling
smashwilson Dec 13, 2018
15f6cfa
Use URL as the Map key
smashwilson Dec 13, 2018
30d230c
A++ error messages
vanessayuenn Dec 13, 2018
870c178
reset error state upon refresh
vanessayuenn Dec 13, 2018
8472a77
copy!
vanessayuenn Dec 13, 2018
446741e
leverage the existing ErrorView
vanessayuenn Dec 13, 2018
624da7a
don't always show logout button on errorview
vanessayuenn Dec 13, 2018
52623a1
add test for when fetch fails
Dec 13, 2018
7f8707d
update component atlas
vanessayuenn Dec 13, 2018
18a8973
fix test to deal with improved error handling
Dec 13, 2018
66e5a62
:shirt:
Dec 13, 2018
aa5f337
test diff parsing error state
Dec 13, 2018
424b5c4
:shirt: againnn
Dec 13, 2018
879c638
istanbul ignore dev debugging code to log rate limits
Dec 13, 2018
aeae3b3
add test for refetching data
Dec 14, 2018
714ec4b
more istanbul ignoring
Dec 14, 2018
d5a0f63
Fix PrTimeline scrolling issues
simurai Dec 14, 2018
d84707e
Make header more compact
simurai Dec 14, 2018
23e81f2
add test for if network request fails
Dec 14, 2018
dfaa101
:shirt:
Dec 14, 2018
92573bf
Merge branch 'master' into 18-dec-files-changed-tab
Dec 14, 2018
abc7a0a
add counts to tabs
Dec 14, 2018
a85931f
add required props to `pullRequestDetailViewProps` fixture thingy
Dec 14, 2018
001ebfc
fix PullRequestDetailView tabs tests
Dec 14, 2018
47d9f4f
:shirt:
Dec 14, 2018
6f5fd17
fix tab metrics tests
Dec 15, 2018
c1d1c72
put istanbul ignore in the right place
Dec 15, 2018
ca3fab2
:fire: .only
Dec 15, 2018
3a4763c
more styling tweaks
Dec 15, 2018
eac9755
Merge branch 'master' into pr-1829/atom/18-dec-files-changed-tab
smashwilson Dec 15, 2018
34ea974
:shirt:
smashwilson Dec 15, 2018
1e91002
Tweak tab colors
simurai Dec 17, 2018
7aadd36
Increase contrast for messageHeadline
simurai Dec 17, 2018
1390a6a
Use font-size from themes in FilePatchViews
simurai Dec 17, 2018
8ab8ef4
Make branches wrap
simurai Dec 17, 2018
3d5018a
Make headerLink wrap
simurai Dec 17, 2018
c62bb51
for realsies istanbul ignore relay-network-layer-manager
Dec 17, 2018
14a2d27
IssueishDetailItem uses `github.com` as its host
smashwilson Dec 17, 2018
3397d53
workdirPath is missing when looking at an issueish from another repo
smashwilson Dec 17, 2018
788dd70
onBranch and openCommit will not be set for issues
smashwilson Dec 17, 2018
e2bfeea
Pass Endpoint into RemoteContainer separately
smashwilson Dec 17, 2018
0228ee0
add tests for UserStore uncovered lines
Dec 17, 2018
83c8ecb
stupid .only
Dec 17, 2018
b745c37
:shirt: I really need to fix my in editor linting.
Dec 17, 2018
b9b29c3
log console errors in `PullRequestChangedFilesContainer`
Dec 17, 2018
1c58579
add test for `UserStore.loadMentionableUsers`
Dec 17, 2018
ac64240
add tests for `ErrorView`
Dec 17, 2018
0e9e1cd
Move dock styles to its own file
simurai Dec 18, 2018
12c6df1
Separate left/right and bottom docks
simurai Dec 18, 2018
8b1055b
Restyle PR panes in docks
simurai Dec 18, 2018
41f4045
Style Commit Detail in dock
simurai Dec 18, 2018
412cfae
Fix styling for issues
simurai Dec 18, 2018
54d3190
remove unused import
vanessayuenn Dec 18, 2018
f422a4b
hide unstage / staging buttons for filemode and symlink changes
Dec 18, 2018
edc4226
add tests for FilePatchHeaderView buttons
Dec 18, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .nycrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
],
"exclude": [
"lib/views/git-cache-view.js",
"lib/views/git-timings-view.js"
"lib/views/git-timings-view.js",
"lib/relay-network-layer-manager.js"
]
}
7 changes: 7 additions & 0 deletions docs/react-component-atlas.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@ This is a high-level overview of the structure of the React component tree that
> > > [`<PrCommitView>`](/lib/views/pr-commit-view.js)
> > >
> > > Enumerate the commits associated with a pull request.
> >
> > > [`<PullRequestChangedFilesContainer>`](/lib/containers/pr-changed-files-container.js)
> > >
> > > Show all the changes, separated by files, introduced in a pull request.
> > >
> > > > [`<MultiFilePatchController>`](/lib/controllers/multi-file-patch-controller.js)
> > > > [`<MultiFilePatchView>`](/lib/views/multi-file-patch-view.js)
>
> > [`<InitDialog>`](/lib/views/init-dialog.js)
> > [`<CloneDialog>`](/lib/views/clone-dialog.js)
Expand Down
15 changes: 12 additions & 3 deletions lib/containers/current-pull-request-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ import {QueryRenderer, graphql} from 'react-relay';
import {Disposable} from 'event-kit';

import {autobind} from '../helpers';
import {RemotePropType, RemoteSetPropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types';
import {
RemotePropType, RemoteSetPropType, BranchSetPropType, OperationStateObserverPropType, EndpointPropType,
} from '../prop-types';
import IssueishListController, {BareIssueishListController} from '../controllers/issueish-list-controller';
import CreatePullRequestTile from '../views/create-pull-request-tile';
import RelayNetworkLayerManager from '../relay-network-layer-manager';

export default class CurrentPullRequestContainer extends React.Component {
static propTypes = {
// Relay payload
repository: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultBranchRef: PropTypes.shape({
Expand All @@ -19,16 +22,22 @@ export default class CurrentPullRequestContainer extends React.Component {
}),
}).isRequired,

// Connection
endpoint: EndpointPropType.isRequired,
token: PropTypes.string.isRequired,
host: PropTypes.string.isRequired,

// Search constraints
limit: PropTypes.number,

// Repository model attributes
remoteOperationObserver: OperationStateObserverPropType.isRequired,
remote: RemotePropType.isRequired,
remotes: RemoteSetPropType.isRequired,
branches: BranchSetPropType.isRequired,
aheadCount: PropTypes.number,
pushInProgress: PropTypes.bool.isRequired,

// Actions
onOpenIssueish: PropTypes.func.isRequired,
onCreatePr: PropTypes.func.isRequired,
}
Expand All @@ -45,7 +54,7 @@ export default class CurrentPullRequestContainer extends React.Component {
}

render() {
const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.host, this.props.token);
const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.endpoint, this.props.token);

const head = this.props.branches.getHeadBranch();
if (!head.isPresent()) {
Expand Down
48 changes: 37 additions & 11 deletions lib/containers/issueish-detail-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,45 @@ import PropTypes from 'prop-types';
import yubikiri from 'yubikiri';
import {QueryRenderer, graphql} from 'react-relay';

import {autobind} from '../helpers';
import RelayNetworkLayerManager from '../relay-network-layer-manager';
import {GithubLoginModelPropType} from '../prop-types';
import {GithubLoginModelPropType, ItemTypePropType, EndpointPropType} from '../prop-types';
import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy';
import GithubLoginView from '../views/github-login-view';
import LoadingView from '../views/loading-view';
import QueryErrorView from '../views/query-error-view';
import ObserveModel from '../views/observe-model';
import IssueishDetailController from '../controllers/issueish-detail-controller';
import RelayEnvironment from '../views/relay-environment';
import {autobind} from '../helpers';
import IssueishDetailController from '../controllers/issueish-detail-controller';

export default class IssueishDetailContainer extends React.Component {
static propTypes = {
host: PropTypes.string,
// Connection
endpoint: EndpointPropType.isRequired,

// Issueish selection criteria
owner: PropTypes.string.isRequired,
repo: PropTypes.string.isRequired,
issueishNumber: PropTypes.number.isRequired,

// Package models
repository: PropTypes.object.isRequired,
loginModel: GithubLoginModelPropType.isRequired,

// Atom environment
workspace: PropTypes.object.isRequired,
commands: PropTypes.object.isRequired,
keymaps: PropTypes.object.isRequired,
tooltips: PropTypes.object.isRequired,
config: PropTypes.object.isRequired,

// Action methods
switchToIssueish: PropTypes.func.isRequired,
onTitleChange: PropTypes.func.isRequired,
destroy: PropTypes.func.isRequired,

workspace: PropTypes.object.isRequired,
// Item context
itemType: ItemTypePropType.isRequired,
}

constructor(props) {
Expand All @@ -42,7 +56,7 @@ export default class IssueishDetailContainer extends React.Component {

fetchToken(loginModel) {
return yubikiri({
token: loginModel.getToken(this.props.host),
token: loginModel.getToken(this.props.endpoint.getLoginAccount()),
});
}

Expand Down Expand Up @@ -97,7 +111,7 @@ export default class IssueishDetailContainer extends React.Component {
return <LoadingView />;
}

const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.host, token);
const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.endpoint, token);
const query = graphql`
query issueishDetailContainerQuery
(
Expand Down Expand Up @@ -136,13 +150,13 @@ export default class IssueishDetailContainer extends React.Component {
environment={environment}
query={query}
variables={variables}
render={queryResult => this.renderWithResult(queryResult, repoData)}
render={queryResult => this.renderWithResult(queryResult, repoData, token)}
/>
</RelayEnvironment.Provider>
);
}

renderWithResult({error, props, retry}, repoData) {
renderWithResult({error, props, retry}, repoData, token) {
if (error) {
return (
<QueryErrorView
Expand All @@ -164,6 +178,7 @@ export default class IssueishDetailContainer extends React.Component {
<IssueishDetailController
{...props}
{...repoData}
localRepository={this.props.repository}
issueishNumber={this.props.issueishNumber}
fetch={repository.fetch.bind(repository)}
checkout={repository.checkout.bind(repository)}
Expand All @@ -172,16 +187,27 @@ export default class IssueishDetailContainer extends React.Component {
onTitleChange={this.props.onTitleChange}
switchToIssueish={this.props.switchToIssueish}
workdirPath={repository.getWorkingDirectoryPath()}

endpoint={this.props.endpoint}
token={token}

workspace={this.props.workspace}
commands={this.props.commands}
keymaps={this.props.keymaps}
tooltips={this.props.tooltips}
config={this.props.config}

itemType={this.props.itemType}
destroy={this.props.destroy}
/>
);
}

handleLogin(token) {
return this.props.loginModel.setToken(this.props.host, token);
return this.props.loginModel.setToken(this.props.endpoint.getLoginAccount(), token);
}

handleLogout() {
return this.props.loginModel.removeToken(this.props.host);
return this.props.loginModel.removeToken(this.props.endpoint.getLoginAccount());
}
}
10 changes: 7 additions & 3 deletions lib/containers/issueish-search-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,22 @@ import {QueryRenderer, graphql} from 'react-relay';
import {Disposable} from 'event-kit';

import {autobind} from '../helpers';
import {SearchPropType, OperationStateObserverPropType} from '../prop-types';
import {SearchPropType, OperationStateObserverPropType, EndpointPropType} from '../prop-types';
import IssueishListController, {BareIssueishListController} from '../controllers/issueish-list-controller';
import RelayNetworkLayerManager from '../relay-network-layer-manager';

export default class IssueishSearchContainer extends React.Component {
static propTypes = {
// Connection information
endpoint: EndpointPropType.isRequired,
token: PropTypes.string.isRequired,
host: PropTypes.string.isRequired,

// Search model
limit: PropTypes.number,
search: SearchPropType.isRequired,
remoteOperationObserver: OperationStateObserverPropType.isRequired,

// Action methods
onOpenIssueish: PropTypes.func.isRequired,
onOpenSearch: PropTypes.func.isRequired,
}
Expand All @@ -32,7 +36,7 @@ export default class IssueishSearchContainer extends React.Component {
}

render() {
const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.host, this.props.token);
const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.endpoint, this.props.token);

if (this.props.search.isNull()) {
return (
Expand Down
118 changes: 118 additions & 0 deletions lib/containers/pr-changed-files-container.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import React from 'react';
import PropTypes from 'prop-types';
import {parse as parseDiff} from 'what-the-diff';

import {ItemTypePropType, EndpointPropType} from '../prop-types';
import MultiFilePatchController from '../controllers/multi-file-patch-controller';
import LoadingView from '../views/loading-view';
import ErrorView from '../views/error-view';
import {buildMultiFilePatch} from '../models/patch';

export default class PullRequestChangedFilesContainer extends React.Component {
static propTypes = {
// Pull request properties
owner: PropTypes.string.isRequired,
repo: PropTypes.string.isRequired,
number: PropTypes.number.isRequired,

// Connection properties
endpoint: EndpointPropType.isRequired,
token: PropTypes.string.isRequired,

// Item context
itemType: ItemTypePropType.isRequired,

// action methods
destroy: PropTypes.func.isRequired,

// Atom environment
workspace: PropTypes.object.isRequired,
commands: PropTypes.object.isRequired,
keymaps: PropTypes.object.isRequired,
tooltips: PropTypes.object.isRequired,
config: PropTypes.object.isRequired,

// local repo as opposed to pull request repo
localRepository: PropTypes.object.isRequired,

// refetch diff on refresh
shouldRefetch: PropTypes.bool.isRequired,
}

constructor(props) {
super(props);
this.state = {isLoading: true, error: null};
this.fetchDiff();
}

componentDidUpdate(prevProps) {
if (this.props.shouldRefetch && !prevProps.shouldRefetch) {
this.setState({isLoading: true, error: null});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always makes me nervous when I see setState used synchronously. I think it's okay here because we don't actually need to wait for the re-render with {isLoading: true} to complete before we start fetching the updated diff.

this.fetchDiff();
}
}

// Generate a v3 GitHub API REST URL for the pull request resource.
// Example: https://api.github.com/repos/atom/github/pulls/1829
getDiffURL() {
return this.props.endpoint.getRestURI('repos', this.props.owner, this.props.repo, 'pulls', this.props.number);
}

buildPatch(rawDiff) {
const diffs = parseDiff(rawDiff);
return buildMultiFilePatch(diffs);
}

async fetchDiff() {
const diffError = (message, err = null) => new Promise(resolve => {
if (err) {
// eslint-disable-next-line no-console
console.error(err);
}
this.setState({isLoading: false, error: message}, resolve);
});
const url = this.getDiffURL();

const response = await fetch(url, {
headers: {
Accept: 'application/vnd.github.v3.diff',
Authorization: `bearer ${this.props.token}`,
},
// eslint-disable-next-line handle-callback-err
}).catch(err => {
diffError(`Network error encountered at fetching ${url}`, err);
});
if (this.state.error) {
return;
}
try {
if (response && response.ok) {
const rawDiff = await response.text();
const multiFilePatch = this.buildPatch(rawDiff);
await new Promise(resolve => this.setState({isLoading: false, multiFilePatch}, resolve));
} else {
diffError(`Unable to fetch diff for this pull request${response ? ': ' + response.statusText : ''}.`);
}
} catch (err) {
diffError('Unable to parse diff for this pull request.', err);
}
}

render() {
if (this.state.isLoading) {
return <LoadingView />;
}

if (this.state.error) {
return <ErrorView descriptions={[this.state.error]} />;
}

return (
<MultiFilePatchController
multiFilePatch={this.state.multiFilePatch}
repository={this.props.localRepository}
{...this.props}
/>
);
}
}
Loading