A Flask server for React data dashboards
Project description
Cardboard
A simple data dashboard for use in Flask apps. Each card on the board manages its own WebSocket connection to the server to be abe to handle multiple high bandwidth data sources such as audio or high frequency sensor data which could otherwise saturate a single multiplexed Flask SocketIO connection.
While this project was intended for use on localhost, it should be able to be deployed to the web as well, though we haven't needed to try this yet. This library is being created for a very specific use case in a private project, but perhaps someone out there will find it useful too.
Prerequisites
- Python 3.7+
- Npm 10.8+
- GNU Make 3.8+
Development
Project Initialization
After cloning the repository, install backend and frontend dependencies. The make init target will install both backend and frontend dependencies.
Install Dependencies
make init
Alternatively, you can separately install the backend dependencies with pip and the frontend dependencies with npm.
Install Backend Dependencies with Pip
From the project root run pip install:
pip install -r requirements.txt
Install Frontend Dependencies with npm
From the cardboard_ui directory, run npm install:
cd cardboard_ui
npm install
Start the Development Servers
For development, the Flask development server can be used to automatically reload when backend Python file changes are detected. The Vite development server can be used to automatically reload when front-end Javascript or CSS files change. The Flask server runs on http://127.0.0.1:5000. The Vite server runs on http://127.0.0.1:5173. When running the development servers, access the app from a webbrowser using the Vite server at http://127.0.0.1:5173.
- Start the Flask development server:
make start_flask
- Start the Vite development server:
make start_vite
Start the WSGI Production Server
For production, Gunicorn is used to run the WSGI app on http://127.0.0.1:5000. The Vite server is not used. The front-end resources must be compiled and packaged and will be served by the production server.
- Start the Gunicorn WSGI server:
make start_wsgi
Installation of Published Packages
This section describes how to install the cardboard packages for development and production. This assumes cardboard is being integrated into a Python Flask application with a front-end built using Vite with the React plugin. In this context, we assume the basic directory structures:
project-root/
.venv/
flask-dir/
app.py
ui-dir/
node_modules/
src/
main.jsx
index.css
vite.config.js
package.json
Install Production Packages
Backend
cd <project-root>
pip install cardboard
cd <ui-dir>
npm install cardboard-ui
Installing from Local Dev Projects
This assums you've cloned the Cardboard git repository to cardboard-project-root
.
Backend
pip install <cardboard-project-root>/dist/cardboard-<version>-py3-none-any.whl
Frontend
cd <cardboard-project-root>/cardboard_ui
npm link
cd <project-root>/<ui-dir>
npm link cardboard-ui
Installing from TestPyPi
Use this command to install from the TestPyPi registry instead of the proeuction PyPi registry.
pip install -i https://test.pypi.org/simple/ cardboard
Usage
- Create an configure the Flask app for either developmet or production mode.
- Load the Vite manifest
- Import the cardboard blueprint into the Flask app.
- Register the blueprint.
- Load a json board configuration file.
- Add the cardboard javascript and css assets to the Flask index.html template
- Add a <div> with the id 'root' to the <body> of index.html.
- Render the Board component into the root div in main.jsx.
app.py
"""
Example Flask cardboard server
"""
from flask import Flask, render_template, send_from_directory, jsonify, request
from cardboard import cardboard, blueprints
import os
import json
# Load environment variables
FLASK_ENV = os.environ.get("FLASK_ENV", default="production")
VITE_MANIFEST = os.environ.get("VITE_MANIFEST", default="./test_ui/dist/.vite/manifest.json")
# If development, serve static resources from the ui src, otherwise serve from ui dist
if FLASK_ENV == "development":
app = Flask(__name__, template_folder="templates", static_folder="../test_ui/src")
else:
app = Flask(__name__, template_folder="templates", static_folder="../test_ui/dist")
# Load the Vite manifest
manifest_file = "./test_ui/dist/.vite/manifest.json"
with open(manifest_file, "r") as f:
manifest = json.load(f)
# Register cardboard blueprint routes
app.register_blueprint(blueprints.cardboard_blueprint)
@app.route("/")
def index():
"""
Serve the index.html template, pass it the development mode and the server url
:return: rendered index.html template
"""
development = FLASK_ENV == "development"
cardboard_server="http://127.0.0.1:5000"
return render_template("index.html", development=development, cardboard_server=cardboard_server)
@app.route('/src/<path:file>')
def serve_src(file):
"""
Serve the Vite .jsx or .css assets defined in the Vite manifest.
This will be used only in production mode. In development, the assets get served by the Vite dev server.
:param file:
:return:
"""
global manifest
path = request.path
if path.startswith("/"):
path = path[1:]
if path.endswith(".css"):
key = path.replace(".css", ".jsx")
if key not in manifest:
return jsonify({"Error": f"Manifest entry not found: {key}"}), 404
if 'css' not in manifest[key]:
return jsonify({"Error": f"No css for manifest entry {key}"}), 404
css = manifest[key]['css']
if len(css) == 0:
return jsonify({"Error": f"CSS list for manifest entry {key} is empty"}), 404
f = css[0]
else:
if path not in manifest:
return jsonify({"Error": f"File not found: {path}"}), 404
f = manifest[f'{path}']['file']
return send_from_directory(app.static_folder, f)
if __name__ == "__main__":
print(f"Hello cardboard")
with open("./cards.json") as f:
board_json = json.load(f)
cardboard.configure_board(data=board_json)
app.run(host="127.0.0.1", port=5000, debug=True)
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hello, Cardboard</title>
</head>
<body style="width: 100vw; height: 100vh;">
<!-- React container, Cardboard components well be rendered here -->
<div id="root" style="width: 100%; height: 100%;"></div>
<!-- Load the template data passed from the Flask server -->
<script>
const cardboard_server = "{{cardboard_server}}"
const development = "{{development}}"
console.log("cardboard_server=" + cardboard_server)
console.log("development=" + development)
</script>
<!-- Refer to Vite Backend Integration documentation: -->
<!-- https://vite.dev/guide/backend-integration.html -->
{% if development %}
<!-- If development mode, setup proxying to the Vite dev server. -->
<!-- Make sure the Vite dev server is running on port 5173 -->
<script type="module">
console.log("DEV MODE!")
import RefreshRuntime from 'http://localhost:5173/@react-refresh'
RefreshRuntime.injectIntoGlobalHook(window)
window.$RefreshReg$ = () => {}
window.$RefreshSig$ = () => (type) => type
window.__vite_plugin_react_preamble_installed__ = true
</script>
<script type="module" src="http://localhost:5173/@vite/client"></script>
<script type="module" src="http://localhost:5173/src/main.jsx"></script>
{% else %}
<!-- If production mode, we serve the compiled assets from the flask server -->
<!-- Vite dev server does not need to be running -->
<script type="module" crossorigin src="/src/main.jsx"></script>
<link rel="stylesheet" crossorigin href="/src/main.css">
{% endif %}
</body>
</html>
main.jsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { Board } from 'cardboard-ui'
import 'cardboard-ui/dist/style.css'
// Get the root div by Id and render the cardboard React component into it.
// Pass the cardboard_server template parameter (from the Flask server) to the Board component.
createRoot(document.getElementById('root')).render(
<StrictMode>
<div className="flex flex-col">
<Board cardboard_server={cardboard_server} />
</div>
</StrictMode>,
)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file cardboard_server-0.1.1.tar.gz
.
File metadata
- Download URL: cardboard_server-0.1.1.tar.gz
- Upload date:
- Size: 14.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1c07dd35d863131d0d60be24825e5a70404504f2e2753947be9dab9384ff1064 |
|
MD5 | 827b8429a50f9ff82d97b0800852e1d5 |
|
BLAKE2b-256 | 943909be0e6989d9adb14c5e8fb511323b29caff81b0d70c413bd20d8035111b |
File details
Details for the file cardboard_server-0.1.1-py3-none-any.whl
.
File metadata
- Download URL: cardboard_server-0.1.1-py3-none-any.whl
- Upload date:
- Size: 12.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 925aebda5a38e93a59bf07c9ca261165100b33dc7414daeb8a0394d5b4ebeafe |
|
MD5 | 2704c465b741fbe7092a03d584f98897 |
|
BLAKE2b-256 | 3d021e7788fda2890716c74f7c5e5e457b721f87cf1c6bb088ad3176755c49ac |