Hi!
This is my private dashboard. The goal of this project is to have a place to collect my web applications, independently on the technology.
The Dashboard itself is built in React, but each application might be built with other frameworks (like Vue) and the backend can be different for every application.
Clone dependency repositories:
# Assuming you are in your ~/repositories folder, clone
# dashboard-ui-style (mandatory)
git clone git@github.com:vittoriozamboni/dashboard-ui-style.git
cd dashboard-ui-style
yarn link
cd ../
# dashboard-finance (optional)
git clone git@github.com:vittoriozamboni/dashboard-finance.git
cd dashboard-finance
yarn link
cd ../
From main folder of this repository, now install all global dependencies and link local ones:
# Install packages
yarn
# Local packages
yarn link "@vzamboni/dashboard-ui-style"
# Start development, by default listening on 3000
yarn start
# Create production bundle
yarn build
To test build package, user a local web server.
One easy way is to use http-server
package:
# Install the node package, globally or locally
sudo npm install http-server -g
# Run from main directory
http-server build/
This will create a local server listening on port 8080.
Dashboard is based on React
v16.8 and create-react-app
, with ejected configuration. It uses standard PropTypes
for props validation.
Redux
v4 is the store manager, and scss
the preferred way of using stylesheets.
react-router
v5;react-redux
v6;react-virtualized
v9;formik
v1.5;react-color
v2;
highlight.js
v9;
flexboxgrid
v6;
For specific versions, see package.json
file.
DashboardMenu
component allows to create menus in the dashboard header.
There are few blocks used:
-- container (class: dashboard-menu__container) --------------------
| -- header (class: dashboard-menu__header) ---------------------- |
| | -- header block (class: dashboard-menu__header-block) ------ | |
| | | -- block item (class: dashboard-menu__header-item) ------| | |
| | |----------------------------------------------------------| | |
| |--------------------------------------------------------------| |
| -- body (class: dashboard-menu__body) -------------------------- |
| |--------------------------------------------------------------| |
--------------------------------------------------------------------
DashboardMenu accepts three block props, whose names are defined in constants
file: left
, center
and right
.
Each of them defines a specific part of the header, and accepted properties must be valid React nodes or strings, or an array of any of them.
Based on the passed props, the size of each blocks is calculated in percentages: for example, if only left
and right
are passed, each of them is 50%. Plus, text align is set as the name of the property itself.
import { DashboardMenu } from 'components/dashboard-menu/DashboardMenu';
const RightComponent = () => {
return <span>Hello User!</span>;
};
function Header() {
return <DashboardMenu
left={['Menu Item 1', 'Menu Item 2']}
center='Dashboard'
right={<RightComponent />}
/>
}
Dashboard Menu has a special section called body
. It represents an invisible (until opened) section that can be filled with a component.
In order to be used, a special type of object should be passed in a block. It must have at least two keys, headerLabel
and bodyItem
.
The first is a string or a component that will be rendered in the header; when headerLabel
is clicked the second will be
rendered inside the body (the hidden part).
This should extend DashboardItem
component, which will receive few props from DashboardMenu itself.
import React, { Component } from 'react';
import { DashboardMenu, DashboardItem } from 'components/dashboard-menu/DashboardMenu';
const RightComponent = () => {
return <span>Hello User!</span>;
};
class Applications extends DashboardItem {
render() {
const { query } = this.props;
return <div>
This will be the list of installed applications! Query: {query}
</div>;
}
}
export class Header extends Component {
render() {
return <header>
<DashboardMenu
left={[{ headerLabel: 'Applications', bodyItem: Applications }, 'Menu Item 2']}
center='Dashboard'
right={<RightComponent />}
/>
</header>;
}
}
Store management is implemented by using redux
.
An empty store is created inside store/store.js
file with a mechanism to add reducers dynamically by using the following command:
store.registerReducer(STORE_KEY, REDUCER_FUNCTION);
Whenever a new reducer is registered, the store
will replace all the reducers using replaceReducer
method adding the new one as well.
Example used in the application:
store.registerReducer('authentication', authReducers.authentication);
requests
is a module based on fetch
that simplifies calls by adding headers and payload conversion facilitations. There are two shorthands: get
and post
.
For a more detailed description, see README.md file in libs/requests
folder.
Provides a simple error class called Exception
that takes an object when instanciated and stores it in errorData
. This can be retrieved by using getErrorData
method.
authentication
module helps to authenticate the user on server.
The idea is to have a valid token and store it locally after a successfull login by using localStorage.
When the page is loaded the first time and a token is set, the authentication
module will attempt to auto-login with that token. If the token is no longer valid, it will be deleted.
When a new token is obtained or after the successfull auto-login, it's added to common headers in requests
module.
For a more detailed description, see README.md file in libs/authentication
folder.
Libs talks to each other, as well as with store, generating the following tree.
exceptions ----|
| |
store | requests
|-- authentication --|
Few configuration variables can be customized. They can be defined inside config
folder in two files:
serverConfig.dev.json
;serverConfig.prod.json
;
The two files are not saved in the repository.
The content will be loaded accordingly.
Keys of the JSON file will be used to create configuration constants in config.js
file.
Key | Default | Description |
---|---|---|
BACKEND_URL | http://localhost/ |
Base URL used by requests module. |
For example, to override BACKEND_URL
in Dev mode, you can use the following serverConfig.dev.json
:
{
"BACKEND_URL": "http://localhost:8091/"
}
Following the tutorial of this video, I have forked create-react-app
.
Instead of ejecting and maintaining all the configurations, I changed the create-react-app
/ react-scripts
to parse a file called dashboardWebpack.config.js
and apply the modify
function in a similar way of grasshousedev's createConfig.js.
In this way, it's easy to change the Webpack configuration without ejecting!
When changes are pushed to the official create-react-app
they should be merged into the forked repository.
After cloning the fork locally, I've launched the following command:
git remote add upstream https://github.com/facebook/create-react-app.git
Now, to keep it updated:
git fetch upstream
git rebase upstream/master
Uninstall the custom package and then install using 'file' prefix:
yarn remove @vzamboni/react-scripts
Copy this to package.json
into dependencies section:
"@vzamboni/react-scripts": "file:~/repositories/create-react-app/packages/react-scripts",
Then, reinstall:
yarn install
# After installation, run
yarn start
Main developer: Vittorio Zamboni.