blueprint-modular 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- blueprint_modular-0.1.1/PKG-INFO +179 -0
- blueprint_modular-0.1.1/README.md +156 -0
- blueprint_modular-0.1.1/blueprint_modular.egg-info/PKG-INFO +179 -0
- blueprint_modular-0.1.1/blueprint_modular.egg-info/SOURCES.txt +10 -0
- blueprint_modular-0.1.1/blueprint_modular.egg-info/dependency_links.txt +1 -0
- blueprint_modular-0.1.1/blueprint_modular.egg-info/entry_points.txt +2 -0
- blueprint_modular-0.1.1/blueprint_modular.egg-info/requires.txt +5 -0
- blueprint_modular-0.1.1/blueprint_modular.egg-info/top_level.txt +1 -0
- blueprint_modular-0.1.1/bpm/__init__.py +234 -0
- blueprint_modular-0.1.1/bpm/cli.py +245 -0
- blueprint_modular-0.1.1/pyproject.toml +37 -0
- blueprint_modular-0.1.1/setup.cfg +4 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: blueprint-modular
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Briques Python prêtes à l'emploi pour vos interfaces de données
|
|
5
|
+
Author-email: Rémi <contact@blueprint-modular.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://blueprint-modular.com
|
|
8
|
+
Project-URL: Documentation, https://docs.blueprint-modular.com
|
|
9
|
+
Keywords: dashboard,ui,framework,python,data
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
21
|
+
Requires-Dist: black; extra == "dev"
|
|
22
|
+
Requires-Dist: ruff; extra == "dev"
|
|
23
|
+
|
|
24
|
+
# Blueprint Modular
|
|
25
|
+
|
|
26
|
+
**Briques prêtes à l'emploi. Vous écrivez la logique.**
|
|
27
|
+
|
|
28
|
+
Framework Python pour créer des interfaces de données sans HTML ni JS.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install blueprint-modular
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Utilisation rapide
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
bpm --version
|
|
40
|
+
bpm init --name mon-app
|
|
41
|
+
cd mon-app
|
|
42
|
+
bpm run app.py
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
En Python :
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
import bpm
|
|
49
|
+
|
|
50
|
+
bpm.title("Mon tableau de bord")
|
|
51
|
+
bpm.metric("CA", 142500, delta=3200)
|
|
52
|
+
bpm.table(df)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Documentation
|
|
56
|
+
|
|
57
|
+
https://docs.blueprint-modular.com
|
|
58
|
+
|
|
59
|
+
## Statut
|
|
60
|
+
|
|
61
|
+
Blueprint Modular est en développement actif (alpha).
|
|
62
|
+
Certaines fonctionnalités sont en cours d'implémentation.
|
|
63
|
+
|
|
64
|
+
## Licence
|
|
65
|
+
|
|
66
|
+
MIT
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
# Site de documentation (ce dépôt)
|
|
71
|
+
|
|
72
|
+
Site statique de documentation **Blueprint Modular** (BPM) : landing, composants et référence API. Projet isolé pour être hébergé sur un **domaine dédié** (OVH + VPS).
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Projet portable — une seule copie
|
|
77
|
+
|
|
78
|
+
**Pour reprendre le projet Blueprint Modular dans une autre instance Cursor :** copiez tout le dossier **`blueprint-modular`** (ce dossier). Un seul copier-coller suffit.
|
|
79
|
+
|
|
80
|
+
Ce dossier contient tout ce qui est lié au site Blueprint Modular :
|
|
81
|
+
- Les **3 pages du site** (accueil, Components, API Reference) pour déploiement sur un domaine à la racine
|
|
82
|
+
- Les **versions pour /api/docs** (sous-dossier `api-docs/`) pour intégration dans MyPortfolio
|
|
83
|
+
- Les **logos** (Logo BPM.png, Logo-BPM-nom.jpg, Logo-BPM-seul.png)
|
|
84
|
+
- Les **scripts de déploiement** (PowerShell et Bash) et le **guide** (DEPLOIEMENT_DOMAINE.md)
|
|
85
|
+
- Les **exemples Nginx** (HTTP et HTTPS)
|
|
86
|
+
|
|
87
|
+
Aucune dépendance au reste du repo : vous pouvez ouvrir uniquement ce dossier dans Cursor et tout éditer, prévisualiser et déployer.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Structure du projet (frontend / backend)
|
|
92
|
+
|
|
93
|
+
| Dossier / fichier | Rôle |
|
|
94
|
+
|-------------------|------|
|
|
95
|
+
| **frontend/** | Tout le code client (UI, doc, composants). |
|
|
96
|
+
| **frontend/bpm/** | Composants React BPM + composants doc (DocNav, DocSidebar, DocLayout, CodeBlock). |
|
|
97
|
+
| **frontend/doc-app/** | Site doc en React (recommandé). Build : `cd frontend/doc-app && npm run build` → `dist/`. |
|
|
98
|
+
| **frontend/static/** | Site doc HTML statique : index.html, doc.css, get-started/, api-reference/, deploy/, knowledge-base/, cheat-sheet, components, reference. |
|
|
99
|
+
| **frontend/api-docs/** | Pages pour l'URL /api/docs (MyPortfolio). |
|
|
100
|
+
| **backend/** | Réservé au code serveur (API, etc.). Aucun backend pour l'instant — voir backend/README.md. |
|
|
101
|
+
| **deploy/** | Scripts de déploiement : setup.sh, update.sh, nginx.conf. |
|
|
102
|
+
| **Logo BPM.png**, **Logo-BPM-*** | Logos (racine). |
|
|
103
|
+
| **app.py** | Exemple d’app BPM : <code>bpm run app.py</code>. |
|
|
104
|
+
| **deploy_blueprint_modular.ps1** | Déploie **frontend/static/** + Logo vers le VPS. |
|
|
105
|
+
| **DEPLOIEMENT_DOMAINE.md** | Guide : DNS, Nginx, Certbot. |
|
|
106
|
+
|
|
107
|
+
*(Ancienne liste détaillée ci-dessous.)*
|
|
108
|
+
|
|
109
|
+
| Fichier / dossier | Rôle |
|
|
110
|
+
|------------------|------|
|
|
111
|
+
| **index.html** (dans frontend/static/) | **Page d'accueil doc** (headline BPM, installation rapide, liens Get started / API Reference / Deploy, What's new) |
|
|
112
|
+
| **doc.css** | Feuille de style commune du site doc (thème BPM, accent #d4af37, dark mode) |
|
|
113
|
+
| **get-started/** | Installation, Fundamentals, First app |
|
|
114
|
+
| **api-reference/** | Text, Data, Metrics, Charts, Inputs, Layout, Panels, Media, Status, Chat, Config |
|
|
115
|
+
| **bpm/** | Composants React BPM (Button, Panel, Table, etc.) + **composants doc** : DocNav, DocSidebar, DocLayout, CodeBlock. |
|
|
116
|
+
| **doc-app/** | **Site doc en React** : utilise uniquement les composants BPM. Build : `cd doc-app && npm run build` → `dist/`. |
|
|
117
|
+
| **app.py** | Exemple d’app BPM : <code>bpm run app.py</code> (voir Installation). |
|
|
118
|
+
| **deploy/** | **Scripts de déploiement** : setup.sh, update.sh, nginx.conf, CHECKLIST.md — voir deploy/README.md. |
|
|
119
|
+
| **.env.example** | Exemple pour .env sur le serveur (ENVIRONMENT=production). |
|
|
120
|
+
| **knowledge-base/** | FAQ, Troubleshooting |
|
|
121
|
+
| **cheat-sheet.html** | Cheat sheet (toutes les fonctions BPM) |
|
|
122
|
+
| **components.html** | Ancienne page catalogue composants (conservée si besoin) |
|
|
123
|
+
| **reference.html** | Ancienne référence API (conservée si besoin) |
|
|
124
|
+
| **Logo BPM.png** | Logo Blueprint Modular (accueil domaine) |
|
|
125
|
+
| **Logo-BPM-nom.jpg** | Logo avec nom (landing /api/docs) |
|
|
126
|
+
| **Logo-BPM-seul.png** | Logo seul (nav des pages /api/docs) |
|
|
127
|
+
| **api-docs/** | Versions des 3 pages pour l’URL /api/docs (voir api-docs/README.txt pour copier vers frontend/public) |
|
|
128
|
+
| **documentation/** | README indiquant que la doc est en HTML statique à la racine (voir ci-dessous). |
|
|
129
|
+
| **DEPLOIEMENT_DOMAINE.md** | Guide complet : DNS, Nginx, Certbot, déploiement |
|
|
130
|
+
| **nginx-bpm-domain.conf.example** | Exemple de vhost Nginx (HTTP seul, pour Certbot) |
|
|
131
|
+
| **nginx-bpm-domain-https.conf.example** | Exemple de vhost Nginx HTTPS complet (après Certbot) |
|
|
132
|
+
| **deploy_blueprint_modular.ps1** | Script PowerShell : copie des fichiers statiques (index, components, reference, logos) vers le VPS. |
|
|
133
|
+
| **deploy_blueprint_modular_full.ps1** | Script PowerShell : déploiement complet (app + static) via archive + SSH (puis `deploy/update.sh` sur le serveur). |
|
|
134
|
+
| **deploy_blueprint_modular.sh** | Script Bash (Linux / WSL) équivalent (fichiers statiques). |
|
|
135
|
+
|
|
136
|
+
Les liens internes du site à la racine utilisent `/`, `/components` et `/reference`. Les fichiers dans `api-docs/` utilisent `/api/docs`, `/api/docs/components`, `/api/docs/reference`.
|
|
137
|
+
|
|
138
|
+
### Fichiers pour le déploiement
|
|
139
|
+
|
|
140
|
+
Le script **deploy_blueprint_modular.ps1** déploie **frontend/static/** et **Logo BPM.png** (Ã la racine). **favicon.ico** Ã la racine est optionnel.
|
|
141
|
+
|
|
142
|
+
## Prévisualisation en local
|
|
143
|
+
|
|
144
|
+
**Site doc statique (HTML)** — depuis le dossier des fichiers statiques :
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
cd frontend/static && python -m http.server 8080
|
|
148
|
+
# Puis ouvrir http://localhost:8080
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Site doc (React + BPM)** — recommandé :
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
cd frontend/doc-app && npm install && cp "../../Logo BPM.png" "public/Logo BPM.png" && npm run dev
|
|
155
|
+
# Puis ouvrir l’URL affichée (http://localhost:5173)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Déploiement — www.blueprint-modular.com (fichiers statiques)
|
|
159
|
+
|
|
160
|
+
Le site doc est construit avec les **composants BPM** (React) dans **frontend/doc-app/**.
|
|
161
|
+
|
|
162
|
+
1. En local : `cd frontend/doc-app && npm run build` → les fichiers sont dans **frontend/doc-app/dist/**.
|
|
163
|
+
2. Déployer **frontend/doc-app/dist/** vers le VPS, ou utiliser **deploy_blueprint_modular.ps1** (depuis Windows) pour le site **HTML statique** (**frontend/static/**), ou **deploy/deploy-from-git.sh** (sur le serveur, après clone du repo — voir **deploy/README.md**).
|
|
164
|
+
3. Nginx : servir les fichiers statiques (voir **deploy/nginx.conf** : `root` + `try_files`).
|
|
165
|
+
|
|
166
|
+
Repo : [github.com/remigit55/blueprint-modular](https://github.com/remigit55/blueprint-modular).
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Déploiement site statique (ancien / alternatif)
|
|
171
|
+
|
|
172
|
+
Pour déployer uniquement les **fichiers HTML statiques** :
|
|
173
|
+
|
|
174
|
+
1. Lire **[DEPLOIEMENT_DOMAINE.md](./DEPLOIEMENT_DOMAINE.md)**.
|
|
175
|
+
2. Configurer le DNS, créer le vhost Nginx (partir de **nginx-bpm-domain.conf.example**), Certbot, puis déployer les fichiers avec **deploy_blueprint_modular.ps1** ou **deploy_blueprint_modular.sh** (variables SERVER_IP, SSH_KEY à adapter).
|
|
176
|
+
|
|
177
|
+
## Projet isolé (Cursor / VS Code)
|
|
178
|
+
|
|
179
|
+
Pour travailler uniquement sur Blueprint Modular sans charger tout le repo MyPortfolio : **Fichier → Ouvrir le dossier** → sélectionner le dossier **`blueprint-modular`** (et non la racine du repo). Tout le nécessaire pour éditer les HTML, prévisualiser et déployer est ici ; aucune dépendance Node ou Python n'est requise pour le site statique. Voir aussi la section **Projet portable** en tête de ce README.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Blueprint Modular
|
|
2
|
+
|
|
3
|
+
**Briques prêtes à l'emploi. Vous écrivez la logique.**
|
|
4
|
+
|
|
5
|
+
Framework Python pour créer des interfaces de données sans HTML ni JS.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install blueprint-modular
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Utilisation rapide
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bpm --version
|
|
17
|
+
bpm init --name mon-app
|
|
18
|
+
cd mon-app
|
|
19
|
+
bpm run app.py
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
En Python :
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
import bpm
|
|
26
|
+
|
|
27
|
+
bpm.title("Mon tableau de bord")
|
|
28
|
+
bpm.metric("CA", 142500, delta=3200)
|
|
29
|
+
bpm.table(df)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Documentation
|
|
33
|
+
|
|
34
|
+
https://docs.blueprint-modular.com
|
|
35
|
+
|
|
36
|
+
## Statut
|
|
37
|
+
|
|
38
|
+
Blueprint Modular est en développement actif (alpha).
|
|
39
|
+
Certaines fonctionnalités sont en cours d'implémentation.
|
|
40
|
+
|
|
41
|
+
## Licence
|
|
42
|
+
|
|
43
|
+
MIT
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
# Site de documentation (ce dépôt)
|
|
48
|
+
|
|
49
|
+
Site statique de documentation **Blueprint Modular** (BPM) : landing, composants et référence API. Projet isolé pour être hébergé sur un **domaine dédié** (OVH + VPS).
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Projet portable — une seule copie
|
|
54
|
+
|
|
55
|
+
**Pour reprendre le projet Blueprint Modular dans une autre instance Cursor :** copiez tout le dossier **`blueprint-modular`** (ce dossier). Un seul copier-coller suffit.
|
|
56
|
+
|
|
57
|
+
Ce dossier contient tout ce qui est lié au site Blueprint Modular :
|
|
58
|
+
- Les **3 pages du site** (accueil, Components, API Reference) pour déploiement sur un domaine à la racine
|
|
59
|
+
- Les **versions pour /api/docs** (sous-dossier `api-docs/`) pour intégration dans MyPortfolio
|
|
60
|
+
- Les **logos** (Logo BPM.png, Logo-BPM-nom.jpg, Logo-BPM-seul.png)
|
|
61
|
+
- Les **scripts de déploiement** (PowerShell et Bash) et le **guide** (DEPLOIEMENT_DOMAINE.md)
|
|
62
|
+
- Les **exemples Nginx** (HTTP et HTTPS)
|
|
63
|
+
|
|
64
|
+
Aucune dépendance au reste du repo : vous pouvez ouvrir uniquement ce dossier dans Cursor et tout éditer, prévisualiser et déployer.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Structure du projet (frontend / backend)
|
|
69
|
+
|
|
70
|
+
| Dossier / fichier | Rôle |
|
|
71
|
+
|-------------------|------|
|
|
72
|
+
| **frontend/** | Tout le code client (UI, doc, composants). |
|
|
73
|
+
| **frontend/bpm/** | Composants React BPM + composants doc (DocNav, DocSidebar, DocLayout, CodeBlock). |
|
|
74
|
+
| **frontend/doc-app/** | Site doc en React (recommandé). Build : `cd frontend/doc-app && npm run build` → `dist/`. |
|
|
75
|
+
| **frontend/static/** | Site doc HTML statique : index.html, doc.css, get-started/, api-reference/, deploy/, knowledge-base/, cheat-sheet, components, reference. |
|
|
76
|
+
| **frontend/api-docs/** | Pages pour l'URL /api/docs (MyPortfolio). |
|
|
77
|
+
| **backend/** | Réservé au code serveur (API, etc.). Aucun backend pour l'instant — voir backend/README.md. |
|
|
78
|
+
| **deploy/** | Scripts de déploiement : setup.sh, update.sh, nginx.conf. |
|
|
79
|
+
| **Logo BPM.png**, **Logo-BPM-*** | Logos (racine). |
|
|
80
|
+
| **app.py** | Exemple d’app BPM : <code>bpm run app.py</code>. |
|
|
81
|
+
| **deploy_blueprint_modular.ps1** | Déploie **frontend/static/** + Logo vers le VPS. |
|
|
82
|
+
| **DEPLOIEMENT_DOMAINE.md** | Guide : DNS, Nginx, Certbot. |
|
|
83
|
+
|
|
84
|
+
*(Ancienne liste détaillée ci-dessous.)*
|
|
85
|
+
|
|
86
|
+
| Fichier / dossier | Rôle |
|
|
87
|
+
|------------------|------|
|
|
88
|
+
| **index.html** (dans frontend/static/) | **Page d'accueil doc** (headline BPM, installation rapide, liens Get started / API Reference / Deploy, What's new) |
|
|
89
|
+
| **doc.css** | Feuille de style commune du site doc (thème BPM, accent #d4af37, dark mode) |
|
|
90
|
+
| **get-started/** | Installation, Fundamentals, First app |
|
|
91
|
+
| **api-reference/** | Text, Data, Metrics, Charts, Inputs, Layout, Panels, Media, Status, Chat, Config |
|
|
92
|
+
| **bpm/** | Composants React BPM (Button, Panel, Table, etc.) + **composants doc** : DocNav, DocSidebar, DocLayout, CodeBlock. |
|
|
93
|
+
| **doc-app/** | **Site doc en React** : utilise uniquement les composants BPM. Build : `cd doc-app && npm run build` → `dist/`. |
|
|
94
|
+
| **app.py** | Exemple d’app BPM : <code>bpm run app.py</code> (voir Installation). |
|
|
95
|
+
| **deploy/** | **Scripts de déploiement** : setup.sh, update.sh, nginx.conf, CHECKLIST.md — voir deploy/README.md. |
|
|
96
|
+
| **.env.example** | Exemple pour .env sur le serveur (ENVIRONMENT=production). |
|
|
97
|
+
| **knowledge-base/** | FAQ, Troubleshooting |
|
|
98
|
+
| **cheat-sheet.html** | Cheat sheet (toutes les fonctions BPM) |
|
|
99
|
+
| **components.html** | Ancienne page catalogue composants (conservée si besoin) |
|
|
100
|
+
| **reference.html** | Ancienne référence API (conservée si besoin) |
|
|
101
|
+
| **Logo BPM.png** | Logo Blueprint Modular (accueil domaine) |
|
|
102
|
+
| **Logo-BPM-nom.jpg** | Logo avec nom (landing /api/docs) |
|
|
103
|
+
| **Logo-BPM-seul.png** | Logo seul (nav des pages /api/docs) |
|
|
104
|
+
| **api-docs/** | Versions des 3 pages pour l’URL /api/docs (voir api-docs/README.txt pour copier vers frontend/public) |
|
|
105
|
+
| **documentation/** | README indiquant que la doc est en HTML statique à la racine (voir ci-dessous). |
|
|
106
|
+
| **DEPLOIEMENT_DOMAINE.md** | Guide complet : DNS, Nginx, Certbot, déploiement |
|
|
107
|
+
| **nginx-bpm-domain.conf.example** | Exemple de vhost Nginx (HTTP seul, pour Certbot) |
|
|
108
|
+
| **nginx-bpm-domain-https.conf.example** | Exemple de vhost Nginx HTTPS complet (après Certbot) |
|
|
109
|
+
| **deploy_blueprint_modular.ps1** | Script PowerShell : copie des fichiers statiques (index, components, reference, logos) vers le VPS. |
|
|
110
|
+
| **deploy_blueprint_modular_full.ps1** | Script PowerShell : déploiement complet (app + static) via archive + SSH (puis `deploy/update.sh` sur le serveur). |
|
|
111
|
+
| **deploy_blueprint_modular.sh** | Script Bash (Linux / WSL) équivalent (fichiers statiques). |
|
|
112
|
+
|
|
113
|
+
Les liens internes du site à la racine utilisent `/`, `/components` et `/reference`. Les fichiers dans `api-docs/` utilisent `/api/docs`, `/api/docs/components`, `/api/docs/reference`.
|
|
114
|
+
|
|
115
|
+
### Fichiers pour le déploiement
|
|
116
|
+
|
|
117
|
+
Le script **deploy_blueprint_modular.ps1** déploie **frontend/static/** et **Logo BPM.png** (Ã la racine). **favicon.ico** Ã la racine est optionnel.
|
|
118
|
+
|
|
119
|
+
## Prévisualisation en local
|
|
120
|
+
|
|
121
|
+
**Site doc statique (HTML)** — depuis le dossier des fichiers statiques :
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
cd frontend/static && python -m http.server 8080
|
|
125
|
+
# Puis ouvrir http://localhost:8080
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Site doc (React + BPM)** — recommandé :
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
cd frontend/doc-app && npm install && cp "../../Logo BPM.png" "public/Logo BPM.png" && npm run dev
|
|
132
|
+
# Puis ouvrir l’URL affichée (http://localhost:5173)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Déploiement — www.blueprint-modular.com (fichiers statiques)
|
|
136
|
+
|
|
137
|
+
Le site doc est construit avec les **composants BPM** (React) dans **frontend/doc-app/**.
|
|
138
|
+
|
|
139
|
+
1. En local : `cd frontend/doc-app && npm run build` → les fichiers sont dans **frontend/doc-app/dist/**.
|
|
140
|
+
2. Déployer **frontend/doc-app/dist/** vers le VPS, ou utiliser **deploy_blueprint_modular.ps1** (depuis Windows) pour le site **HTML statique** (**frontend/static/**), ou **deploy/deploy-from-git.sh** (sur le serveur, après clone du repo — voir **deploy/README.md**).
|
|
141
|
+
3. Nginx : servir les fichiers statiques (voir **deploy/nginx.conf** : `root` + `try_files`).
|
|
142
|
+
|
|
143
|
+
Repo : [github.com/remigit55/blueprint-modular](https://github.com/remigit55/blueprint-modular).
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Déploiement site statique (ancien / alternatif)
|
|
148
|
+
|
|
149
|
+
Pour déployer uniquement les **fichiers HTML statiques** :
|
|
150
|
+
|
|
151
|
+
1. Lire **[DEPLOIEMENT_DOMAINE.md](./DEPLOIEMENT_DOMAINE.md)**.
|
|
152
|
+
2. Configurer le DNS, créer le vhost Nginx (partir de **nginx-bpm-domain.conf.example**), Certbot, puis déployer les fichiers avec **deploy_blueprint_modular.ps1** ou **deploy_blueprint_modular.sh** (variables SERVER_IP, SSH_KEY à adapter).
|
|
153
|
+
|
|
154
|
+
## Projet isolé (Cursor / VS Code)
|
|
155
|
+
|
|
156
|
+
Pour travailler uniquement sur Blueprint Modular sans charger tout le repo MyPortfolio : **Fichier → Ouvrir le dossier** → sélectionner le dossier **`blueprint-modular`** (et non la racine du repo). Tout le nécessaire pour éditer les HTML, prévisualiser et déployer est ici ; aucune dépendance Node ou Python n'est requise pour le site statique. Voir aussi la section **Projet portable** en tête de ce README.
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: blueprint-modular
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Briques Python prêtes à l'emploi pour vos interfaces de données
|
|
5
|
+
Author-email: Rémi <contact@blueprint-modular.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://blueprint-modular.com
|
|
8
|
+
Project-URL: Documentation, https://docs.blueprint-modular.com
|
|
9
|
+
Keywords: dashboard,ui,framework,python,data
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
21
|
+
Requires-Dist: black; extra == "dev"
|
|
22
|
+
Requires-Dist: ruff; extra == "dev"
|
|
23
|
+
|
|
24
|
+
# Blueprint Modular
|
|
25
|
+
|
|
26
|
+
**Briques prêtes à l'emploi. Vous écrivez la logique.**
|
|
27
|
+
|
|
28
|
+
Framework Python pour créer des interfaces de données sans HTML ni JS.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install blueprint-modular
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Utilisation rapide
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
bpm --version
|
|
40
|
+
bpm init --name mon-app
|
|
41
|
+
cd mon-app
|
|
42
|
+
bpm run app.py
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
En Python :
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
import bpm
|
|
49
|
+
|
|
50
|
+
bpm.title("Mon tableau de bord")
|
|
51
|
+
bpm.metric("CA", 142500, delta=3200)
|
|
52
|
+
bpm.table(df)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Documentation
|
|
56
|
+
|
|
57
|
+
https://docs.blueprint-modular.com
|
|
58
|
+
|
|
59
|
+
## Statut
|
|
60
|
+
|
|
61
|
+
Blueprint Modular est en développement actif (alpha).
|
|
62
|
+
Certaines fonctionnalités sont en cours d'implémentation.
|
|
63
|
+
|
|
64
|
+
## Licence
|
|
65
|
+
|
|
66
|
+
MIT
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
# Site de documentation (ce dépôt)
|
|
71
|
+
|
|
72
|
+
Site statique de documentation **Blueprint Modular** (BPM) : landing, composants et référence API. Projet isolé pour être hébergé sur un **domaine dédié** (OVH + VPS).
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Projet portable — une seule copie
|
|
77
|
+
|
|
78
|
+
**Pour reprendre le projet Blueprint Modular dans une autre instance Cursor :** copiez tout le dossier **`blueprint-modular`** (ce dossier). Un seul copier-coller suffit.
|
|
79
|
+
|
|
80
|
+
Ce dossier contient tout ce qui est lié au site Blueprint Modular :
|
|
81
|
+
- Les **3 pages du site** (accueil, Components, API Reference) pour déploiement sur un domaine à la racine
|
|
82
|
+
- Les **versions pour /api/docs** (sous-dossier `api-docs/`) pour intégration dans MyPortfolio
|
|
83
|
+
- Les **logos** (Logo BPM.png, Logo-BPM-nom.jpg, Logo-BPM-seul.png)
|
|
84
|
+
- Les **scripts de déploiement** (PowerShell et Bash) et le **guide** (DEPLOIEMENT_DOMAINE.md)
|
|
85
|
+
- Les **exemples Nginx** (HTTP et HTTPS)
|
|
86
|
+
|
|
87
|
+
Aucune dépendance au reste du repo : vous pouvez ouvrir uniquement ce dossier dans Cursor et tout éditer, prévisualiser et déployer.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Structure du projet (frontend / backend)
|
|
92
|
+
|
|
93
|
+
| Dossier / fichier | Rôle |
|
|
94
|
+
|-------------------|------|
|
|
95
|
+
| **frontend/** | Tout le code client (UI, doc, composants). |
|
|
96
|
+
| **frontend/bpm/** | Composants React BPM + composants doc (DocNav, DocSidebar, DocLayout, CodeBlock). |
|
|
97
|
+
| **frontend/doc-app/** | Site doc en React (recommandé). Build : `cd frontend/doc-app && npm run build` → `dist/`. |
|
|
98
|
+
| **frontend/static/** | Site doc HTML statique : index.html, doc.css, get-started/, api-reference/, deploy/, knowledge-base/, cheat-sheet, components, reference. |
|
|
99
|
+
| **frontend/api-docs/** | Pages pour l'URL /api/docs (MyPortfolio). |
|
|
100
|
+
| **backend/** | Réservé au code serveur (API, etc.). Aucun backend pour l'instant — voir backend/README.md. |
|
|
101
|
+
| **deploy/** | Scripts de déploiement : setup.sh, update.sh, nginx.conf. |
|
|
102
|
+
| **Logo BPM.png**, **Logo-BPM-*** | Logos (racine). |
|
|
103
|
+
| **app.py** | Exemple d’app BPM : <code>bpm run app.py</code>. |
|
|
104
|
+
| **deploy_blueprint_modular.ps1** | Déploie **frontend/static/** + Logo vers le VPS. |
|
|
105
|
+
| **DEPLOIEMENT_DOMAINE.md** | Guide : DNS, Nginx, Certbot. |
|
|
106
|
+
|
|
107
|
+
*(Ancienne liste détaillée ci-dessous.)*
|
|
108
|
+
|
|
109
|
+
| Fichier / dossier | Rôle |
|
|
110
|
+
|------------------|------|
|
|
111
|
+
| **index.html** (dans frontend/static/) | **Page d'accueil doc** (headline BPM, installation rapide, liens Get started / API Reference / Deploy, What's new) |
|
|
112
|
+
| **doc.css** | Feuille de style commune du site doc (thème BPM, accent #d4af37, dark mode) |
|
|
113
|
+
| **get-started/** | Installation, Fundamentals, First app |
|
|
114
|
+
| **api-reference/** | Text, Data, Metrics, Charts, Inputs, Layout, Panels, Media, Status, Chat, Config |
|
|
115
|
+
| **bpm/** | Composants React BPM (Button, Panel, Table, etc.) + **composants doc** : DocNav, DocSidebar, DocLayout, CodeBlock. |
|
|
116
|
+
| **doc-app/** | **Site doc en React** : utilise uniquement les composants BPM. Build : `cd doc-app && npm run build` → `dist/`. |
|
|
117
|
+
| **app.py** | Exemple d’app BPM : <code>bpm run app.py</code> (voir Installation). |
|
|
118
|
+
| **deploy/** | **Scripts de déploiement** : setup.sh, update.sh, nginx.conf, CHECKLIST.md — voir deploy/README.md. |
|
|
119
|
+
| **.env.example** | Exemple pour .env sur le serveur (ENVIRONMENT=production). |
|
|
120
|
+
| **knowledge-base/** | FAQ, Troubleshooting |
|
|
121
|
+
| **cheat-sheet.html** | Cheat sheet (toutes les fonctions BPM) |
|
|
122
|
+
| **components.html** | Ancienne page catalogue composants (conservée si besoin) |
|
|
123
|
+
| **reference.html** | Ancienne référence API (conservée si besoin) |
|
|
124
|
+
| **Logo BPM.png** | Logo Blueprint Modular (accueil domaine) |
|
|
125
|
+
| **Logo-BPM-nom.jpg** | Logo avec nom (landing /api/docs) |
|
|
126
|
+
| **Logo-BPM-seul.png** | Logo seul (nav des pages /api/docs) |
|
|
127
|
+
| **api-docs/** | Versions des 3 pages pour l’URL /api/docs (voir api-docs/README.txt pour copier vers frontend/public) |
|
|
128
|
+
| **documentation/** | README indiquant que la doc est en HTML statique à la racine (voir ci-dessous). |
|
|
129
|
+
| **DEPLOIEMENT_DOMAINE.md** | Guide complet : DNS, Nginx, Certbot, déploiement |
|
|
130
|
+
| **nginx-bpm-domain.conf.example** | Exemple de vhost Nginx (HTTP seul, pour Certbot) |
|
|
131
|
+
| **nginx-bpm-domain-https.conf.example** | Exemple de vhost Nginx HTTPS complet (après Certbot) |
|
|
132
|
+
| **deploy_blueprint_modular.ps1** | Script PowerShell : copie des fichiers statiques (index, components, reference, logos) vers le VPS. |
|
|
133
|
+
| **deploy_blueprint_modular_full.ps1** | Script PowerShell : déploiement complet (app + static) via archive + SSH (puis `deploy/update.sh` sur le serveur). |
|
|
134
|
+
| **deploy_blueprint_modular.sh** | Script Bash (Linux / WSL) équivalent (fichiers statiques). |
|
|
135
|
+
|
|
136
|
+
Les liens internes du site à la racine utilisent `/`, `/components` et `/reference`. Les fichiers dans `api-docs/` utilisent `/api/docs`, `/api/docs/components`, `/api/docs/reference`.
|
|
137
|
+
|
|
138
|
+
### Fichiers pour le déploiement
|
|
139
|
+
|
|
140
|
+
Le script **deploy_blueprint_modular.ps1** déploie **frontend/static/** et **Logo BPM.png** (Ã la racine). **favicon.ico** Ã la racine est optionnel.
|
|
141
|
+
|
|
142
|
+
## Prévisualisation en local
|
|
143
|
+
|
|
144
|
+
**Site doc statique (HTML)** — depuis le dossier des fichiers statiques :
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
cd frontend/static && python -m http.server 8080
|
|
148
|
+
# Puis ouvrir http://localhost:8080
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Site doc (React + BPM)** — recommandé :
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
cd frontend/doc-app && npm install && cp "../../Logo BPM.png" "public/Logo BPM.png" && npm run dev
|
|
155
|
+
# Puis ouvrir l’URL affichée (http://localhost:5173)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Déploiement — www.blueprint-modular.com (fichiers statiques)
|
|
159
|
+
|
|
160
|
+
Le site doc est construit avec les **composants BPM** (React) dans **frontend/doc-app/**.
|
|
161
|
+
|
|
162
|
+
1. En local : `cd frontend/doc-app && npm run build` → les fichiers sont dans **frontend/doc-app/dist/**.
|
|
163
|
+
2. Déployer **frontend/doc-app/dist/** vers le VPS, ou utiliser **deploy_blueprint_modular.ps1** (depuis Windows) pour le site **HTML statique** (**frontend/static/**), ou **deploy/deploy-from-git.sh** (sur le serveur, après clone du repo — voir **deploy/README.md**).
|
|
164
|
+
3. Nginx : servir les fichiers statiques (voir **deploy/nginx.conf** : `root` + `try_files`).
|
|
165
|
+
|
|
166
|
+
Repo : [github.com/remigit55/blueprint-modular](https://github.com/remigit55/blueprint-modular).
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Déploiement site statique (ancien / alternatif)
|
|
171
|
+
|
|
172
|
+
Pour déployer uniquement les **fichiers HTML statiques** :
|
|
173
|
+
|
|
174
|
+
1. Lire **[DEPLOIEMENT_DOMAINE.md](./DEPLOIEMENT_DOMAINE.md)**.
|
|
175
|
+
2. Configurer le DNS, créer le vhost Nginx (partir de **nginx-bpm-domain.conf.example**), Certbot, puis déployer les fichiers avec **deploy_blueprint_modular.ps1** ou **deploy_blueprint_modular.sh** (variables SERVER_IP, SSH_KEY à adapter).
|
|
176
|
+
|
|
177
|
+
## Projet isolé (Cursor / VS Code)
|
|
178
|
+
|
|
179
|
+
Pour travailler uniquement sur Blueprint Modular sans charger tout le repo MyPortfolio : **Fichier → Ouvrir le dossier** → sélectionner le dossier **`blueprint-modular`** (et non la racine du repo). Tout le nécessaire pour éditer les HTML, prévisualiser et déployer est ici ; aucune dépendance Node ou Python n'est requise pour le site statique. Voir aussi la section **Projet portable** en tête de ce README.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
blueprint_modular.egg-info/PKG-INFO
|
|
4
|
+
blueprint_modular.egg-info/SOURCES.txt
|
|
5
|
+
blueprint_modular.egg-info/dependency_links.txt
|
|
6
|
+
blueprint_modular.egg-info/entry_points.txt
|
|
7
|
+
blueprint_modular.egg-info/requires.txt
|
|
8
|
+
blueprint_modular.egg-info/top_level.txt
|
|
9
|
+
bpm/__init__.py
|
|
10
|
+
bpm/cli.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bpm
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BPM — Blueprint Modular runtime.
|
|
3
|
+
Registry $ (refs réactives) et @ (inscription / décorateurs).
|
|
4
|
+
APIs composants (title, button, write, metric, etc.) pour bpm run app.py.
|
|
5
|
+
"""
|
|
6
|
+
__version__ = "0.1.1"
|
|
7
|
+
|
|
8
|
+
from typing import Any, Callable, Optional, TypeVar
|
|
9
|
+
|
|
10
|
+
# --- Rendu : nœuds collectés pendant l'exécution du script ---
|
|
11
|
+
_current_nodes: list[dict[str, Any]] = []
|
|
12
|
+
_rerun_requested = False
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class SessionState(dict):
|
|
16
|
+
"""État persisté entre les runs (équivalent session_state)."""
|
|
17
|
+
|
|
18
|
+
def __getattr__(self, key: str) -> Any:
|
|
19
|
+
try:
|
|
20
|
+
return self[key]
|
|
21
|
+
except KeyError:
|
|
22
|
+
raise AttributeError(key)
|
|
23
|
+
|
|
24
|
+
def __setattr__(self, key: str, value: Any) -> None:
|
|
25
|
+
self[key] = value
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# État de session partagé (une session par processus pour l'instant)
|
|
29
|
+
session_state = SessionState()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _node(typ: str, **props: Any) -> None:
|
|
33
|
+
_current_nodes.append({"type": typ, "props": props})
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_current_nodes() -> list[dict[str, Any]]:
|
|
37
|
+
"""Retourne la liste des nœuds du run en cours (usage interne serveur)."""
|
|
38
|
+
return list(_current_nodes)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def reset_current_nodes() -> None:
|
|
42
|
+
"""Réinitialise la liste des nœuds (usage interne serveur)."""
|
|
43
|
+
global _current_nodes, _rerun_requested
|
|
44
|
+
_current_nodes = []
|
|
45
|
+
_rerun_requested = False
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def rerun() -> None:
|
|
49
|
+
"""Demande un re-run du script (après interaction)."""
|
|
50
|
+
global _rerun_requested
|
|
51
|
+
_rerun_requested = True
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def rerun_requested() -> bool:
|
|
55
|
+
"""Indique si rerun() a été appelé (usage interne serveur)."""
|
|
56
|
+
return _rerun_requested
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# --- APIs composants (enregistrent un nœud de rendu) ---
|
|
60
|
+
def title(text: str, level: int = 1) -> None:
|
|
61
|
+
_node("title", text=text, level=level)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def write(text: str) -> None:
|
|
65
|
+
_node("write", text=str(text))
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def markdown(text: str) -> None:
|
|
69
|
+
_node("markdown", text=text)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def button(label: str, key: Optional[str] = None) -> bool:
|
|
73
|
+
"""Retourne True si le bouton a été cliqué (côté serveur, après re-run)."""
|
|
74
|
+
_node("button", label=label, key=key or f"btn_{len(_current_nodes)}")
|
|
75
|
+
return session_state.get(f"_clicked_{key or f'btn_{len(_current_nodes)-1}'}") is True
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def metric(label: str, value: Any, delta: Optional[Any] = None) -> None:
|
|
79
|
+
_node("metric", label=str(label), value=value, delta=delta)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def table(data: Any) -> None:
|
|
83
|
+
"""Accepte une liste de dicts ou un objet avec .to_dict('records')."""
|
|
84
|
+
if hasattr(data, "to_dict"):
|
|
85
|
+
rows = data.to_dict("records")
|
|
86
|
+
elif isinstance(data, list) and data and isinstance(data[0], dict):
|
|
87
|
+
rows = data
|
|
88
|
+
else:
|
|
89
|
+
rows = list(data) if data else []
|
|
90
|
+
_node("table", rows=rows)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def header(text: str) -> None:
|
|
94
|
+
_node("header", text=text)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def subheader(text: str) -> None:
|
|
98
|
+
_node("subheader", text=text)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def caption(text: str) -> None:
|
|
102
|
+
_node("caption", text=text)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def code(code: str, language: str = "python") -> None:
|
|
106
|
+
_node("code", code=code, language=language)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def divider() -> None:
|
|
110
|
+
_node("divider")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def toggle(label: str, value: bool = False, key: Optional[str] = None) -> bool:
|
|
114
|
+
_node("toggle", label=label, value=value, key=key or f"toggle_{len(_current_nodes)}")
|
|
115
|
+
return session_state.get(f"_toggle_{key or f'toggle_{len(_current_nodes)-1}'}", value)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def panel(title_text: str, body: str = "", variant: str = "info") -> None:
|
|
119
|
+
_node("panel", title=title_text, body=body, variant=variant)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def set_page_config(
|
|
123
|
+
page_title: str = "BPM App",
|
|
124
|
+
layout: str = "centered",
|
|
125
|
+
**kwargs: Any,
|
|
126
|
+
) -> None:
|
|
127
|
+
"""Configure la page (titre, layout). Pour l'instant enregistré mais pas utilisé par le rendu."""
|
|
128
|
+
_node("page_config", page_title=page_title, layout=layout, **kwargs)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
# --- Registry @ : stockage par nom ---
|
|
132
|
+
_REGISTRY: dict[str, Any] = {}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def register(name: str, value: Any) -> None:
|
|
136
|
+
"""Enregistre une valeur sous un nom (@)."""
|
|
137
|
+
_REGISTRY[name] = value
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def get_registered(name: str) -> Any:
|
|
141
|
+
"""Retourne la valeur enregistrée sous ce nom."""
|
|
142
|
+
return _REGISTRY.get(name)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# --- Refs réactives $ ---
|
|
146
|
+
_REFS: dict[str, Any] = {}
|
|
147
|
+
_REF_SUBSCRIBERS: dict[str, list[Callable[[Any], None]]] = {}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class Ref:
|
|
151
|
+
"""Réf réactive : get/set/subscribe."""
|
|
152
|
+
|
|
153
|
+
def __init__(self, name: str, initial: Any = None):
|
|
154
|
+
self._name = name
|
|
155
|
+
if name not in _REFS:
|
|
156
|
+
_REFS[name] = initial
|
|
157
|
+
if name not in _REF_SUBSCRIBERS:
|
|
158
|
+
_REF_SUBSCRIBERS[name] = []
|
|
159
|
+
|
|
160
|
+
def get(self) -> Any:
|
|
161
|
+
return _REFS.get(self._name)
|
|
162
|
+
|
|
163
|
+
def set(self, value: Any) -> None:
|
|
164
|
+
_REFS[self._name] = value
|
|
165
|
+
for cb in _REF_SUBSCRIBERS.get(self._name, []):
|
|
166
|
+
cb(value)
|
|
167
|
+
|
|
168
|
+
def subscribe(self, callback: Callable[[Any], None]) -> Callable[[], None]:
|
|
169
|
+
_REF_SUBSCRIBERS.setdefault(self._name, []).append(callback)
|
|
170
|
+
|
|
171
|
+
def unsubscribe():
|
|
172
|
+
_REF_SUBSCRIBERS[self._name].remove(callback)
|
|
173
|
+
|
|
174
|
+
return unsubscribe
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def ref(name: str, initial: Any = None) -> Ref:
|
|
178
|
+
"""Crée ou récupère une ref réactive ($)."""
|
|
179
|
+
return Ref(name, initial)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
# --- Décorateurs @ ---
|
|
183
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def page(page_id: str) -> Callable[[F], F]:
|
|
187
|
+
"""Décorateur : enregistre une fonction comme page (@bpm.page('id'))."""
|
|
188
|
+
|
|
189
|
+
def decorator(fn: F) -> F:
|
|
190
|
+
register(f"page:{page_id}", fn)
|
|
191
|
+
return fn
|
|
192
|
+
|
|
193
|
+
return decorator
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def sidebar(fn: F) -> F:
|
|
197
|
+
"""Décorateur : enregistre le contenu de la sidebar (@bpm.sidebar)."""
|
|
198
|
+
register("sidebar", fn)
|
|
199
|
+
return fn
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def cache_data(fn: F) -> F:
|
|
203
|
+
"""Décorateur : cache le résultat de la fonction (@bpm.cache_data). Stub : pas de cache pour l'instant."""
|
|
204
|
+
return fn
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
__all__ = [
|
|
208
|
+
"set_page_config",
|
|
209
|
+
"register",
|
|
210
|
+
"get_registered",
|
|
211
|
+
"ref",
|
|
212
|
+
"Ref",
|
|
213
|
+
"page",
|
|
214
|
+
"sidebar",
|
|
215
|
+
"cache_data",
|
|
216
|
+
"session_state",
|
|
217
|
+
"get_current_nodes",
|
|
218
|
+
"reset_current_nodes",
|
|
219
|
+
"rerun",
|
|
220
|
+
"rerun_requested",
|
|
221
|
+
"title",
|
|
222
|
+
"write",
|
|
223
|
+
"markdown",
|
|
224
|
+
"button",
|
|
225
|
+
"metric",
|
|
226
|
+
"table",
|
|
227
|
+
"header",
|
|
228
|
+
"subheader",
|
|
229
|
+
"caption",
|
|
230
|
+
"code",
|
|
231
|
+
"divider",
|
|
232
|
+
"toggle",
|
|
233
|
+
"panel",
|
|
234
|
+
]
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI BPM — bpm run app.py, bpm init.
|
|
3
|
+
Point d'entrée : bpm = bpm.cli:main
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
import runpy
|
|
11
|
+
import sys
|
|
12
|
+
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
13
|
+
from typing import Optional
|
|
14
|
+
from urllib.parse import parse_qs, urlparse
|
|
15
|
+
|
|
16
|
+
# Import après que le répertoire de travail soit celui de l'app
|
|
17
|
+
def _run_script(script_path: str) -> list:
|
|
18
|
+
"""Exécute script_path et retourne la liste des nœuds de rendu."""
|
|
19
|
+
import bpm
|
|
20
|
+
bpm.reset_current_nodes()
|
|
21
|
+
script_dir = os.path.abspath(os.path.dirname(script_path))
|
|
22
|
+
if script_dir not in sys.path:
|
|
23
|
+
sys.path.insert(0, script_dir)
|
|
24
|
+
old_cwd = os.getcwd()
|
|
25
|
+
try:
|
|
26
|
+
os.chdir(script_dir)
|
|
27
|
+
runpy.run_path(script_path, run_name="__main__")
|
|
28
|
+
return bpm.get_current_nodes()
|
|
29
|
+
finally:
|
|
30
|
+
os.chdir(old_cwd)
|
|
31
|
+
if script_dir in sys.path:
|
|
32
|
+
sys.path.remove(script_dir)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _nodes_to_html(nodes: list) -> str:
|
|
36
|
+
"""Génère une page HTML qui affiche les nœuds (rendu minimal côté client)."""
|
|
37
|
+
nodes_js = json.dumps(nodes, default=str, ensure_ascii=False)
|
|
38
|
+
return f"""<!DOCTYPE html>
|
|
39
|
+
<html lang="fr">
|
|
40
|
+
<head>
|
|
41
|
+
<meta charset="utf-8" />
|
|
42
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
43
|
+
<title>BPM App</title>
|
|
44
|
+
<style>
|
|
45
|
+
body {{ font-family: system-ui, sans-serif; margin: 1rem 2rem; max-width: 800px; }}
|
|
46
|
+
.bpm-title {{ font-size: 1.5rem; font-weight: 700; margin: 1rem 0; }}
|
|
47
|
+
.bpm-write {{ margin: 0.5rem 0; }}
|
|
48
|
+
.bpm-metric {{ display: inline-block; padding: 1rem; margin: 0.5rem; background: #f0f0f0; border-radius: 8px; }}
|
|
49
|
+
.bpm-metric .value {{ font-size: 1.5rem; font-weight: 700; }}
|
|
50
|
+
.bpm-metric .delta {{ font-size: 0.85rem; color: #666; }}
|
|
51
|
+
.bpm-button {{ padding: 0.5rem 1rem; margin: 0.25rem; cursor: pointer; background: #1A4B8F; color: #fff; border: none; border-radius: 6px; }}
|
|
52
|
+
.bpm-button:hover {{ opacity: 0.9; }}
|
|
53
|
+
table {{ border-collapse: collapse; width: 100%; margin: 1rem 0; }}
|
|
54
|
+
th, td {{ border: 1px solid #ddd; padding: 0.5rem; text-align: left; }}
|
|
55
|
+
th {{ background: #f5f5f5; }}
|
|
56
|
+
.bpm-panel {{ padding: 1rem; margin: 1rem 0; border-radius: 8px; border-left: 4px solid #00A3E0; background: #f8f9fa; }}
|
|
57
|
+
.bpm-code {{ background: #1e1e1e; color: #d4d4d4; padding: 1rem; border-radius: 6px; overflow-x: auto; font-family: monospace; font-size: 0.9rem; }}
|
|
58
|
+
hr {{ margin: 1rem 0; border: none; border-top: 1px solid #eee; }}
|
|
59
|
+
</style>
|
|
60
|
+
</head>
|
|
61
|
+
<body>
|
|
62
|
+
<div id="root"></div>
|
|
63
|
+
<script>
|
|
64
|
+
const nodes = {nodes_js};
|
|
65
|
+
const root = document.getElementById('root');
|
|
66
|
+
function render(nodes) {{
|
|
67
|
+
root.innerHTML = '';
|
|
68
|
+
nodes.forEach(n => {{
|
|
69
|
+
const div = document.createElement('div');
|
|
70
|
+
div.className = 'bpm-' + n.type;
|
|
71
|
+
if (n.type === 'title') {{
|
|
72
|
+
const el = document.createElement('h' + (n.props.level || 1));
|
|
73
|
+
el.textContent = n.props.text;
|
|
74
|
+
root.appendChild(el);
|
|
75
|
+
}} else if (n.type === 'write' || n.type === 'markdown') {{
|
|
76
|
+
const p = document.createElement('div');
|
|
77
|
+
p.innerHTML = n.props.text;
|
|
78
|
+
root.appendChild(p);
|
|
79
|
+
}} else if (n.type === 'button') {{
|
|
80
|
+
const btn = document.createElement('button');
|
|
81
|
+
btn.className = 'bpm-button';
|
|
82
|
+
btn.textContent = n.props.label;
|
|
83
|
+
btn.onclick = () => {{ window.location.href = '/?clicked=' + encodeURIComponent(n.props.key || n.props.label); }};
|
|
84
|
+
root.appendChild(btn);
|
|
85
|
+
}} else if (n.type === 'metric') {{
|
|
86
|
+
const m = document.createElement('div');
|
|
87
|
+
m.className = 'bpm-metric';
|
|
88
|
+
m.innerHTML = '<div class="value">' + n.props.value + '</div><div>' + n.props.label + '</div>' +
|
|
89
|
+
(n.props.delta != null ? '<div class="delta">' + n.props.delta + '</div>' : '');
|
|
90
|
+
root.appendChild(m);
|
|
91
|
+
}} else if (n.type === 'table') {{
|
|
92
|
+
const t = document.createElement('table');
|
|
93
|
+
const rows = n.props.rows || [];
|
|
94
|
+
if (rows.length) {{
|
|
95
|
+
const thead = document.createElement('thead');
|
|
96
|
+
const tr = document.createElement('tr');
|
|
97
|
+
Object.keys(rows[0]).forEach(k => {{ const th = document.createElement('th'); th.textContent = k; tr.appendChild(th); }});
|
|
98
|
+
thead.appendChild(tr); t.appendChild(thead);
|
|
99
|
+
const tbody = document.createElement('tbody');
|
|
100
|
+
rows.forEach(row => {{ const tr = document.createElement('tr'); Object.values(row).forEach(v => {{ const td = document.createElement('td'); td.textContent = v; tr.appendChild(td); }}); tbody.appendChild(tr); }});
|
|
101
|
+
t.appendChild(tbody);
|
|
102
|
+
}}
|
|
103
|
+
root.appendChild(t);
|
|
104
|
+
}} else if (n.type === 'header') {{
|
|
105
|
+
const h = document.createElement('h2');
|
|
106
|
+
h.textContent = n.props.text;
|
|
107
|
+
root.appendChild(h);
|
|
108
|
+
}} else if (n.type === 'subheader') {{
|
|
109
|
+
const h = document.createElement('h3');
|
|
110
|
+
h.textContent = n.props.text;
|
|
111
|
+
root.appendChild(h);
|
|
112
|
+
}} else if (n.type === 'caption') {{
|
|
113
|
+
const p = document.createElement('p');
|
|
114
|
+
p.style.color = '#666'; p.style.fontSize = '0.9rem';
|
|
115
|
+
p.textContent = n.props.text;
|
|
116
|
+
root.appendChild(p);
|
|
117
|
+
}} else if (n.type === 'code') {{
|
|
118
|
+
const pre = document.createElement('pre');
|
|
119
|
+
pre.className = 'bpm-code';
|
|
120
|
+
pre.textContent = n.props.code;
|
|
121
|
+
root.appendChild(pre);
|
|
122
|
+
}} else if (n.type === 'divider') {{
|
|
123
|
+
root.appendChild(document.createElement('hr'));
|
|
124
|
+
}} else if (n.type === 'panel') {{
|
|
125
|
+
const p = document.createElement('div');
|
|
126
|
+
p.className = 'bpm-panel';
|
|
127
|
+
p.innerHTML = '<strong>' + n.props.title + '</strong><br/>' + (n.props.body || '');
|
|
128
|
+
root.appendChild(p);
|
|
129
|
+
}} else {{
|
|
130
|
+
const p = document.createElement('p');
|
|
131
|
+
p.textContent = JSON.stringify(n);
|
|
132
|
+
root.appendChild(p);
|
|
133
|
+
}}
|
|
134
|
+
}});
|
|
135
|
+
}}
|
|
136
|
+
render(nodes);
|
|
137
|
+
</script>
|
|
138
|
+
</body>
|
|
139
|
+
</html>"""
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def run(script_path: str, port: int = 8501, host: str = "127.0.0.1") -> None:
|
|
143
|
+
"""Lance le serveur BPM qui exécute script_path à chaque requête."""
|
|
144
|
+
script_path = os.path.abspath(script_path)
|
|
145
|
+
if not os.path.isfile(script_path):
|
|
146
|
+
print(f"Erreur : fichier introuvable {script_path}", file=sys.stderr)
|
|
147
|
+
sys.exit(1)
|
|
148
|
+
|
|
149
|
+
class BPMHandler(BaseHTTPRequestHandler):
|
|
150
|
+
def do_GET(self):
|
|
151
|
+
parsed = urlparse(self.path)
|
|
152
|
+
query = parse_qs(parsed.query)
|
|
153
|
+
# Marquer un bouton cliqué pour le prochain run
|
|
154
|
+
clicked = query.get("clicked", [None])[0]
|
|
155
|
+
if clicked:
|
|
156
|
+
import bpm
|
|
157
|
+
bpm.session_state["_clicked_" + clicked] = True
|
|
158
|
+
try:
|
|
159
|
+
nodes = _run_script(script_path)
|
|
160
|
+
# Consommer le clic après le run pour que le bouton ne reste pas True
|
|
161
|
+
import bpm
|
|
162
|
+
for k in list(bpm.session_state.keys()):
|
|
163
|
+
if k.startswith("_clicked_"):
|
|
164
|
+
del bpm.session_state[k]
|
|
165
|
+
except Exception as e:
|
|
166
|
+
self.send_response(500)
|
|
167
|
+
self.send_header("Content-type", "text/html; charset=utf-8")
|
|
168
|
+
self.end_headers()
|
|
169
|
+
self.wfile.write(
|
|
170
|
+
f"<html><body><h1>Erreur</h1><pre>{e!r}</pre></body></html>".encode("utf-8")
|
|
171
|
+
)
|
|
172
|
+
return
|
|
173
|
+
html = _nodes_to_html(nodes)
|
|
174
|
+
self.send_response(200)
|
|
175
|
+
self.send_header("Content-type", "text/html; charset=utf-8")
|
|
176
|
+
self.end_headers()
|
|
177
|
+
self.wfile.write(html.encode("utf-8"))
|
|
178
|
+
|
|
179
|
+
def log_message(self, format, *args):
|
|
180
|
+
print(f"[BPM] {args[0]}")
|
|
181
|
+
|
|
182
|
+
server = ThreadingHTTPServer((host, port), BPMHandler)
|
|
183
|
+
print(f"BPM : app servie sur http://{host}:{port}")
|
|
184
|
+
print(f" Script : {script_path}")
|
|
185
|
+
print(" Arrêt : Ctrl+C")
|
|
186
|
+
try:
|
|
187
|
+
server.serve_forever()
|
|
188
|
+
except KeyboardInterrupt:
|
|
189
|
+
server.shutdown()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def init(name: str = "mon-app") -> None:
|
|
193
|
+
"""Scaffold une app BPM vide (dossier avec app.py, README.md, requirements.txt)."""
|
|
194
|
+
os.makedirs(name, exist_ok=True)
|
|
195
|
+
app_py = os.path.join(name, "app.py")
|
|
196
|
+
if os.path.exists(app_py):
|
|
197
|
+
print(f"Le dossier '{name}' contient déjà app.py.", file=sys.stderr)
|
|
198
|
+
sys.exit(1)
|
|
199
|
+
with open(app_py, "w", encoding="utf-8") as f:
|
|
200
|
+
f.write('''import bpm
|
|
201
|
+
|
|
202
|
+
bpm.set_page_config(page_title="Mon App", layout="wide")
|
|
203
|
+
bpm.title("Mon App Blueprint Modular")
|
|
204
|
+
bpm.write("Bienvenue sur votre première app BPM.")
|
|
205
|
+
|
|
206
|
+
bpm.metric("Valeur exemple", 142500, delta=3200)
|
|
207
|
+
''')
|
|
208
|
+
with open(os.path.join(name, "README.md"), "w", encoding="utf-8") as f:
|
|
209
|
+
f.write(f"# {name}\n\nApp Blueprint Modular.\n\n## Lancer\n\n```\nbpm run app.py\n```\n")
|
|
210
|
+
with open(os.path.join(name, "requirements.txt"), "w", encoding="utf-8") as f:
|
|
211
|
+
f.write("blueprint-modular>=0.1.0\n")
|
|
212
|
+
print(f"App '{name}' créée.")
|
|
213
|
+
print(f" cd {name}")
|
|
214
|
+
print(f" bpm run app.py")
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def main() -> None:
|
|
218
|
+
from bpm import __version__
|
|
219
|
+
parser = argparse.ArgumentParser(
|
|
220
|
+
prog="bpm",
|
|
221
|
+
description="Blueprint Modular — Framework Python pour interfaces de données",
|
|
222
|
+
)
|
|
223
|
+
parser.add_argument(
|
|
224
|
+
"--version", "-v",
|
|
225
|
+
action="version",
|
|
226
|
+
version=f"blueprint-modular {__version__}",
|
|
227
|
+
)
|
|
228
|
+
sub = parser.add_subparsers(dest="command")
|
|
229
|
+
run_parser = sub.add_parser("run", help="Lancer une app BPM")
|
|
230
|
+
run_parser.add_argument("file", nargs="?", default="app.py", help="Fichier Python (défaut: app.py)")
|
|
231
|
+
run_parser.add_argument("--port", "-p", type=int, default=8501, help="Port (défaut: 8501)")
|
|
232
|
+
run_parser.add_argument("--host", default="127.0.0.1", help="Host (défaut: 127.0.0.1)")
|
|
233
|
+
init_parser = sub.add_parser("init", help="Scaffolder une app vide")
|
|
234
|
+
init_parser.add_argument("--name", default="mon-app", help="Nom du projet (défaut: mon-app)")
|
|
235
|
+
args = parser.parse_args()
|
|
236
|
+
if args.command == "run":
|
|
237
|
+
run(args.file, port=args.port, host=args.host)
|
|
238
|
+
elif args.command == "init":
|
|
239
|
+
init(args.name)
|
|
240
|
+
else:
|
|
241
|
+
parser.print_help()
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
if __name__ == "__main__":
|
|
245
|
+
main()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "blueprint-modular"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "Briques Python prêtes à l'emploi pour vos interfaces de données"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [{ name = "Rémi", email = "contact@blueprint-modular.com" }]
|
|
13
|
+
keywords = ["dashboard", "ui", "framework", "python", "data"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
]
|
|
23
|
+
dependencies = []
|
|
24
|
+
|
|
25
|
+
[project.optional-dependencies]
|
|
26
|
+
dev = ["pytest>=7.0", "black", "ruff"]
|
|
27
|
+
|
|
28
|
+
[project.scripts]
|
|
29
|
+
bpm = "bpm.cli:main"
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://blueprint-modular.com"
|
|
33
|
+
Documentation = "https://docs.blueprint-modular.com"
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.packages.find]
|
|
36
|
+
where = ["."]
|
|
37
|
+
include = ["bpm*"]
|