import { ref, computed, watch } from 'vue' export interface CallHistoryItem { id: string componentCode: string componentName: string timestamp: number inputs: unknown error?: string duration: number statusCode?: number } const HISTORY_STORAGE_KEY = 's8n_call_history' const MAX_HISTORY_ITEMS = 50 const KEEP_REQUEST_INFO_KEY = 's8n_keep_request_info' export function useCallHistory(currentComponentCode?: () => string | undefined) { const callHistory = ref([]) const keepRequestInfo = ref(false) const callHistoryFilter = ref<'all' | 'current'>('all') const loadKeepRequestInfo = () => { const stored = localStorage.getItem(KEEP_REQUEST_INFO_KEY) if (stored) { try { keepRequestInfo.value = JSON.parse(stored) } catch (e) { console.error('Failed to parse keep request info', e) } } } const saveKeepRequestInfo = () => { localStorage.setItem(KEEP_REQUEST_INFO_KEY, JSON.stringify(keepRequestInfo.value)) } const loadCallHistory = () => { const stored = localStorage.getItem(HISTORY_STORAGE_KEY) if (stored) { try { callHistory.value = JSON.parse(stored) } catch (e) { console.error('Failed to parse call history', e) } } } const saveCallHistory = () => { localStorage.setItem(HISTORY_STORAGE_KEY, JSON.stringify(callHistory.value)) } const addCallHistory = (item: Omit) => { // Deep clone inputs to prevent reference sharing const clonedItem = { ...item, inputs: item.inputs !== undefined ? JSON.parse(JSON.stringify(item.inputs)) : item.inputs, } // If keepRequestInfo is false, strip sensitive or large input data const processedItem = { ...clonedItem } if (!keepRequestInfo.value) { // Keep only essential metadata about inputs, not the full data if (processedItem.inputs && typeof processedItem.inputs === 'object') { const inputs = processedItem.inputs as Record // Create a minimal representation showing input structure without values const minimalInputs: Record = {} for (const key in inputs) { if (Object.prototype.hasOwnProperty.call(inputs, key)) { const value = inputs[key] if (value === null || value === undefined) { minimalInputs[key] = value } else if (Array.isArray(value)) { minimalInputs[key] = `[Array of ${value.length} items]` } else if (typeof value === 'object') { minimalInputs[key] = `{Object with ${Object.keys(value).length} keys}` } else if (typeof value === 'string' && value.length > 50) { minimalInputs[key] = `${value.substring(0, 47)}...` } else { minimalInputs[key] = value } } } processedItem.inputs = minimalInputs } } const newItem = { ...processedItem, id: Date.now().toString() + Math.random().toString(36).substring(2), } callHistory.value.unshift(newItem) if (callHistory.value.length > MAX_HISTORY_ITEMS) { callHistory.value = callHistory.value.slice(0, MAX_HISTORY_ITEMS) } saveCallHistory() } const clearCallHistory = () => { callHistory.value = [] saveCallHistory() } const getStatusColor = (statusCode: number): string => { if (statusCode >= 200 && statusCode < 300) return 'positive' if (statusCode >= 300 && statusCode < 400) return 'info' if (statusCode >= 400 && statusCode < 500) return 'warning' if (statusCode >= 500) return 'negative' return 'grey' } const truncateError = (error: string): string => { if (error.length <= 50) return error return error.substring(0, 47) + '...' } const selectHistoryItem = (item: CallHistoryItem) => { // For now, just log the selection console.log('Selected history item:', item) // Could implement functionality to load the component and inputs } const filteredCallHistory = computed(() => { const history = callHistory.value if (callHistoryFilter.value === 'all') { return history } // filter by current component const currentCode = currentComponentCode ? currentComponentCode() : undefined if (!currentCode) { return history } return history.filter((item) => item.componentCode === currentCode) }) // Watch keepRequestInfo to save changes watch(keepRequestInfo, () => { saveKeepRequestInfo() }) return { callHistory, keepRequestInfo, callHistoryFilter, loadKeepRequestInfo, loadCallHistory, addCallHistory, clearCallHistory, getStatusColor, truncateError, selectHistoryItem, filteredCallHistory, } }