Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4f34ead
feat(docs): redesign documentation layout and add SRE/DLS demo routes
ManuMar28 Sep 18, 2026
4a45d1a
Merge remote-tracking branch 'origin/main' into frontend-cleanup
ManuMar28 Sep 18, 2026
6de5ff0
fix(settings): remove inactive buttons for avatar, 2FA and sessions
ManuMar28 Sep 18, 2026
d57d091
fix(landing): align pricing copy with usage-based billing rules
ManuMar28 Sep 18, 2026
9ec87ab
fix(api-keys): use official @caerus-dev/sdk and CaerusClient in quick…
ManuMar28 Sep 18, 2026
aabf951
fix(docs): add missing idempotency-error and not-found-error sections…
ManuMar28 Sep 18, 2026
af1c5c3
fix(dashboard): refactor usage page with real billing data, spanish l…
ManuMar28 Sep 18, 2026
8def551
Merge remote-tracking branch 'origin/main' into frontend-cleanup
ManuMar28 Sep 18, 2026
4c58d9f
fix(dashboard): preserve route env and tab parameters in lock and res…
ManuMar28 Sep 19, 2026
b759a38
refactor(dashboard): replace native window.confirm with accessible Ra…
ManuMar28 Sep 19, 2026
2d91ff2
fix(dashboard): rename notifications tab and back button to webhooks
ManuMar28 Sep 19, 2026
27734e1
chore(settings): remove leftover debug console logs in environment de…
ManuMar28 Sep 19, 2026
d3045bb
fix(landing): point footer github link to official caerus-dev organiz…
ManuMar28 Sep 19, 2026
75a6410
docs: fix section anchor id from aviones to control-plane-vs-data-plane
ManuMar28 Sep 19, 2026
7c64cd7
style: fix missing spanish accents (período, críticas, adquisición)
ManuMar28 Sep 19, 2026
3c94843
style: fix 'queismos' in confirmation dialogs (seguro de que)
ManuMar28 Sep 19, 2026
d1b8169
style: unify role labels across platform (VIEWER to Lector)
ManuMar28 Sep 19, 2026
ee22501
security(usage): escape CSV cells and neutralize formula injection on…
ManuMar28 Sep 21, 2026
2e2ee21
fix(usage): handle user fetch error with retry UI and remove fabricat…
ManuMar28 Sep 21, 2026
dd0c4e0
fix(usage): aggregate daily telemetry and handle unavailable chart da…
ManuMar28 Sep 21, 2026
3337ac7
fix(usage): calculate per-application usage from environment telemetr…
ManuMar28 Sep 21, 2026
76dbaa7
fix(docs): close mobile navigation sheet on route change
ManuMar28 Sep 21, 2026
18f0e52
refactor(pricing): remove hard-coded billing plan limits from preview…
ManuMar28 Sep 21, 2026
0715617
docs(errors): correct gRPC status mapping for ConflictError to FAILED…
ManuMar28 Sep 21, 2026
f8d6c9e
docs(errors): update idempotency sample to use ValidationError with I…
ManuMar28 Sep 21, 2026
c09c555
docs(errors): rename NotFoundError to ResourceNotFoundError to match …
ManuMar28 Sep 21, 2026
ef72815
Merge remote-tracking branch 'origin/main' into frontend-cleanup
ManuMar28 Sep 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ node_modules
.vercel
.claude/
.env*
.codegraph/
package-lock.json
pnpm-workspace.yaml
12 changes: 6 additions & 6 deletions app/dashboard/api-keys/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ export default function ApiKeysPage() {
className="h-7 text-xs gap-1"
onClick={() =>
copyToClipboard(
`import { Caerus } from '@caerus/sdk'\n\nconst client = new Caerus({\n apiKey: process.env.CAERUS_API_KEY\n})`,
`import { CaerusClient } from '@caerus-dev/sdk'\n\nconst caerus = new CaerusClient({\n apiKey: process.env.CAERUS_API_KEY\n})`,
"snippet"
)
}
Expand All @@ -355,14 +355,14 @@ export default function ApiKeysPage() {
<code>
<span className="text-chart-2">import</span>
{" { "}
<span className="text-chart-3">Caerus</span>
<span className="text-chart-3">CaerusClient</span>
{" } "}
<span className="text-chart-2">from</span>{" "}
<span className="text-primary">{`'@caerus/sdk'`}</span>
<span className="text-primary">{`'@caerus-dev/sdk'`}</span>
{"\n\n"}
<span className="text-chart-2">const</span> client ={" "}
<span className="text-chart-2">const</span> caerus ={" "}
<span className="text-chart-2">new</span>{" "}
<span className="text-chart-3">Caerus</span>
<span className="text-chart-3">CaerusClient</span>
{"({\n"}
{" "}apiKey: process.env.
<span className="text-primary">CAERUS_API_KEY</span>
Expand All @@ -379,7 +379,7 @@ export default function ApiKeysPage() {
<DialogHeader>
<DialogTitle>Revocar API Key</DialogTitle>
<DialogDescription>
¿Estás seguro que deseas revocar la API Key con prefijo{" "}
¿Estás seguro de que deseas revocar la API Key con prefijo{" "}
<span className="font-mono font-semibold text-foreground">{keyToRevoke?.keyPrefix}••••</span>?
Esta acción es irreversible y los clientes que usen esta clave ya no podrán autenticarse.
</DialogDescription>
Expand Down
29 changes: 22 additions & 7 deletions app/dashboard/applications/[id]/locks/[lockId]/edit/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
"use client"

import { use, useEffect, useState } from "react"
import { use, useEffect, useState, Suspense } from "react"
import { LockForm, LockFormValues } from "@/components/dashboard/lock-form"
import { Loader2 } from "lucide-react"

export default function EditLockPage({
params,
}: {
params: Promise<{ id: string; lockId: string }>
}) {
const { id, lockId } = use(params)
function EditLockContainer({ id, lockId }: { id: string; lockId: string }) {
const [initialData, setInitialData] = useState<LockFormValues | null>(null)
const [isLoading, setIsLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
Expand Down Expand Up @@ -65,3 +60,23 @@ export default function EditLockPage({
/>
)
}

export default function EditLockPage({
params,
}: {
params: Promise<{ id: string; lockId: string }>
}) {
const { id, lockId } = use(params)

return (
<Suspense
fallback={
<div className="flex items-center justify-center py-12">
<Loader2 className="w-8 h-8 text-primary animate-spin" />
</div>
}
>
<EditLockContainer id={id} lockId={lockId} />
</Suspense>
)
}
12 changes: 6 additions & 6 deletions app/dashboard/applications/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,7 @@ export default function ApplicationDashboard({
</TabsTrigger>
<TabsTrigger value="webhooks" className="gap-1.5 px-3">
<Webhook className="h-4 w-4" />
<span>Notificaciones</span>
<span>Webhooks</span>
</TabsTrigger>
<TabsTrigger value="metrics" className="gap-1.5 px-3">
<LineChart className="h-4 w-4" />
Expand Down Expand Up @@ -829,7 +829,7 @@ export default function ApplicationDashboard({
<DialogHeader>
<DialogTitle>Eliminar Plantilla de Recurso</DialogTitle>
<DialogDescription>
¿Estás seguro que deseas eliminar la plantilla de recurso{" "}
¿Estás seguro de que deseas eliminar la plantilla de recurso{" "}
<span className="font-semibold text-foreground">{templateToDelete?.name}</span>?
Esta acción es irreversible y revocaría el acceso a este recurso en el motor SRE.
</DialogDescription>
Expand Down Expand Up @@ -857,7 +857,7 @@ export default function ApplicationDashboard({
<DialogHeader>
<DialogTitle>Revocar API Key</DialogTitle>
<DialogDescription>
¿Estás seguro que deseas revocar la API Key con prefijo{" "}
¿Estás seguro de que deseas revocar la API Key con prefijo{" "}
<span className="font-mono font-semibold text-foreground">{keyToRevoke?.keyPrefix}••••</span>?
Esta acción es irreversible y los clientes que usen esta clave ya no podrán autenticarse.
</DialogDescription>
Expand Down Expand Up @@ -917,7 +917,7 @@ export default function ApplicationDashboard({
<DialogHeader>
<DialogTitle>Eliminar Plantilla de Lock</DialogTitle>
<DialogDescription>
¿Estás seguro que deseas eliminar la plantilla de lock{" "}
¿Estás seguro de que deseas eliminar la plantilla de lock{" "}
<span className="font-semibold text-foreground">{lockToDelete?.namespace}</span>?
Esta acción es irreversible.
</DialogDescription>
Expand Down Expand Up @@ -967,7 +967,7 @@ export default function ApplicationDashboard({
<DialogHeader>
<DialogTitle>Eliminar Webhook</DialogTitle>
<DialogDescription>
¿Estás seguro que deseas eliminar el webhook con URL{" "}
¿Estás seguro de que deseas eliminar el webhook con URL{" "}
<span className="font-semibold text-foreground">{webhookToDelete?.url}</span>?
Esta acción es irreversible.
</DialogDescription>
Expand Down Expand Up @@ -999,7 +999,7 @@ export default function ApplicationDashboard({
<DialogHeader>
<DialogTitle>Rotar Secreto de Webhook</DialogTitle>
<DialogDescription>
¿Estás seguro que deseas rotar el secreto del webhook con URL{" "}
¿Estás seguro de que deseas rotar el secreto del webhook con URL{" "}
<span className="font-semibold text-foreground">{webhookToRotate?.url}</span>?
El secreto anterior se invalidará inmediatamente y las nuevas peticiones se firmarán con el nuevo.
</DialogDescription>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
"use client"

import { use, useEffect, useState } from "react"
import { use, useEffect, useState, Suspense } from "react"
import { ResourceForm } from "@/components/dashboard/resource-form"
import { Loader2 } from "lucide-react"

export default function EditResourcePage({
params,
}: {
params: Promise<{ id: string; resourceId: string }>
}) {
const { id, resourceId } = use(params)
function EditResourceContainer({ id, resourceId }: { id: string; resourceId: string }) {
const [initialData, setInitialData] = useState<any>(null)
const [isLoading, setIsLoading] = useState(true)

Expand Down Expand Up @@ -69,3 +64,23 @@ export default function EditResourcePage({
/>
)
}

export default function EditResourcePage({
params,
}: {
params: Promise<{ id: string; resourceId: string }>
}) {
const { id, resourceId } = use(params)

return (
<Suspense
fallback={
<div className="flex items-center justify-center py-12">
<Loader2 className="w-8 h-8 text-primary animate-spin" />
</div>
}
>
<EditResourceContainer id={id} resourceId={resourceId} />
</Suspense>
)
}
7 changes: 3 additions & 4 deletions app/dashboard/applications/[id]/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -244,17 +244,16 @@ export default function ApplicationSettingsPage({

const handleDeleteEnvConfirm = async () => {
if (!selectedEnvForDelete) return
console.log("INTENTANDO ELIMINAR ENTORNO:", selectedEnvForDelete.name, "CON ID:", selectedEnvForDelete.id)
setIsSavingEnv(true)
setDeleteEnvError(null)
try {
console.log("URL DE FETCH:", `/api/applications/${id}/environments/${selectedEnvForDelete.id}`)
const res = await fetch(`/api/applications/${id}/environments/${selectedEnvForDelete.id}`, {
method: "DELETE",
})
if (res.ok) {
setEnvironments((prev) => prev.filter((e) => e.id !== selectedEnvForDelete.id))
refreshApps(); setConfirmDeleteEnvOpen(false)
refreshApps()
setConfirmDeleteEnvOpen(false)
setSelectedEnvForDelete(null)
} else {
const errData = await res.json().catch(() => ({ message: "Error al eliminar el ambiente" }))
Expand Down Expand Up @@ -664,7 +663,7 @@ export default function ApplicationSettingsPage({
<DialogHeader>
<DialogTitle>Eliminar Ambiente</DialogTitle>
<DialogDescription>
¿Estás seguro que deseas eliminar el ambiente{" "}
¿Estás seguro de que deseas eliminar el ambiente{" "}
<span className="font-semibold text-foreground">{selectedEnvForDelete?.name}</span>?
Esta acción es irreversible y eliminará todos los recursos, locks y API keys asociados a este ambiente.
</DialogDescription>
Expand Down
8 changes: 4 additions & 4 deletions app/dashboard/applications/[id]/team/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ interface Invitation {
const roleLabels: Record<string, { label: string; color: string }> = {
OWNER: { label: "Propietario", color: "bg-purple-500/20 text-purple-400 border-purple-500/30" },
ADMIN: { label: "Administrador", color: "bg-blue-500/20 text-blue-400 border-blue-500/30" },
VIEWER: { label: "Visor", color: "bg-gray-500/20 text-gray-400 border-gray-500/30" },
VIEWER: { label: "Lector", color: "bg-gray-500/20 text-gray-400 border-gray-500/30" },
}

export default function TeamPage({
Expand Down Expand Up @@ -394,7 +394,7 @@ export default function TeamPage({
<SelectItem value="VIEWER">
<div className="flex items-center gap-2">
<Users className="w-4 h-4 text-zinc-400" />
Visor (Solo lectura)
Lector (Solo lectura)
</div>
</SelectItem>
</SelectContent>
Expand Down Expand Up @@ -574,7 +574,7 @@ export default function TeamPage({
<DialogHeader>
<DialogTitle>Remover Colaborador</DialogTitle>
<DialogDescription>
¿Estás seguro que deseas remover a{" "}
¿Estás seguro de que deseas remover a{" "}
<span className="font-semibold text-foreground">
{collaboratorToRemove?.email}
</span>{" "}
Expand Down Expand Up @@ -632,7 +632,7 @@ export default function TeamPage({
</SelectTrigger>
<SelectContent>
<SelectItem value="ADMIN">Administrador</SelectItem>
<SelectItem value="VIEWER">Visor (Solo lectura)</SelectItem>
<SelectItem value="VIEWER">Lector (Solo lectura)</SelectItem>
</SelectContent>
</Select>
</div>
Expand Down
4 changes: 2 additions & 2 deletions app/dashboard/applications/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const getRoleBadge = (role: string) => {
default:
return (
<Badge variant="outline" className="bg-zinc-500/10 text-zinc-400 border-zinc-500/20 text-xs font-semibold">
Visor
Lector
</Badge>
);
}
Expand Down Expand Up @@ -373,7 +373,7 @@ export default function ApplicationsPage() {
<DialogHeader>
<DialogTitle>Eliminar Aplicación</DialogTitle>
<DialogDescription>
¿Estás seguro que deseas eliminar la aplicación{" "}
¿Estás seguro de que deseas eliminar la aplicación{" "}
<span className="font-medium text-foreground">
{appToDelete?.name}
</span>
Expand Down
8 changes: 4 additions & 4 deletions app/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,14 @@ export default async function DashboardPage() {
case "ADMIN":
return (
<Badge variant="outline" className="bg-blue-500/10 text-blue-400 border-blue-500/20 text-xs font-semibold">
Colaborador (Admin)
Administrador
</Badge>
);
case "VIEWER":
default:
return (
<Badge variant="outline" className="bg-zinc-500/10 text-zinc-400 border-zinc-500/20 text-xs font-semibold">
Colaborador (Viewer)
Lector
</Badge>
);
}
Expand Down Expand Up @@ -189,7 +189,7 @@ export default async function DashboardPage() {
<div>
<CardTitle className="text-base font-semibold flex items-center gap-2">
<Gauge className="h-4 w-4 text-primary" />
Consumo del Periodo Actual ({userProfile?.billingUsage?.period || "Mensual"})
Consumo del Período Actual ({userProfile?.billingUsage?.period || "Mensual"})
</CardTitle>
<CardDescription className="text-xs text-muted-foreground mt-0.5">
{isEnterprise
Expand All @@ -208,7 +208,7 @@ export default async function DashboardPage() {
{isEnterprise ? (
<div className="flex items-center justify-between text-xs py-1">
<span className="text-muted-foreground">
<strong className="text-foreground font-mono">{consumedUnits.toLocaleString()}</strong> requests consumidas este periodo
<strong className="text-foreground font-mono">{consumedUnits.toLocaleString()}</strong> requests consumidas este período
</span>
<Badge variant="outline" className="bg-purple-500/10 text-purple-400 border-purple-500/20 text-[10px] font-semibold">
Sin límite estricto
Expand Down
31 changes: 0 additions & 31 deletions app/dashboard/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Separator } from "@/components/ui/separator"
import {
Select,
SelectContent,
Expand Down Expand Up @@ -102,16 +101,6 @@ export default function SettingsPage() {
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center gap-4">
<div className="flex h-16 w-16 items-center justify-center rounded-full bg-primary/20 text-primary font-bold text-xl">
{user?.name?.substring(0, 2)?.toUpperCase() || "US"}
</div>
<div>
<Button variant="outline" size="sm">
Cambiar Avatar
</Button>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="name">Nombre Completo</Label>
Expand Down Expand Up @@ -172,16 +161,6 @@ export default function SettingsPage() {
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center justify-between">
<div>
<p className="font-medium">Autenticación en Dos Pasos (2FA)</p>
<p className="text-sm text-muted-foreground">
Agregá una capa extra de seguridad a tu cuenta
</p>
</div>
<Button variant="outline">Activar 2FA</Button>
</div>
<Separator />
<div className="flex items-center justify-between">
<div>
<p className="font-medium">Cambiar Contraseña</p>
Expand All @@ -191,16 +170,6 @@ export default function SettingsPage() {
</div>
<Button variant="outline">Cambiar</Button>
</div>
<Separator />
<div className="flex items-center justify-between">
<div>
<p className="font-medium">Sesiones Activas</p>
<p className="text-sm text-muted-foreground">
Administrá los dispositivos donde iniciaste sesión
</p>
</div>
<Button variant="outline">Ver Sesiones</Button>
</div>
</CardContent>
</Card>

Expand Down
Loading