003e419a93
- Migration FK CASCADE/SET NULL pour toutes les FK vers pieces.id (miroir de la fix Composant) + cleanup des orphelins existants avec audit log - Helper ensurePieceExists() qui catch EntityNotFoundException dans MachineStructureController et CustomFieldValueController - Script SQL standalone scripts/cleanup_orphan_piece_refs.sql pour nettoyer la prod sans attendre la migration - Affiche les machines (avec leur site) utilisant la pièce avant la confirmation de suppression
90 lines
3.3 KiB
TypeScript
90 lines
3.3 KiB
TypeScript
export const resolveDeleteImpact = (entity: Record<string, any>): string[] => {
|
|
const impacts: string[] = []
|
|
const machineLinks = Array.isArray(entity?.machineLinks) ? entity.machineLinks.length : entity?.machineLinksCount ?? 0
|
|
const documents = Array.isArray(entity?.documents) ? entity.documents.length : entity?.documentsCount ?? 0
|
|
const customFields = Array.isArray(entity?.customFieldValues) ? entity.customFieldValues.length : entity?.customFieldValuesCount ?? 0
|
|
if (machineLinks > 0) impacts.push(`${machineLinks} liaison${machineLinks > 1 ? 's' : ''} machine`)
|
|
if (documents > 0) impacts.push(`${documents} document${documents > 1 ? 's' : ''}`)
|
|
if (customFields > 0) impacts.push(`${customFields} valeur${customFields > 1 ? 's' : ''} de champs personnalisés`)
|
|
return impacts
|
|
}
|
|
|
|
export const buildDeleteMessage = (entityName: string, impacts: string[]): string => {
|
|
const lines = [`Voulez-vous vraiment supprimer « ${entityName} » ?`]
|
|
if (impacts.length) {
|
|
lines.push(`Cela supprimera également :\n• ${impacts.join('\n• ')}`)
|
|
}
|
|
lines.push('Cette action est irréversible.')
|
|
return lines.join('\n\n')
|
|
}
|
|
|
|
interface UsedInMachine {
|
|
id: string
|
|
name: string | null
|
|
site?: { id: string; name: string | null } | null
|
|
}
|
|
|
|
interface UsedInEntity {
|
|
id: string
|
|
name: string | null
|
|
}
|
|
|
|
export interface UsageInfo {
|
|
machines?: UsedInMachine[]
|
|
composants?: UsedInEntity[]
|
|
pieces?: UsedInEntity[]
|
|
}
|
|
|
|
const formatMachineLine = (m: UsedInMachine): string => {
|
|
const name = m.name?.trim() || '(sans nom)'
|
|
const siteName = m.site?.name?.trim()
|
|
return siteName ? `${name} (${siteName})` : name
|
|
}
|
|
|
|
/**
|
|
* Builds a delete-confirmation message that lists the machines (and other
|
|
* entities) currently using the item. The user sees exactly what will be
|
|
* detached before they confirm the deletion.
|
|
*/
|
|
export const buildDeleteMessageWithUsage = (
|
|
entityName: string,
|
|
entityLabel: string,
|
|
usage: UsageInfo,
|
|
): string => {
|
|
const machines = usage.machines ?? []
|
|
const composants = usage.composants ?? []
|
|
const pieces = usage.pieces ?? []
|
|
|
|
const lines = [`Voulez-vous vraiment supprimer « ${entityName} » ?`]
|
|
|
|
if (machines.length > 0) {
|
|
const header = machines.length === 1
|
|
? `${entityLabel} est actuellement utilisée par 1 machine :`
|
|
: `${entityLabel} est actuellement utilisée par ${machines.length} machines :`
|
|
const bullets = machines.map((m) => `• ${formatMachineLine(m)}`).join('\n')
|
|
lines.push(`${header}\n${bullets}\n\nLa supprimer la retirera de ${machines.length === 1 ? 'cette machine' : 'ces machines'}.`)
|
|
}
|
|
|
|
if (composants.length > 0) {
|
|
const header = composants.length === 1
|
|
? 'Elle est également référencée par 1 composant :'
|
|
: `Elle est également référencée par ${composants.length} composants :`
|
|
const bullets = composants
|
|
.map((c) => `• ${c.name?.trim() || '(sans nom)'}`)
|
|
.join('\n')
|
|
lines.push(`${header}\n${bullets}`)
|
|
}
|
|
|
|
if (pieces.length > 0) {
|
|
const header = pieces.length === 1
|
|
? 'Elle est également utilisée par 1 pièce :'
|
|
: `Elle est également utilisée par ${pieces.length} pièces :`
|
|
const bullets = pieces
|
|
.map((p) => `• ${p.name?.trim() || '(sans nom)'}`)
|
|
.join('\n')
|
|
lines.push(`${header}\n${bullets}`)
|
|
}
|
|
|
|
lines.push('Cette action est irréversible.')
|
|
return lines.join('\n\n')
|
|
} |