OCWA's user interface is powered by a modern JavaScript application, employing Babel, React and Redux for view rendering and state management. Development and production builds use Webpack and the server uses Express to interface with authentication, HTTP endpoints and file details.
It is recommended that you have a good understanding of modern JavaScript development and the Redux development stack and new features like Generators. See more in Code Structure and Style for more details.
If you are interested in just viewing the application in a production ready, compiled state, view the OCWA quick start guide. To boot up just the front end, skip ahead to the installation instructions.
The frontend directory includes a default config file, found in frontend/config/default.json.example
. There are some default values filled in, as well as placeholder values. Copy and rename the file as default.json
before starting the application with $ npm start
. Details for each property are below.
The assigned port for the front-end Express app.
Defaults to 8000
The assigned websocket port. Must match the same value in the Forum service config config.
Defaults to 3001
Any random key for cookies
Used to sign the token after login.
If you have a documentation site set up, adding this URL will add a help menu item to the app bar menu.
Defaults to localhost
See Forum service config for reference.
Defaults to http://localhost:3000
See Forum service config for reference.
Defaults to ws://localhost:3001
See Request service config for reference.
Defaults to http://localhost:3002
See Request service config for reference.
Defaults to ws://localhost:2998
See Storage service README for reference.
Defaults to http://localhost:1080
Defines the identifying group exporters belong to. See more at Groups and Modes.
Defaults to /exporter
Defines the identifying group output checkers belong to. See more at Groups and Modes.
Defaults to /oc
Defines the identifying group users with permissions to view reports belong to. See more at Groups and Modes.
Defaults to /reports
There are 2 different environments that the interface will accommodate. Exporting data/code out of a Secure Research Environment or importing. See more at Groups and Modes.
export
: Inside the SRE to export code
download
: Outside the SRE to import data/code
Defaults to export
If enabled the New Request form will allow users to pick between data and code requests.
Defaults to false
If codeExportEnabled
is on then you need to set the host of the repository so pull requests will work, for example something like https://subdomain.bc.com/shares/
.
Define an user object based on the Passport authentication. Recommended configuration would look something like this:
"auth": {
"authorizationEndpoint": "https://host/auth/realms/realm/protocol/openid-connect/auth",
"callbackURL": "http://localhost:8000/auth",
"clientID": "outputchecker",
"clientSecret": "secrect",
"issuer": "https://host/auth/realms/realm",
"logoutURL": "https://host/auth/realms/realm/protocol/openid-connect/logout?redirect_uri=http://localhost:8000",
"scope": "openid offline_access profile",
"tokenEndpoint": "https://host/auth/realms/realm/protocol/openid-connect/token",
"userInfoURL": "https://host/auth/realms/realm/protocol/openid-connect/userinfo"
}
Storage settings are for connecting to Minio via their JavaScript API. All of these settings are required. See more about Minio's JavaScript Client here.
See Storage service README for this value.
Defaults to localhost
See Storage service README for this value.
Defaults to 9000
Set to true
if using https
.
Defaults to false
Set to the bucket you are storing your files in. See the Storage service README for these values.
See the Storage service README for these values.
See the Storage service README for these values.
NOTE: Minio is only used for file viewing. TUSD is used for uploading though there is no configuration required to upload via the frontend.
Declare which property on a authenticated user object is the ID key.
Defaults to preferred_username
but can be whatever your authentication setup outputs.
There are 3 groups a user can belong to;
This interface allows a user to create new data or code export requests or download files from the SRE, depending on which environment OCWA is running in. In the SRE you can download approved import requests and outside of SRE you can download approved export requests.
Output Checkers can review requests and approve them or flag the request and discuss the reasons why the request has been flagged with the exporter.
Reports is a simple analytics tool that gathers all submitted requests for purposes of analyzing trends like approval time, and can be filtered by project or exporter.
In addition there are 2 states the Exporter or Output Check interface can be viewed as; import
into the SRE or export
out of the SRE. The interface differences betweeen these modes is minimal, mostly string localization, though there can be minor functionality differences with the application as whole.
All installs require an instance of mongodb available.
- npm 6.4.1 or newer
- node 10.15.1 LTS or newer
- Docker 18.09.1 or newer
Copy and rename config/default.json.example
to config/default.json
and fill in the values. See Configuration for details.
npm install
npm start
Note that if you want to use a test user, ensure the default.json
config has the following fields:
testGroup
: set to either/exporter
,/reports
or/oc
testJWT:exporter
: A JWT that matches the above format (make sure thegroup
array includes '/exporter')testJWT:oc
: A JWT that matches the above format (make sure thegroup
array includes '/oc**)
NOTE: DO NOT INCLUDE THESE VALUES IN PRODUCTION
You will need Docker installed. Build the container by running $ docker build .
, then run the following commands:
hostip=$(ifconfig en0 | awk '$1 == "inet" {print $2}')
port=8000
docker run -e TOKEN_ENDPOINT=<oidc token endpoint> -e USER_INFO_ENDPOINT=<oidc user info endpoint> -e AUTH_ENDPOINT=<authendpoint> -e AUTH_CALLBACK_URL=<host/auth> -e AUTH_CLIENT=<oidc client> -e AUTH_ISSUER=<oidc issuer> -e AUTH_LOGOUT_URL=<oidc logout url> -e AUTH_SCOPES="openid offline_access" -e CLIENT_SECRET=<YOUR_CLIENT_SECRET> -e JWT_SECRET=<YOUR_API_SECRET> -e COOKIE_SECRET=<COOKIE_SECRET> -e HOST=docker -e FORUM_API_HOST=$hostip:3000 -e EXPORTER_GROUP="/exporter" -e OC_GROUP="/oc" -e REPORTS_GROUP="/reports" -e EXPORTER_MODE="export" -e FORUM_SOCKET_HOST=$hostip:3001 -e REQUEST_API_HOST=$hostip:3002 -e REQUEST_SOCKET_HOST=$hostip:2998 -e FILES_API_HOST=$hostip:1080 -e USER_ID_FIELD=email -e PORT=$port --add-host=docker:$hostip -p $port:$port <DOCKER_IMAGE>
For both below helm commands make a copy of values.yaml
within the helm/ocwa-frontend directory and modify it to contain the values specific for your deployment. Learn more about Helm here.
Helm Install (Kubernetes)
helm install --name ocwa-frontend --namespace ocwa ./helm/ocwa-frontend -f ./helm/ocwa-frontend/config.yaml
Helm Update (Kubernetes)
helm upgrade --name ocwa-frontend ./helm/ocwa-frontend -f ./helm/ocwa-frontend/config.yaml
This project aims to stay up-to-date with latest versions of the modern JavaScript development stack. Babel transpiles modern syntax (e.g. destructoring, generators, etc), React is the view library, Redux for state management, Redux-Saga for side effects and AtlasKit components for UI.
The most advanced concept is the use of Generators when applied in sagas, but Redux Saga's website has good documentation and resources to help you get started.
For quality and consistency ESLint is used to ensure common mistakes are caught while coding and Prettier formats your code into "prettier" and more readable code, but also standardized, which leads to a more consistent code base.
The UI employs a ducks-like style to structure, which seeks to break up the different domains of a project into separate modules responsible for their own content (e.g. Requests are handled in the requests
module, discussions in the discussions
module etc). All public facing code is kept in the /src
directory.
All the global components that can be used across modules.
See more about modules below.
All the global components that can be used across modules.
Functions that are useful across the entire project.
Each module contains a specific stack of the following:
/ ..
/ actions.js
/ components
/ containers
/ reducer.js (or (/reducer))
/ sagas.js
/ utils.js (if necessary)
This allows each module to have its own reducer data structure, actions and side-effects, but all of these are optional. Reducers and sagas are included during boot by the src/index.js
entry file.
A quick note on containers/components if you are not familiar with Redux. Containers are file that connects the redux state object with a component and are kept separate to keep components dumb when it comes to where they get their data from. The /data
module however containers a special connect helper that will help compose a data-fetching container.
To compose a data-aware component, in a module's actions.js
export the following action:
// anymodule/actions.js
import { createDataAction } from '@src/modules/data/actions';
export const fetchRequests = createDataAction('requests/get');
Then create a container which is composed like so:
// anymodule/containers/requests.js
import { connect } from 'react-redux';
import withRequest from '@src/modules/data/components/data-request';
import Requests from '../components/requests';
import { requestsListSchema } from '../schemas';
const mapStateToProps = () => ({}); // Decorate the connect method as you normally would
export default connect(
mapStateToProps,
{
// If dispatch props has a `initialRequest` prop, it'll fire that on mount
initialRequest: ({ page }) =>
fetchRequest(
// If there are 2 arguments, the first one is considered a meta object
{
page: 1,
},
// The other object is the request object, with details about the request
{
url: `/api/v1/requests?page=${page}`, // compose the API endpoint you wish to fetch your data from
schema: requestsListSchema, // Assign a normalized schema if relevant
}
),
}
)(withRequest(Requests)); // Add the higher-order component here to add loading props and kick off the request.
Data is stored in the data
reducer property, with entities
being the full data object, fetchStatus
being the status of the request, which can be loading
, loaded
or failed
.
In some cases you might add a dataType
to the request container if you are requesting a payload that isn't able to be normalized into an ID based key/value storage object.
To run the tests run
npm test