cache inteligente: Turso primero, luego KAPPA con deteccion de cambios
This commit is contained in:
+88
-12
@@ -1,14 +1,16 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { kappa } from '@/services/kappa-api'
|
import { kappa } from '@/services/kappa-api'
|
||||||
import { tauriDb } from '@/services/tauri-db'
|
import { tauriDb, type UserStoryRecord, type EpicRecord } from '@/services/tauri-db'
|
||||||
import { stripHtml } from '@/services/clean-html'
|
import { stripHtml } from '@/services/clean-html'
|
||||||
import type { KappaUserStory, KappaLogbookEntry, KappaPlanningEntry, KappaEpicDevelopment } from '@/types/kappa'
|
import type { KappaUserStory, KappaLogbookEntry, KappaPlanningEntry, KappaEpicDevelopment } from '@/types/kappa'
|
||||||
|
|
||||||
export const useWorkItemsStore = defineStore('workitems', () => {
|
export const useWorkItemsStore = defineStore('workitems', () => {
|
||||||
const creating = ref(false)
|
const creating = ref(false)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
const syncing = ref(false)
|
||||||
const error = ref<string | null>(null)
|
const error = ref<string | null>(null)
|
||||||
|
const firstVisit = ref<Set<number>>(new Set())
|
||||||
|
|
||||||
const userStories = ref<KappaUserStory[]>([])
|
const userStories = ref<KappaUserStory[]>([])
|
||||||
const epics = ref<KappaEpicDevelopment[]>([])
|
const epics = ref<KappaEpicDevelopment[]>([])
|
||||||
@@ -49,42 +51,115 @@ export const useWorkItemsStore = defineStore('workitems', () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isFirstVisit = !firstVisit.value.has(id)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [stories, logs, plans, epicData] = await Promise.all([
|
// 1. Cargar desde Turso (instantáneo)
|
||||||
|
if (!isFirstVisit) {
|
||||||
|
const [localEpics, localHUs] = await Promise.all([
|
||||||
|
tauriDb.getEpics(id).catch(() => [] as EpicRecord[]),
|
||||||
|
tauriDb.getUserStories(id).catch(() => [] as UserStoryRecord[]),
|
||||||
|
])
|
||||||
|
|
||||||
|
epics.value = localEpics.map(e => ({
|
||||||
|
id: e.id,
|
||||||
|
code: e.code || undefined,
|
||||||
|
name: e.name,
|
||||||
|
title: e.name,
|
||||||
|
description: e.description || undefined,
|
||||||
|
status: e.status || undefined,
|
||||||
|
client_taker: e.client_taker || undefined,
|
||||||
|
initiative: id,
|
||||||
|
}))
|
||||||
|
|
||||||
|
userStories.value = localHUs.map(hu => ({
|
||||||
|
id: hu.id,
|
||||||
|
code: hu.code || undefined,
|
||||||
|
title: hu.title,
|
||||||
|
description: hu.description || undefined,
|
||||||
|
acceptance_criteria: hu.acceptance_criteria || undefined,
|
||||||
|
status: hu.status || undefined,
|
||||||
|
priority: hu.priority || undefined,
|
||||||
|
initiative: id,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Consultar KAPPA (siempre, para detectar cambios)
|
||||||
|
syncing.value = true
|
||||||
|
const [stories, epicData] = await Promise.all([
|
||||||
kappa.getAllUserStories(id).catch(() => [] as KappaUserStory[]),
|
kappa.getAllUserStories(id).catch(() => [] as KappaUserStory[]),
|
||||||
kappa.getLogbooks(id).catch(() => [] as KappaLogbookEntry[]),
|
|
||||||
kappa.getPlannings(id).catch(() => [] as KappaPlanningEntry[]),
|
|
||||||
kappa.getAllEpicDevelopment(id).catch(() => [] as KappaEpicDevelopment[]),
|
kappa.getAllEpicDevelopment(id).catch(() => [] as KappaEpicDevelopment[]),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
// 3. Merge: detectar nuevos/cambiados
|
||||||
|
const localHUIds = new Set(userStories.value.map(hu => hu.id))
|
||||||
|
const newHUs = stories.filter(s => !localHUIds.has(s.id))
|
||||||
|
|
||||||
|
const localEpicIds = new Set(epics.value.map(e => e.id))
|
||||||
|
const newEpics = epicData.filter(e => !localEpicIds.has(e.id))
|
||||||
|
|
||||||
|
// 4. Actualizar UI con datos frescos de KAPPA
|
||||||
userStories.value = stories
|
userStories.value = stories
|
||||||
logbooks.value = Array.isArray(logs) ? logs : ((logs as any).results ?? [])
|
|
||||||
plannings.value = Array.isArray(plans) ? plans : ((plans as any).results ?? [])
|
|
||||||
|
|
||||||
epics.value = epicData.map(epic => ({
|
epics.value = epicData.map(epic => ({
|
||||||
...epic,
|
...epic,
|
||||||
description: stripHtml(epic.description || ''),
|
description: stripHtml(epic.description || ''),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
syncHUsToTurso(id, userStories.value)
|
// 5. Guardar en Turso: insertar/actualizar HUs y épicas
|
||||||
|
if (isFirstVisit || newHUs.length > 0) {
|
||||||
|
await syncHUsToTurso(id, isFirstVisit ? stories : newHUs)
|
||||||
|
}
|
||||||
|
if (isFirstVisit || newEpics.length > 0) {
|
||||||
|
await syncEpicsToTurso(id, isFirstVisit ? epicData : newEpics)
|
||||||
|
}
|
||||||
|
|
||||||
|
firstVisit.value.add(id)
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
error.value = e.message
|
error.value = e.message
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
syncing.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function syncHUsToTurso(projectId: number, hus: KappaUserStory[]) {
|
async function syncHUsToTurso(projectId: number, hus: KappaUserStory[]) {
|
||||||
for (const hu of hus) {
|
for (const hu of hus) {
|
||||||
await tauriDb.saveWorkItem({
|
await tauriDb.saveUserStory({
|
||||||
id: hu.id ?? 0,
|
id: hu.id ?? 0,
|
||||||
project_id: projectId,
|
initiative_id: projectId,
|
||||||
|
epic_id: null,
|
||||||
code: hu.code ?? null,
|
code: hu.code ?? null,
|
||||||
title: hu.title,
|
title: hu.title,
|
||||||
description: stripHtml(hu.description || ''),
|
description: stripHtml(hu.description || ''),
|
||||||
type: 'hu',
|
acceptance_criteria: hu.acceptance_criteria ?? null,
|
||||||
status: hu.status || 'backlog',
|
status: hu.status ?? null,
|
||||||
priority: hu.priority || 'medium',
|
priority: hu.priority ?? null,
|
||||||
|
story_points: null,
|
||||||
|
estimated_hours: null,
|
||||||
|
actual_hours: null,
|
||||||
|
assigned_to: null,
|
||||||
|
created_at: null,
|
||||||
|
}).catch(() => {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function syncEpicsToTurso(projectId: number, epicsData: KappaEpicDevelopment[]) {
|
||||||
|
for (const epic of epicsData) {
|
||||||
|
await tauriDb.saveEpic({
|
||||||
|
id: epic.id,
|
||||||
|
initiative_id: projectId,
|
||||||
|
code: epic.code ?? null,
|
||||||
|
name: epic.name || epic.title || `Épica ${epic.id}`,
|
||||||
|
description: epic.description ?? null,
|
||||||
|
status: epic.status ?? null,
|
||||||
|
client_taker: null,
|
||||||
|
stimated_start_date: null,
|
||||||
|
stimated_end_date: null,
|
||||||
|
start_date: null,
|
||||||
|
end_date: null,
|
||||||
|
created_at: null,
|
||||||
|
updated_at: null,
|
||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,6 +167,7 @@ export const useWorkItemsStore = defineStore('workitems', () => {
|
|||||||
return {
|
return {
|
||||||
creating,
|
creating,
|
||||||
loading,
|
loading,
|
||||||
|
syncing,
|
||||||
error,
|
error,
|
||||||
userStories,
|
userStories,
|
||||||
epics,
|
epics,
|
||||||
|
|||||||
Reference in New Issue
Block a user