1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-01 08:21:15 +03:00
awx/CONTRIBUTING.md
Kia Lam e3a6a20049
Update contributing doc to include:
- Method naming convention
- Initial Empty State convention
2019-03-21 12:51:23 -04:00

4.8 KiB

Ansible AWX/Tower V2

Hi there! We're excited to have you as a contributor.

Have questions about this document or anything not covered here? Feel free to reach out to any of the contributors of this repository found here: https://github.com/ansible/awx-pf/graphs/contributors

Table of contents

Things to know prior to submitting code

  • All code submissions are done through pull requests against the master branch.
  • If collaborating with someone else on the same branch, please use --force-with-lease instead of --force when pushing up code. This will prevent you from accidentally overwriting commits pushed by someone else. For more information, see https://git-scm.com/docs/git-push#git-push---force-with-leaseltrefnamegt

Setting up your development environment

The UI is built using ReactJS and Patternfly.

Prerequisites

Node and npm

The AWX UI requires the following:

  • Node 8.x LTS
  • NPM 6.x LTS

Run the following to install all the dependencies:

(host) $ npm run install

Build the User Interface

Run the following to build the AWX UI:

(host) $ npm run start

Accessing the AWX web interface

You can now log into the AWX web interface at https://127.0.0.1:3001.

Working with React

Class constructors vs Class properties

It is good practice to use constructor-bound instance methods rather than methods as class properties. Methods as arrow functions provide lexical scope and are bound to the Component class instance instead of the class itself. This makes it so we cannot easily test a Component's methods without invoking an instance of the Component and calling the method directly within our tests.

BAD:

  class MyComponent extends React.Component {
    constructor(props) {
      super(props);
    }

    myEventHandler = () => {
      // do a thing
    }
  }

GOOD:

  class MyComponent extends React.Component {
    constructor(props) {
      super(props);
      this.myEventHandler = this.myEventHandler.bind(this);
    }

    myEventHandler() {
      // do a thing
    }
  }

Binding

It is good practice to bind our class methods within our class constructor method for the following reasons:

  1. Avoid defining the method every time render() is called.
  2. Performance advantages.
  3. Ease of testing.

Typechecking with PropTypes

Shared components should have their prop values typechecked. This will help catch bugs when components get refactored/renamed.

About.propTypes = {
  ansible_version: PropTypes.string,
  isOpen: PropTypes.bool,
  onClose: PropTypes.func.isRequired,
  version: PropTypes.string,
};

About.defaultProps = {
  ansible_version: null,
  isOpen: false,
  version: null,
};

Naming Functions

Here are the guidelines for how to name functions.

Naming Convention Description
handle<x> Use for methods that process events
on<x> Use for component prop names
toggle<x> Use for methods that flip one value to the opposite value
show<x> Use for methods that always set a value to show or add an element
hide<x> Use for methods that always set a value to hide or remove an element
create<x> Use for methods that make API POST requests
read<x> Use for methods that make API GET requests
update<x> Use for methods that make API PATCH requests
destroy<x> Use for methods that make API DESTROY requests
replace<x> Use for methods that make API PUT requests
disassociate<x> Use for methods that pass { disassociate: true } as a data param to an endpoint
associate<x> Use for methods that pass a resource id as a data param to an endpoint

Default State Initialization

When declaring empty initial states, prefer the following instead of leaving them undefined:

this.state = {
  somethingA: null,
  somethingB: [],
  somethingC: 0,
  somethingD: {},
  somethingE: '',
}