From 4cc613d1df1740ad86b0d335b405a5c8dc45be20 Mon Sep 17 00:00:00 2001 From: hreyes Date: Thu, 5 Feb 2026 12:35:03 -0600 Subject: [PATCH] checkpoint/backup-fail-server --- .../general_catalogs/doda/columns.ts | 2 +- .../general_catalogs/doda/data-table.svelte | 121 ++++++++++++++++++ .../keyboard/KeyboardManager.svelte | 11 +- frontend/src/lib/server/api.ts | 16 +-- .../general_catalogs/concepts/+page.svelte | 9 +- .../general_catalogs/doda/+page.svelte | 45 +++++-- .../general_catalogs/packages/+page.svelte | 105 +++++++-------- 7 files changed, 234 insertions(+), 75 deletions(-) create mode 100644 frontend/src/lib/components/dashboard/general_catalogs/doda/data-table.svelte diff --git a/frontend/src/lib/components/dashboard/general_catalogs/doda/columns.ts b/frontend/src/lib/components/dashboard/general_catalogs/doda/columns.ts index 946aed85..2636ab51 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/doda/columns.ts +++ b/frontend/src/lib/components/dashboard/general_catalogs/doda/columns.ts @@ -32,7 +32,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef[] { }, { id: 'actions', - Headers: 'Acciones', + header: 'Acciones', cell: ({ row }) => { return renderComponent(DataTableActions, { item: row.original, diff --git a/frontend/src/lib/components/dashboard/general_catalogs/doda/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/doda/data-table.svelte new file mode 100644 index 00000000..bcf39690 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/doda/data-table.svelte @@ -0,0 +1,121 @@ + + +
+
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + onRowClick?.(row.original)} + class="cursor-pointer hover:bg-muted/50 transition-colors {row.getIsSelected() + ? 'bg-primary/10' + : ''}" + > + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + +
+ + +
+
+ Total: {totalItems} +
+
+ + +
+
+
diff --git a/frontend/src/lib/components/keyboard/KeyboardManager.svelte b/frontend/src/lib/components/keyboard/KeyboardManager.svelte index 90296274..931c679c 100644 --- a/frontend/src/lib/components/keyboard/KeyboardManager.svelte +++ b/frontend/src/lib/components/keyboard/KeyboardManager.svelte @@ -25,9 +25,12 @@ 'input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]):not([role="tab"])' ); - // Find the first one that is actually visible + // Find the first one that is actually visible AND not in the sidebar const firstVisible = Array.from(focusables).find((el) => { const htmlEl = el as HTMLElement; + // Exclude sidebar elements + if (htmlEl.closest('[data-sidebar="sidebar"]')) return false; + return !!(htmlEl.offsetWidth || htmlEl.offsetHeight || htmlEl.getClientRects().length); }) as HTMLElement; @@ -60,6 +63,9 @@ const elements = document.querySelectorAll('button, [role="tab"], a'); const target = Array.from(elements).find((el) => { const text = el.textContent?.trim() || ''; + // Exclude sidebar + if (el.closest('[data-sidebar="sidebar"]')) return false; + return text.toLowerCase().includes(keyword.toLowerCase()); }) as HTMLElement; @@ -276,6 +282,9 @@ const target = event.target as HTMLElement; if (!target) return; + // Exclude sidebar from any magic scrolling + if (target.closest('[data-sidebar="sidebar"]')) return; + // Check if it's an interactive element we care about const isInteractive = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A'].includes(target.tagName) || diff --git a/frontend/src/lib/server/api.ts b/frontend/src/lib/server/api.ts index 19ed846f..a338dc06 100644 --- a/frontend/src/lib/server/api.ts +++ b/frontend/src/lib/server/api.ts @@ -156,7 +156,7 @@ export async function authenticatedFetch( } // Construir URL completa - const url = endpoint.startsWith('http') ? endpoint : `${baseUrl}${endpoint}`; + const url = endpoint.startsWith('http') ? endpoint : `${baseUrl}${endpoint}`; // Crear AbortController para timeout const controller = new AbortController(); @@ -171,7 +171,7 @@ export async function authenticatedFetch( const headers = isFormData ? { 'Authorization': `Bearer ${accessToken}`, ...(options.headers as Record || {}) } : createAuthHeaders(accessToken, options.headers as Record); - + let response = await fetch(url, { ...options, headers, @@ -202,7 +202,7 @@ export async function authenticatedFetch( const newHeaders = isFormData ? { 'Authorization': `Bearer ${newToken}`, ...(options.headers as Record || {}) } : createAuthHeaders(newToken, options.headers as Record); - + response = await fetch(url, { ...options, headers: newHeaders, @@ -263,7 +263,7 @@ export async function validateAuth( } const keycloakData = await response.json(); - + // Obtener perfil adicional del usuario (avatar, bio, etc.) try { const profileResponse = await authenticatedFetch( @@ -272,7 +272,7 @@ export async function validateAuth( cookies, fetch ); - + if (profileResponse.ok) { const profileData = await profileResponse.json(); // Combinar datos de Keycloak con datos del perfil @@ -287,7 +287,7 @@ export async function validateAuth( } catch (profileError) { console.warn('⚠️ [API] No se pudo cargar el perfil del usuario, usando solo datos de Keycloak'); } - + return keycloakData; } catch (error) { // Si es un redirect, re-lanzarlo @@ -365,14 +365,14 @@ export async function handleApiResponse( if (response.status === 204) { return { data: null as T }; } - + const data = await response.json(); return { data }; } // Manejar errores const errorData = await response.json().catch(() => ({ detail: 'Error desconocido' })); - + const error = { detail: errorData.detail || errorData.message || 'Error en la petición', status: response.status, diff --git a/frontend/src/routes/dashboard/general_catalogs/concepts/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/concepts/+page.svelte index c8c3eb10..63507986 100644 --- a/frontend/src/routes/dashboard/general_catalogs/concepts/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/concepts/+page.svelte @@ -15,15 +15,14 @@ let { data }: { data: PageData } = $props(); let createDialogOpen = $state(false); + let dialogOpen = $state(false); // Atajos useShortcuts( 'Lista Conceptos', obtenerAtajosListaConceptos({ manejarNuevo: () => (createDialogOpen = true), - manejarActualizar: () => goto($page.url, { invalidateAll: true }), - manejarEditar: () => console.log('Editar concepto'), - manejarEliminar: () => console.log('Eliminar concepto') + manejarActualizar: () => goto($page.url, { invalidateAll: true }) }) ); @@ -88,5 +87,7 @@ /> - + {#if dialogOpen} + + {/if} diff --git a/frontend/src/routes/dashboard/general_catalogs/doda/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/doda/+page.svelte index 005b41b8..12b3b2d8 100644 --- a/frontend/src/routes/dashboard/general_catalogs/doda/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/doda/+page.svelte @@ -12,6 +12,7 @@ import { invalidateAll } from '$app/navigation'; import { useShortcuts } from '$lib/hooks/use-shortcuts'; import { obtenerAtajosListaDoda } from '$lib/config/shortcuts/dashboard/general_catalogs/doda/list'; + import type { Doda } from '$lib/api/dashboard/a76/general_catalogs/doda'; let { data } = $props(); let dialogOpen = $state(false); @@ -20,20 +21,39 @@ let searchIntegration = $state($page.url.searchParams.get('integration_number') || ''); let timeout: ReturnType; + // Selection + let selectedId = $state(null); + + // Funciones de acción + function handleCreateClick() { + goto('/dashboard/general_catalogs/doda/edit'); + } + + function handleEditSelected() { + if (selectedId) { + goto(`/dashboard/general_catalogs/doda/edit/${selectedId}`); + } else { + console.log('Seleccione un registro para editar (Alt+Shift+E)'); + } + } + + function handleDelete() { + if (selectedId) { + // Implement delete logic or dialog + console.log('Eliminar no implementado en esta vista. Use el menú de acciones.'); + } else { + console.log('Seleccione un registro para eliminar (Alt+Shift+D)'); + } + } + // Atajos useShortcuts( 'Lista DODA', obtenerAtajosListaDoda({ - manejarNuevo: () => goto('/dashboard/general_catalogs/doda/edit'), + manejarNuevo: handleCreateClick, manejarActualizar: handleSuccess, - manejarEditar: () => { - // Nota: La edición requiere un ID, pero la lista actual no rastrea selección. - // Por ahora apuntamos a la página de nuevo como placeholder o documentamos que requiere selección. - toast.info('Seleccione un registro para editar (Alt+Shift+E)'); - }, - manejarEliminar: () => { - toast.info('Seleccione un registro para eliminar (Alt+Shift+D)'); - } + manejarEditar: handleEditSelected, + manejarEliminar: handleDelete }) ); @@ -53,6 +73,7 @@ function handleSuccess() { const url = new URL($page.url); goto(url, { invalidateAll: true }); + selectedId = null; } @@ -85,8 +106,12 @@ columns={createColumns(handleSuccess)} pageCount={data.dodas?.pages || 0} totalItems={data.dodas?.total || 0} + {selectedId} + onRowClick={handleRowClick} /> - + {#if dialogOpen} + + {/if} diff --git a/frontend/src/routes/dashboard/general_catalogs/packages/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/packages/+page.svelte index 8330f896..b64e7205 100644 --- a/frontend/src/routes/dashboard/general_catalogs/packages/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/packages/+page.svelte @@ -1,57 +1,60 @@
@@ -60,7 +63,7 @@

Bultos y Embalajes

Gestión del catálogo de bultos y embalajes

- @@ -68,12 +71,12 @@
- +
@@ -88,5 +91,5 @@ />
- +