Backend: - Enrich machine snapshot with componentLinks/pieceLinks/productLinks - Detect link add/remove in MachineAuditSubscriber onFlush - Add link diff comparison in restore preview - Add link restoration in applyRestore for machines - Add integrity warnings for missing linked entities Frontend (submodule update): - Single save button replacing auto-save-on-blur - Link versioning display in version list and restore modal Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
118 lines
5.0 KiB
Markdown
118 lines
5.0 KiB
Markdown
# Machine : Bouton Save Unique + Versioning des Liens
|
|
|
|
**Date :** 2026-03-26
|
|
**Statut :** Approuvé
|
|
|
|
## Contexte
|
|
|
|
La page machine utilise actuellement un auto-save au blur pour chaque champ (info, custom fields, constructeurs). Les pages composant/pièce/produit utilisent un bouton unique "Enregistrer les modifications" en bas du formulaire. L'objectif est d'aligner la page machine sur ce pattern.
|
|
|
|
De plus, les ajouts/suppressions de liens composant/pièce/produit sur une machine ne sont pas tracés dans le versioning. Ils doivent l'être.
|
|
|
|
## Volet 1 : Bouton Save Unique
|
|
|
|
### Comportement cible
|
|
|
|
- En mode édition, tous les champs (info machine, custom field values, custom field definitions, constructeurs) sont modifiés localement sans appel API.
|
|
- Un bouton "Enregistrer les modifications" en bas du formulaire sauvegarde tout d'un coup.
|
|
- Un bouton "Annuler" réinitialise l'état local et sort du mode édition.
|
|
- Les documents restent en upload/suppression immédiate (inchangé).
|
|
- Les ajouts/suppressions de liens composant/pièce/produit restent immédiats via modales (inchangé).
|
|
|
|
### Changements frontend
|
|
|
|
#### MachineInfoCard.vue
|
|
- Supprimer les `@blur` → `$emit('blur-field')` sur les inputs (nom, référence)
|
|
- Supprimer le `@change` qui émet `blur-field` sur le select site
|
|
- Supprimer les `@blur` → `$emit('update-custom-field', field)` sur tous les champs custom
|
|
- Conserver `@input` / `@update:*` / `set-custom-field-value` pour la mise à jour de l'état local
|
|
- Le `MachineCustomFieldDefEditor` perd son bouton save propre : l'état est collecté au submit global
|
|
|
|
#### machine/[id].vue
|
|
- Supprimer le handler `@blur-field`
|
|
- Supprimer le handler `@update-custom-field`
|
|
- `@update:constructeur-ids` met à jour l'état local sans save
|
|
- Ajouter le bloc boutons en bas (pattern identique à component/[id]/index.vue) :
|
|
- "Annuler" (btn-ghost) → `cancelEdition()` : réinitialise depuis `machine.value` + sort du mode édition
|
|
- "Enregistrer les modifications" (btn-primary, disabled si `!canSubmit`) → `submitEdition()`
|
|
|
|
#### useMachineDetailData.ts
|
|
- Exposer `saving` ref
|
|
- Exposer `submitEdition()` :
|
|
1. `updateMachineInfo()` — PATCH machine (nom, ref, site, constructeurs)
|
|
2. Batch save custom field values (tous les `visibleMachineCustomFields` avec valeur)
|
|
3. Save custom field definitions si modifiées (`fieldDefs.saveDefinitions()`)
|
|
4. `loadMachineData()` pour recharger
|
|
5. Sortie du mode édition + toast succès
|
|
- Exposer `cancelEdition()` :
|
|
1. `initMachineFields()` — réinitialise nom, ref, site, constructeurs depuis `machine.value`
|
|
2. `syncMachineCustomFields()` — réinitialise les custom fields
|
|
3. Sort du mode édition
|
|
|
|
#### useMachineDetailUpdates.ts
|
|
- `handleMachineConstructeurChange` ne déclenche plus `updateMachineInfo()`, met juste à jour le ref local
|
|
|
|
#### useMachineDetailCustomFields.ts
|
|
- `updateMachineCustomField` n'est plus appelé au blur — sera appelé en batch par `submitEdition()`
|
|
- Ajouter méthode `saveAllMachineCustomFields()` qui itère sur les champs visibles et sauvegarde ceux avec valeur
|
|
|
|
### Validation (`canSubmit`)
|
|
- Machine existe
|
|
- Nom non vide
|
|
- Pas en cours de sauvegarde (`!saving.value`)
|
|
- `canEdit` est true
|
|
|
|
## Volet 2 : Versioning des Liens Machine
|
|
|
|
### Comportement cible
|
|
|
|
Quand un composant, pièce ou produit est ajouté ou supprimé d'une machine, cela doit :
|
|
1. Incrémenter la `version` de la Machine
|
|
2. Créer une entrée `AuditLog` avec diff et snapshot
|
|
|
|
### Changements backend
|
|
|
|
#### MachineAuditSubscriber — enrichir le snapshot
|
|
Ajouter au snapshot machine les liens :
|
|
```php
|
|
'componentLinks' => array_map(fn($link) => [
|
|
'id' => $link->getId(),
|
|
'composantId' => $link->getComposant()->getId(),
|
|
'composantName' => $link->getComposant()->getName(),
|
|
], $entity->getComponentLinks()->toArray()),
|
|
'pieceLinks' => [...],
|
|
'productLinks' => [...],
|
|
```
|
|
|
|
#### Nouveau subscriber ou service : MachineLinkAuditService
|
|
Écouter les événements Doctrine `postPersist` et `postRemove` sur les 3 entités link.
|
|
Quand un lien est créé/supprimé :
|
|
1. Récupérer la Machine parente
|
|
2. Incrémenter `$machine->incrementVersion()`
|
|
3. Créer un `AuditLog` :
|
|
- `entityType: 'machine'`
|
|
- `entityId: $machine->getId()`
|
|
- `action: 'update'`
|
|
- `diff: { addedComponent: {id, name} }` ou `{ removedPiece: {id, name} }`
|
|
- `snapshot:` snapshot complet de la machine (avec liens mis à jour)
|
|
- `version:` nouvelle version
|
|
|
|
### Labels pour le diff (frontend)
|
|
Ajouter au `historyFieldLabels` de la page machine :
|
|
```js
|
|
addedComponent: 'Composant ajouté',
|
|
removedComponent: 'Composant supprimé',
|
|
addedPiece: 'Pièce ajoutée',
|
|
removedPiece: 'Pièce supprimée',
|
|
addedProduct: 'Produit ajouté',
|
|
removedProduct: 'Produit supprimé',
|
|
```
|
|
|
|
## Ce qui ne change PAS
|
|
|
|
- Upload/suppression de documents (immédiat)
|
|
- Pattern read/edit toggle dans le header
|
|
- L'affichage des sections composants/pièces/produits
|
|
- Les modales d'ajout/suppression de liens (restent immédiates)
|
|
- Le versioning des autres entités (composant, pièce, produit)
|