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

Refactor main package entry point - #332

Merged
BinaryMuse merged 48 commits into
masterfrom
mkt-ku-main-package-refactor
Dec 6, 2016
Merged

BinaryMuse merged 48 commits into
masterfrom
mkt-ku-main-package-refactor

Conversation

@BinaryMuse

Copy link
Copy Markdown
Contributor

This PR makes some fairly significant changes to the main entry point of the package (GithubPackage). It also attempts to make the code cleaner by switching up the management of top-level controllers. In detail:

  1. GithubPackage was full of logic related specifically to the Git portion of the package. Adding GitHub-specific functionality was awkward as it gave the class multiple responsibilities and made it feel quite bloated. Most of this logic is moved to GithubPackageController, which will probably be renamed to something more specific to Git.

  2. All the logic for managing the top-level controllers (GitPanelController, FilePatchController, and StatusBarTileController) was lost in a maze of callbacks, event-driven code, and conditionals designed to figure out if we should create, update, or destroy the given controllers. I've moved this logic into a React-driven declarative component that uses new meta-components like Panel, StatusBar, and PaneItem to wrap Atom's imperative API in a declarative interface. Now, simply removing the <Panel><GitPanelController /></Panel> from the return value of render is enough to remove the panel.

    All the new meta-components are documented. As these are new, there may be issues in certain edge cases.

Michelle Tilley added 17 commits November 23, 2016 12:46
* git-package-controller.js -> github-package-controller.js
* move static props into `static prop =` inside class
Previously, rendering an Etch component with React required creating a
new class by passing the Etch component class to `EtchReactAdapter` and
rendering what was returned with React. Instead, EtchReactAdapter allows
you to specify which component to wrap and what props to pass it
declaratively via JSX, and will manage the component lifecycle itself.
@kuychaco
kuychaco force-pushed the mkt-ku-main-package-refactor branch from d4f922d to c77d690 Compare December 1, 2016 03:06
@BinaryMuse
BinaryMuse force-pushed the mkt-ku-main-package-refactor branch from 39ad9a4 to b85ea2f Compare December 6, 2016 01:01
@BinaryMuse

BinaryMuse commented Dec 6, 2016 •

Copy link
Copy Markdown
Contributor Author

This is ready to be merged. Here's a quick summary of what we've changed:

  • The GithubPackage class now has fewer responsibilities: serialize/deserialize state upon activation/deactivation, watch for the top-level repo to change (as the active pane item changes), and render the GitController with React in response.
  • Most of the Git-specific logic that lived in GithubPackage now lives in GitController, a React component responsible for rendering the status bar tiles, the side panel, and the main diff view.
    1. GitController makes use of new high-level components like Panel and PaneItem to bridge Atom's imperative APIs using a declarative, JSX-based interface (e.g. an Atom panel gets created when a <Panel /> mounts, and removed when it unmounts).

    2. Etch components are rendered declaratively, also using JSX, via an EtchWrapper React component that knows how to bridge into the Etch API.

      The combination of these two things makes the logic associated with managing imperative APIs like creating Atom panels and creating, updating, and destroying Etch components much easier to reason about (just check the state to see what's being rendered). This all works with the React Dev Tools for easy debugging.

  • Most of the tests for GithubPackage and GitController are now much simpler as we have two kinds of tests: (1) call some methods or perform some actions and ensure correct state is set, and (2) ensure that a certain state renders the correct child components. Using enzyme's shallow rendering, testing React components is easier and faster than testing Etch ones. The former tests are fairly straightforward even when async, and the latter tests are all synchronous.

While the raw number of lines of code has gone up in this PR, there are a few things to consider:

  1. This is partially due to using a JSX style that spans several lines, making it easier to parse elements when there are many props, e.g.:

    <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>
  2. There are several new reusable abstractions that make it easier to interact with Atom from within React, including Panel, PaneItem, and StatusBar. Each of these contain generous documentation and property type checking via React's propTypes.

  3. Because of the declarative nature of the refactored code, the control flow is generally easier to follow, and much easier to debug (especially when using the React Dev Tools).

Comment thread lib/controllers/git-controller.js Outdated
this.setState({gitPanelActive: true}, () => {
// TODO: why doesn't a setTimeout of 0 or even 100 work here?
// Suspect it has to do with the command palette closing...
setTimeout(() => this.focusGitPanel(), 200)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The high timeout is necessary even when the command palette isn't being used (e.g. when using a keyboard shortcut). I have no idea why. 🔥

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants