From 30a85b4432b7a99344b06e40eb54858f5e829748 Mon Sep 17 00:00:00 2001 From: unrenamed Date: Mon, 14 Oct 2024 13:49:54 +0300 Subject: [PATCH 1/7] fix(dashboard): move "bucket not found" placeholder under Audit Logs filters --- .../app/(app)/audit/[bucket]/page.tsx | 71 +++++++++---------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/apps/dashboard/app/(app)/audit/[bucket]/page.tsx b/apps/dashboard/app/(app)/audit/[bucket]/page.tsx index 237c2af876..d6e6f2f064 100644 --- a/apps/dashboard/app/(app)/audit/[bucket]/page.tsx +++ b/apps/dashboard/app/(app)/audit/[bucket]/page.tsx @@ -87,19 +87,6 @@ export default async function AuditPage(props: Props) { }, }, }); - if (!bucket) { - return ( - - - - - Bucket Not Found - - The specified audit log bucket does not exist or you do not have access to it. - - - ); - } return (
@@ -159,29 +146,41 @@ export default async function AuditPage(props: Props) { } > - ({ - id: l.id, - event: l.event, - time: l.time, - actor: { - id: l.actorId, - name: l.actorName, - type: l.actorType, - }, - location: l.remoteIp, - description: l.display, - targets: l.targets.map((t) => ({ - id: t.id, - type: t.type, - name: t.name, - })), - }))} - before={props.searchParams.before ? Number(props.searchParams.before) : undefined} - selectedEvents={selectedEvents} - selectedUsers={selectedUsers} - selectedRootKeys={selectedRootKeys} - /> + {!bucket ? ( + + + + + Bucket Not Found + + The specified audit log bucket does not exist or you do not have access to it. + + + ) : ( + ({ + id: l.id, + event: l.event, + time: l.time, + actor: { + id: l.actorId, + name: l.actorName, + type: l.actorType, + }, + location: l.remoteIp, + description: l.display, + targets: l.targets.map((t) => ({ + id: t.id, + type: t.type, + name: t.name, + })), + }))} + before={props.searchParams.before ? Number(props.searchParams.before) : undefined} + selectedEvents={selectedEvents} + selectedUsers={selectedUsers} + selectedRootKeys={selectedRootKeys} + /> + )}
From 52845110889403d523c9211bf3adbf4c99cd189c Mon Sep 17 00:00:00 2001 From: unrenamed Date: Mon, 14 Oct 2024 14:11:07 +0300 Subject: [PATCH 2/7] fix(dashboard): filter Audit Logs by active keys and rate limits --- apps/dashboard/app/(app)/audit/[bucket]/page.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/dashboard/app/(app)/audit/[bucket]/page.tsx b/apps/dashboard/app/(app)/audit/[bucket]/page.tsx index d6e6f2f064..32df9ea04d 100644 --- a/apps/dashboard/app/(app)/audit/[bucket]/page.tsx +++ b/apps/dashboard/app/(app)/audit/[bucket]/page.tsx @@ -43,6 +43,7 @@ export default async function AuditPage(props: Props) { and(eq(table.tenantId, tenantId), isNull(table.deletedAt)), with: { ratelimitNamespaces: { + where: (table, { isNull }) => isNull(table.deletedAt), columns: { id: true, name: true, @@ -358,7 +359,12 @@ const UserFilter: React.FC<{ tenantId: string }> = async ({ tenantId }) => { const RootKeyFilter: React.FC<{ workspaceId: string }> = async ({ workspaceId }) => { const rootKeys = await db.query.keys.findMany({ - where: (table, { eq }) => eq(table.forWorkspaceId, workspaceId), + where: (table, { eq, and, or, isNull, gt }) => + and( + eq(table.forWorkspaceId, workspaceId), + isNull(table.deletedAt), + or(isNull(table.expires), gt(table.expires, new Date())), + ), columns: { id: true, name: true, From 853ea2a669eab53a4673a531896c56765189df05 Mon Sep 17 00:00:00 2001 From: unrenamed Date: Mon, 14 Oct 2024 14:40:11 +0300 Subject: [PATCH 3/7] fix(dashboard): resolve hydration error by using consistent date formatting Replace `toLocaleDateString()` with `date-fns` to ensure consistent date formatting between server and client. This prevents hydration mismatches caused by differing time zones or locale settings, ensuring stable rendering across environments. --- apps/dashboard/app/(app)/audit/[bucket]/row.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/dashboard/app/(app)/audit/[bucket]/row.tsx b/apps/dashboard/app/(app)/audit/[bucket]/row.tsx index 2a1307ae56..3fae544320 100644 --- a/apps/dashboard/app/(app)/audit/[bucket]/row.tsx +++ b/apps/dashboard/app/(app)/audit/[bucket]/row.tsx @@ -5,6 +5,7 @@ import { Badge } from "@/components/ui/badge"; import { Code } from "@/components/ui/code"; import { TableCell, TableRow } from "@/components/ui/table"; import { cn } from "@/lib/utils"; +import { format } from "date-fns"; import { ChevronDown, KeySquare, Minus } from "lucide-react"; import { useState } from "react"; @@ -85,10 +86,10 @@ export const Row: React.FC = ({ auditLog, user }) => {
- {new Date(auditLog.time).toLocaleDateString()} + {format(new Date(auditLog.time), 'dd/MM/yyyy')} - {new Date(auditLog.time).toLocaleTimeString()} + {format(new Date(auditLog.time), 'dd/MM/yyyy')}
From dd0f147b4e561cd8143083eeebeee96b1c9373b7 Mon Sep 17 00:00:00 2001 From: unrenamed Date: Mon, 14 Oct 2024 15:59:20 +0300 Subject: [PATCH 4/7] refactor(dashboard): extract audit log mapping logic for improved readability The mapping logic within the component is complex due to nested structures. Extracting this logic into a separate function or utility enhances readability and maintainability. --- .../app/(app)/audit/[bucket]/page.tsx | 43 +++++++++++-------- internal/db/src/schema/audit_logs.ts | 3 ++ 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/apps/dashboard/app/(app)/audit/[bucket]/page.tsx b/apps/dashboard/app/(app)/audit/[bucket]/page.tsx index 32df9ea04d..97db9d2e66 100644 --- a/apps/dashboard/app/(app)/audit/[bucket]/page.tsx +++ b/apps/dashboard/app/(app)/audit/[bucket]/page.tsx @@ -16,6 +16,8 @@ import { Suspense } from "react"; import { BucketSelect } from "./bucket-select"; import { Filter } from "./filter"; import { Row } from "./row"; +import { SelectAuditLogTarget, type SelectAuditLog } from "@unkey/db/src/schema"; + export const dynamic = "force-dynamic"; export const runtime = "edge"; @@ -31,11 +33,34 @@ type Props = { }; }; +type AuditLogWithTargets = SelectAuditLog & { targets: Array }; + /** * Parse searchParam string arrays */ const filterParser = parseAsArrayOf(parseAsString).withDefault([]); +/** + * Utility to map log with targets to log entry + */ +const toLogEntry = (l: AuditLogWithTargets) => ({ + id: l.id, + event: l.event, + time: l.time, + actor: { + id: l.actorId, + name: l.actorName, + type: l.actorType, + }, + location: l.remoteIp, + description: l.display, + targets: l.targets.map((t) => ({ + id: t.id, + type: t.type, + name: t.name, + })), +}); + export default async function AuditPage(props: Props) { const tenantId = getTenantId(); const workspace = await db.query.workspaces.findFirst({ @@ -159,23 +184,7 @@ export default async function AuditPage(props: Props) { ) : ( ({ - id: l.id, - event: l.event, - time: l.time, - actor: { - id: l.actorId, - name: l.actorName, - type: l.actorType, - }, - location: l.remoteIp, - description: l.display, - targets: l.targets.map((t) => ({ - id: t.id, - type: t.type, - name: t.name, - })), - }))} + logs={bucket.logs.map(toLogEntry)} before={props.searchParams.before ? Number(props.searchParams.before) : undefined} selectedEvents={selectedEvents} selectedUsers={selectedUsers} diff --git a/internal/db/src/schema/audit_logs.ts b/internal/db/src/schema/audit_logs.ts index 7b93649054..faaa9b4c6a 100644 --- a/internal/db/src/schema/audit_logs.ts +++ b/internal/db/src/schema/audit_logs.ts @@ -137,3 +137,6 @@ export const auditLogTargetRelations = relations(auditLogTarget, ({ one }) => ({ references: [auditLog.id], }), })); + +export type SelectAuditLog = typeof auditLog.$inferSelect; +export type SelectAuditLogTarget = typeof auditLogTarget.$inferSelect; From 092406705774d3433cf6ceaf4cdf64b077c38cc3 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 09:19:20 +0000 Subject: [PATCH 5/7] [autofix.ci] apply automated fixes --- apps/dashboard/app/(app)/audit/[bucket]/page.tsx | 2 +- apps/dashboard/app/(app)/audit/[bucket]/row.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/dashboard/app/(app)/audit/[bucket]/page.tsx b/apps/dashboard/app/(app)/audit/[bucket]/page.tsx index 97db9d2e66..e865a0c64b 100644 --- a/apps/dashboard/app/(app)/audit/[bucket]/page.tsx +++ b/apps/dashboard/app/(app)/audit/[bucket]/page.tsx @@ -7,6 +7,7 @@ import { getTenantId } from "@/lib/auth"; import { db } from "@/lib/db"; import { clerkClient } from "@clerk/nextjs"; import type { User } from "@clerk/nextjs/server"; +import type { SelectAuditLog, SelectAuditLogTarget } from "@unkey/db/src/schema"; import { unkeyAuditLogEvents } from "@unkey/schema/src/auditlog"; import { Box, X } from "lucide-react"; import Link from "next/link"; @@ -16,7 +17,6 @@ import { Suspense } from "react"; import { BucketSelect } from "./bucket-select"; import { Filter } from "./filter"; import { Row } from "./row"; -import { SelectAuditLogTarget, type SelectAuditLog } from "@unkey/db/src/schema"; export const dynamic = "force-dynamic"; export const runtime = "edge"; diff --git a/apps/dashboard/app/(app)/audit/[bucket]/row.tsx b/apps/dashboard/app/(app)/audit/[bucket]/row.tsx index 3fae544320..d25175437c 100644 --- a/apps/dashboard/app/(app)/audit/[bucket]/row.tsx +++ b/apps/dashboard/app/(app)/audit/[bucket]/row.tsx @@ -86,10 +86,10 @@ export const Row: React.FC = ({ auditLog, user }) => {
- {format(new Date(auditLog.time), 'dd/MM/yyyy')} + {format(new Date(auditLog.time), "dd/MM/yyyy")} - {format(new Date(auditLog.time), 'dd/MM/yyyy')} + {format(new Date(auditLog.time), "dd/MM/yyyy")}
From ba0c64a851b140a8a9c40cfb140aab8ed15a5125 Mon Sep 17 00:00:00 2001 From: unrenamed Date: Sun, 20 Oct 2024 14:09:59 +0300 Subject: [PATCH 6/7] fix(dashboard): silence hydration mismatch warning in audit bucket row Revert static datetime formatting using `date-fns` to `toLocaleDateString()` to better suit global users. Suppress the hydration mismatch warnings caused by differences between server and client-side rendered dates. Co-authored-by: @chronark PR: #2413 --- apps/dashboard/app/(app)/audit/[bucket]/row.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/dashboard/app/(app)/audit/[bucket]/row.tsx b/apps/dashboard/app/(app)/audit/[bucket]/row.tsx index d25175437c..7f8dfa920c 100644 --- a/apps/dashboard/app/(app)/audit/[bucket]/row.tsx +++ b/apps/dashboard/app/(app)/audit/[bucket]/row.tsx @@ -5,7 +5,6 @@ import { Badge } from "@/components/ui/badge"; import { Code } from "@/components/ui/code"; import { TableCell, TableRow } from "@/components/ui/table"; import { cn } from "@/lib/utils"; -import { format } from "date-fns"; import { ChevronDown, KeySquare, Minus } from "lucide-react"; import { useState } from "react"; @@ -85,11 +84,11 @@ export const Row: React.FC = ({ auditLog, user }) => {
- - {format(new Date(auditLog.time), "dd/MM/yyyy")} + + {new Date(auditLog.time).toLocaleDateString()} - - {format(new Date(auditLog.time), "dd/MM/yyyy")} + + {new Date(auditLog.time).toLocaleDateString()}
From 88aedd4ef7ceca1c135eadab7da85849773dfc2f Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:01:46 +0000 Subject: [PATCH 7/7] [autofix.ci] apply automated fixes --- apps/dashboard/app/(app)/audit/[bucket]/row.tsx | 4 ++-- apps/www/app/glossary/[slug]/page.tsx | 4 ++-- apps/www/app/glossary/client.tsx | 4 ++-- apps/www/components/glossary/search.tsx | 6 +++--- apps/www/components/glossary/terms-rolodex-desktop.tsx | 8 ++++---- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/dashboard/app/(app)/audit/[bucket]/row.tsx b/apps/dashboard/app/(app)/audit/[bucket]/row.tsx index 7f8dfa920c..a1694526a1 100644 --- a/apps/dashboard/app/(app)/audit/[bucket]/row.tsx +++ b/apps/dashboard/app/(app)/audit/[bucket]/row.tsx @@ -85,10 +85,10 @@ export const Row: React.FC = ({ auditLog, user }) => {
- {new Date(auditLog.time).toLocaleDateString()} + {new Date(auditLog.time).toLocaleDateString()} - {new Date(auditLog.time).toLocaleDateString()} + {new Date(auditLog.time).toLocaleDateString()}
diff --git a/apps/www/app/glossary/[slug]/page.tsx b/apps/www/app/glossary/[slug]/page.tsx index 0afcf55c21..6590715495 100644 --- a/apps/www/app/glossary/[slug]/page.tsx +++ b/apps/www/app/glossary/[slug]/page.tsx @@ -1,6 +1,8 @@ import { CTA } from "@/components/cta"; import { Frame } from "@/components/frame"; +import { FilterableCommand } from "@/components/glossary/search"; +import TermsRolodexDesktop from "@/components/glossary/terms-rolodex-desktop"; import TermsStepperMobile from "@/components/glossary/terms-stepper-mobile"; import { MDX } from "@/components/mdx-content"; import { TopLeftShiningLight, TopRightShiningLight } from "@/components/svg/background-shiny"; @@ -14,8 +16,6 @@ import Link from "next/link"; import { notFound } from "next/navigation"; import { FAQ } from "./faq"; import Takeaways from "./takeaways"; -import TermsRolodexDesktop from "@/components/glossary/terms-rolodex-desktop"; -import { FilterableCommand } from "@/components/glossary/search"; export const generateStaticParams = async () => allGlossaries.map((term) => ({ diff --git a/apps/www/app/glossary/client.tsx b/apps/www/app/glossary/client.tsx index 1e6f16dd06..ff3734f54c 100644 --- a/apps/www/app/glossary/client.tsx +++ b/apps/www/app/glossary/client.tsx @@ -2,14 +2,14 @@ import { CTA } from "@/components/cta"; import { ChangelogLight } from "@/components/svg/changelog"; +import { type Glossary, allGlossaries } from "@/.content-collections/generated"; import { PrimaryButton } from "@/components/button"; import { Container } from "@/components/container"; import { FilterableCommand } from "@/components/glossary/search"; import { MeteorLinesAngular } from "@/components/ui/meteorLines"; import { LogIn } from "lucide-react"; -import Link from "next/link"; -import { allGlossaries, type Glossary } from "@/.content-collections/generated"; import { Zap } from "lucide-react"; +import Link from "next/link"; export function GlossaryClient() { const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""); diff --git a/apps/www/components/glossary/search.tsx b/apps/www/components/glossary/search.tsx index 8d31b8b9cb..a6926f5a42 100644 --- a/apps/www/components/glossary/search.tsx +++ b/apps/www/components/glossary/search.tsx @@ -1,7 +1,6 @@ "use client"; -import * as React from "react"; -import { Command as CommandPrimitive } from "cmdk"; +import type { Glossary } from "@/.content-collections/generated"; import { Command, CommandEmpty, @@ -10,8 +9,9 @@ import { CommandList, } from "@/components/ui/command"; import { cn } from "@/lib/utils"; +import { Command as CommandPrimitive } from "cmdk"; import { useRouter } from "next/navigation"; -import type { Glossary } from "@/.content-collections/generated"; +import * as React from "react"; export function FilterableCommand(props: { placeholder: string; diff --git a/apps/www/components/glossary/terms-rolodex-desktop.tsx b/apps/www/components/glossary/terms-rolodex-desktop.tsx index 17af33a986..fd1544b3cd 100644 --- a/apps/www/components/glossary/terms-rolodex-desktop.tsx +++ b/apps/www/components/glossary/terms-rolodex-desktop.tsx @@ -1,12 +1,12 @@ "use client"; -import { useState } from "react"; -import Link from "next/link"; +import type { Glossary } from "@/.content-collections/generated"; import { Button } from "@/components/ui/button"; -import { ChevronUpIcon, ChevronDownIcon } from "lucide-react"; import { cn } from "@/lib/utils"; +import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"; +import Link from "next/link"; import { useParams } from "next/navigation"; -import type { Glossary } from "@/.content-collections/generated"; +import { useState } from "react"; export default function TermsRolodexDesktop({ className,