- useEntityVersions composable (list, preview, restore API calls) - EntityVersionList component with auto-refresh after save - VersionRestoreModal with context-aware messages per entity type - Integrate into machine, composant, piece, product detail pages - Add restore action label to historyDisplayUtils - Show structure slots in composant/piece consultation mode Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
99 lines
2.5 KiB
TypeScript
99 lines
2.5 KiB
TypeScript
import { ref, toValue } from 'vue'
|
|
import { useApi } from '~/composables/useApi'
|
|
import type { MaybeRef } from 'vue'
|
|
|
|
export interface VersionEntry {
|
|
version: number
|
|
action: 'create' | 'update' | 'restore' | string
|
|
createdAt: string
|
|
actor: { id: string; label: string } | null
|
|
diff: Record<string, { from: unknown; to: unknown }> | null
|
|
}
|
|
|
|
export interface RestorePreview {
|
|
version: number
|
|
restoreMode: 'full' | 'partial'
|
|
diff: Record<string, { current: unknown; restored: unknown }>
|
|
warnings: Array<{
|
|
field: string
|
|
message: string
|
|
missingEntityId: string | null
|
|
missingEntityName: string | null
|
|
}>
|
|
snapshot: Record<string, unknown>
|
|
}
|
|
|
|
export interface RestoreResult {
|
|
success: boolean
|
|
newVersion: number
|
|
restoredFromVersion: number
|
|
restoreMode: 'full' | 'partial'
|
|
warnings: RestorePreview['warnings']
|
|
}
|
|
|
|
const ENTITY_ENDPOINTS: Record<string, string> = {
|
|
machine: '/machines',
|
|
composant: '/composants',
|
|
piece: '/pieces',
|
|
product: '/products',
|
|
}
|
|
|
|
interface Deps {
|
|
entityType: MaybeRef<string>
|
|
entityId: MaybeRef<string>
|
|
}
|
|
|
|
export function useEntityVersions(deps: Deps) {
|
|
const { get, post } = useApi()
|
|
|
|
const versions = ref<VersionEntry[]>([])
|
|
const loading = ref(false)
|
|
const error = ref<string | null>(null)
|
|
|
|
const getPath = () => {
|
|
const type = toValue(deps.entityType)
|
|
const id = toValue(deps.entityId)
|
|
const base = ENTITY_ENDPOINTS[type]
|
|
return `${base}/${id}`
|
|
}
|
|
|
|
const fetchVersions = async () => {
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
const result = await get(`${getPath()}/versions`)
|
|
if (!result.success) {
|
|
error.value = result.error ?? 'Impossible de charger les versions.'
|
|
versions.value = []
|
|
return
|
|
}
|
|
versions.value = result.data?.items ?? []
|
|
}
|
|
catch (err: any) {
|
|
error.value = err?.message ?? 'Erreur inconnue'
|
|
versions.value = []
|
|
}
|
|
finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const fetchPreview = async (version: number): Promise<RestorePreview | null> => {
|
|
const result = await get<RestorePreview>(`${getPath()}/versions/${version}/preview`)
|
|
if (!result.success || !result.data) {
|
|
return null
|
|
}
|
|
return result.data
|
|
}
|
|
|
|
const restore = async (version: number): Promise<RestoreResult | null> => {
|
|
const result = await post<RestoreResult>(`${getPath()}/versions/${version}/restore`, {})
|
|
if (!result.success || !result.data) {
|
|
return null
|
|
}
|
|
return result.data
|
|
}
|
|
|
|
return { versions, loading, error, fetchVersions, fetchPreview, restore }
|
|
}
|