3 Commits

Author SHA1 Message Date
Matthieu
d4fc0f1fee fix(slots) : check API response before updating local state on slot selection
The save functions (savePieceSlotSelection, saveProductSlotSelection,
saveSubcomponentSlotSelection) were not checking result.success before
updating local state and showing success toast. Since useApi.patch()
never throws, the catch block was dead code and errors were silently
ignored while the UI showed success.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 11:31:19 +01:00
Matthieu
f8403ddfbc docs(changelog) : add v1.9.1 release notes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 10:53:21 +01:00
Matthieu
428da471d1 fix(component-edit) : force reload catalog to display pre-selected slot items
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 10:32:07 +01:00
5 changed files with 34 additions and 29 deletions

View File

@@ -81,10 +81,10 @@ onMounted(() => {
watch(
() => props.modelValue,
(value) => {
if (typeof value === 'string') {
if (typeof value === 'string' && value) {
const exists = composantOptions.value.some((c: any) => c.id === value)
if (!exists && composantOptions.value.length === 0 && !loading.value) {
loadComposants({ itemsPerPage: 200 }).catch((error: unknown) => {
if (!exists && !loading.value) {
loadComposants({ itemsPerPage: 200, force: true }).catch((error: unknown) => {
console.error('Erreur lors du chargement des composants:', error)
})
}

View File

@@ -81,10 +81,10 @@ onMounted(() => {
watch(
() => props.modelValue,
(value) => {
if (typeof value === 'string') {
if (typeof value === 'string' && value) {
const exists = pieceOptions.value.some((piece: any) => piece.id === value)
if (!exists && pieceOptions.value.length === 0 && !loading.value) {
loadPieces({ itemsPerPage: 200 }).catch((error: unknown) => {
if (!exists && !loading.value) {
loadPieces({ itemsPerPage: 200, force: true }).catch((error: unknown) => {
console.error('Erreur lors du chargement des pièces:', error)
})
}

View File

@@ -81,10 +81,10 @@ onMounted(() => {
watch(
() => props.modelValue,
(value) => {
if (typeof value === 'string') {
if (typeof value === 'string' && value) {
const exists = productOptions.value.some((product) => product.id === value)
if (!exists && productOptions.value.length === 0 && !loading.value) {
loadProducts().catch((error) => {
if (!exists && !loading.value) {
loadProducts({ force: true }).catch((error) => {
console.error('Erreur lors du chargement des produits:', error)
})
}

View File

@@ -313,9 +313,8 @@ export function useComponentEdit(componentId: string) {
})
const savePieceSlotSelection = async (slotId: string, selectedPieceId: string | null) => {
try {
await patch(`/composant-piece-slots/${slotId}`, { selectedPieceId })
// Update local structure
const result = await patch(`/composant-piece-slots/${slotId}`, { selectedPieceId })
if (result.success) {
const structure = component.value?.structure
if (structure?.pieces) {
const slot = (structure.pieces as any[]).find((s: any) => s.slotId === slotId)
@@ -323,14 +322,11 @@ export function useComponentEdit(componentId: string) {
}
toast.showSuccess('Pièce mise à jour')
}
catch (error: any) {
toast.showError(error?.message || 'Erreur lors de la mise à jour')
}
}
const saveProductSlotSelection = async (slotId: string, selectedProductId: string | null) => {
try {
await patch(`/composant-product-slots/${slotId}`, { selectedProductId })
const result = await patch(`/composant-product-slots/${slotId}`, { selectedProductId })
if (result.success) {
const structure = component.value?.structure
if (structure?.products) {
const slot = (structure.products as any[]).find((s: any) => s.slotId === slotId)
@@ -338,14 +334,11 @@ export function useComponentEdit(componentId: string) {
}
toast.showSuccess('Produit mis à jour')
}
catch (error: any) {
toast.showError(error?.message || 'Erreur lors de la mise à jour')
}
}
const saveSubcomponentSlotSelection = async (slotId: string, selectedComposantId: string | null) => {
try {
await patch(`/composant-subcomponent-slots/${slotId}`, { selectedComposantId })
const result = await patch(`/composant-subcomponent-slots/${slotId}`, { selectedComposantId })
if (result.success) {
const structure = component.value?.structure
if (structure?.subcomponents) {
const slot = (structure.subcomponents as any[]).find((s: any) => s.slotId === slotId)
@@ -353,9 +346,6 @@ export function useComponentEdit(componentId: string) {
}
toast.showSuccess('Sous-composant mis à jour')
}
catch (error: any) {
toast.showError(error?.message || 'Erreur lors de la mise à jour')
}
}
const saveSlotQuantity = async (entry: SelectionEntry) => {
@@ -511,11 +501,11 @@ export function useComponentEdit(componentId: string) {
])
loading.value = false
// Load catalogs for slot selectors
// Load catalogs for slot selectors (force: true to bypass cache from list pages that load fewer items)
Promise.allSettled([
loadPieces({ itemsPerPage: 200 }),
loadProducts({ itemsPerPage: 200 }),
loadComposants({ itemsPerPage: 200 }),
loadPieces({ itemsPerPage: 200, force: true }),
loadProducts({ itemsPerPage: 200, force: true }),
loadComposants({ itemsPerPage: 200, force: true }),
]).catch(() => {})
})

View File

@@ -69,6 +69,21 @@ const badgeClass = (type: ChangeType) => {
}
const releases: Release[] = [
{
version: 'v1.9.1',
date: '2026-03-16',
changes: [
{ type: 'feat', text: 'Normalisation JSON tables relationnelles : les structures des composants (pièces, produits, sous-composants) et les squelettes des catégories sont désormais stockés dans des tables dédiées au lieu de colonnes JSON, améliorant la fiabilité et les performances des requêtes' },
{ type: 'feat', text: 'Synchronisation des catégories (ModelType Sync) : la modification d\'une catégorie (ajout/suppression de slots ou champs personnalisés) peut être propagée automatiquement à tous les éléments existants de cette catégorie, avec prévisualisation des changements avant application' },
{ type: 'feat', text: 'Sélection interactive des items dans les slots : sur la page d\'édition d\'un composant, il est maintenant possible de choisir directement la pièce, le produit ou le sous-composant assigné à chaque emplacement du squelette via des sélecteurs avec recherche' },
{ type: 'feat', text: 'Endpoints PATCH pour les slots composant : modification de la quantité et de l\'item sélectionné sur les slots pièce, produit et sous-composant' },
{ type: 'feat', text: 'Table de relation pièce ↔ produit (PieceProductSlot) avec versioning pour le suivi des modifications de structure' },
{ type: 'feat', text: 'Gestion des champs personnalisés sur les catégories : synchronisation automatique des définitions de champs (ajout, modification, suppression) lors de la sauvegarde d\'une catégorie' },
{ type: 'feat', text: 'Suite de tests étendue : 219 tests couvrant les stratégies de synchronisation, le contrôleur de sync et les nouvelles entités' },
{ type: 'fix', text: 'Correction de l\'affichage des sélections pré-existantes dans les slots : les pièces, produits et sous-composants déjà assignés sont maintenant correctement affichés à l\'ouverture de la page d\'édition (correction du cache catalogue)' },
{ type: 'fix', text: 'Fallback position/orderIndex sur index de tableau dans les stratégies de sync pour éviter les erreurs quand le champ est absent' },
],
},
{
version: 'v1.9.0',
date: '2026-03-09',