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
48 commits
Select commit Hold shift + click to select a range
ab4ea9a
WIP: move main package code to GitPackageController
Nov 23, 2016
a0ac19b
:art: Package controller refactor:
Nov 23, 2016
8f7892b
Replace EtchReactAdapter function with EtchWrapper component
Nov 23, 2016
4131d19
:art:
Nov 23, 2016
2a35d86
Render on initial package activation
Nov 23, 2016
4a6f7ba
Add reattachDomNode prop to EtchWrapper component
Nov 25, 2016
cafc9d4
Add Portal component
Nov 25, 2016
1303b1d
Add PaneItem component
Nov 25, 2016
252d6a0
Add Panel component
Nov 25, 2016
f5f0f22
Render GitPanelController with React
Nov 25, 2016
b6d5867
Basic FilePatchController rendering
Nov 25, 2016
45dce22
Tear down React app on package deactivation
Nov 25, 2016
ffea917
:art: Extract Atom/Etch helper components into separate files
Nov 25, 2016
40dce6a
Improve FilePatch rendering management
Nov 25, 2016
20f25ac
Remove unused comments
Nov 25, 2016
9ab386d
Change up GitPanel focus logic
Nov 25, 2016
a735b1e
:art:
Nov 25, 2016
5551ff0
Handle amending
Nov 28, 2016
1af71fd
GithubPackageController :arrow_right: GitController
Nov 28, 2016
2c5c6f9
Fix edge cases around updating wrapped components moved into panels
Nov 29, 2016
bb577ea
:fire: unused GithubPackage#didChangeAmending
Nov 29, 2016
abfbb86
:fire: unused methods in GithubPackage
Nov 29, 2016
61ed981
Change Portal and related components' `getItem` props
Nov 29, 2016
e1bc7f5
Implement showing merge conflict files on GitPanel click
Nov 29, 2016
59eecb3
Fix leaking subscriptions when deactivating and reactivating package
Nov 29, 2016
794f1bc
:art: activeRepository -> nextActiveRepository
Nov 29, 2016
6085991
Serialize and restore GitPanel state
Nov 29, 2016
672ae3f
Clean up status bar consumption
Nov 29, 2016
2c85205
First pass at fixing tests
Nov 29, 2016
c1ece95
I need dis
Nov 30, 2016
9f39cfc
Add test for Portal
Nov 30, 2016
e665bb1
Add test for Panel
Nov 30, 2016
276156a
Add createRenderer React test helper and refactor tests
Nov 30, 2016
12ae9a4
Make Panel call prop when Atom panel is destroyed unexpectedly
kuychaco Dec 1, 2016
deff4b4
:art: extract code into before/afterEach
kuychaco Dec 1, 2016
9bfe994
Add tests for PaneItem
kuychaco Dec 1, 2016
287eed5
:arrow_up: sinon@2.0.0-pre.4
kuychaco Dec 1, 2016
c77d690
Move subset of package state into GitController
kuychaco Dec 1, 2016
49635c4
Always use this.props in Atom wrapper components
Dec 6, 2016
d7171f1
Add visible prop to Panel
Dec 6, 2016
c86b83f
:arrow_up: atom-mocha-test-runner@0.3.1
Dec 6, 2016
057273f
Make until() error have sync stack trace
Dec 6, 2016
b85ea2f
Finish React entry point refactor
Dec 6, 2016
405e943
Merge remote-tracking branch 'origin/master' into mkt-ku-main-package…
Dec 6, 2016
7435dac
Destroy ModelObserver when GitController unmounts
Dec 6, 2016
f6d43dc
:fire: unused focusFilePatchView
Dec 6, 2016
1e8d32b
Add EtchWrapper test
Dec 6, 2016
496638a
¯\(º_o)/¯
Dec 6, 2016
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
13 changes: 6 additions & 7 deletions lib/controllers/file-patch-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {Emitter, CompositeDisposable} from 'atom'
import etch from 'etch'

import FilePatchView from '../views/file-patch-view'
import ModelObserver from '../models/model-observer'

