refactor(composables): merge 3 history composables into generic (F2.2)
Create useEntityHistory.ts with parameterized entity type. Rewrite useComponentHistory, usePieceHistory, useProductHistory as thin backward-compatible wrappers (67→13 LOC each). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,67 +1,12 @@
|
|||||||
import { ref } from 'vue'
|
/**
|
||||||
import { useApi } from '~/composables/useApi'
|
* Backward-compatible wrapper around useEntityHistory.
|
||||||
|
* Real logic lives in useEntityHistory.ts.
|
||||||
|
*/
|
||||||
|
import { useEntityHistory, type EntityHistoryActor, type EntityHistoryEntry } from './useEntityHistory'
|
||||||
|
|
||||||
export type ComponentHistoryActor = {
|
export type ComponentHistoryActor = EntityHistoryActor
|
||||||
id: string
|
export type ComponentHistoryEntry = EntityHistoryEntry
|
||||||
label: string
|
|
||||||
|
export function useComponentHistory() {
|
||||||
|
return useEntityHistory('composant')
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ComponentHistoryEntry = {
|
|
||||||
id: string
|
|
||||||
action: 'create' | 'update' | 'delete' | string
|
|
||||||
createdAt: string
|
|
||||||
actor: ComponentHistoryActor | null
|
|
||||||
diff: Record<string, { from: unknown; to: unknown }> | null
|
|
||||||
snapshot: Record<string, unknown> | null
|
|
||||||
}
|
|
||||||
|
|
||||||
const extractItems = (payload: any): ComponentHistoryEntry[] => {
|
|
||||||
if (Array.isArray(payload?.items)) {
|
|
||||||
return payload.items
|
|
||||||
}
|
|
||||||
if (Array.isArray(payload?.member)) {
|
|
||||||
return payload.member
|
|
||||||
}
|
|
||||||
if (Array.isArray(payload?.['hydra:member'])) {
|
|
||||||
return payload['hydra:member']
|
|
||||||
}
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useComponentHistory () {
|
|
||||||
const { get } = useApi()
|
|
||||||
|
|
||||||
const history = ref<ComponentHistoryEntry[]>([])
|
|
||||||
const loading = ref(false)
|
|
||||||
const error = ref<string | null>(null)
|
|
||||||
|
|
||||||
const loadHistory = async (componentId: string) => {
|
|
||||||
loading.value = true
|
|
||||||
error.value = null
|
|
||||||
try {
|
|
||||||
const result = await get(`/composants/${componentId}/history`)
|
|
||||||
if (!result.success) {
|
|
||||||
error.value = result.error ?? 'Impossible de charger l’historique.'
|
|
||||||
history.value = []
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
history.value = extractItems(result.data) as ComponentHistoryEntry[]
|
|
||||||
return { success: true, data: history.value }
|
|
||||||
} catch (err: any) {
|
|
||||||
const message = err?.message ?? 'Erreur inconnue'
|
|
||||||
error.value = message
|
|
||||||
history.value = []
|
|
||||||
return { success: false, error: message }
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
history,
|
|
||||||
loading,
|
|
||||||
error,
|
|
||||||
loadHistory,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
69
app/composables/useEntityHistory.ts
Normal file
69
app/composables/useEntityHistory.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* Generic entity history composable.
|
||||||
|
*
|
||||||
|
* Replaces useComponentHistory, usePieceHistory, useProductHistory which were
|
||||||
|
* 99% identical (only the API endpoint differed).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useApi } from '~/composables/useApi'
|
||||||
|
|
||||||
|
export type EntityHistoryActor = {
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EntityHistoryEntry = {
|
||||||
|
id: string
|
||||||
|
action: 'create' | 'update' | 'delete' | string
|
||||||
|
createdAt: string
|
||||||
|
actor: EntityHistoryActor | null
|
||||||
|
diff: Record<string, { from: unknown; to: unknown }> | null
|
||||||
|
snapshot: Record<string, unknown> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
const ENTITY_ENDPOINTS: Record<string, string> = {
|
||||||
|
composant: '/composants',
|
||||||
|
piece: '/pieces',
|
||||||
|
product: '/products',
|
||||||
|
}
|
||||||
|
|
||||||
|
const extractItems = (payload: any): EntityHistoryEntry[] => {
|
||||||
|
if (Array.isArray(payload?.items)) return payload.items
|
||||||
|
if (Array.isArray(payload?.member)) return payload.member
|
||||||
|
if (Array.isArray(payload?.['hydra:member'])) return payload['hydra:member']
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useEntityHistory(entityType: 'composant' | 'piece' | 'product') {
|
||||||
|
const { get } = useApi()
|
||||||
|
const basePath = ENTITY_ENDPOINTS[entityType]
|
||||||
|
|
||||||
|
const history = ref<EntityHistoryEntry[]>([])
|
||||||
|
const loading = ref(false)
|
||||||
|
const error = ref<string | null>(null)
|
||||||
|
|
||||||
|
const loadHistory = async (entityId: string) => {
|
||||||
|
loading.value = true
|
||||||
|
error.value = null
|
||||||
|
try {
|
||||||
|
const result = await get(`${basePath}/${entityId}/history`)
|
||||||
|
if (!result.success) {
|
||||||
|
error.value = result.error ?? 'Impossible de charger l\'historique.'
|
||||||
|
history.value = []
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
history.value = extractItems(result.data)
|
||||||
|
return { success: true, data: history.value }
|
||||||
|
} catch (err: any) {
|
||||||
|
const message = err?.message ?? 'Erreur inconnue'
|
||||||
|
error.value = message
|
||||||
|
history.value = []
|
||||||
|
return { success: false, error: message }
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { history, loading, error, loadHistory }
|
||||||
|
}
|
||||||
@@ -1,67 +1,12 @@
|
|||||||
import { ref } from 'vue'
|
/**
|
||||||
import { useApi } from '~/composables/useApi'
|
* Backward-compatible wrapper around useEntityHistory.
|
||||||
|
* Real logic lives in useEntityHistory.ts.
|
||||||
|
*/
|
||||||
|
import { useEntityHistory, type EntityHistoryActor, type EntityHistoryEntry } from './useEntityHistory'
|
||||||
|
|
||||||
export type PieceHistoryActor = {
|
export type PieceHistoryActor = EntityHistoryActor
|
||||||
id: string
|
export type PieceHistoryEntry = EntityHistoryEntry
|
||||||
label: string
|
|
||||||
|
export function usePieceHistory() {
|
||||||
|
return useEntityHistory('piece')
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PieceHistoryEntry = {
|
|
||||||
id: string
|
|
||||||
action: 'create' | 'update' | 'delete' | string
|
|
||||||
createdAt: string
|
|
||||||
actor: PieceHistoryActor | null
|
|
||||||
diff: Record<string, { from: unknown; to: unknown }> | null
|
|
||||||
snapshot: Record<string, unknown> | null
|
|
||||||
}
|
|
||||||
|
|
||||||
const extractItems = (payload: any): PieceHistoryEntry[] => {
|
|
||||||
if (Array.isArray(payload?.items)) {
|
|
||||||
return payload.items
|
|
||||||
}
|
|
||||||
if (Array.isArray(payload?.member)) {
|
|
||||||
return payload.member
|
|
||||||
}
|
|
||||||
if (Array.isArray(payload?.['hydra:member'])) {
|
|
||||||
return payload['hydra:member']
|
|
||||||
}
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
export function usePieceHistory () {
|
|
||||||
const { get } = useApi()
|
|
||||||
|
|
||||||
const history = ref<PieceHistoryEntry[]>([])
|
|
||||||
const loading = ref(false)
|
|
||||||
const error = ref<string | null>(null)
|
|
||||||
|
|
||||||
const loadHistory = async (pieceId: string) => {
|
|
||||||
loading.value = true
|
|
||||||
error.value = null
|
|
||||||
try {
|
|
||||||
const result = await get(`/pieces/${pieceId}/history`)
|
|
||||||
if (!result.success) {
|
|
||||||
error.value = result.error ?? 'Impossible de charger l’historique.'
|
|
||||||
history.value = []
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
history.value = extractItems(result.data) as PieceHistoryEntry[]
|
|
||||||
return { success: true, data: history.value }
|
|
||||||
} catch (err: any) {
|
|
||||||
const message = err?.message ?? 'Erreur inconnue'
|
|
||||||
error.value = message
|
|
||||||
history.value = []
|
|
||||||
return { success: false, error: message }
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
history,
|
|
||||||
loading,
|
|
||||||
error,
|
|
||||||
loadHistory,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,67 +1,12 @@
|
|||||||
import { ref } from 'vue'
|
/**
|
||||||
import { useApi } from '~/composables/useApi'
|
* Backward-compatible wrapper around useEntityHistory.
|
||||||
|
* Real logic lives in useEntityHistory.ts.
|
||||||
|
*/
|
||||||
|
import { useEntityHistory, type EntityHistoryActor, type EntityHistoryEntry } from './useEntityHistory'
|
||||||
|
|
||||||
export type ProductHistoryActor = {
|
export type ProductHistoryActor = EntityHistoryActor
|
||||||
id: string
|
export type ProductHistoryEntry = EntityHistoryEntry
|
||||||
label: string
|
|
||||||
|
export function useProductHistory() {
|
||||||
|
return useEntityHistory('product')
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ProductHistoryEntry = {
|
|
||||||
id: string
|
|
||||||
action: 'create' | 'update' | 'delete' | string
|
|
||||||
createdAt: string
|
|
||||||
actor: ProductHistoryActor | null
|
|
||||||
diff: Record<string, { from: unknown; to: unknown }> | null
|
|
||||||
snapshot: Record<string, unknown> | null
|
|
||||||
}
|
|
||||||
|
|
||||||
const extractItems = (payload: any): ProductHistoryEntry[] => {
|
|
||||||
if (Array.isArray(payload?.items)) {
|
|
||||||
return payload.items
|
|
||||||
}
|
|
||||||
if (Array.isArray(payload?.member)) {
|
|
||||||
return payload.member
|
|
||||||
}
|
|
||||||
if (Array.isArray(payload?.['hydra:member'])) {
|
|
||||||
return payload['hydra:member']
|
|
||||||
}
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useProductHistory () {
|
|
||||||
const { get } = useApi()
|
|
||||||
|
|
||||||
const history = ref<ProductHistoryEntry[]>([])
|
|
||||||
const loading = ref(false)
|
|
||||||
const error = ref<string | null>(null)
|
|
||||||
|
|
||||||
const loadHistory = async (productId: string) => {
|
|
||||||
loading.value = true
|
|
||||||
error.value = null
|
|
||||||
try {
|
|
||||||
const result = await get(`/products/${productId}/history`)
|
|
||||||
if (!result.success) {
|
|
||||||
error.value = result.error ?? 'Impossible de charger l’historique.'
|
|
||||||
history.value = []
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
history.value = extractItems(result.data) as ProductHistoryEntry[]
|
|
||||||
return { success: true, data: history.value }
|
|
||||||
} catch (err: any) {
|
|
||||||
const message = err?.message ?? 'Erreur inconnue'
|
|
||||||
error.value = message
|
|
||||||
history.value = []
|
|
||||||
return { success: false, error: message }
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
history,
|
|
||||||
loading,
|
|
||||||
error,
|
|
||||||
loadHistory,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user