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

Commit

Permalink
Merge pull request #2308 from wadethestealth/project-management
Browse files Browse the repository at this point in the history
Project Management
  • Loading branch information
smashwilson authored Oct 28, 2019
2 parents 79afbab + 1069fc9 commit aae4848
Show file tree
Hide file tree
Showing 29 changed files with 790 additions and 396 deletions.
2 changes: 1 addition & 1 deletion lib/atom/marker.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const DecorableContext = React.createContext();
class BareMarker extends React.Component {
static propTypes = {
...markerProps,
id: PropTypes.string,
id: PropTypes.number,
bufferRange: RangePropType,
markableHolder: RefHolderPropType,
children: PropTypes.node,
Expand Down
3 changes: 0 additions & 3 deletions lib/containers/current-pull-request-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ export default class CurrentPullRequestContainer extends React.Component {
aheadCount: PropTypes.number,
pushInProgress: PropTypes.bool.isRequired,

workspace: PropTypes.object.isRequired,

// Actions
onOpenIssueish: PropTypes.func.isRequired,
onOpenReviews: PropTypes.func.isRequired,
Expand Down Expand Up @@ -164,7 +162,6 @@ export default class CurrentPullRequestContainer extends React.Component {
total={associatedPullRequests.totalCount}
results={associatedPullRequests.nodes}
isLoading={false}
workspace={this.props.workspace}
endpoint={this.props.endpoint}
resultFilter={issueish => issueish.getHeadRepositoryID() === this.props.repository.id}
{...this.controllerProps()}
Expand Down
14 changes: 12 additions & 2 deletions lib/containers/github-tab-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,18 @@ export default class GitHubTabContainer extends React.Component {
}

if (!this.props.repository.isPresent()) {
// TODO include a better message here.
return null;
return (
<GitHubTabController
{...this.props}
remoteOperationObserver={this.state.remoteOperationObserver}

allRemotes={new RemoteSet()}
branches={new BranchSet()}
aheadCount={0}
pushInProgress={false}
isLoading={false}
/>
);
}

return (
Expand Down
9 changes: 8 additions & 1 deletion lib/controllers/git-tab-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export default class GitTabController extends React.Component {
workingDirectoryPath: PropTypes.string,
mergeMessage: PropTypes.string,
fetchInProgress: PropTypes.bool.isRequired,
currentWorkDir: PropTypes.string,

workspace: PropTypes.object.isRequired,
commands: PropTypes.object.isRequired,
Expand All @@ -51,6 +52,9 @@ export default class GitTabController extends React.Component {
openFiles: PropTypes.func.isRequired,
openInitializeDialog: PropTypes.func.isRequired,
controllerRef: RefHolderPropType,
changeWorkingDirectory: PropTypes.func.isRequired,
onDidChangeWorkDirs: PropTypes.func.isRequired,
getCurrentWorkDirs: PropTypes.func.isRequired,
};

constructor(props, context) {
Expand Down Expand Up @@ -99,7 +103,7 @@ export default class GitTabController extends React.Component {
unstagedChanges={this.props.unstagedChanges}
stagedChanges={this.props.stagedChanges}
mergeConflicts={this.props.mergeConflicts}
workingDirectoryPath={this.props.workingDirectoryPath}
workingDirectoryPath={this.props.workingDirectoryPath || this.props.currentWorkDir}
mergeMessage={this.props.mergeMessage}
userStore={this.userStore}
selectedCoAuthors={this.state.selectedCoAuthors}
Expand All @@ -119,6 +123,9 @@ export default class GitTabController extends React.Component {
openFiles={this.props.openFiles}
discardWorkDirChangesForPaths={this.props.discardWorkDirChangesForPaths}
undoLastDiscard={this.props.undoLastDiscard}
changeWorkingDirectory={this.props.changeWorkingDirectory}
getCurrentWorkDirs={this.props.getCurrentWorkDirs}
onDidChangeWorkDirs={this.props.onDidChangeWorkDirs}

attemptFileStageOperation={this.attemptFileStageOperation}
attemptStageAllOperation={this.attemptStageAllOperation}
Expand Down
10 changes: 9 additions & 1 deletion lib/controllers/github-tab-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export default class GitHubTabController extends React.Component {
aheadCount: PropTypes.number,
pushInProgress: PropTypes.bool.isRequired,
isLoading: PropTypes.bool.isRequired,
currentWorkDir: PropTypes.string,

changeWorkingDirectory: PropTypes.func.isRequired,
onDidChangeWorkDirs: PropTypes.func.isRequired,
getCurrentWorkDirs: PropTypes.func.isRequired,
}

render() {
Expand All @@ -42,7 +47,7 @@ export default class GitHubTabController extends React.Component {
loginModel={this.props.loginModel}
rootHolder={this.props.rootHolder}

workingDirectory={this.props.workingDirectory}
workingDirectory={this.props.workingDirectory || this.props.currentWorkDir}
branches={this.props.branches}
currentBranch={currentBranch}
remotes={gitHubRemotes}
Expand All @@ -54,6 +59,9 @@ export default class GitHubTabController extends React.Component {

handlePushBranch={this.handlePushBranch}
handleRemoteSelect={this.handleRemoteSelect}
changeWorkingDirectory={this.props.changeWorkingDirectory}
getCurrentWorkDirs={this.props.getCurrentWorkDirs}
onDidChangeWorkDirs={this.props.onDidChangeWorkDirs}
/>
);
}
Expand Down
1 change: 0 additions & 1 deletion lib/controllers/issueish-list-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ export class BareIssueishListController extends React.Component {
onOpenMore: PropTypes.func,

emptyComponent: PropTypes.func,
workspace: PropTypes.object,
endpoint: EndpointPropType,
needReviewsButton: PropTypes.bool,
};
Expand Down
15 changes: 15 additions & 0 deletions lib/controllers/root-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,14 @@ export default class RootController extends React.Component {
switchboard: PropTypes.instanceOf(Switchboard),
pipelineManager: PropTypes.object,

currentWorkDir: PropTypes.string,

// Git actions
initialize: PropTypes.func.isRequired,
clone: PropTypes.func.isRequired,

// Control
changeWorkingDirectory: PropTypes.func.isRequired,
startOpen: PropTypes.bool,
startRevealed: PropTypes.bool,
}
Expand Down Expand Up @@ -258,6 +261,10 @@ export default class RootController extends React.Component {
}

renderPaneItems() {
const {workdirContextPool} = this.props;
const getCurrentWorkDirs = workdirContextPool.getCurrentWorkDirs.bind(workdirContextPool);
const onDidChangeWorkDirs = workdirContextPool.onDidChangePoolContexts.bind(workdirContextPool);

return (
<Fragment>
<PaneItem
Expand All @@ -284,6 +291,10 @@ export default class RootController extends React.Component {
discardWorkDirChangesForPaths={this.discardWorkDirChangesForPaths}
undoLastDiscard={this.undoLastDiscard}
refreshResolutionProgress={this.refreshResolutionProgress}
currentWorkDir={this.props.currentWorkDir}
getCurrentWorkDirs={getCurrentWorkDirs}
onDidChangeWorkDirs={onDidChangeWorkDirs}
changeWorkingDirectory={this.props.changeWorkingDirectory}
/>
)}
</PaneItem>
Expand All @@ -297,6 +308,10 @@ export default class RootController extends React.Component {
repository={this.props.repository}
loginModel={this.props.loginModel}
workspace={this.props.workspace}
currentWorkDir={this.props.currentWorkDir}
getCurrentWorkDirs={getCurrentWorkDirs}
onDidChangeWorkDirs={onDidChangeWorkDirs}
changeWorkingDirectory={this.props.changeWorkingDirectory}
/>
)}
</PaneItem>
Expand Down
35 changes: 35 additions & 0 deletions lib/error-boundary.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import PropTypes from 'prop-types';

export default class ErrorBoundary extends React.Component {
static propTypes = {
children: PropTypes.node.isRequired,
fallback: PropTypes.any,
};

constructor(props) {
super(props);
this.state = {hasError: false, error: null, errorInfo: null};
}

static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return {hasError: true};
}

componentDidCatch(error, errorInfo) {
this.setState({
error,
errorInfo,
});
}

render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return this.props.fallback ? this.props.fallback : null;
}

return this.props.children;
}
}
91 changes: 33 additions & 58 deletions lib/github-package.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,14 @@ export default class GithubPackage {
return !!event.target.closest('.github-FilePatchListView').querySelector('.is-selected');
};

const handleProjectPathsChange = () => {
const activeRepository = this.getActiveRepository();
const activeRepositoryPath = activeRepository ? activeRepository.getWorkingDirectoryPath() : null;
this.scheduleActiveContextUpdate({activeRepositoryPath});
};

this.subscriptions.add(
this.project.onDidChangePaths(this.scheduleActiveContextUpdate),
this.workspace.getCenter().onDidChangeActivePaneItem(this.scheduleActiveContextUpdate),
this.project.onDidChangePaths(handleProjectPathsChange),
this.styleCalculator.startWatching(
'github-package-styles',
['editor.fontSize', 'editor.fontFamily', 'editor.lineHeight', 'editor.tabLength'],
Expand Down Expand Up @@ -269,6 +274,10 @@ export default class GithubPackage {
}));
}

const changeWorkingDirectory = workingDirectory => {
this.scheduleActiveContextUpdate({activeRepositoryPath: workingDirectory});
};

this.renderFn(
<RootController
ref={c => { this.controller = c; }}
Expand All @@ -294,6 +303,8 @@ export default class GithubPackage {
startOpen={this.startOpen}
startRevealed={this.startRevealed}
removeFilePatchItem={this.removeFilePatchItem}
currentWorkDir={this.getActiveWorkdir()}
changeWorkingDirectory={changeWorkingDirectory}
/>, this.element, callback,
);
}
Expand Down Expand Up @@ -495,14 +506,13 @@ export default class GithubPackage {
* Derive the git working directory context that should be used for the package's git operations based on the current
* state of the Atom workspace. In priority, this prefers:
*
* - A git working directory that contains the active pane item in the workspace's center.
* - A git working directory corresponding to a single Project.
* - When initially activating the package, the working directory that was active when the package was last
* serialized.
* - The preferred git working directory set by the user (This is also the working directory that was active when the
* package was last serialized).
* - A git working directory corresponding to "first" Project, whether or not there is a single project or multiple.
* - The current context, unchanged, which may be a `NullWorkdirContext`.
*
* First updates the pool of resident contexts to match all git working directories that correspond to open
* projects and pane items.
* projects.
*/
async getNextContext(savedState) {
const workdirs = new Set(
Expand All @@ -514,50 +524,34 @@ export default class GithubPackage {
),
);

const fromPaneItem = async maybeItem => {
const itemPath = pathForPaneItem(maybeItem);

if (!itemPath) {
return {};
}

const itemWorkdir = await this.workdirCache.find(itemPath);

if (itemWorkdir && !this.project.contains(itemPath)) {
workdirs.add(itemWorkdir);
}

return {itemPath, itemWorkdir};
};

const active = await fromPaneItem(this.workspace.getCenter().getActivePaneItem());

// Update pool with the open projects
this.contextPool.set(workdirs, savedState);

if (active.itemPath) {
// Prefer an active item
return this.contextPool.getContext(active.itemWorkdir || active.itemPath);
if (savedState.activeRepositoryPath) {
// Preferred git directory (the preferred directory or the last serialized directory).
const stateContext = this.contextPool.getContext(savedState.activeRepositoryPath);
// If the context exists chose it, else continue.
if (stateContext.isPresent()) {
return stateContext;
}
}

if (this.project.getPaths().length === 1) {
// Single project
const projectPath = this.project.getPaths()[0];
const projectPaths = this.project.getPaths();

if (projectPaths.length >= 1) {
// Single or multiple projects (just choose the first, the user can select after)
const projectPath = projectPaths[0];
const activeWorkingDir = await this.workdirCache.find(projectPath);
return this.contextPool.getContext(activeWorkingDir || projectPath);
}

if (this.project.getPaths().length === 0 && !this.activeContext.getRepository().isUndetermined()) {
if (projectPaths.length === 0 && !this.activeContext.getRepository().isUndetermined()) {
// No projects. Revert to the absent context unless we've guessed that more projects are on the way.
return WorkdirContext.absent({pipelineManager: this.pipelineManager});
}

// Restore models from saved state. Will return a NullWorkdirContext if this path is not presently
// resident in the pool.
const savedWorkingDir = savedState.activeRepositoryPath;
if (savedWorkingDir) {
return this.contextPool.getContext(savedWorkingDir);
}

// It is only possible to reach here if there there was no preferred directory, there are no project paths and the
// the active context's repository is not undetermined.
return this.activeContext;
}

Expand Down Expand Up @@ -600,22 +594,3 @@ export default class GithubPackage {
}
}
}

function pathForPaneItem(paneItem) {
if (!paneItem) {
return null;
}

// Likely GitHub package provided pane item
if (typeof paneItem.getWorkingDirectory === 'function') {
return paneItem.getWorkingDirectory();
}

// TextEditor-like
if (typeof paneItem.getPath === 'function') {
return paneItem.getPath();
}

// Oh well
return null;
}
Loading

0 comments on commit aae4848

Please sign in to comment.