-
Notifications
You must be signed in to change notification settings - Fork 4
Adding new features
[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.)
Go to TopNav.react.js and add another button.
(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.
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
.
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 (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.
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
.
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.
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,
Found a problem in the wiki? Is it out of sync with the current code? Broken link? Typo? Feel free to make an edit if you know how to fix it, otherwise open an issue :)