fix
This commit is contained in:
@@ -124,6 +124,7 @@ const isLoadingAll = ref(false)
|
||||
const loadingProgress = ref(0)
|
||||
|
||||
// Get the table store for this specific datasource (using name, not table)
|
||||
// The plugin has already loaded all caches, so this just retrieves the existing instance
|
||||
const tableStore = computed(() => {
|
||||
if (typeof $getTableStore === 'function') {
|
||||
return $getTableStore(props.metadata.name)
|
||||
|
||||
@@ -277,8 +277,12 @@ const totalRowCount = computed(() => {
|
||||
})
|
||||
|
||||
// Methods
|
||||
function selectTable(tableName: string) {
|
||||
if (selectedTableName.value === tableName) return
|
||||
async function selectTable(tableName: string) {
|
||||
console.log(`[Explorer] selectTable called with: ${tableName}`)
|
||||
if (selectedTableName.value === tableName) {
|
||||
console.log(`[Explorer] Table ${tableName} already selected, skipping`)
|
||||
return
|
||||
}
|
||||
|
||||
selectedTableName.value = tableName
|
||||
|
||||
@@ -286,20 +290,31 @@ function selectTable(tableName: string) {
|
||||
if (typeof $getTableStore === 'function') {
|
||||
const store = $getTableStore(tableName)
|
||||
if (store) {
|
||||
console.log(`[Explorer] Got store for ${tableName} via plugin`)
|
||||
currentTableStore.value = store
|
||||
// Initialize the store (loads from cache or fetches)
|
||||
store.initialize()
|
||||
|
||||
// Load from cache first (async from IndexedDB)
|
||||
await store.loadFromCache()
|
||||
console.log(`[Explorer] After loadFromCache, store has ${store.recordCount} records`)
|
||||
|
||||
// Note: We don't call initialize() here because MetadatosCard will handle loading
|
||||
// initialize() would trigger a fetch, but we want manual control via the buttons
|
||||
}
|
||||
} else {
|
||||
// Fallback: create store directly
|
||||
console.log(`[Explorer] Creating store for ${tableName} directly (fallback)`)
|
||||
currentTableStore.value = useTableDataStore(tableName)
|
||||
currentTableStore.value.initialize()
|
||||
await currentTableStore.value.loadFromCache()
|
||||
console.log(`[Explorer] After loadFromCache, store has ${currentTableStore.value.recordCount} records`)
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshTableData() {
|
||||
console.log('[Explorer] refreshTableData called')
|
||||
if (currentTableStore.value) {
|
||||
console.log(`[Explorer] Refreshing data for current table (${selectedTableName.value})`)
|
||||
await currentTableStore.value.refreshData()
|
||||
console.log(`[Explorer] After refresh, store has ${currentTableStore.value.recordCount} records`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,13 +355,15 @@ function formatCellValue(value: unknown): string {
|
||||
|
||||
// Lifecycle
|
||||
onMounted(async () => {
|
||||
console.log('[Explorer] onMounted: Initializing metadata store')
|
||||
await metadataStore.initialize()
|
||||
|
||||
// Auto-select first table if available
|
||||
if (metadataStore.hasMetadata && !selectedTableName.value) {
|
||||
const firstTable = metadataStore.allTables[0]
|
||||
if (firstTable) {
|
||||
selectTable(firstTable.table)
|
||||
console.log(`[Explorer] Auto-selecting first table: ${firstTable.name}`)
|
||||
selectTable(firstTable.name) // Use name instead of table
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -354,7 +371,8 @@ onMounted(async () => {
|
||||
// Auto-select first table when metadata becomes available
|
||||
watch(() => metadataStore.hasMetadata, (hasMetadata) => {
|
||||
if (hasMetadata && !selectedTableName.value && metadataStore.allTables.length > 0) {
|
||||
selectTable(metadataStore.allTables[0].table)
|
||||
console.log('[Explorer] Metadata became available, auto-selecting first table')
|
||||
selectTable(metadataStore.allTables[0].name) // Use name instead of table
|
||||
}
|
||||
})
|
||||
</script>
|
||||
64
nuxt4-app/app/plugins/tableStores.client.ts
Normal file
64
nuxt4-app/app/plugins/tableStores.client.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { useMetadataStore } from '~/stores/metadata'
|
||||
import { createTableDataStore } from '~/stores/tableDataFactory'
|
||||
|
||||
export default defineNuxtPlugin(async (nuxtApp) => {
|
||||
console.log('[TableStoresPlugin] Initializing...')
|
||||
|
||||
// Wait for metadata to be available
|
||||
const metadataStore = useMetadataStore()
|
||||
|
||||
// Initialize metadata first
|
||||
await metadataStore.initialize()
|
||||
console.log(`[TableStoresPlugin] Metadata initialized, found ${metadataStore.allTables.length} tables`)
|
||||
|
||||
// Create stores for all available tables and preload from cache
|
||||
const tableStores = new Map<string, ReturnType<typeof createTableDataStore>>()
|
||||
const storeInstances = new Map<string, ReturnType<ReturnType<typeof createTableDataStore>>>()
|
||||
|
||||
// Load all caches in parallel for better performance
|
||||
const cacheLoadPromises = metadataStore.allTables.map(async (metadata) => {
|
||||
const datasourceName = metadata.name // Use datasource name, not table name
|
||||
console.log(`[TableStoresPlugin] Creating store for datasource: ${datasourceName}`)
|
||||
|
||||
const storeFactory = createTableDataStore(datasourceName, 100)
|
||||
const storeInstance = storeFactory()
|
||||
|
||||
// Register both factory and instance
|
||||
tableStores.set(datasourceName, storeFactory)
|
||||
storeInstances.set(datasourceName, storeInstance)
|
||||
|
||||
// Load from cache immediately
|
||||
await storeInstance.loadFromCache()
|
||||
console.log(`[TableStoresPlugin] Loaded ${storeInstance.recordCount} records for ${datasourceName}`)
|
||||
})
|
||||
|
||||
// Wait for all caches to load
|
||||
await Promise.all(cacheLoadPromises)
|
||||
console.log('[TableStoresPlugin] All caches loaded successfully')
|
||||
|
||||
// Provide access to table stores
|
||||
return {
|
||||
provide: {
|
||||
tableStores,
|
||||
// Helper function to get a table store (returns existing instance)
|
||||
getTableStore: (tableName: string) => {
|
||||
// First try to get existing instance
|
||||
const existingInstance = storeInstances.get(tableName)
|
||||
if (existingInstance) {
|
||||
return existingInstance
|
||||
}
|
||||
|
||||
// Fall back to creating new instance from factory
|
||||
const storeFactory = tableStores.get(tableName)
|
||||
if (!storeFactory) {
|
||||
console.warn(`[TableStoresPlugin] Table store for "${tableName}" not found`)
|
||||
return null
|
||||
}
|
||||
|
||||
const newInstance = storeFactory()
|
||||
storeInstances.set(tableName, newInstance)
|
||||
return newInstance
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1,4 +1,5 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { tableDataStorage } from '~/utils/storage'
|
||||
|
||||
export interface TableDataState<T = Record<string, unknown>> {
|
||||
data: T[]
|
||||
@@ -23,8 +24,8 @@ export interface TableDataActions<T = Record<string, unknown>> {
|
||||
loadData(force?: boolean): Promise<void>
|
||||
refreshData(): Promise<void>
|
||||
fetchData(): Promise<void>
|
||||
clearData(): void
|
||||
loadFromCache(): void
|
||||
clearData(): Promise<void>
|
||||
loadFromCache(): Promise<void>
|
||||
extractErrorMessage(error: unknown): string
|
||||
initialize(): Promise<void>
|
||||
getRecord(id: string | number): T | undefined
|
||||
@@ -169,16 +170,16 @@ export function createTableDataStore<T = Record<string, unknown>>(
|
||||
this.lastUpdated = new Date().toISOString()
|
||||
this.initialized = true
|
||||
|
||||
// Persist to localStorage for offline access
|
||||
// Persist to IndexedDB for offline access
|
||||
if (process.client) {
|
||||
try {
|
||||
localStorage.setItem(cacheKey, JSON.stringify({
|
||||
await tableDataStorage.setItem(cacheKey, {
|
||||
data: this.data,
|
||||
lastUpdated: this.lastUpdated,
|
||||
limit: this.limit
|
||||
}))
|
||||
})
|
||||
} catch (error) {
|
||||
console.warn(`Failed to persist ${tableName} data to localStorage:`, error)
|
||||
console.warn(`Failed to persist ${tableName} data to IndexedDB:`, error)
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
@@ -195,9 +196,9 @@ export function createTableDataStore<T = Record<string, unknown>>(
|
||||
},
|
||||
|
||||
/**
|
||||
* Load data from localStorage cache
|
||||
* Load data from IndexedDB cache
|
||||
*/
|
||||
loadFromCache(): void {
|
||||
async loadFromCache(): Promise<void> {
|
||||
if (!process.client) {
|
||||
console.log(`[${tableName}] loadFromCache: Not on client, skipping`)
|
||||
return
|
||||
@@ -205,9 +206,8 @@ export function createTableDataStore<T = Record<string, unknown>>(
|
||||
|
||||
try {
|
||||
console.log(`[${tableName}] loadFromCache: Attempting to load from key: ${cacheKey}`)
|
||||
const cached = localStorage.getItem(cacheKey)
|
||||
if (cached) {
|
||||
const parsedCache = JSON.parse(cached)
|
||||
const parsedCache = await tableDataStorage.getItem(cacheKey)
|
||||
if (parsedCache) {
|
||||
console.log(`[${tableName}] loadFromCache: Found ${parsedCache.data?.length || 0} records in cache`)
|
||||
this.data = parsedCache.data || []
|
||||
this.lastUpdated = parsedCache.lastUpdated || null
|
||||
@@ -225,7 +225,7 @@ export function createTableDataStore<T = Record<string, unknown>>(
|
||||
/**
|
||||
* Clear all data
|
||||
*/
|
||||
clearData(): void {
|
||||
async clearData(): Promise<void> {
|
||||
this.data = []
|
||||
this.error = null
|
||||
this.lastUpdated = null
|
||||
@@ -233,7 +233,7 @@ export function createTableDataStore<T = Record<string, unknown>>(
|
||||
|
||||
if (process.client) {
|
||||
try {
|
||||
localStorage.removeItem(cacheKey)
|
||||
await tableDataStorage.removeItem(cacheKey)
|
||||
} catch (error) {
|
||||
console.warn(`Failed to clear ${tableName} data cache:`, error)
|
||||
}
|
||||
@@ -260,7 +260,7 @@ export function createTableDataStore<T = Record<string, unknown>>(
|
||||
*/
|
||||
async initialize(): Promise<void> {
|
||||
// Load from cache first for immediate availability
|
||||
this.loadFromCache()
|
||||
await this.loadFromCache()
|
||||
|
||||
// Then try to fetch fresh data
|
||||
await this.loadData()
|
||||
@@ -349,30 +349,29 @@ export function createTableDataStore<T = Record<string, unknown>>(
|
||||
|
||||
console.log(`[${tableName}] loadAllDataInBatches: Finished loading ${this.data.length} records`)
|
||||
|
||||
// Persist to localStorage
|
||||
// Persist to IndexedDB
|
||||
if (process.client) {
|
||||
try {
|
||||
console.log(`[${tableName}] loadAllDataInBatches: Persisting to localStorage with key: ${cacheKey}`)
|
||||
console.log(`[${tableName}] loadAllDataInBatches: Persisting to IndexedDB with key: ${cacheKey}`)
|
||||
const dataToSave = {
|
||||
data: this.data,
|
||||
lastUpdated: this.lastUpdated,
|
||||
limit: this.limit
|
||||
}
|
||||
console.log(`[${tableName}] loadAllDataInBatches: Saving ${dataToSave.data.length} records`)
|
||||
localStorage.setItem(cacheKey, JSON.stringify(dataToSave))
|
||||
console.log(`[${tableName}] loadAllDataInBatches: Successfully saved to localStorage`)
|
||||
await tableDataStorage.setItem(cacheKey, dataToSave)
|
||||
console.log(`[${tableName}] loadAllDataInBatches: Successfully saved to IndexedDB`)
|
||||
|
||||
// Verify it was saved
|
||||
const saved = localStorage.getItem(cacheKey)
|
||||
const saved = await tableDataStorage.getItem(cacheKey)
|
||||
if (saved) {
|
||||
const parsed = JSON.parse(saved)
|
||||
console.log(`[${tableName}] loadAllDataInBatches: Verification - localStorage contains ${parsed.data?.length || 0} records`)
|
||||
console.log(`[${tableName}] loadAllDataInBatches: Verification - IndexedDB contains ${saved.data?.length || 0} records`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[${tableName}] loadAllDataInBatches: Failed to persist data to localStorage:`, error)
|
||||
console.error(`[${tableName}] loadAllDataInBatches: Failed to persist data to IndexedDB:`, error)
|
||||
}
|
||||
} else {
|
||||
console.log(`[${tableName}] loadAllDataInBatches: Not on client, skipping localStorage`)
|
||||
console.log(`[${tableName}] loadAllDataInBatches: Not on client, skipping IndexedDB`)
|
||||
}
|
||||
|
||||
if (onProgress) {
|
||||
@@ -466,30 +465,29 @@ export function createTableDataStore<T = Record<string, unknown>>(
|
||||
this.lastUpdated = new Date().toISOString()
|
||||
console.log(`[${tableName}] loadLatestDataInBatches: Added ${newRecordsCount} new records, total: ${this.data.length}`)
|
||||
|
||||
// Persist to localStorage
|
||||
// Persist to IndexedDB
|
||||
if (process.client) {
|
||||
try {
|
||||
console.log(`[${tableName}] loadLatestDataInBatches: Persisting to localStorage with key: ${cacheKey}`)
|
||||
console.log(`[${tableName}] loadLatestDataInBatches: Persisting to IndexedDB with key: ${cacheKey}`)
|
||||
const dataToSave = {
|
||||
data: this.data,
|
||||
lastUpdated: this.lastUpdated,
|
||||
limit: this.limit
|
||||
}
|
||||
console.log(`[${tableName}] loadLatestDataInBatches: Saving ${dataToSave.data.length} records`)
|
||||
localStorage.setItem(cacheKey, JSON.stringify(dataToSave))
|
||||
console.log(`[${tableName}] loadLatestDataInBatches: Successfully saved to localStorage`)
|
||||
await tableDataStorage.setItem(cacheKey, dataToSave)
|
||||
console.log(`[${tableName}] loadLatestDataInBatches: Successfully saved to IndexedDB`)
|
||||
|
||||
// Verify it was saved
|
||||
const saved = localStorage.getItem(cacheKey)
|
||||
const saved = await tableDataStorage.getItem(cacheKey)
|
||||
if (saved) {
|
||||
const parsed = JSON.parse(saved)
|
||||
console.log(`[${tableName}] loadLatestDataInBatches: Verification - localStorage contains ${parsed.data?.length || 0} records`)
|
||||
console.log(`[${tableName}] loadLatestDataInBatches: Verification - IndexedDB contains ${saved.data?.length || 0} records`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[${tableName}] loadLatestDataInBatches: Failed to persist data to localStorage:`, error)
|
||||
console.error(`[${tableName}] loadLatestDataInBatches: Failed to persist data to IndexedDB:`, error)
|
||||
}
|
||||
} else {
|
||||
console.log(`[${tableName}] loadLatestDataInBatches: Not on client, skipping localStorage`)
|
||||
console.log(`[${tableName}] loadLatestDataInBatches: Not on client, skipping IndexedDB`)
|
||||
}
|
||||
|
||||
if (onProgress) {
|
||||
|
||||
305
nuxt4-app/app/utils/storage.ts
Normal file
305
nuxt4-app/app/utils/storage.ts
Normal file
@@ -0,0 +1,305 @@
|
||||
/**
|
||||
* Storage utility that uses IndexedDB for table data and localStorage for config/secrets
|
||||
*
|
||||
* Strategy:
|
||||
* - IndexedDB: ALL table/datasource data (can store hundreds of MB)
|
||||
* - localStorage: Only for secrets, variables, configurations (small data)
|
||||
*/
|
||||
|
||||
const DB_NAME = 'analitica-nucleo-db'
|
||||
const DB_VERSION = 1
|
||||
const STORE_NAME = 'table-data'
|
||||
|
||||
let dbInstance: IDBDatabase | null = null
|
||||
|
||||
/**
|
||||
* Initialize IndexedDB
|
||||
*/
|
||||
async function initDB(): Promise<IDBDatabase> {
|
||||
if (dbInstance) return dbInstance
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open(DB_NAME, DB_VERSION)
|
||||
|
||||
request.onerror = () => {
|
||||
console.error('[Storage] IndexedDB error:', request.error)
|
||||
reject(request.error)
|
||||
}
|
||||
|
||||
request.onsuccess = () => {
|
||||
dbInstance = request.result
|
||||
console.log('[Storage] IndexedDB initialized successfully')
|
||||
resolve(dbInstance)
|
||||
}
|
||||
|
||||
request.onupgradeneeded = (event) => {
|
||||
const db = (event.target as IDBOpenDBRequest).result
|
||||
|
||||
// Create object store if it doesn't exist
|
||||
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
||||
db.createObjectStore(STORE_NAME, { keyPath: 'key' })
|
||||
console.log('[Storage] Created object store:', STORE_NAME)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Deep clone to remove reactivity and make data serializable for IndexedDB
|
||||
*/
|
||||
function toPlainObject(obj: any): any {
|
||||
// Use JSON parse/stringify to deep clone and remove all reactivity/proxies
|
||||
try {
|
||||
return JSON.parse(JSON.stringify(obj))
|
||||
} catch (error) {
|
||||
console.error('[Storage] Failed to convert to plain object:', error)
|
||||
return obj
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save data to IndexedDB
|
||||
*/
|
||||
async function saveToIndexedDB(key: string, data: any): Promise<boolean> {
|
||||
try {
|
||||
const db = await initDB()
|
||||
|
||||
// Convert reactive objects to plain objects
|
||||
const plainData = toPlainObject(data)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([STORE_NAME], 'readwrite')
|
||||
const store = transaction.objectStore(STORE_NAME)
|
||||
|
||||
const request = store.put({
|
||||
key,
|
||||
value: plainData,
|
||||
timestamp: Date.now()
|
||||
})
|
||||
|
||||
request.onsuccess = () => {
|
||||
console.log(`[Storage] Saved to IndexedDB: ${key}`)
|
||||
resolve(true)
|
||||
}
|
||||
|
||||
request.onerror = () => {
|
||||
console.error(`[Storage] Failed to save to IndexedDB: ${key}`, request.error)
|
||||
reject(request.error)
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[Storage] IndexedDB save error:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load data from IndexedDB
|
||||
*/
|
||||
async function loadFromIndexedDB(key: string): Promise<any | null> {
|
||||
try {
|
||||
const db = await initDB()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([STORE_NAME], 'readonly')
|
||||
const store = transaction.objectStore(STORE_NAME)
|
||||
const request = store.get(key)
|
||||
|
||||
request.onsuccess = () => {
|
||||
if (request.result) {
|
||||
console.log(`[Storage] Loaded from IndexedDB: ${key}`)
|
||||
resolve(request.result.value)
|
||||
} else {
|
||||
console.log(`[Storage] No data found in IndexedDB for: ${key}`)
|
||||
resolve(null)
|
||||
}
|
||||
}
|
||||
|
||||
request.onerror = () => {
|
||||
console.error(`[Storage] Failed to load from IndexedDB: ${key}`, request.error)
|
||||
reject(request.error)
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[Storage] IndexedDB load error:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove data from IndexedDB
|
||||
*/
|
||||
async function removeFromIndexedDB(key: string): Promise<boolean> {
|
||||
try {
|
||||
const db = await initDB()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([STORE_NAME], 'readwrite')
|
||||
const store = transaction.objectStore(STORE_NAME)
|
||||
const request = store.delete(key)
|
||||
|
||||
request.onsuccess = () => {
|
||||
console.log(`[Storage] Removed from IndexedDB: ${key}`)
|
||||
resolve(true)
|
||||
}
|
||||
|
||||
request.onerror = () => {
|
||||
console.error(`[Storage] Failed to remove from IndexedDB: ${key}`, request.error)
|
||||
reject(request.error)
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[Storage] IndexedDB remove error:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Storage interface for table/datasource data (uses IndexedDB exclusively)
|
||||
*/
|
||||
export const tableDataStorage = {
|
||||
/**
|
||||
* Save table data to IndexedDB (for large datasets)
|
||||
*/
|
||||
async setItem(key: string, data: any): Promise<void> {
|
||||
if (!process.client) {
|
||||
console.log('[TableDataStorage] Not on client, skipping storage')
|
||||
return
|
||||
}
|
||||
|
||||
const dataString = JSON.stringify(data)
|
||||
const dataSizeKB = new Blob([dataString]).size / 1024
|
||||
console.log(`[TableDataStorage] Saving ${dataSizeKB.toFixed(2)} KB to IndexedDB for key: ${key}`)
|
||||
|
||||
try {
|
||||
const success = await saveToIndexedDB(key, data)
|
||||
if (success) {
|
||||
console.log(`[TableDataStorage] ✓ Successfully saved ${dataSizeKB.toFixed(2)} KB to IndexedDB`)
|
||||
return
|
||||
} else {
|
||||
throw new Error('Failed to save to IndexedDB')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[TableDataStorage] ✗ Failed to save to IndexedDB:', error)
|
||||
throw new Error(`No se pudo guardar la tabla: ${error}`)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Load table data from IndexedDB
|
||||
*/
|
||||
async getItem(key: string): Promise<any | null> {
|
||||
if (!process.client) {
|
||||
console.log('[TableDataStorage] Not on client, skipping storage')
|
||||
return null
|
||||
}
|
||||
|
||||
console.log(`[TableDataStorage] Loading from IndexedDB: ${key}`)
|
||||
|
||||
try {
|
||||
const data = await loadFromIndexedDB(key)
|
||||
if (data !== null) {
|
||||
const dataString = JSON.stringify(data)
|
||||
const dataSizeKB = new Blob([dataString]).size / 1024
|
||||
console.log(`[TableDataStorage] ✓ Loaded ${dataSizeKB.toFixed(2)} KB from IndexedDB`)
|
||||
return data
|
||||
} else {
|
||||
console.log(`[TableDataStorage] No data found in IndexedDB for: ${key}`)
|
||||
return null
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[TableDataStorage] ✗ Failed to load from IndexedDB:', error)
|
||||
return null
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove table data from IndexedDB
|
||||
*/
|
||||
async removeItem(key: string): Promise<void> {
|
||||
if (!process.client) return
|
||||
|
||||
console.log(`[TableDataStorage] Removing from IndexedDB: ${key}`)
|
||||
|
||||
try {
|
||||
await removeFromIndexedDB(key)
|
||||
console.log(`[TableDataStorage] ✓ Removed from IndexedDB: ${key}`)
|
||||
} catch (error) {
|
||||
console.error('[TableDataStorage] ✗ Failed to remove from IndexedDB:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Storage interface for config/secrets (uses localStorage exclusively)
|
||||
*/
|
||||
export const configStorage = {
|
||||
/**
|
||||
* Save config/secrets to localStorage (for small data only)
|
||||
*/
|
||||
setItem(key: string, data: any): void {
|
||||
if (!process.client) {
|
||||
console.log('[ConfigStorage] Not on client, skipping storage')
|
||||
return
|
||||
}
|
||||
|
||||
const dataString = JSON.stringify(data)
|
||||
const dataSizeKB = new Blob([dataString]).size / 1024
|
||||
console.log(`[ConfigStorage] Saving ${dataSizeKB.toFixed(2)} KB to localStorage for key: ${key}`)
|
||||
|
||||
try {
|
||||
localStorage.setItem(key, dataString)
|
||||
console.log(`[ConfigStorage] ✓ Saved to localStorage`)
|
||||
} catch (error: any) {
|
||||
if (error.name === 'QuotaExceededError') {
|
||||
console.error('[ConfigStorage] ✗ localStorage quota exceeded')
|
||||
throw new Error('No hay espacio en localStorage para guardar la configuración')
|
||||
}
|
||||
throw error
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Load config/secrets from localStorage
|
||||
*/
|
||||
getItem(key: string): any | null {
|
||||
if (!process.client) {
|
||||
console.log('[ConfigStorage] Not on client, skipping storage')
|
||||
return null
|
||||
}
|
||||
|
||||
console.log(`[ConfigStorage] Loading from localStorage: ${key}`)
|
||||
|
||||
try {
|
||||
const item = localStorage.getItem(key)
|
||||
if (item) {
|
||||
const data = JSON.parse(item)
|
||||
const dataSizeKB = new Blob([item]).size / 1024
|
||||
console.log(`[ConfigStorage] ✓ Loaded ${dataSizeKB.toFixed(2)} KB from localStorage`)
|
||||
return data
|
||||
} else {
|
||||
console.log(`[ConfigStorage] No data found in localStorage for: ${key}`)
|
||||
return null
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[ConfigStorage] ✗ Failed to load from localStorage:', error)
|
||||
return null
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove config/secrets from localStorage
|
||||
*/
|
||||
removeItem(key: string): void {
|
||||
if (!process.client) return
|
||||
|
||||
console.log(`[ConfigStorage] Removing from localStorage: ${key}`)
|
||||
|
||||
try {
|
||||
localStorage.removeItem(key)
|
||||
console.log(`[ConfigStorage] ✓ Removed from localStorage: ${key}`)
|
||||
} catch (error) {
|
||||
console.error('[ConfigStorage] ✗ Failed to remove from localStorage:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import { useMetadataStore } from '~/stores/metadata'
|
||||
import { createTableDataStore } from '~/stores/tableDataFactory'
|
||||
|
||||
export default defineNuxtPlugin(async (nuxtApp) => {
|
||||
// Wait for metadata to be available
|
||||
const metadataStore = useMetadataStore()
|
||||
|
||||
// Initialize metadata first
|
||||
await metadataStore.initialize()
|
||||
|
||||
// Create stores for all available tables
|
||||
const tableStores = new Map<string, ReturnType<typeof createTableDataStore>>()
|
||||
|
||||
metadataStore.allTables.forEach((table) => {
|
||||
const storeName = table.table
|
||||
const storeFactory = createTableDataStore(storeName, 100)
|
||||
|
||||
// Register the store
|
||||
tableStores.set(storeName, storeFactory)
|
||||
|
||||
// Optionally initialize stores in the background (lazy loading)
|
||||
// You can uncomment this to preload all data
|
||||
// const storeInstance = storeFactory()
|
||||
// storeInstance.loadFromCache()
|
||||
})
|
||||
|
||||
// Provide access to table stores
|
||||
return {
|
||||
provide: {
|
||||
tableStores,
|
||||
// Helper function to get a table store
|
||||
getTableStore: (tableName: string) => {
|
||||
const storeFactory = tableStores.get(tableName)
|
||||
if (!storeFactory) {
|
||||
console.warn(`Table store for "${tableName}" not found`)
|
||||
return null
|
||||
}
|
||||
return storeFactory()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user