proyectos: status true/false ahora muestra Activo/Inactivo via i18n

This commit is contained in:
2026-05-27 21:44:41 -05:00
parent 66b3e24fec
commit 9ae2af3ea2
10 changed files with 64 additions and 18 deletions
+30 -4
View File
@@ -11,6 +11,8 @@ pub struct Project {
pub status: String,
pub start_date: Option<String>,
pub end_date: Option<String>,
pub hus_count: Option<i64>,
pub epics_count: Option<i64>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
@@ -155,7 +157,7 @@ async fn get_conn(db_path: &str) -> Result<libsql::Connection, String> {
let conn = db.connect().map_err(|e| format!("Connect: {e}"))?;
conn.execute_batch(
"CREATE TABLE IF NOT EXISTS projects (
" CREATE TABLE IF NOT EXISTS projects (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
key TEXT,
@@ -163,6 +165,8 @@ async fn get_conn(db_path: &str) -> Result<libsql::Connection, String> {
status TEXT DEFAULT 'active',
start_date TEXT,
end_date TEXT,
hus_count INTEGER DEFAULT 0,
epics_count INTEGER DEFAULT 0,
created_at TEXT DEFAULT (datetime('now'))
);
@@ -325,7 +329,7 @@ pub mod commands {
let conn = get_conn(&db_path).await?;
let mut rows = conn
.query("SELECT id, name, key, description, status, start_date, end_date FROM projects ORDER BY name", ())
.query("SELECT id, name, key, description, status, start_date, end_date, hus_count, epics_count FROM projects ORDER BY name", ())
.await
.map_err(|e| format!("Query: {e}"))?;
@@ -339,6 +343,8 @@ pub mod commands {
status: row.get::<String>(4).unwrap_or_else(|_| "active".into()),
start_date: row.get::<String>(5).ok(),
end_date: row.get::<String>(6).ok(),
hus_count: row.get::<i64>(7).ok(),
epics_count: row.get::<i64>(8).ok(),
});
}
Ok(projects)
@@ -350,8 +356,8 @@ pub mod commands {
let conn = get_conn(&db_path).await?;
conn.execute(
"INSERT OR REPLACE INTO projects (id, name, key, description, status, start_date, end_date)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
"INSERT OR REPLACE INTO projects (id, name, key, description, status, start_date, end_date, hus_count, epics_count)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)",
libsql::params![
project.id,
project.name,
@@ -360,6 +366,8 @@ pub mod commands {
project.status,
project.start_date,
project.end_date,
project.hus_count,
project.epics_count,
],
)
.await
@@ -368,6 +376,24 @@ pub mod commands {
Ok(conn.last_insert_rowid())
}
#[tauri::command]
pub async fn update_project_counts(state: State<'_, Mutex<String>>, initiative_id: i64) -> Result<(), String> {
let db_path = state.lock().map_err(|e| e.to_string())?.clone();
let conn = get_conn(&db_path).await?;
conn.execute(
"UPDATE projects SET
hus_count = (SELECT COUNT(*) FROM user_stories WHERE initiative_id = ?1),
epics_count = (SELECT COUNT(*) FROM epics WHERE initiative_id = ?1)
WHERE id = ?1",
libsql::params![initiative_id],
)
.await
.map_err(|e| format!("Update counts: {e}"))?;
Ok(())
}
#[tauri::command]
pub async fn delete_project(state: State<'_, Mutex<String>>, id: i64) -> Result<(), String> {
let db_path = state.lock().map_err(|e| e.to_string())?.clone();
+1
View File
@@ -22,6 +22,7 @@ fn main() {
.invoke_handler(tauri::generate_handler![
commands::get_projects,
commands::save_project,
commands::update_project_counts,
commands::delete_project,
commands::get_work_items,
commands::save_work_item,
+3 -1
View File
@@ -41,7 +41,7 @@
"common": {
"loading": "Loading...",
"retry": "Retry",
"backToProjects": "Back to Projects",
"backToProjects": "Back to Projects",
"noDescription": "No description"
},
"sidebar": {
@@ -79,6 +79,8 @@
"selectProject": "Select a project from the sidebar"
},
"status": {
"active": "Active",
"inactive": "Inactive",
"backlog": "Backlog",
"todo": "To do",
"inProgress": "In progress",
+3 -1
View File
@@ -41,7 +41,7 @@
"common": {
"loading": "Cargando...",
"retry": "Reintentar",
"backToProjects": "Volver a Proyectos",
"backToProjects": "Volver a Proyectos",
"noDescription": "Sin descripción"
},
"sidebar": {
@@ -79,6 +79,8 @@
"selectProject": "Seleccioná un proyecto del panel lateral"
},
"status": {
"active": "Activo",
"inactive": "Inactivo",
"backlog": "Backlog",
"todo": "Por hacer",
"inProgress": "En progreso",
+5
View File
@@ -18,6 +18,8 @@ export interface ProjectRecord {
status: string
start_date: string | null
end_date: string | null
hus_count: number | null
epics_count: number | null
}
export interface EpicRecord {
@@ -141,6 +143,9 @@ export const tauriDb = {
saveProject(project: ProjectRecord): Promise<number> {
return safeInvoke('save_project', { project })
},
updateProjectCounts(initiativeId: number): Promise<void> {
return safeInvoke('update_project_counts', { initiativeId })
},
deleteProject(id: number): Promise<void> {
return safeInvoke('delete_project', { id })
},
+2
View File
@@ -49,6 +49,8 @@ export const useProjectsStore = defineStore('projects', () => {
status: p.status || 'active',
start_date: p.start_date ?? null,
end_date: p.end_date ?? null,
hus_count: null,
epics_count: null,
}).catch(() => {})
}
}
+2
View File
@@ -114,6 +114,8 @@ export const useWorkItemsStore = defineStore('workitems', () => {
if (isFirstVisit || newEpics.length > 0) {
await syncEpicsToTurso(id, isFirstVisit ? epicData : newEpics)
}
// Actualizar contadores en projects
await tauriDb.updateProjectCounts(id).catch(() => {})
firstVisit.value.add(id)
} catch (e: any) {
+1 -1
View File
@@ -84,7 +84,7 @@ const statusLabel = (status: unknown) => {
<FileText class="size-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div class="text-2xl font-bold">{{ workItems.totalHUs }}</div>
<div id="dashboard-stats-hus-count" class="text-2xl font-bold">{{ workItems.totalHUs }}</div>
<p class="text-xs text-muted-foreground">{{ t('dashboard.husSubtitle') }}</p>
</CardContent>
</Card>
+1 -1
View File
@@ -136,7 +136,7 @@ const tabContent: Record<string, { title: string; description: string; cards: {
<SiteHeader :active-tab="viewingProject ? 'projects' : activeTab" />
<div class="flex flex-1 flex-col">
<div class="@container/main flex flex-1 flex-col gap-2">
<div class="flex flex-col gap-4 py-4 md:gap-6 md:py-6">
<div class="flex flex-col gap-0 py-4 md:gap-0 md:py-6">
<template v-if="viewingProject">
<div class="px-4 lg:px-6">
<button
+16 -10
View File
@@ -15,6 +15,20 @@ import { Skeleton } from "@/components/ui/skeleton"
const { t } = useI18n()
const projects = useProjectsStore()
function getStatusVariant(status?: string) {
const s = String(status ?? '').toLowerCase()
if (s === 'true' || ['active', 'completado', 'done', 'completed'].includes(s)) return 'default'
if (s === 'false' || ['inactive', 'paused', 'cancelled'].includes(s)) return 'secondary'
return 'outline'
}
function getStatusLabel(status?: string) {
const s = String(status ?? '').toLowerCase()
if (s === 'true' || s === 'active') return t('status.active')
if (s === 'false' || s === 'inactive') return t('status.inactive')
return s || '—'
}
const emit = defineEmits<{
'select-project': [id: number]
}>()
@@ -23,14 +37,6 @@ onMounted(() => {
projects.fetchProjects()
})
function getStatusVariant(status?: string) {
switch (status) {
case 'active': return 'default'
case 'completed': return 'secondary'
case 'paused': return 'outline'
default: return 'default'
}
}
</script>
<template>
@@ -95,8 +101,8 @@ function getStatusVariant(status?: string) {
<CardTitle class="text-base">
{{ p.initiative_name || p.name || t('projects.unnamedFallback', { id: p.id }) }}
</CardTitle>
<Badge :variant="getStatusVariant(p.status)">
{{ p.status || 'active' }}
<Badge id="projects-status-badge" :variant="getStatusVariant(p.status)">
{{ getStatusLabel(p.status) }}
</Badge>
</div>
<CardDescription class="line-clamp-2">