Refactor code, tests and bug fixes - #13
Merged
Merged
Conversation
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
…nd add high-contrast skeleton loaders
There was a problem hiding this comment.
Pull request overview
This PR refactors and enhances the Caerus dashboard UX/UI around applications/environments/resources, introduces more consistent skeleton-loading states, improves shared resource duplication feedback, and adds a Vitest-based test setup with new type definitions.
Changes:
- Reworked environment color/preset handling and expanded environment “kind” support across UI (badges/dots/cards).
- Added skeleton loaders and refactored dashboard pages into reusable components/tabs for smoother loading transitions.
- Introduced Vitest configuration + new unit tests, plus new
types/*domain interfaces.
Reviewed changes
Copilot reviewed 39 out of 41 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| vitest.config.mts | Adds Vitest configuration for running tests. |
| package.json | Adds pnpm packageManager pin and test script via Vitest; adds Vitest dependency. |
| pnpm-lock.yaml | Locks new Vitest/Vite/testing dependencies. |
| types/application.ts | Adds application- and environment-related TypeScript interfaces. |
| types/resource.ts | Adds Resource interface. |
| types/lock.ts | Adds Lock interface. |
| types/api-key.ts | Adds ApiKey interface. |
| types/billing.ts | Adds billing-related interfaces (Plan/Invoice). |
| types/index.ts | Exports all type modules from a single entrypoint. |
| lib/utils.ts | Expands env color logic, presets, localStorage persistence, and environment dot aggregation helper. |
| lib/mocks/dashboard.ts | Extracts dashboard mock stats/activity into shared mocks. |
| lib/mocks/applications.ts | Adds mock environment data helpers and a TTL formatting helper. |
| components/ui/use-toast.ts | Removes legacy toast hook implementation. |
| components/ui/use-mobile.tsx | Removes legacy mobile breakpoint hook. |
| components/ui/sonner.tsx | Switches Sonner toaster to use the new local ThemeProvider. |
| components/ui/skeleton.tsx | Updates Skeleton styling for improved realism/contrast. |
| components/theme-provider.tsx | Replaces next-themes provider with a custom ThemeProvider/useTheme implementation. |
| components/dashboard/sidebar.tsx | Adds skeleton loading for app list, optimizes fetch behavior, updates env dots rendering. |
| components/dashboard/shared/stat-card.tsx | Introduces reusable stat card component for dashboard stats. |
| components/dashboard/shared/env-badge.tsx | Introduces reusable environment badge component. |
| components/dashboard/resource-form.tsx | Preserves selected env query param when redirecting after save. |
| components/dashboard/header.tsx | Switches theme hook import to the new ThemeProvider. |
| components/dashboard/applications/tabs/resources-tab.tsx | Adds Resources tab component with skeletons and env-colored UI. |
| components/dashboard/applications/tabs/locks-tab.tsx | Adds Locks tab component with skeletons and env-colored UI. |
| components/dashboard/applications/tabs/api-keys-tab.tsx | Adds API Keys tab component with skeletons and env-colored UI. |
| components/dashboard/applications/duplicate-template-dialog.tsx | Adds shared resource “duplicate to envs” dialog with translated error messaging and toast feedback. |
| components/dashboard/applications/application-detail-skeleton.tsx | Adds detailed skeleton for application detail page. |
| components/dashboard/applications/application-card.tsx | Adds reusable application card component. |
| app/layout.tsx | Mounts Sonner <Toaster /> in RootLayout and uses new ThemeProvider. |
| app/globals.css | Adds custom-scrollbar CSS utility. |
| app/dashboard/page.tsx | Refactors dashboard page to use shared StatCard/EnvBadge and extracted mocks. |
| app/dashboard/applications/page.tsx | Improves applications page loading UX with skeleton grid and refactors environment badges. |
| app/dashboard/applications/[id]/page.tsx | Major refactor: new env selector, tabs extraction, skeleton loading, duplication dialog integration. |
| app/dashboard/applications/[id]/settings/page.tsx | Adds environment color preset selection and “create env” deep-link behavior. |
| app/api/shared-resource-templates/route.ts | Improves backend error parsing/normalization for POST failures. |
| .gitignore | Ignores .claude/ directory. |
| tests/schemas/validation.test.ts | Adds schema validation tests (Zod rules). |
| tests/proxy.test.ts | Adds middleware/proxy behavior tests. |
| tests/lib/utils.test.ts | Adds tests for cn and getEnvColors. |
| tests/lib/api.test.ts | Adds tests for backend fetch helpers and auth token header behavior. |
| tests/api/routes.test.ts | Adds tests for internal Next.js API route handlers. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+110
to
+126
| let kind: EnvKind = envKind(envName) | ||
|
|
||
| let savedColor: string | null = customPresetId || null | ||
| if (!savedColor && typeof window !== "undefined") { | ||
| if (envId) { | ||
| savedColor = localStorage.getItem(`caerus_env_color_${envId}`) | ||
| } | ||
| if (!savedColor && envName) { | ||
| savedColor = localStorage.getItem(`caerus_env_color_name_${envName.toLowerCase()}`) | ||
| } | ||
| } | ||
|
|
||
| if (savedColor && savedColor in map) { | ||
| kind = savedColor as EnvKind | ||
| } | ||
|
|
||
| return map[kind] || map.slate |
Comment on lines
+102
to
+118
| <Card | ||
| key={lock.id} | ||
| className={cn( | ||
| 'bg-card/50 border-border py-0 border-l-2', | ||
| getEnvColors(selectedEnv).borderStrong | ||
| )} | ||
| > | ||
| <CardContent className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 py-3 px-4"> | ||
| <div className="flex items-center gap-3"> | ||
| <div | ||
| className={cn( | ||
| 'flex h-10 w-10 shrink-0 items-center justify-center rounded-lg', | ||
| getEnvColors(selectedEnv).bg | ||
| )} | ||
| > | ||
| <Lock className={cn('h-5 w-5', getEnvColors(selectedEnv).text)} /> | ||
| </div> |
Comment on lines
+88
to
+108
| <Card | ||
| key={key.id} | ||
| className={cn( | ||
| 'bg-card/50 border-border py-0 border-l-2', | ||
| getEnvColors(selectedEnv).borderStrong | ||
| )} | ||
| > | ||
| <CardContent className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 py-3 px-4"> | ||
| <div className="flex items-center gap-3"> | ||
| <div | ||
| className={cn( | ||
| 'flex h-10 w-10 shrink-0 items-center justify-center rounded-lg border', | ||
| key.state === 'ACTIVE' | ||
| ? cn( | ||
| getEnvColors(selectedEnv).bg, | ||
| getEnvColors(selectedEnv).border, | ||
| getEnvColors(selectedEnv).text | ||
| ) | ||
| : 'bg-secondary text-muted-foreground border-border' | ||
| )} | ||
| > |
Comment on lines
+149
to
+153
| result.push({ | ||
| kind, | ||
| colors: getEnvColors(kind), | ||
| }) | ||
| } |
Comment on lines
+298
to
+318
| const { visibleDots, overflowCount, allNames } = getUniqueEnvDots(app.environments, 3); | ||
| const extraCount = app.environments.length - visibleDots.length; | ||
| return ( | ||
| <span className="flex shrink-0 items-center gap-1"> | ||
| {visibleDots.map(({ kind, colors }) => ( | ||
| <span | ||
| key={kind} | ||
| className={cn("h-1.5 w-1.5 rounded-full", colors.dot)} | ||
| title={allNames.join(", ")} | ||
| /> | ||
| ))} | ||
| {extraCount > 0 && ( | ||
| <span | ||
| className="text-[10px] font-mono font-medium text-muted-foreground/80 leading-none" | ||
| title={allNames.join(", ")} | ||
| > | ||
| +{extraCount} | ||
| </span> | ||
| )} | ||
| </span> | ||
| ); |
Comment on lines
+199
to
+207
| <Checkbox | ||
| id={`env-${env.id}`} | ||
| checked={isChecked} | ||
| onCheckedChange={() => handleToggleEnv(env.id.toString())} | ||
| /> | ||
| <Label htmlFor={`env-${env.id}`} className="cursor-pointer font-medium text-sm flex items-center gap-2"> | ||
| <span className={cn("h-2.5 w-2.5 rounded-full shrink-0", colors.dot)} /> | ||
| <span>{env.name}</span> | ||
| </Label> |
Comment on lines
+43
to
+56
| React.useEffect(() => { | ||
| const root = document.documentElement | ||
| root.classList.remove('light', 'dark') | ||
|
|
||
| let effectiveTheme: 'dark' | 'light' = 'dark' | ||
| if (theme === 'system') { | ||
| effectiveTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' | ||
| } else { | ||
| effectiveTheme = theme | ||
| } | ||
|
|
||
| root.classList.add(effectiveTheme) | ||
| setResolvedTheme(effectiveTheme) | ||
| }, [theme]) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📌 Resumen de Cambios
Este PR introduce mejoras significativas de UX/UI, optimizaciones de rendimiento y correcciones de errores en la interfaz de gestión de aplicaciones, ambientes y recursos compartidos de Caerus.
🎨 1. Rediseño y Mejora del Selector de Ambientes
outlineelegante con indicador de color (dot) y menú desplegable.+ Nuevo Ambienteabre el modal de creación de ambiente directamente en la página de configuración (action=create_env).envColors) en los contadores y estados vacíos de los encabezados de pestañas.⚡ 2. Transiciones de Carga y Skeleton Loaders Ultra-Realistas
useEffecten la Sidebar ([]mount único) evitando re-consultar la API en cada navegación entre pantallas.📋 3. Corrección y Rediseño de "Duplicar Recurso Compartido"
w-56) y alineación vertical de las opciones ("Configurar", "Duplicar...", "Eliminar").Sonner) al completar la duplicación.custom-scrollbar), tamaño del modal ampliado (sm:max-w-lg) y márgenes inferiores reducidos.🛠️ 4. Correcciones Técnicas
ThemeProvideryuseThemepara eliminar advertencias en la consola de desarrollo sobre<script>inline.<Toaster position="bottom-right" />en elRootLayout(app/layout.tsx).envColorsrespetando elpresetIdde cada ambiente (p. ej. violeta paralocal-test).