This document describes the design of the software that implements the Fortran Playground. Currently covered is the design of the frontend component of the system. The design of the backend will be documented in a later update.
The playground consists of a frontend built using React which communicates with a Flask App responsible for executing user codes in a sandboxed environment using a Docker Container.
There are various components which handle different parts of the website. All the styling is done using React-Bootstrap components.
We use an Ace Editor port for React called
React-Ace.
All information about Editor settings is stored under frontend/src/Editor.js
.
The editor settings are passed down as props to the react-ace component and
offer various configuration options check
this page to experiment with
different parameters.
For example, to change the theme import it from react-ace library:
import "ace-builds/src-noconflict/theme-github";
and change the theme prop inside Editor.js
.
The navbar is configured under frontend/src/Navbar.js
.
It uses the default bootstrap navbar component.
The content for tutorial is stored inside the tutorial.json file, which is
generated by the backend from tutorial.yml
file.
A tutorial part consists of 3 sections- a title, content inside it and the code
for the respective exercise.
To add a new exercise append the three parameters inside the file at
src/backend/tutorial.yml
, e.g.:
- title: Heading for exercise
content: A breif explanation for the topic
code: "Code for the exercise"
Restart the server so it can compile the yaml into a JSON. The changes will be immediately reflected. To update the tutorial you can commit this JSON to the main repository via a pull request.
Please make sure that you configure the code properly with proper string formatting. This can be done by entering the code inside the editor first and copying the outputted "code" parameter inside the POST request. This also ensures your code works properly.
The tutorial is handled by the TutorialCard
component insidde
src/TutorialCard.js
with respective props for Heading and Title.
The change for code happens automatically by the tutFunc
function inside
App.js
bounded by the switching buttons.
The InputBox is a separate component which has props passed down from App.js
to effectively manage state for the input.
The source file frontend/src/App.js
houses all of our states and major
functionalities (API Calls, Library Selection).
- States:
- Text: Code inside the editor.
- Output: Output the is received from the backend after execution on container.
- Input: User input for the code that is to be executed
- Exercise: Current exercise the user is on There are also states which hold information on status for various toggleable elements on the site:
- isLoading: Spinner until output is received from API
- inputOn: Input box button toggle
- showTutorial: Prompt for the quickstart tutorial
- show: Pop up modal for library selection
- stdlibOn: State that manages whether stdlib has been selected by user or not
- Buttons for the tutorial are managed by
goRight
andgoLeft
functions, they iterate on the tutorial.json usingexercise
state. - API: POST Request to the backend server is done via
handleClick
function. The request contains 3 parameters code, the input for it and the libraries selected by the user. The response from this request is stored in the output state. - Custom styling from buttons is stored under the style tag inside run-button class.
- The Output Section is inside the terminal class. All elements in this section are made via Bootstrap Cards. The Tutorial Card Component is also inside the terminal class.
- The Modal Pop up for library selection is also a part of this section. It holds the switches for libraries toggle.
- To add a new library in the frontend, add a new
<Form.Check>
component with appropriate props and create a new state for the library. For example:
const [packageOn, ispackageOn] = useState(false)
<Form.Check
type="switch"
id="custom-switch"
label="library-name"
onChange{onLibSelect}
checked={packageOn} />
Then create a new onLibSelect
function as follows:
const onLibSelect = () => {
setpackageOn(!packageOn);
if(!packageOn){
libs.push("library-name")
}
else{
if(libs.includes("library-name")){
libs = libs.filter(item => item !== "library-name")
}
}
The styling for the app is defined in frontend/src/App.css
.
All styles are applied from a single CSS file.