export default class FilePatchController {
constructor (props) {
Expand All @@ -15,23 +14,17 @@ export default class FilePatchController {
this.unstageHunk = this.unstageHunk.bind(this)
this.stageLines = this.stageLines.bind(this)
this.unstageLines = this.unstageLines.bind(this)
this.repositoryObserver = new ModelObserver({
didUpdate: () => this.props.onRepoRefresh && this.props.onRepoRefresh()
})
this.repositoryObserver.setActiveModel(props.repository)
etch.initialize(this)
}

async update (props) {
this.props = Object.assign({}, this.props, props)
this.emitter.emit('did-change-title', this.getTitle())
await this.repositoryObserver.setActiveModel(props.repository)
return etch.update(this)
}

destroy () {
this.emitter.emit('did-destroy')
this.repositoryObserver.destroy()
return etch.destroy(this)
}

Expand Down Expand Up @@ -105,4 +98,10 @@ export default class FilePatchController {
didDestroyFilePatch () {
this.destroy()
}

focus () {
if (this.refs.filePatchView) {
this.refs.filePatchView.focus()
}
}
}
219 changes: 219 additions & 0 deletions lib/controllers/git-controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
/** @babel */

import path from 'path'

import {CompositeDisposable, Disposable, File} from 'atom'

import React from 'react'
import ReactDom from 'react-dom'

import EtchWrapper from '../views/etch-wrapper'
import StatusBar from '../views/status-bar'
import Panel from '../views/panel'
import PaneItem from '../views/pane-item'
import FilePatchController from './file-patch-controller'
import GitPanelController from './git-panel-controller'
import StatusBarTileController from './status-bar-tile-controller'
import ModelObserver from '../models/model-observer'

const nullFilePatchState = {
filePath: null,
filePatch: null,
stagingStatus: null,
amending: null,
}

export default class GitController extends React.Component {
static propTypes = {
workspace: React.PropTypes.object.isRequired,
commandRegistry: React.PropTypes.object.isRequired,
notificationManager: React.PropTypes.object.isRequired,
repository: React.PropTypes.object,
statusBar: React.PropTypes.object,
savedState: React.PropTypes.object,
}

static defaultProps = {
savedState: {},
}

serialize () {
return {
gitPanelActive: this.state.gitPanelActive
}
}

constructor (props, context) {
super(props, context)
this.state = {
...nullFilePatchState,
gitPanelActive: !!props.savedState.gitPanelActive,
}

this.showFilePatchForPath = this.showFilePatchForPath.bind(this)
this.showMergeConflictFileForPath = this.showMergeConflictFileForPath.bind(this)
this.didChangeAmending = this.didChangeAmending.bind(this)
this.onRepoRefresh = this.onRepoRefresh.bind(this)
this.toggleGitPanel = this.toggleGitPanel.bind(this)
this.openAndFocusGitPanel = this.openAndFocusGitPanel.bind(this)
this.focusFilePatchView = this.focusFilePatchView.bind(this)
this.focusGitPanel = this.focusGitPanel.bind(this)
this.subscriptions = new CompositeDisposable()
this.subscriptions.add(
props.commandRegistry.add('atom-workspace', {
'git:toggle-git-panel': this.toggleGitPanel.bind(this),
'git:focus-git-panel': this.openAndFocusGitPanel.bind(this),
})
)

this.repositoryObserver = new ModelObserver({
didUpdate: () => this.onRepoRefresh()
})
this.repositoryObserver.setActiveModel(props.repository)
this.subscriptions.add(
new Disposable(() => this.repositoryObserver.destroy())
)
}

componentWillReceiveProps(newProps) {
this.repositoryObserver.setActiveModel(newProps.repository)
}

render () {
return (
<div>
{this.renderStatusBarTile()}
{this.renderGitPanel()}
{(this.state.filePath && this.state.filePatch) ? this.renderFilePatchController() : null}
</div>
)
}

renderStatusBarTile () {
return (
<StatusBar statusBar={this.props.statusBar} onConsumeStatusBar={(sb) => this.onConsumeStatusBar(sb)}>
<EtchWrapper type="span">
<StatusBarTileController
workspace={this.props.workspace}
repository={this.props.repository}
toggleGitPanel={this.toggleGitPanel}
/>
</EtchWrapper>
</StatusBar>
)
}

renderGitPanel () {
return (
<Panel
workspace={this.props.workspace}
location="right"
getItem={({subtree}) => subtree.getWrappedComponent()}
onDidClosePanel={() => this.setState({gitPanelActive: false})}
visible={!!this.state.gitPanelActive}
>
<EtchWrapper ref={c => this.gitPanelController = c} reattachDomNode={false}>
<GitPanelController
workspace={this.props.workspace}
commandRegistry={this.props.commandRegistry}
notificationManager={this.props.notificationManager}
repository={this.props.repository}
didSelectFilePath={this.showFilePatchForPath}
didSelectMergeConflictFile={this.showMergeConflictFileForPath}
didChangeAmending={this.didChangeAmending}
focusFilePatchView={this.focusFilePatchView}
/>
</EtchWrapper>
</Panel>
)
}

renderFilePatchController () {
return (
<PaneItem
workspace={this.props.workspace}
getItem={({subtree}) => subtree.getWrappedComponent()}
ref={c => this.filePatchControllerPane = c}
onDidCloseItem={() => this.setState({...nullFilePatchState})}
>
<EtchWrapper ref={c => this.filePatchController = c} reattachDomNode={false}>
<FilePatchController
repository={this.props.repository}
filePatch={this.state.filePatch}
stagingStatus={this.state.stagingStatus}
onRepoRefresh={this.onRepoRefresh}
/>
</EtchWrapper>
</PaneItem>
)
}

componentWillUnmount () {
this.subscriptions.dispose()
}

onConsumeStatusBar (statusBar) {
if (statusBar.disableGitInfoTile) {
statusBar.disableGitInfoTile()
}
}

async showFilePatchForPath (filePath, stagingStatus, {activate, amending} = {}) {
if (!filePath) return
const repository = this.props.repository
if (!repository) return

const filePatch = await repository.getFilePatchForPath(filePath, {staged: stagingStatus === 'staged', amending})
if (filePatch) {
this.setState({ filePath, filePatch, stagingStatus, amending }, () => {
// TODO: can be better done w/ a prop?
if (activate && this.filePatchControllerPane) {
this.filePatchControllerPane.activate()
}
})
} else {
this.setState({...nullFilePatchState})
}
}

onRepoRefresh () {
return this.showFilePatchForPath(this.state.filePath, this.state.stagingStatus, {amending: this.state.amending})
}

async showMergeConflictFileForPath (relativeFilePath, {focus} = {}) {
const absolutePath = path.join(this.props.repository.getWorkingDirectoryPath(), relativeFilePath)
if (await new File(absolutePath).exists()) {
return this.props.workspace.open(absolutePath, {activatePane: Boolean(focus), pending: true})
} else {
this.props.notificationManager.addInfo('File has been deleted.')
}
}

didChangeAmending (isAmending) {
return this.showFilePatchForPath(this.state.filePath, this.state.stagingStatus, {amending: isAmending})
}

toggleGitPanel () {
this.setState(state => ({gitPanelActive: !state.gitPanelActive}))
}

openAndFocusGitPanel () {
if (!this.state.gitPanelActive) {
this.setState({gitPanelActive: true}, () => this.focusGitPanel())
} else {
this.focusGitPanel()
}
}

focusGitPanel () {
if (this.gitPanelController) {
this.gitPanelController.getWrappedComponent().focus()
}
}

focusFilePatchView () {
if (this.filePatchController) {
this.filePatchController.getWrappedComponent().focus()
}
}
}
11 changes: 8 additions & 3 deletions lib/controllers/git-panel-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,11 @@ export default class GitPanelController {
}

async update (props) {
const oldProps = this.props
this.props = Object.assign({}, this.props, props)
await this.repositoryObserver.setActiveModel(props.repository)
if (this.props.repository !== oldProps.repository) {
await this.repositoryObserver.setActiveModel(props.repository)
}
return etch.update(this)
}

Expand Down Expand Up @@ -157,7 +160,7 @@ export default class GitPanelController {
}

setAmending (isAmending) {
if (this.props.didChangeAmending) this.props.didChangeAmending()
if (this.props.didChangeAmending) this.props.didChangeAmending(isAmending)
this.isAmending = isAmending
return this.repositoryObserver.refreshModelData(this.getActiveRepository())
}
Expand All @@ -171,6 +174,8 @@ export default class GitPanelController {
}

focus () {
if (this.refs.gitPanel) this.refs.gitPanel.focus()
if (this.refs.gitPanel) {
this.refs.gitPanel.focus()
}
}
}
3 changes: 2 additions & 1 deletion lib/controllers/status-bar-tile-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,10 @@ export default class StatusBarTileController {
this.showingPushPullMenuView = true
}

destroy () {
destroy (removeDomNode) {
this.branchTooltipDisposable && this.branchTooltipDisposable.dispose()
this.pushPullTooltipDisposable && this.pushPullTooltipDisposable.dispose()
this.repositoryObserver.destroy()
etch.destroy(this, removeDomNode)
}
}
Loading