An application that helps users manage the vulnerabilities of their repositories.
Online demo: http://45.252.248.235:8080/
├── frontend # Frontend codes
├── scripts # Script configurations
├── src # Source folder
├── libs # Internal libraries
├── main # Main codes of the project
├── api # API handlers
├── apps # Apps, each app corresponds to a route
├── components # Project-level shared components
├── contexts # React contexts
├── css # Shared CSS/Less variables and mixins
├── errors # Errors: Not found, Forbidden, etc
├── i18n # I18n configuration and translations
├── layout # Common layout for the site
├── models # Business models: Repo, List, Card
├── routing # Routing configuration
├── store # Client-side data source
├── templates # Shared templates, they are React components as well
├── tests # Integration, snapshot tests
├── theme # UI theme preferences
├── uikit # UI Kit shared between internal projects
├── public # Static assets
├── simple-backend # Backend codes
Environment: Node 16 is recommended.
First, clone the project from GitHub:
git clone https://github.com/vanquyettran/vulnerability-dashboard.git
From the root directory, install the application by running the following commands:
npm install
npm run build-dev
# Production build:
# npm run build-prod
Start the application by running:
npm start
The application will be available at http://localhost:8080/
Docker is also supported:
docker-compose build
docker-compose up -d
Now, you can access http://localhost:8080/ to use the application.
To stop it:
docker-compose stop
Tear down:
docker-compose down
To test the frontend codes, run the following commands:
cd frontend
npm test
cd frontend
# Compile and export the frontend output to ./public/bundles
npm run build
# Build and watch for changes
npm run watch
# Similar to build, but the output will be minified for the production
npm run dist
# Development command to "copy" the theme variables from JS to Less
npm run themify
# ESLint check
npm run lint
# Test frontend
npm test
The application allows users to manage the vulnerabilities of their repos. It contains 2 screens: Dashboard and Kanban board. The Dashboard screen shows all repos. Here, users can add new repos as well as edit or delete listed repos. When users click on a repo name, they will be navigated to the Kanban board screen.
Each Kanban board contains 4 columns: Open, Confirmed, False Positive, and Fixed. Each column contains vulnerability cards with the corresponding status.
Users can move cards between columns by dragging and dropping them to the desired columns. However, not all but only some moves are accepted:
- Open to either Confirmed, False Positive, and Fixed.
- Confirmed to Fixed. Vulnerability cards in False Positive and Fixed cannot be moved to any other columns.
Users also can create new cards by clicking on the button at the end of each column, or edit/delete cards by clicking on the pencil and trash buttons on each card.
When users click on the repo text, a popup will be displayed to shows the detailed information. Here, users can take some notes, change repo text or status as well. They also can see the activity log of when and where the card was moved from and to.
Basically, I use React and TypeScript to build this project. I also use some of my own tools/libraries.
I use Less library to write CSS as I pretty like it. I also combine the modularization plugin to make CSS of each component does not conflict with others.
About the state management, I used Recoil.js - an experimental library of Facebook. It introduces Atom architecture. So, we have some state management architectures:
- Flux (Redux, Zustand)
- Proxy (Mobx, Valtio)
- Atomic (Recoil, Jotai)
Recoil is new and closer to hooks, so I was tried to use it.
I use my own library to handle HTTP requests. Basically, it has two main parts: Parcel constructor and Request singleton.
- Parcel constructor: Contains all information need to make the request
- Request singleton: Makes requests with parcels, and tracking/cancel/... the process Parcel constructor also supports some useful features:
- Payload validation: If you set the payload as invalid, Request will reject it.
- Support tests with mock data. It is used to validate the data as the final barrier before sending it to the server.
- Expected response data: It is used to describe how the response data will be if the request was successful. Then, this data will be saved to the local state while requests still run in the background. In case of failure, the local data will fall back to the previous state.
Basically, I use three entity data stores (atoms):
repoData
listData
cardData
Each entity refers to other entities using IDs, such as card.listId ~ list.id
.
For each entity data, we can read and write using two hooks:
useEntityData()
: It provides APIs to access entity data and trigger re-rendering as the data changes.useEntityActions()
: Every update to the entity data needs to be done by these actions. They are responsible for making requests to the server and updating the data to the store. Some actions can run in the background, update the store immediately and only notify users in case of error as well as roll back the data.
Diagram: ./frontend/diagrams/StateManagementDiagram.svg
- Implement request caching
- Implement request retrying on error
- Cover more test cases