addon
This commit is contained in:
390
docs/FEATURE_EDIT_PERIPHERAL.md
Executable file
390
docs/FEATURE_EDIT_PERIPHERAL.md
Executable file
@@ -0,0 +1,390 @@
|
||||
# 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()">×</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
|
||||
Reference in New Issue
Block a user