fix(composant) : preserve skeleton selections on form validation error

Shared module-level loading ref in useComposants caused structureDataLoading
to toggle during submission, unmounting the skeleton assignment UI. On remount,
watchers cleared selections not found in the limited local catalog.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matthieu
2026-03-26 10:36:07 +01:00
parent 452de8b069
commit d197d30eb0
2 changed files with 27 additions and 13 deletions

View File

@@ -106,7 +106,7 @@ export function useComponentCreate() {
const availableProducts = computed(() => productCatalogRef.value ?? [])
const availableComponents = computed(() => componentCatalogRef.value ?? [])
const structureDataLoading = computed(
() => piecesLoading.value || componentsLoading.value || productsLoading.value,
() => !submitting.value && (piecesLoading.value || componentsLoading.value || productsLoading.value),
)
const fetchedPieceTypeMap = ref<Record<string, string>>({})

View File

@@ -279,6 +279,11 @@ export function useStructureAssignmentFetch(deps: StructureAssignmentFetchDeps)
if (deps.isRoot()) {
return
}
// Only clear if we have loaded options (cache or catalog); skip when options are empty
// because the fetch may not have completed yet.
if (!options.length) {
return
}
const hasMatch = options.some(
(component) => component.id === deps.assignment.selectedComponentId,
)
@@ -293,12 +298,18 @@ export function useStructureAssignmentFetch(deps: StructureAssignmentFetchDeps)
() => [deps.pieces, deps.assignment.pieces],
() => {
for (const pieceAssignment of deps.assignment.pieces) {
const options = getPieceOptions(pieceAssignment)
if (
pieceAssignment.selectedPieceId
&& !options.some((piece) => piece.id === pieceAssignment.selectedPieceId)
) {
pieceAssignment.selectedPieceId = ''
const hasCachedOptions = !!pieceOptionsByPath.value[pieceAssignment.path]
// Only clear selections when we have loaded options (cached or from catalog).
// When no cache exists, a fetch is about to fire — clearing now would lose
// user input before the real option list arrives.
if (hasCachedOptions) {
const options = getPieceOptions(pieceAssignment)
if (
pieceAssignment.selectedPieceId
&& !options.some((piece) => piece.id === pieceAssignment.selectedPieceId)
) {
pieceAssignment.selectedPieceId = ''
}
}
if (!primedPiecePaths.has(pieceAssignment.path) && !pieceOptionsByPath.value[pieceAssignment.path]) {
primedPiecePaths.add(pieceAssignment.path)
@@ -313,12 +324,15 @@ export function useStructureAssignmentFetch(deps: StructureAssignmentFetchDeps)
() => [deps.products, deps.assignment.products],
() => {
for (const productAssignment of deps.assignment.products) {
const options = getProductOptions(productAssignment)
if (
productAssignment.selectedProductId
&& !options.some((product) => product.id === productAssignment.selectedProductId)
) {
productAssignment.selectedProductId = ''
const hasCachedOptions = !!productOptionsByPath.value[productAssignment.path]
if (hasCachedOptions) {
const options = getProductOptions(productAssignment)
if (
productAssignment.selectedProductId
&& !options.some((product) => product.id === productAssignment.selectedProductId)
) {
productAssignment.selectedProductId = ''
}
}
if (!primedProductPaths.has(productAssignment.path) && !productOptionsByPath.value[productAssignment.path]) {
primedProductPaths.add(productAssignment.path)