Files
serv_benchmark/docs/FEATURE_EDIT_PERIPHERAL.md
Gilles Soulier c67befc549 addon
2026-01-05 16:08:01 +01:00

391 lines
10 KiB
Markdown
Executable File

# Fonctionnalité : Modifier un périphérique
## 🎯 Objectif
Implémenter le bouton "Modifier" dans la page de détail d'un périphérique pour permettre l'édition complète des informations.
## ✅ Implémentation
### 1. Interface HTML
**Fichier** : `frontend/peripheral-detail.html`
#### Modale d'édition (lignes 305-453)
```html
<!-- Edit Peripheral Modal -->
<div id="modal-edit" class="modal">
<div class="modal-content modal-large">
<div class="modal-header">
<h2><i class="fas fa-edit"></i> Modifier le périphérique</h2>
<span class="close" onclick="closeEditModal()">&times;</span>
</div>
<div class="modal-body">
<form id="form-edit-peripheral" onsubmit="savePeripheral(event)">
<!-- Formulaire complet avec tous les champs -->
</form>
</div>
</div>
</div>
```
#### Sections du formulaire
1. **Identification**
- Nom (requis)
- Type principal (requis)
- Sous-type
- Marque
- Modèle
- Numéro de série
2. **Achat**
- Boutique
- Date d'achat
- Prix
- Devise
- Garantie (mois)
3. **État et localisation**
- État (Neuf, Bon, Usagé, Défectueux, Retiré)
- Note (système d'étoiles cliquables)
- Quantité totale
- Quantité disponible
4. **Documentation technique**
- Synthèse (Markdown)
- CLI / Données structurées (YAML)
- CLI / Rapport système (Markdown)
- Spécifications (Markdown)
- Notes (Markdown)
### 2. Style CSS
**Fichier** : `frontend/css/peripherals.css` (lignes 284-287)
```css
.modal-content.modal-large {
max-width: 1400px;
width: 95%;
}
```
**Caractéristiques** :
- Modale plus large pour afficher tous les champs
- Responsive (95% de la largeur sur petit écran)
- Max 1400px sur grand écran
### 3. JavaScript - Fonctions
**Fichier** : `frontend/js/peripheral-detail.js`
#### `toggleEditMode()` (ligne 461-494)
**Rôle** : Ouvrir la modale et pré-remplir le formulaire avec les données actuelles
```javascript
function toggleEditMode() {
if (!peripheral) {
showError('Aucun périphérique chargé');
return;
}
// Populate form with peripheral data
document.getElementById('edit-nom').value = peripheral.nom || '';
document.getElementById('edit-type_principal').value = peripheral.type_principal || '';
// ... tous les autres champs ...
// Show modal
document.getElementById('modal-edit').style.display = 'block';
}
```
**Gère** :
- Vérification que le périphérique est chargé
- Pré-remplissage de tous les champs du formulaire
- Gestion des valeurs nulles avec fallback
- Appel `setEditRating()` pour les étoiles
#### `closeEditModal()` (ligne 496-498)
**Rôle** : Fermer la modale d'édition
```javascript
function closeEditModal() {
document.getElementById('modal-edit').style.display = 'none';
}
```
#### `setEditRating(rating)` (ligne 500-513)
**Rôle** : Mettre à jour l'affichage des étoiles dans le formulaire d'édition
```javascript
function setEditRating(rating) {
const stars = document.querySelectorAll('#edit-star-rating .fa-star');
const ratingInput = document.getElementById('edit-rating');
ratingInput.value = rating;
stars.forEach((star, index) => {
if (index < rating) {
star.classList.add('active');
} else {
star.classList.remove('active');
}
});
}
```
**Fonctionnalités** :
- Met à jour le champ hidden `edit-rating`
- Ajoute/retire la classe `active` sur les étoiles
- Permet sélection visuelle interactive
#### Event listener étoiles (ligne 516-525)
```javascript
document.addEventListener('DOMContentLoaded', () => {
const editStars = document.querySelectorAll('#edit-star-rating .fa-star');
editStars.forEach(star => {
star.addEventListener('click', () => {
const rating = parseInt(star.getAttribute('data-rating'));
setEditRating(rating);
});
});
});
```
**Rôle** : Rendre les étoiles cliquables pour modifier la note
#### `savePeripheral(event)` (ligne 527-559)
**Rôle** : Sauvegarder les modifications via l'API
```javascript
async function savePeripheral(event) {
event.preventDefault();
const form = event.target;
const formData = new FormData(form);
const data = {};
// Convert FormData to object
for (let [key, value] of formData.entries()) {
// Convert numeric fields
if (['prix', 'garantie_duree_mois', 'quantite_totale', 'quantite_disponible', 'rating'].includes(key)) {
data[key] = value ? parseFloat(value) : null;
} else {
data[key] = value || null;
}
}
try {
const response = await apiRequest(`/peripherals/${peripheralId}`, {
method: 'PUT',
body: JSON.stringify(data)
});
showSuccess('Périphérique mis à jour avec succès');
closeEditModal();
// Reload peripheral data
await loadPeripheral();
} catch (error) {
console.error('Error updating peripheral:', error);
showError('Erreur lors de la mise à jour du périphérique');
}
}
```
**Processus** :
1. Empêche soumission formulaire par défaut
2. Récupère les données du formulaire
3. Convertit FormData en objet JavaScript
4. Convertit champs numériques en nombres
5. Envoie requête PUT à l'API
6. Affiche message succès/erreur
7. Ferme la modale
8. Recharge les données pour rafraîchir l'affichage
### 4. API Backend
**Endpoint** : `PUT /api/peripherals/{peripheral_id}`
**Fichier** : `backend/app/api/endpoints/peripherals.py` (ligne 177-187)
```python
@router.put("/{peripheral_id}", response_model=PeripheralDetail)
def update_peripheral(
peripheral_id: int,
peripheral_data: PeripheralUpdate,
db: Session = Depends(get_peripherals_db)
):
"""Update a peripheral"""
peripheral = PeripheralService.update_peripheral(db, peripheral_id, peripheral_data)
if not peripheral:
raise HTTPException(status_code=404, detail="Peripheral not found")
return peripheral
```
**Schéma attendu** : `PeripheralUpdate` (Pydantic)
**Retour** : `PeripheralDetail` (données complètes du périphérique)
## 🔄 Flux d'utilisation
```
1. User clique "Modifier" dans page détail
2. toggleEditMode() appelé
│ ├─> Vérifie que peripheral est chargé
│ ├─> Pré-remplit tous les champs du formulaire
│ ├─> Configure les étoiles de notation
│ └─> Affiche la modale
3. User modifie les champs souhaités
│ └─> Peut cliquer sur les étoiles pour changer la note
4. User clique "Enregistrer"
5. savePeripheral() appelé
│ ├─> Récupère données du formulaire
│ ├─> Convertit types numériques
│ ├─> PUT /api/peripherals/{id}
│ └─> Backend met à jour en BDD
6. Success
│ ├─> Message "Périphérique mis à jour avec succès"
│ ├─> Ferme modale
│ └─> Recharge peripheral pour afficher nouvelles données
```
## 📊 Champs éditables
| Catégorie | Champ | Type | Requis |
|-----------|-------|------|--------|
| **Identification** | nom | text | ✅ |
| | type_principal | text | ✅ |
| | sous_type | text | |
| | marque | text | |
| | modele | text | |
| | numero_serie | text | |
| **Achat** | boutique | text | |
| | date_achat | date | |
| | prix | number | |
| | devise | text(3) | |
| | garantie_duree_mois | number | |
| **État** | etat | select | |
| | rating | number(0-5) | |
| | quantite_totale | number | |
| | quantite_disponible | number | |
| **Documentation** | synthese | textarea | |
| | cli_yaml | textarea | |
| | cli_raw | textarea | |
| | specifications | textarea | |
| | notes | textarea | |
**Total** : 22 champs éditables
## 🎨 Interface utilisateur
### Bouton "Modifier"
**Position** : Dans le header de la carte "Informations générales"
```html
<button class="btn btn-primary" onclick="toggleEditMode()" id="btn-edit">
<i class="fas fa-edit"></i> Modifier
</button>
```
**Style** :
- Bouton bleu primaire
- Icône crayon Font Awesome
- Positionné à droite du header
### Modale d'édition
**Dimensions** :
- Largeur : 95% (mobile) → max 1400px (desktop)
- Layout : Grille responsive 3 colonnes
**Sections** :
- 3 colonnes pour les champs principaux
- Pleine largeur pour documentation technique
- Actions (Annuler / Enregistrer) en bas
### Retour utilisateur
**Messages** :
- ✅ Succès : "Périphérique mis à jour avec succès" (vert)
- ❌ Erreur : "Erreur lors de la mise à jour du périphérique" (rouge)
- ⚠️ Validation : "Aucun périphérique chargé" (orange)
## 🧪 Tests
### Test manuel
1. **Ouvrir page détail** : `/peripheral-detail.html?id=3`
2. **Cliquer "Modifier"** : Modale s'ouvre avec données pré-remplies
3. **Modifier champs** : Ex: changer nom, prix, note
4. **Cliquer étoiles** : Note change visuellement
5. **Cliquer "Enregistrer"** : Message succès + modale se ferme
6. **Vérifier affichage** : Nouvelles valeurs affichées
### Test API
```bash
# Mettre à jour un périphérique
curl -X PUT "http://10.0.0.50:8007/api/peripherals/3" \
-H "Content-Type: application/json" \
-H "X-API-Token: YOUR_TOKEN" \
-d '{
"nom": "Logitech MX Master 3 (Updated)",
"prix": 99.99,
"rating": 5
}'
```
**Résultat attendu** :
```json
{
"id": 3,
"nom": "Logitech MX Master 3 (Updated)",
"prix": 99.99,
"rating": 5,
...
}
```
## 📝 Fichiers modifiés
### Créés
-`docs/FEATURE_EDIT_PERIPHERAL.md` - Cette documentation
### Modifiés
-`frontend/peripheral-detail.html` - Ajout modale d'édition
-`frontend/js/peripheral-detail.js` - Fonctions édition complètes
-`frontend/css/peripherals.css` - Style `.modal-large`
### Backend (déjà existant)
-`backend/app/api/endpoints/peripherals.py` - Endpoint PUT
-`backend/app/services/peripheral_service.py` - Service update
-`backend/app/schemas/peripheral.py` - Schema PeripheralUpdate
## 🚀 Améliorations futures possibles
- [ ] Validation côté client (longueurs, formats)
- [ ] Champs device_id et location_id (dropdowns)
- [ ] Confirmation avant fermeture si modifications non sauvegardées
- [ ] Historique des modifications (audit trail)
- [ ] Mode "édition rapide" (inline editing)
- [ ] Raccourci clavier (Ctrl+E)
---
**Date** : 31 décembre 2025
**Statut** : ✅ Implémenté et fonctionnel
**Impact** : Permet l'édition complète des périphériques depuis la page de détail