Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"use client";

import { revalidateTag } from "@/app/actions";
import { toast } from "@/components/ui/toaster";
import { tags } from "@/lib/cache";
import { trpc } from "@/lib/trpc/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { Button, DialogContainer, Input } from "@unkey/ui";
Expand Down Expand Up @@ -46,15 +44,15 @@ export const DeleteNamespaceDialog = ({
name: "",
},
});

const trpcUtils = trpc.useUtils();
const isValid = watch("name") === namespace.name;

const deleteNamespace = trpc.ratelimit.namespace.delete.useMutation({
onSuccess() {
toast.success("Namespace Deleted", {
description: "Your namespace and all its overridden identifiers have been deleted.",
});
revalidateTag(tags.namespace(namespace.id));
trpcUtils.ratelimit.namespace.query.invalidate();
router.push("/ratelimits");
onOpenChange(false);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export const STATUS_STYLES = {
hover: "hover:text-accent-11 dark:hover:text-accent-12 hover:bg-grayA-3",
selected: "text-accent-12 bg-grayA-3 hover:text-accent-12",
badge: {
default: "bg-grayA-3 text-grayA-11 group-hover:bg-grayA-5",
selected: "bg-grayA-5 text-grayA-12 hover:bg-grayA-5",
default: "bg-grayA-3 text-grayA-11 group-hover:bg-grayA-5 border-transparent",
selected: "bg-grayA-5 text-grayA-12 hover:bg-grayA-5 border-grayA-3",
},
focus: "focus:ring-accent-7",
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
"use client";

import { NamespaceNavbar } from "../namespace-navbar";
import { getWorkspaceDetails } from "../namespace.actions";
import { LogsClient } from "./components/logs-client";

export default async function RatelimitLogsPage({
export default function RatelimitLogsPage({
params: { namespaceId },
}: {
params: { namespaceId: string };
}) {
const { namespace, ratelimitNamespaces } = await getWorkspaceDetails(namespaceId);

return (
<div>
<NamespaceNavbar
namespaceId={namespaceId}
activePage={{
href: `/ratelimits/${namespace.id}/logs`,
href: `/ratelimits/${namespaceId}/logs`,
text: "Logs",
}}
namespace={namespace}
ratelimitNamespaces={ratelimitNamespaces}
/>
<LogsClient namespaceId={namespaceId} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,70 @@ import { QuickNavPopover } from "@/components/navbar-popover";
import { NavbarActionButton } from "@/components/navigation/action-button";
import { CopyableIDButton } from "@/components/navigation/copyable-id-button";
import { Navbar } from "@/components/navigation/navbar";
import { ChevronExpandY, Gauge } from "@unkey/icons";
import { trpc } from "@/lib/trpc/client";
import { ChevronExpandY, Gauge, TaskUnchecked } from "@unkey/icons";
import dynamic from "next/dynamic";
import { useState } from "react";
import { IdentifierDialog } from "./_components/identifier-dialog";

const IdentifierDialog = dynamic(
() => import("./_components/identifier-dialog").then((mod) => mod.IdentifierDialog),
{
loading: () => null,
ssr: false,
},
);

type NamespaceNavbarProps = {
namespace: {
id: string;
name: string;
workspaceId: string;
};
ratelimitNamespaces: {
id: string;
name: string;
}[];
namespaceId: string;
includeOverrides?: boolean;
activePage: {
href: string;
text: string;
};
};

export const NamespaceNavbar = ({
namespace,
ratelimitNamespaces,
namespaceId,
includeOverrides = false,
activePage,
}: NamespaceNavbarProps) => {
const [open, setOpen] = useState<boolean>(false);
const [open, setOpen] = useState(false);

const { data, isLoading } = trpc.ratelimit.namespace.queryDetails.useQuery({
namespaceId,
includeOverrides,
});

if (!data || isLoading) {
return (
<Navbar>
<Navbar.Breadcrumbs icon={<Gauge />}>
<Navbar.Breadcrumbs.Link href="/ratelimits">Ratelimits</Navbar.Breadcrumbs.Link>
<Navbar.Breadcrumbs.Link href="#" isIdentifier className="group" noop>
<div className="h-6 w-20 bg-grayA-3 rounded animate-pulse transition-all " />
</Navbar.Breadcrumbs.Link>
<Navbar.Breadcrumbs.Link href="#" noop active>
<div className="hover:bg-gray-3 rounded-lg flex items-center gap-1 p-1">
<div className="h-6 w-16 bg-grayA-3 rounded animate-pulse transition-all " />
<ChevronExpandY className="size-4" />
</div>
</Navbar.Breadcrumbs.Link>
</Navbar.Breadcrumbs>
<Navbar.Actions>
<div className="h-7 w-[146px] bg-grayA-3 rounded-md animate-pulse border border-grayA-4 transition-all " />
<div className="h-7 bg-grayA-2 border border-gray-6 rounded-md animate-pulse px-3 flex gap-2 items-center justify-center w-[260px] transition-all ">
<div className="h-3 w-[260px] bg-grayA-3 rounded" />
<div>
<TaskUnchecked size="sm-regular" className="!size-4" />
</div>
</div>
</Navbar.Actions>
</Navbar>
);
}

const { namespace, ratelimitNamespaces } = data;

return (
<>
<Navbar>
Expand Down Expand Up @@ -91,7 +129,9 @@ export const NamespaceNavbar = ({
<CopyableIDButton value={namespace.id} />
</Navbar.Actions>
</Navbar>
<IdentifierDialog onOpenChange={setOpen} isModalOpen={open} namespaceId={namespace.id} />
{open && (
<IdentifierDialog onOpenChange={setOpen} isModalOpen={open} namespaceId={namespace.id} />
)}
</>
);
};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Badge } from "@/components/ui/badge";
import { trpc } from "@/lib/trpc/client";
import { cn } from "@/lib/utils";
import { ChartActivity2 } from "@unkey/icons";
import { TimestampInfo } from "@unkey/ui";
import { useRef, useState } from "react";
import { STATUS_STYLES } from "../_overview/components/table/utils/get-row-class";

type LastUsedCellProps = {
namespaceId: string;
identifier: string;
};

export const LastUsedCell = ({ namespaceId, identifier }: LastUsedCellProps) => {
const { data, isLoading, isError } = trpc.ratelimit.namespace.queryRatelimitLastUsed.useQuery({
namespaceId,
identifier,
});
const badgeRef = useRef<HTMLDivElement>(null);
const [showTooltip, setShowTooltip] = useState(false);

return (
<Badge
ref={badgeRef}
className={cn(
"px-1.5 rounded-md flex gap-2 items-center max-w-min h-[22px] border-none cursor-pointer",
isError
? "bg-error-3 text-error-11 border border-error-5"
: STATUS_STYLES.success.badge.default,
)}
onMouseOver={() => {
setShowTooltip(true);
}}
onMouseLeave={() => {
setShowTooltip(false);
}}
>
<div>
<ChartActivity2 size="sm-regular" />
</div>
<div className="truncate">
{isLoading ? (
<div className="flex items-center w-full space-x-1">
<div className="h-2 w-2 bg-grayA-5 rounded-full animate-pulse" />
<div className="h-2 w-12 bg-grayA-5 rounded animate-pulse" />
<div className="h-2 w-12 bg-grayA-5 rounded animate-pulse" />
</div>
) : isError ? (
"Failed to load"
) : data?.lastUsed ? (
<TimestampInfo
displayType="relative"
value={data.lastUsed}
className="truncate"
triggerRef={badgeRef}
open={showTooltip}
onOpenChange={setShowTooltip}
/>
) : (
"Never used"
)}
</div>
</Badge>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { Badge } from "@/components/ui/badge";
import { VirtualTable } from "@/components/virtual-table";
import type { Column } from "@/components/virtual-table/types";
import { formatNumber } from "@/lib/fmt";
import { trpc } from "@/lib/trpc/client";
import { cn } from "@/lib/utils";
import { Empty } from "@unkey/ui";
import ms from "ms";
import { LastUsedCell } from "./last-used-cell";
import { OverridesTableAction } from "./logs-actions";

type Override = {
Expand All @@ -18,8 +20,6 @@ type Override = {

type Props = {
namespaceId: string;
ratelimits: Override[];
lastUsedTimes: Record<string, number | null>;
};

const STATUS_STYLES = {
Expand All @@ -37,7 +37,6 @@ const STATUS_STYLES = {

const getRowClassName = () => {
const style = STATUS_STYLES.default;

return cn(
style.base,
style.hover,
Expand All @@ -47,7 +46,13 @@ const getRowClassName = () => {
);
};

export const OverridesTable = ({ namespaceId, ratelimits, lastUsedTimes }: Props) => {
export const OverridesTable = ({ namespaceId }: Props) => {
const { data, isLoading } = trpc.ratelimit.namespace.queryDetails.useQuery({
namespaceId,
includeOverrides: true,
});

const overrides = data?.namespace?.overrides ?? [];
const columns: Column<Override>[] = [
{
key: "identifier",
Expand Down Expand Up @@ -115,17 +120,9 @@ export const OverridesTable = ({ namespaceId, ratelimits, lastUsedTimes }: Props
key: "lastUsed",
header: "Last used",
width: "20%",
render: (override) => {
const lastUsed = lastUsedTimes[override.identifier];
if (lastUsed) {
return (
<span className="font-mono text-xs text-content-subtle">
{ms(Date.now() - lastUsed)} ago
</span>
);
}
return <div className="w-4 h-4 text-content-subtle">─</div>;
},
render: (override) => (
<LastUsedCell namespaceId={namespaceId} identifier={override.identifier} />
),
},
{
key: "actions",
Expand All @@ -148,7 +145,8 @@ export const OverridesTable = ({ namespaceId, ratelimits, lastUsedTimes }: Props

return (
<VirtualTable
data={ratelimits}
data={overrides}
isLoading={isLoading}
columns={columns}
keyExtractor={(override) => override.id}
rowClassName={getRowClassName}
Expand Down
Loading