Skip to content

Adding new features

Emil Rose edited this page Feb 17, 2016 · 21 revisions

[This page assumes you're not a total noob at React/Flux. If this assumption is not sound, you should probably see React-Flux-Intro]

Currently, McLab Web does two things - Kind Analysis and Compilation to Fortran. You do them by clicking the big blue buttons at the top. If you want to make McLab Web do more things, the easiest way to start is by adding another big blue button. (Someday we will run out of space up there - that will be a very good day.)

How to add another big blue button

Go to TopNav.react.js and add another button.

What does this button do

(Almost) everything in McLab Web happens through firing of actions. Sometimes clicking the big blue buttons only fires a single action (as seen here in the fortran button); sometimes clicking the button does more than that (as is done in kind analysis: see here and then here). When clicking a button does lots of things, it is nicer to put all the mess into a separate Actions file in js/actions.

Fun with dispatcher

The dispatcher is assigned to a global variable here for your amusement. Open up a JS console and execute this, and see wonders happen:

debug_dispatcher.dispatch({action: debug_AT.TERMINAL.ADD_NEW_LINE, data: { newLine: 'Do I think? Do I exist?' }})

Let's deconstruct this. The dispatcher API can be found here. Most of the time, the only method you'll be interested in is dispatch. It takes in a payload, which by convention in McLab Web is a JS object with two properties - action (mandatory) and data (optional).

The permissible values of action are predefined in js/constants/AT.js: you will have to add new action types here if you're developing new features. We export the whole AT module as debug_AT here, which is why in the code snippet up there we say debug_AT instead of just AT.

So it looks like we are firing an action that adds a new line to the Terminal. How do we know what the format of the data object should be? A quick code search for AT.TERMINAL.ADD_NEW_LINE reveals that the only store that consumes this action is TerminalBufferStore, and by reading the code of the __onDispatch method or looking at the comment, we discover that the data object needs to have a newLine attribute, which is exactly what we have done up there.

When developing new features, you may find it convenient to have to ability to fire specific actions with the debug_dispatcher.

Feeding actions to stores

The primary consumer of all these actions are different stores. Stores hold pieces of application state. For example, ActiveSidePanelStore holds the information about which side panel is currently open; FortranCompileConfigStore stores the configuration for Fortran compilation.

Adding a new feature may require adding several new stores. Stores have no setter methods - you implement an __onDispatch method that is invoked whenever any action is fired, and the store state can only be updated inside this method. You create as many getter methods as you need.

Use flux-utils to create stores. Store is the base store class, and ReduceStore and MapStore are convenient subclasses for specific use cases. See js/stores for the full diversity of stores currently implemented in McLab Web.

Containers read data from stores

Containers (aka FluxContainers) (aka React Containers) are the only React components that talk to stores. CodeContainer is a good example of a container. A container has a getStores method that should return a list of stores it subscribes to. Any time any of these subscribed stores emit a change, the calculateState method of the container gets called. This method gathers all the data from the stores, and returns an object that is set as the state of the React component. Calling setState on React components lead to a rerender, so the render method of the container is called.

Typically the render method of containers contain minimal logic - most of the complicated logic is deferred to descendent React components. Containers pass data to its children exclusively through props.

When you create a container, name it somethingSomethingContainer so that it's explicit.

Other React components

The non-container React components (aka View components) take the passed down props and finally render some HTML (or maybe not - there can be a pretty long chain of React components.) For example, the FileExplorer gets its props from FileExplorerContainer, and then rendered a bunch of HTML along with other React components like FileTile and FolderTile.

Talking to the server

Here is an example of how McLabWeb communicates with the server to get Kind Analysis results. AJAX communication code is all over the place in the current code base, but for new code we encourage you to put them in an Actions file.

On the server side, you will handle this request by adding a a route in index.js and the implementation of this route in the tools folder.

Note on side panels

If you want a new side panel, you should define a unique key for that panel in SidePanelKeys.js. Then define an OPEN_PANEL action for your panel in AT.js, and add a case in ActiveSidePanelStore.js for that open action.

Define a new container and a view component for the panel. The view component should return a SidePanelBase component. For an example see KindAnalysisPanel,