This commit is contained in:
Gilles Soulier
2026-01-05 16:08:01 +01:00
parent dcba044cd6
commit c67befc549
2215 changed files with 26743 additions and 329 deletions

310
docs/FIXES_UI_IMPROVEMENTS.md Executable file
View File

@@ -0,0 +1,310 @@
# Corrections UI - Icônes par type, Localisation, Boutons
## 🎯 Problèmes corrigés
1. **Icônes génériques** → Icônes spécifiques selon le type de périphérique
2. **Localisation manquante** dans la modale d'édition
3. **Boutons Annuler/Enregistrer** s'affichaient en haut au lieu d'en bas
---
## ✅ 1. Icônes spécifiques par type
### Problème
Tous les périphériques sans photo affichaient l'icône générique `fa-microchip`.
### Solution
**Fichier** : `frontend/js/peripherals.js` (lignes 973-1011)
**Nouvelle fonction `getTypeIcon(type)`** :
```javascript
// Get icon based on peripheral type
function getTypeIcon(type) {
if (!type) return 'fa-microchip';
const typeUpper = type.toUpperCase();
// USB devices
if (typeUpper.includes('USB')) return 'fa-usb';
// Storage devices
if (typeUpper.includes('STOCKAGE') || typeUpper.includes('DISK') ||
typeUpper.includes('SSD') || typeUpper.includes('HDD') ||
typeUpper.includes('FLASH')) return 'fa-hdd';
// Network devices
if (typeUpper.includes('RÉSEAU') || typeUpper.includes('RESEAU') ||
typeUpper.includes('NETWORK') || typeUpper.includes('WIFI') ||
typeUpper.includes('ETHERNET')) return 'fa-network-wired';
// Audio devices
if (typeUpper.includes('AUDIO') || typeUpper.includes('SOUND') ||
typeUpper.includes('SPEAKER') || typeUpper.includes('HEADPHONE')) return 'fa-volume-up';
// Video devices
if (typeUpper.includes('VIDEO') || typeUpper.includes('VIDÉO') ||
typeUpper.includes('WEBCAM') || typeUpper.includes('CAMERA')) return 'fa-video';
// Input devices
if (typeUpper.includes('CLAVIER') || typeUpper.includes('KEYBOARD')) return 'fa-keyboard';
if (typeUpper.includes('SOURIS') || typeUpper.includes('MOUSE')) return 'fa-mouse';
// Other devices
if (typeUpper.includes('BLUETOOTH')) return 'fa-bluetooth';
if (typeUpper.includes('HUB')) return 'fa-project-diagram';
if (typeUpper.includes('ADAPTATEUR') || typeUpper.includes('ADAPTER')) return 'fa-plug';
// Default
return 'fa-microchip';
}
```
**Logique** :
- Détection par mots-clés dans le type (insensible à la casse)
- Support français et anglais
- Fallback vers `fa-microchip` si aucun match
**Utilisation dans le tableau** (lignes 327-328) :
```javascript
${p.thumbnail_url
? `<img src="${escapeHtml(p.thumbnail_url)}" alt="${escapeHtml(p.nom)}" onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
<i class="fas ${getTypeIcon(p.type_principal)}" style="display:none;"></i>`
: `<i class="fas ${getTypeIcon(p.type_principal)}"></i>`
}
```
### Mapping des icônes
| Type | Mots-clés | Icône Font Awesome | Rendu |
|------|-----------|-------------------|-------|
| **USB** | USB | `fa-usb` | 🔌 |
| **Stockage** | STOCKAGE, DISK, SSD, HDD, FLASH | `fa-hdd` | 💾 |
| **Réseau** | RÉSEAU, NETWORK, WIFI, ETHERNET | `fa-network-wired` | 🌐 |
| **Audio** | AUDIO, SOUND, SPEAKER, HEADPHONE | `fa-volume-up` | 🔊 |
| **Vidéo** | VIDEO, VIDÉO, WEBCAM, CAMERA | `fa-video` | 📹 |
| **Clavier** | CLAVIER, KEYBOARD | `fa-keyboard` | ⌨️ |
| **Souris** | SOURIS, MOUSE | `fa-mouse` | 🖱️ |
| **Bluetooth** | BLUETOOTH | `fa-bluetooth` | 🔵 |
| **Hub** | HUB | `fa-project-diagram` | 🔀 |
| **Adaptateur** | ADAPTATEUR, ADAPTER | `fa-plug` | 🔌 |
| **Défaut** | Autre | `fa-microchip` | 💻 |
### Exemples
```javascript
getTypeIcon('USB') // → 'fa-usb'
getTypeIcon('Stockage SSD') // → 'fa-hdd'
getTypeIcon('Réseau WiFi') // → 'fa-network-wired'
getTypeIcon('Webcam') // → 'fa-video'
getTypeIcon('Clavier') // → 'fa-keyboard'
getTypeIcon('Bluetooth') // → 'fa-bluetooth'
getTypeIcon('Hub USB') // → 'fa-usb' (USB détecté en premier)
getTypeIcon('Unknown Type') // → 'fa-microchip' (fallback)
```
---
## ✅ 2. Champ Localisation ajouté
### Problème
Le champ "Localisation" était absent de la section "État et localisation" dans la modale d'édition.
### Solution HTML
**Fichier** : `frontend/peripheral-detail.html` (lignes 393-398)
**Ajout du champ** :
```html
<div class="form-group">
<label for="edit-location_id">Localisation</label>
<select id="edit-location_id" name="location_id">
<option value="">Non définie</option>
</select>
</div>
```
**Position** : Entre "Note" et "Quantité totale"
### Solution JavaScript
**Fichier** : `frontend/js/peripheral-detail.js` (lignes 512-539)
**1. Appel dans `toggleEditMode()` (ligne 513)** :
```javascript
// Load and set location
loadEditLocations(peripheral.location_id);
```
**2. Nouvelle fonction `loadEditLocations()`** :
```javascript
// Load locations for edit modal
async function loadEditLocations(selectedLocationId) {
try {
const locations = await apiRequest('/locations/');
const select = document.getElementById('edit-location_id');
select.innerHTML = '<option value="">Non définie</option>';
locations.forEach(location => {
const option = document.createElement('option');
option.value = location.id;
option.textContent = location.nom;
if (location.id === selectedLocationId) {
option.selected = true;
}
select.appendChild(option);
});
} catch (error) {
console.error('Error loading locations:', error);
}
}
```
**Fonctionnement** :
1. Appel API `GET /locations/` pour récupérer toutes les localisations
2. Peuplement du `<select>` avec les options
3. Pré-sélection de la localisation actuelle du périphérique (si définie)
4. Gestion des erreurs avec console.error
**Résultat** :
- L'utilisateur peut maintenant modifier la localisation lors de l'édition
- La localisation actuelle est pré-sélectionnée
- Option "Non définie" disponible pour retirer la localisation
---
## ✅ 3. Positionnement des boutons en bas
### Problème
Les boutons "Annuler" et "Enregistrer" s'affichaient en haut de la modale au lieu d'en bas.
### Cause
La div `.form-actions` était dans un conteneur `.form-grid` avec `display: grid`. Sans instruction spécifique, elle ne prenait pas toute la largeur et pouvait s'afficher dans une colonne du grid.
### Solution CSS
**Fichier** : `frontend/css/peripherals.css` (ligne 446)
**Modification** :
```css
.form-actions {
grid-column: 1 / -1; /* Take full width of grid */
margin-top: 2rem;
display: flex;
justify-content: flex-end;
gap: 1rem;
padding-top: 1.5rem;
border-top: 1px solid #3e3d32;
}
```
**Ajout de `grid-column: 1 / -1`** :
- Force `.form-actions` à occuper toutes les colonnes du grid
- `-1` = dernière colonne (quelle que soit la taille du grid)
- Assure que les boutons soient toujours en bas, sur toute la largeur
**Résultat** :
```
┌─────────────────────────────────────────────────────┐
│ [Identification] [Achat] [État et localisation] │
│ │
│ [Documentation technique - pleine largeur] │
│ │
├─────────────────────────────────────────────────────┤
│ [Annuler] [Enregistrer] │
└─────────────────────────────────────────────────────┘
```
---
## 📊 Résumé des modifications
### Fichiers modifiés
| Fichier | Lignes | Modification |
|---------|--------|--------------|
| `frontend/js/peripherals.js` | 973-1011 | Fonction `getTypeIcon()` |
| `frontend/js/peripherals.js` | 327-328 | Utilisation de `getTypeIcon()` |
| `frontend/peripheral-detail.html` | 393-398 | Champ localisation ajouté |
| `frontend/js/peripheral-detail.js` | 513 | Appel `loadEditLocations()` |
| `frontend/js/peripheral-detail.js` | 519-539 | Fonction `loadEditLocations()` |
| `frontend/css/peripherals.css` | 446 | `grid-column: 1 / -1` |
### Nouveaux éléments
**Fonctions JavaScript** :
-`getTypeIcon(type)` - Retourne l'icône selon le type
-`loadEditLocations(selectedLocationId)` - Charge les localisations
**Champs HTML** :
-`<select id="edit-location_id">` - Sélecteur de localisation
---
## 🧪 Tests
### Test 1 : Icônes spécifiques
1. Ouvrir `http://10.0.0.50:8087/peripherals.html`
2. Observer la colonne "Photo"
3. Vérifier que les périphériques sans photo affichent des icônes différentes :
- ✅ USB → Icône USB
- ✅ Stockage → Icône disque dur
- ✅ Réseau → Icône réseau
- ✅ Clavier → Icône clavier
- ✅ Souris → Icône souris
### Test 2 : Localisation dans édition
1. Ouvrir un périphérique : `http://10.0.0.50:8087/peripheral-detail.html?id=3`
2. Cliquer sur "Modifier"
3. Vérifier la section "État et localisation"
4. ✅ Le champ "Localisation" est présent
5. ✅ Le select est pré-rempli avec les localisations disponibles
6. ✅ La localisation actuelle est sélectionnée
7. Modifier la localisation et enregistrer
8. ✅ La modification est sauvegardée
### Test 3 : Boutons en bas
1. Ouvrir un périphérique
2. Cliquer sur "Modifier"
3. ✅ Les boutons "Annuler" et "Enregistrer" sont en bas de la modale
4. ✅ Ils occupent toute la largeur (ligne séparatrice visible)
5. ✅ Boutons alignés à droite
---
## 💡 Améliorations futures possibles
### Icônes
- [ ] Icônes personnalisées pour plus de types (Scanner, Imprimante, etc.)
- [ ] Couleurs différentes selon l'état (Neuf = vert, Défectueux = rouge)
- [ ] Possibilité de définir une icône personnalisée par périphérique
### Localisation
- [ ] Création rapide de localisation depuis la modale
- [ ] Affichage du chemin complet (location parent → enfant)
- [ ] Icône de localisation à côté du nom
### Boutons
- [ ] Raccourci clavier (Ctrl+S pour sauvegarder)
- [ ] Confirmation avant fermeture si modifications non sauvegardées
- [ ] Bouton "Appliquer" qui sauvegarde sans fermer la modale
---
**Date** : 31 décembre 2025
**Statut** : ✅ Toutes les corrections appliquées et testées
**Impact** : Interface plus intuitive avec icônes contextuelles, localisation éditable, et boutons correctement positionnés