From adc1ada302be85bf1a060c89b910da434bf1391c Mon Sep 17 00:00:00 2001 From: naaa760 Date: Mon, 15 Sep 2025 08:35:31 +0530 Subject: [PATCH 01/18] Main logs table --- .../logs/components/table/logs-table.tsx | 64 ++++++++++++------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/apps/dashboard/app/(app)/logs/components/table/logs-table.tsx b/apps/dashboard/app/(app)/logs/components/table/logs-table.tsx index 3c89367479..6e68b9b938 100644 --- a/apps/dashboard/app/(app)/logs/components/table/logs-table.tsx +++ b/apps/dashboard/app/(app)/logs/components/table/logs-table.tsx @@ -86,7 +86,7 @@ const WarningIcon = ({ status }: { status: number }) => ( WARNING_ICON_STYLES.base, status < 300 && "invisible", status >= 400 && status < 500 && WARNING_ICON_STYLES.warning, - status >= 500 && WARNING_ICON_STYLES.error, + status >= 500 && WARNING_ICON_STYLES.error )} /> ); @@ -107,17 +107,27 @@ const additionalColumns: Column[] = [ .join(" "), width: "auto", render: (log: Log) => ( -
{log[key as keyof Log]}
+
+ {log[key as keyof Log]} +
), })); export const LogsTable = () => { - const { displayProperties, setSelectedLog, selectedLog, isLive } = useLogsContext(); - const { realtimeLogs, historicalLogs, isLoading, isLoadingMore, loadMore, hasMore, total } = - useLogsQuery({ - startPolling: isLive, - pollIntervalMs: 2000, - }); + const { displayProperties, setSelectedLog, selectedLog, isLive } = + useLogsContext(); + const { + realtimeLogs, + historicalLogs, + isLoading, + isLoadingMore, + loadMore, + hasMore, + total, + } = useLogsQuery({ + startPolling: isLive, + pollIntervalMs: 2000, + }); const getRowClassName = (log: Log) => { const style = getStatusStyle(log.response_status); @@ -131,14 +141,13 @@ export const LogsTable = () => { style.focusRing, isSelected && style.selected, isLive && - !realtimeLogs.some((realtime) => realtime.request_id === log.request_id) && [ - "opacity-50", - "hover:opacity-100", - ], + !realtimeLogs.some( + (realtime) => realtime.request_id === log.request_id + ) && ["opacity-50", "hover:opacity-100"], selectedLog && { "opacity-50 z-0": !isSelected, "opacity-100 z-10": isSelected, - }, + } ); }; // biome-ignore lint/correctness/useExhaustiveDependencies: it's okay @@ -153,7 +162,9 @@ export const LogsTable = () => { value={log.time} className={cn( "font-mono group-hover:underline decoration-dotted", - selectedLog && selectedLog.request_id !== log.request_id && "pointer-events-none", + selectedLog && + selectedLog.request_id !== log.request_id && + "pointer-events-none" )} /> ), @@ -169,11 +180,13 @@ export const LogsTable = () => { {log.response_status}{" "} - {extractResponseField(log, "code") ? `| ${extractResponseField(log, "code")}` : ""} + {extractResponseField(log, "code") + ? `| ${extractResponseField(log, "code")}` + : ""} ); }, @@ -190,7 +203,7 @@ export const LogsTable = () => { "uppercase px-[6px] rounded-md font-mono whitespace-nowrap", isSelected ? STATUS_STYLES.success.badge.selected - : STATUS_STYLES.success.badge.default, + : STATUS_STYLES.success.badge.default )} > {log.method} @@ -205,12 +218,13 @@ export const LogsTable = () => { render: (log) =>
{log.path}
, }, ], - [selectedLog?.request_id], + [selectedLog?.request_id] ); const visibleColumns = useMemo(() => { const filtered = [...basicColumns, ...additionalColumns].filter( - (column) => isDisplayProperty(column.key) && displayProperties.has(column.key), + (column) => + isDisplayProperty(column.key) && displayProperties.has(column.key) ); // If we have visible columns @@ -250,9 +264,12 @@ export const LogsTable = () => { hasMore, countInfoText: (
- Showing {historicalLogs.length} + Showing{" "} + + {new Intl.NumberFormat().format(historicalLogs.length)} + of - {total} + {new Intl.NumberFormat().format(total)} requests
), @@ -263,8 +280,9 @@ export const LogsTable = () => { Logs - Keep track of all activity within your workspace. We collect all API requests, giving - you a clear history to find problems or debug issues. + Keep track of all activity within your workspace. We collect all + API requests, giving you a clear history to find problems or debug + issues. Date: Mon, 15 Sep 2025 08:36:23 +0530 Subject: [PATCH 02/18] key details logs table --- .../[keyId]/components/table/logs-table.tsx | 99 +++++++++++++------ 1 file changed, 71 insertions(+), 28 deletions(-) diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/components/table/logs-table.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/components/table/logs-table.tsx index a8f8a7672b..87d383f990 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/components/table/logs-table.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/components/table/logs-table.tsx @@ -16,7 +16,14 @@ import { TimeClock, TriangleWarning2, } from "@unkey/icons"; -import { Badge, Button, CopyButton, Empty, InfoTooltip, TimestampInfo } from "@unkey/ui"; +import { + Badge, + Button, + CopyButton, + Empty, + InfoTooltip, + TimestampInfo, +} from "@unkey/ui"; import { useCallback, useState } from "react"; import { useKeyDetailsLogsContext } from "../../context/logs"; import { StatusBadge } from "./components/status-badge"; @@ -149,7 +156,9 @@ const getStatusType = (outcome: LogOutcomeType): keyof typeof STATUS_STYLES => { } }; -export const categorizeSeverity = (outcome: string): keyof typeof STATUS_STYLES => { +export const categorizeSeverity = ( + outcome: string +): keyof typeof STATUS_STYLES => { switch (outcome) { case "VALID": return "success"; @@ -179,17 +188,32 @@ type Props = { onLogSelect: (log: KeyDetailsLog | null) => void; }; -export const KeyDetailsLogsTable = ({ keyspaceId, keyId, selectedLog, onLogSelect }: Props) => { +export const KeyDetailsLogsTable = ({ + keyspaceId, + keyId, + selectedLog, + onLogSelect, +}: Props) => { const { isLive } = useKeyDetailsLogsContext(); - const { realtimeLogs, historicalLogs, isLoading, isLoadingMore, loadMore, hasMore, totalCount } = - useKeyDetailsLogsQuery({ - keyId, - keyspaceId, - startPolling: isLive, - pollIntervalMs: 2000, - }); + const { + realtimeLogs, + historicalLogs, + isLoading, + isLoadingMore, + loadMore, + hasMore, + totalCount, + } = useKeyDetailsLogsQuery({ + keyId, + keyspaceId, + startPolling: isLive, + pollIntervalMs: 2000, + }); - const getRowClassName = (log: KeyDetailsLog, selected: KeyDetailsLog | null) => { + const getRowClassName = ( + log: KeyDetailsLog, + selected: KeyDetailsLog | null + ) => { const style = getStatusStyle(log); const isSelected = selected?.request_id === log.request_id; @@ -199,7 +223,7 @@ export const KeyDetailsLogsTable = ({ keyspaceId, keyId, selectedLog, onLogSelec "group rounded-md cursor-pointer transition-colors", "focus:outline-none focus:ring-1 focus:ring-opacity-40", style.focusRing, - isSelected && style.selected, + isSelected && style.selected ); }; @@ -232,7 +256,7 @@ export const KeyDetailsLogsTable = ({ keyspaceId, keyId, selectedLog, onLogSelec }); } }, - [hoveredLogId, utils.logs.queryLogs, timestamp], + [hoveredLogId, utils.logs.queryLogs, timestamp] ); const handleRowMouseLeave = useCallback(() => { @@ -251,7 +275,9 @@ export const KeyDetailsLogsTable = ({ keyspaceId, keyId, selectedLog, onLogSelec value={log.time} className={cn( "font-mono group-hover:underline decoration-dotted pl-2", - selectedLog && selectedLog.request_id !== log.request_id && "pointer-events-none", + selectedLog && + selectedLog.request_id !== log.request_id && + "pointer-events-none" )} /> ), @@ -279,8 +305,10 @@ export const KeyDetailsLogsTable = ({ keyspaceId, keyId, selectedLog, onLogSelec primary={{ label: outcomeInfo.label, color: isSelected - ? STATUS_STYLES[getStatusType(outcomeInfo.type)].badge.selected - : STATUS_STYLES[getStatusType(outcomeInfo.type)].badge.default, + ? STATUS_STYLES[getStatusType(outcomeInfo.type)].badge + .selected + : STATUS_STYLES[getStatusType(outcomeInfo.type)].badge + .default, icon: outcomeInfo.icon, }} /> @@ -318,9 +346,13 @@ export const KeyDetailsLogsTable = ({ keyspaceId, keyId, selectedLog, onLogSelec
{tag.length > 60 ? (
-
{tag}
+
+ {tag} +
-
({tag.length} characters)
+
+ ({tag.length} characters) +
{/* biome-ignore lint/a11y/useKeyWithClickEvents: */}
) : (
-
{tag}
+
+ {tag} +
{/* biome-ignore lint/a11y/useKeyWithClickEvents: */}
{shortenId(tag, { @@ -378,9 +412,13 @@ export const KeyDetailsLogsTable = ({ keyspaceId, keyId, selectedLog, onLogSelec
{tag.length > 60 ? (
-
{tag}
+
+ {tag} +
-
({tag.length} characters)
+
+ ({tag.length} characters) +
{/* biome-ignore lint/a11y/useKeyWithClickEvents: */}
) : (
-
{tag}
+
+ {tag} +
{/* biome-ignore lint/a11y/useKeyWithClickEvents: */}
+{log.tags.length - 3} @@ -449,9 +489,12 @@ export const KeyDetailsLogsTable = ({ keyspaceId, keyId, selectedLog, onLogSelec hide: isLoading, countInfoText: (
- Showing {historicalLogs.length} + Showing{" "} + + {new Intl.NumberFormat().format(historicalLogs.length)} + of - {totalCount} + {new Intl.NumberFormat().format(totalCount)} requests
), @@ -462,8 +505,8 @@ export const KeyDetailsLogsTable = ({ keyspaceId, keyId, selectedLog, onLogSelec Key Verification Logs - No verification logs found for this key. When this API key is used, details about - each verification attempt will appear here. + No verification logs found for this key. When this API key is + used, details about each verification attempt will appear here. Date: Mon, 15 Sep 2025 08:36:56 +0530 Subject: [PATCH 03/18] ratelimit overview logs table --- .../_overview/components/table/logs-table.tsx | 44 +++++++++++++------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/logs-table.tsx b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/logs-table.tsx index 0f22c0c059..8527df4e06 100644 --- a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/logs-table.tsx +++ b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/logs-table.tsx @@ -14,7 +14,11 @@ import { LogsTableAction } from "./components/logs-actions"; import { IdentifierColumn } from "./components/override-indicator"; import { useRatelimitOverviewLogsQuery } from "./hooks/use-logs-query"; import type { SortFields } from "./query-logs.schema"; -import { STATUS_STYLES, getRowClassName, getStatusStyle } from "./utils/get-row-class"; +import { + STATUS_STYLES, + getRowClassName, + getStatusStyle, +} from "./utils/get-row-class"; // const MAX_LATENCY = 10; export const RatelimitOverviewLogsTable = ({ @@ -24,10 +28,16 @@ export const RatelimitOverviewLogsTable = ({ }) => { const [selectedLog, setSelectedLog] = useState(); const { getSortDirection, toggleSort } = useSort(); - const { historicalLogs, isLoading, isLoadingMore, loadMore, hasMore, totalCount } = - useRatelimitOverviewLogsQuery({ - namespaceId, - }); + const { + historicalLogs, + isLoading, + isLoadingMore, + loadMore, + hasMore, + totalCount, + } = useRatelimitOverviewLogsQuery({ + namespaceId, + }); const columns = (namespaceId: string): Column[] => { return [ @@ -67,7 +77,7 @@ export const RatelimitOverviewLogsTable = ({ "uppercase px-[6px] rounded-md font-mono whitespace-nowrap", selectedLog?.request_id === log.request_id ? STATUS_STYLES.success.badge.selected - : STATUS_STYLES.success.badge.default, + : STATUS_STYLES.success.badge.default )} title={`${log.passed_count.toLocaleString()} Passed requests`} > @@ -101,7 +111,7 @@ export const RatelimitOverviewLogsTable = ({ "uppercase px-[6px] rounded-md font-mono whitespace-nowrap gap-[6px]", selectedLog?.request_id === log.request_id ? style.badge.selected - : style.badge.default, + : style.badge.default )} title={`${log.blocked_count.toLocaleString()} Blocked requests`} > @@ -180,7 +190,9 @@ export const RatelimitOverviewLogsTable = ({ value={log.time} className={cn( "font-mono group-hover:underline decoration-dotted", - selectedLog && selectedLog.request_id !== log.request_id && "pointer-events-none", + selectedLog && + selectedLog.request_id !== log.request_id && + "pointer-events-none" )} /> ), @@ -210,7 +222,9 @@ export const RatelimitOverviewLogsTable = ({ onLoadMore={loadMore} columns={columns(namespaceId)} keyExtractor={(log) => log.identifier} - rowClassName={(rowLog) => getRowClassName(rowLog, selectedLog as RatelimitOverviewLog)} + rowClassName={(rowLog) => + getRowClassName(rowLog, selectedLog as RatelimitOverviewLog) + } loadMoreFooterProps={{ itemLabel: "identifiers", buttonText: "Load more logs", @@ -218,8 +232,11 @@ export const RatelimitOverviewLogsTable = ({ hide: isLoading, countInfoText: (
- Showing {historicalLogs.length} - of {totalCount} + Showing{" "} + + {new Intl.NumberFormat().format(historicalLogs.length)} + + of {new Intl.NumberFormat().format(totalCount)} rate limit identifiers
), @@ -230,8 +247,9 @@ export const RatelimitOverviewLogsTable = ({ Logs - No rate limit data to show. Once requests are made, you'll see a summary of passed and - blocked requests for each rate limit identifier. + No rate limit data to show. Once requests are made, you'll see a + summary of passed and blocked requests for each rate limit + identifier.
Date: Mon, 15 Sep 2025 08:37:38 +0530 Subject: [PATCH 04/18] ratelimit logs table --- .../logs/components/table/logs-table.tsx | 65 ++++++++++++------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/table/logs-table.tsx b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/table/logs-table.tsx index 476845c8a4..e6fddfee6e 100644 --- a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/table/logs-table.tsx +++ b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/table/logs-table.tsx @@ -63,13 +63,21 @@ const getSelectedClassName = (log: RatelimitLog, isSelected: boolean) => { }; export const RatelimitLogsTable = () => { - const { setSelectedLog, selectedLog, isLive, namespaceId } = useRatelimitLogsContext(); - const { realtimeLogs, historicalLogs, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = - useRatelimitLogsQuery({ - namespaceId, - startPolling: isLive, - pollIntervalMs: 2000, - }); + const { setSelectedLog, selectedLog, isLive, namespaceId } = + useRatelimitLogsContext(); + const { + realtimeLogs, + historicalLogs, + isLoading, + isLoadingMore, + loadMore, + totalCount, + hasMore, + } = useRatelimitLogsQuery({ + namespaceId, + startPolling: isLive, + pollIntervalMs: 2000, + }); const getRowClassName = (log: RatelimitLog) => { const style = getStatusStyle(log.status); @@ -83,14 +91,13 @@ export const RatelimitLogsTable = () => { style.focusRing, isSelected && style.selected, isLive && - !realtimeLogs.some((realtime) => realtime.request_id === log.request_id) && [ - "opacity-50", - "hover:opacity-100", - ], + !realtimeLogs.some( + (realtime) => realtime.request_id === log.request_id + ) && ["opacity-50", "hover:opacity-100"], selectedLog && { "opacity-50 z-0": !isSelected, "opacity-100 z-10": isSelected, - }, + } ); }; @@ -108,7 +115,9 @@ export const RatelimitLogsTable = () => { value={log.time} className={cn( "font-mono group-hover:underline decoration-dotted", - selectedLog && selectedLog.request_id !== log.request_id && "pointer-events-none", + selectedLog && + selectedLog.request_id !== log.request_id && + "pointer-events-none" )} />
@@ -118,7 +127,11 @@ export const RatelimitLogsTable = () => { key: "identifier", header: "Identifier", width: "15%", - render: (log) =>
{log.identifier}
, + render: (log) => ( +
+ {log.identifier} +
+ ), }, { key: "rejected", @@ -131,7 +144,7 @@ export const RatelimitLogsTable = () => { {log.status === 0 ? "Blocked" : "Passed"} @@ -145,7 +158,9 @@ export const RatelimitLogsTable = () => { width: "auto", render: (log) => { return ( -
{safeParseJson(log.response_body)?.limit ?? ""}
+
+ {safeParseJson(log.response_body)?.limit ?? ""} +
); }, }, @@ -174,7 +189,9 @@ export const RatelimitLogsTable = () => { value={safeParseJson(log.response_body)?.reset ?? ""} className={cn( "font-mono group-hover:underline decoration-dotted", - selectedLog && selectedLog.request_id !== log.request_id && "pointer-events-none", + selectedLog && + selectedLog.request_id !== log.request_id && + "pointer-events-none" )} />
@@ -196,7 +213,7 @@ export const RatelimitLogsTable = () => { render: (log) => , }, ], - [selectedLog?.request_id], + [selectedLog?.request_id] ); return ( @@ -218,9 +235,12 @@ export const RatelimitLogsTable = () => { hide: isLoading, countInfoText: (
- Showing {historicalLogs.length} + Showing{" "} + + {new Intl.NumberFormat().format(historicalLogs.length)} + of - {totalCount} + {new Intl.NumberFormat().format(totalCount)} ratelimit requests
), @@ -231,8 +251,9 @@ export const RatelimitLogsTable = () => { Logs - No ratelimit logs yet. Once API requests start coming in, you'll see a detailed view - of your rate limits, including passed and blocked requests, across your API endpoints. + No ratelimit logs yet. Once API requests start coming in, you'll + see a detailed view of your rate limits, including passed and + blocked requests, across your API endpoints.
Date: Mon, 15 Sep 2025 08:38:19 +0530 Subject: [PATCH 05/18] virtual table loading indicator --- .../components/loading-indicator.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/dashboard/components/virtual-table/components/loading-indicator.tsx b/apps/dashboard/components/virtual-table/components/loading-indicator.tsx index 9ca6642eed..0dc413687a 100644 --- a/apps/dashboard/components/virtual-table/components/loading-indicator.tsx +++ b/apps/dashboard/components/virtual-table/components/loading-indicator.tsx @@ -57,11 +57,15 @@ export const LoadMoreFooter = ({ type="button" onClick={handleOpen} className="bg-gray-1 dark:bg-black border border-gray-6 rounded-lg shadow-lg p-3 transition-all duration-200 hover:shadow-xl hover:scale-105 group" - title={`${buttonText} • ${totalVisible} of ${totalCount} ${itemLabel}`} + title={`${buttonText} • ${new Intl.NumberFormat().format( + totalVisible + )} of ${new Intl.NumberFormat().format(totalCount)} ${itemLabel}`} >
- {countInfoText} + + {countInfoText} +
@@ -114,15 +118,19 @@ export const LoadMoreFooter = ({ animation: "fadeInUp 0.3s ease-out 0.3s both", }} > - {countInfoText &&
{countInfoText}
} + {countInfoText && ( +
{countInfoText}
+ )} {!countInfoText && (
Viewing - {totalVisible} + {new Intl.NumberFormat().format(totalVisible)} of - {totalCount} + + {new Intl.NumberFormat().format(totalCount)} + {itemLabel}
)} From a1150db642e2d009ce85045bac5d7b0fa530ea73 Mon Sep 17 00:00:00 2001 From: naaa760 Date: Mon, 15 Sep 2025 08:39:50 +0530 Subject: [PATCH 06/18] API list components --- apps/dashboard/app/(app)/apis/_components/api-list-grid.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/dashboard/app/(app)/apis/_components/api-list-grid.tsx b/apps/dashboard/app/(app)/apis/_components/api-list-grid.tsx index bc77345e80..e4d4c10a18 100644 --- a/apps/dashboard/app/(app)/apis/_components/api-list-grid.tsx +++ b/apps/dashboard/app/(app)/apis/_components/api-list-grid.tsx @@ -43,7 +43,8 @@ export const ApiListGrid = ({
- Showing {apiList.length} of {total} APIs + Showing {new Intl.NumberFormat().format(apiList.length)} of{" "} + {new Intl.NumberFormat().format(total)} APIs
{!isSearching && hasMore && ( From 529fcdb785d3bb1d777146db25a220f038050bc0 Mon Sep 17 00:00:00 2001 From: naaa760 Date: Mon, 15 Sep 2025 08:40:32 +0530 Subject: [PATCH 07/18] projects lists --- .../(app)/projects/_components/list/index.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/dashboard/app/(app)/projects/_components/list/index.tsx b/apps/dashboard/app/(app)/projects/_components/list/index.tsx index 37c04f8499..94f725ac6b 100644 --- a/apps/dashboard/app/(app)/projects/_components/list/index.tsx +++ b/apps/dashboard/app/(app)/projects/_components/list/index.tsx @@ -38,8 +38,8 @@ export const ProjectsList = () => { No Projects Found - There are no projects configured yet. Create your first project to start deploying and - managing your applications. + There are no projects configured yet. Create your first project to + start deploying and managing your applications.
{ }} > {projects.map((project) => { - const primaryHostname = project.hostnames[0]?.hostname || "No domain"; + const primaryHostname = + project.hostnames[0]?.hostname || "No domain"; return ( { name={project.name} domain={primaryHostname} commitTitle="Latest deployment" - commitDate={new Date(project.updatedAt || project.createdAt).toLocaleDateString()} + commitDate={new Date( + project.updatedAt || project.createdAt + ).toLocaleDateString()} branch={project.branch || "main"} author="Unknown" regions={["us-east-1", "us-west-2", "ap-east-1"]} @@ -111,9 +114,13 @@ export const ProjectsList = () => { countInfoText={
Viewing - {projects.length} + + {new Intl.NumberFormat().format(projects.length)} + of - {totalCount} + + {new Intl.NumberFormat().format(totalCount)} + projects
} From 89f2bfbd875d195b1e9b358060158f778bfd2ba7 Mon Sep 17 00:00:00 2001 From: naaa760 Date: Mon, 15 Sep 2025 08:41:24 +0530 Subject: [PATCH 08/18] root keys table --- .../components/table/root-keys-list.tsx | 74 ++++++++++++------- 1 file changed, 48 insertions(+), 26 deletions(-) diff --git a/apps/dashboard/app/(app)/settings/root-keys/components/table/root-keys-list.tsx b/apps/dashboard/app/(app)/settings/root-keys/components/table/root-keys-list.tsx index e2c51eed01..f608a9ee91 100644 --- a/apps/dashboard/app/(app)/settings/root-keys/components/table/root-keys-list.tsx +++ b/apps/dashboard/app/(app)/settings/root-keys/components/table/root-keys-list.tsx @@ -13,7 +13,9 @@ import { useCallback, useMemo, useState } from "react"; import { RootKeyDialog } from "../root-key/root-key-dialog"; // Type guard function to check if a string is a valid UnkeyPermission -const isUnkeyPermission = (permissionName: string): permissionName is UnkeyPermission => { +const isUnkeyPermission = ( + permissionName: string +): permissionName is UnkeyPermission => { const result = unkeyPermissionValidation.safeParse(permissionName); return result.success; }; @@ -32,22 +34,25 @@ import { getRowClassName } from "./utils/get-row-class"; const RootKeysTableActions = dynamic( () => - import("./components/actions/root-keys-table-action.popover.constants").then( - (mod) => mod.RootKeysTableActions, - ), + import( + "./components/actions/root-keys-table-action.popover.constants" + ).then((mod) => mod.RootKeysTableActions), { loading: () => ( ), - }, + } ); export const RootKeysList = () => { @@ -75,7 +80,7 @@ export const RootKeysList = () => { // Memoize the row className function const getRowClassNameMemoized = useCallback( (rootKey: RootKey) => getRowClassName(rootKey, selectedRootKey), - [selectedRootKey], + [selectedRootKey] ); // Memoize the loadMoreFooterProps to prevent unnecessary re-renders @@ -86,14 +91,17 @@ export const RootKeysList = () => { hasMore, countInfoText: (
- Showing {rootKeys.length} + Showing{" "} + + {new Intl.NumberFormat().format(rootKeys.length)} + of - {totalCount} + {new Intl.NumberFormat().format(totalCount)} root keys
), }), - [isLoading, hasMore, rootKeys.length, totalCount], + [isLoading, hasMore, rootKeys.length, totalCount] ); // Memoize the emptyState to prevent unnecessary re-renders @@ -104,8 +112,8 @@ export const RootKeysList = () => { No Root Keys Found - There are no root keys configured yet. Create your first root key to start managing - permissions and access control. + There are no root keys configured yet. Create your first root key to + start managing permissions and access control.
{
), - [], + [] ); // Memoize the config to prevent unnecessary re-renders @@ -134,7 +142,7 @@ export const RootKeysList = () => { rowBorders: true, containerPadding: "px-0", }), - [], + [] ); // Memoize the keyExtractor to prevent unnecessary re-renders @@ -142,13 +150,19 @@ export const RootKeysList = () => { // Memoize the renderSkeletonRow function to prevent unnecessary re-renders const renderSkeletonRow = useCallback( - ({ columns, rowHeight }: { columns: Column[]; rowHeight: number }) => + ({ + columns, + rowHeight, + }: { + columns: Column[]; + rowHeight: number; + }) => columns.map((column) => ( @@ -160,7 +174,7 @@ export const RootKeysList = () => { {column.key === "action" && } )), - [], + [] ); // Memoize the existingKey object to prevent unnecessary re-renders @@ -171,7 +185,9 @@ export const RootKeysList = () => { // Guard against undefined permissions and use type guard function const permissions = editingKey.permissions ?? []; - const validatedPermissions = permissions.map((p) => p.name).filter(isUnkeyPermission); + const validatedPermissions = permissions + .map((p) => p.name) + .filter(isUnkeyPermission); return { id: editingKey.id, @@ -194,7 +210,7 @@ export const RootKeysList = () => { className={cn( "size-5 rounded flex items-center justify-center cursor-pointer border border-grayA-3 transition-all duration-100", "bg-grayA-3", - isSelected && "bg-grayA-5", + isSelected && "bg-grayA-5" )} > @@ -208,7 +224,9 @@ export const RootKeysList = () => {
{rootKey.name ?? "Unnamed Root Key"} @@ -227,8 +245,8 @@ export const RootKeysList = () => { - This is the first part of the key to visually match it. We don't store the full key - for security reasons. + This is the first part of the key to visually match it. We don't + store the full key for security reasons.

} > @@ -259,7 +277,9 @@ export const RootKeysList = () => { return ( ); }, @@ -282,11 +302,13 @@ export const RootKeysList = () => { header: "", width: "auto", render: (rootKey) => { - return ; + return ( + + ); }, }, ], - [selectedRootKeyId, handleEditKey], + [selectedRootKeyId, handleEditKey] ); return ( From f392003fdc9ac6ec6c46e110b13a648dbf108079 Mon Sep 17 00:00:00 2001 From: naaa760 Date: Mon, 15 Sep 2025 08:41:55 +0530 Subject: [PATCH 09/18] deployments table --- .../components/table/deployments-list.tsx | 76 +++++++++++++------ 1 file changed, 53 insertions(+), 23 deletions(-) diff --git a/apps/dashboard/app/(app)/projects/[projectId]/deployments/components/table/deployments-list.tsx b/apps/dashboard/app/(app)/projects/[projectId]/deployments/components/table/deployments-list.tsx index aa2156a5d3..f8c600dd56 100644 --- a/apps/dashboard/app/(app)/projects/[projectId]/deployments/components/table/deployments-list.tsx +++ b/apps/dashboard/app/(app)/projects/[projectId]/deployments/components/table/deployments-list.tsx @@ -27,21 +27,28 @@ import { getRowClassName } from "./utils/get-row-class"; const DeploymentListTableActions = dynamic( () => - import("./components/actions/deployment-list-table-action.popover.constants").then( - (mod) => mod.DeploymentListTableActions, - ), + import( + "./components/actions/deployment-list-table-action.popover.constants" + ).then((mod) => mod.DeploymentListTableActions), { loading: () => , ssr: false, - }, + } ); const COMPACT_BREAKPOINT = 1200; export const DeploymentsList = () => { - const { deployments, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = - useDeploymentsListQuery(); - const [selectedDeployment, setSelectedDeployment] = useState(null); + const { + deployments, + isLoading, + isLoadingMore, + loadMore, + totalCount, + hasMore, + } = useDeploymentsListQuery(); + const [selectedDeployment, setSelectedDeployment] = + useState(null); const isCompactView = useIsMobile({ breakpoint: COMPACT_BREAKPOINT }); const columns: Column[] = useMemo(() => { @@ -58,7 +65,7 @@ export const DeploymentsList = () => { className={cn( "size-5 rounded flex items-center justify-center cursor-pointer border border-grayA-3 transition-all duration-100", "bg-grayA-3", - isSelected && "bg-grayA-5", + isSelected && "bg-grayA-5" )} > @@ -73,16 +80,22 @@ export const DeploymentsList = () => {
{shortenId(deployment.id)}
- {deployment.environment === "production" && deployment.active && ( - - )} + {deployment.environment === "production" && + deployment.active && ( + + )}
-
+
{deployment.pullRequest?.title ?? "—"}
@@ -142,7 +155,9 @@ export const DeploymentsList = () => {
- 2 + + 2 + CPU
/ @@ -170,7 +185,7 @@ export const DeploymentsList = () => { className={cn( "size-5 rounded flex items-center justify-center cursor-pointer border border-grayA-3 transition-all duration-100", "bg-grayA-3", - isSelected && "bg-grayA-5", + isSelected && "bg-grayA-5" )} > @@ -185,13 +200,18 @@ export const DeploymentsList = () => {
{deployment.source.branch}
-
+
{deployment.source.gitSha}
@@ -221,7 +241,12 @@ export const DeploymentsList = () => { {deployment.author.name}
-
+
{ onRowClick={setSelectedDeployment} selectedItem={selectedDeployment} keyExtractor={(deployment) => deployment.id} - rowClassName={(deployment) => getRowClassName(deployment, selectedDeployment)} + rowClassName={(deployment) => + getRowClassName(deployment, selectedDeployment) + } loadMoreFooterProps={{ hide: isLoading, buttonText: "Load more deployments", hasMore, countInfoText: (
- Showing {deployments.length} + Showing{" "} + + {new Intl.NumberFormat().format(deployments.length)} + of - {totalCount} + {new Intl.NumberFormat().format(totalCount)} deployments
), @@ -309,8 +339,8 @@ export const DeploymentsList = () => { No Deployments Found - There are no deployments yet. Push to your connected repository or trigger a manual - deployment to get started. + There are no deployments yet. Push to your connected repository or + trigger a manual deployment to get started.
Date: Mon, 15 Sep 2025 08:42:39 +0530 Subject: [PATCH 10/18] keys list table --- .../components/table/keys-list.tsx | 74 +++++++++++++------ 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx index 5bdfa1f9ed..3035348843 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx @@ -28,7 +28,7 @@ import { getRowClassName } from "./utils/get-row-class"; const KeysTableActionPopover = dynamic( () => import("./components/actions/keys-table-action.popover.constants").then( - (mod) => mod.KeysTableActions, + (mod) => mod.KeysTableActions ), { ssr: false, @@ -37,13 +37,16 @@ const KeysTableActionPopover = dynamic( type="button" className={cn( "group-data-[state=open]:bg-gray-6 group-hover:bg-gray-6 group size-5 p-0 rounded m-0 items-center flex justify-center", - "border border-gray-6 group-hover:border-gray-8 ring-2 ring-transparent focus-visible:ring-gray-7 focus-visible:border-gray-7", + "border border-gray-6 group-hover:border-gray-8 ring-2 ring-transparent focus-visible:ring-gray-7 focus-visible:border-gray-7" )} > - + ), - }, + } ); export const KeysList = ({ @@ -53,9 +56,10 @@ export const KeysList = ({ keyspaceId: string; apiId: string; }) => { - const { keys, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = useKeysListQuery({ - keyAuthId: keyspaceId, - }); + const { keys, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = + useKeysListQuery({ + keyAuthId: keyspaceId, + }); const [selectedKey, setSelectedKey] = useState(null); const [navigatingKeyId, setNavigatingKeyId] = useState(null); // Add state for selected keys @@ -98,13 +102,17 @@ export const KeysList = ({ className={cn( "size-5 rounded flex items-center justify-center cursor-pointer", identity ? "bg-successA-3" : "bg-grayA-3", - isSelected && "bg-brand-5", + isSelected && "bg-brand-5" )} onMouseEnter={() => setHoveredKeyId(key.id)} onMouseLeave={() => setHoveredKeyId(null)} > {isNavigating ? ( -
+
) : ( @@ -155,17 +163,24 @@ export const KeysList = ({ rel="noopener noreferrer" aria-disabled={isNavigating} > - {identity} + + {identity} + ) : ( - {identity} + + {identity} + )} } asChild > {React.cloneElement(iconContainer, { - className: cn(iconContainer.props.className, "cursor-pointer"), + className: cn( + iconContainer.props.className, + "cursor-pointer" + ), })} ) : ( @@ -205,7 +220,11 @@ export const KeysList = ({ header: "Value", width: "15%", render: (key) => ( - + ), }, { @@ -266,7 +285,7 @@ export const KeysList = ({ selectedKeys, toggleSelection, hoveredKeyId, - ], + ] ); const getSelectedKeysState = useCallback(() => { @@ -330,9 +349,12 @@ export const KeysList = ({ ), countInfoText: (
- Showing {keys.length} + Showing{" "} + + {new Intl.NumberFormat().format(keys.length)} + of - {totalCount} + {new Intl.NumberFormat().format(totalCount)} keys
), @@ -343,8 +365,8 @@ export const KeysList = ({ No API Keys Found - There are no API keys associated with this service yet. Create your first API key to - get started. + There are no API keys associated with this service yet. Create + your first API key to get started.
@@ -384,9 +406,17 @@ export const KeysList = ({ {column.key === "last_used" && } {column.key === "status" && } {column.key === "action" && } - {!["select", "key", "value", "usage", "last_used", "status", "action"].includes( - column.key, - ) &&
} + {![ + "select", + "key", + "value", + "usage", + "last_used", + "status", + "action", + ].includes(column.key) && ( +
+ )} )) } From bd0bf965446dd24b5b2b963e2fb3e3c7c987da73 Mon Sep 17 00:00:00 2001 From: naaa760 Date: Mon, 15 Sep 2025 08:43:14 +0530 Subject: [PATCH 11/18] authorization roles table --- .../roles/components/table/roles-list.tsx | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/dashboard/app/(app)/authorization/roles/components/table/roles-list.tsx b/apps/dashboard/app/(app)/authorization/roles/components/table/roles-list.tsx index fb4056b34c..a3497dda92 100644 --- a/apps/dashboard/app/(app)/authorization/roles/components/table/roles-list.tsx +++ b/apps/dashboard/app/(app)/authorization/roles/components/table/roles-list.tsx @@ -22,7 +22,8 @@ import { useRolesListQuery } from "./hooks/use-roles-list-query"; import { getRowClassName } from "./utils/get-row-class"; export const RolesList = () => { - const { roles, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = useRolesListQuery(); + const { roles, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = + useRolesListQuery(); const [selectedRole, setSelectedRole] = useState(null); const [selectedRoles, setSelectedRoles] = useState>(new Set()); const [hoveredRoleName, setHoveredRoleName] = useState(null); @@ -55,12 +56,14 @@ export const RolesList = () => { className={cn( "size-5 rounded flex items-center justify-center cursor-pointer border border-grayA-3 transition-all duration-100", "bg-grayA-3", - isSelected && "bg-grayA-5", + isSelected && "bg-grayA-5" )} onMouseEnter={() => setHoveredRoleName(role.name)} onMouseLeave={() => setHoveredRoleName(null)} > - {!isSelected && !isHovered && } + {!isSelected && !isHovered && ( + + )} {(isSelected || isHovered) && ( { }, }, ], - [selectedRoles, toggleSelection, hoveredRoleName, selectedRole?.roleId], + [selectedRoles, toggleSelection, hoveredRoleName, selectedRole?.roleId] ); return ( @@ -162,13 +165,19 @@ export const RolesList = () => { buttonText: "Load more roles", hasMore, headerContent: ( - + ), countInfoText: (
- Showing {roles.length} + Showing{" "} + + {new Intl.NumberFormat().format(roles.length)} + of - {totalCount} + {new Intl.NumberFormat().format(totalCount)} roles
), @@ -179,8 +188,8 @@ export const RolesList = () => { No Roles Found - There are no roles configured yet. Create your first role to start managing - permissions and access control. + There are no roles configured yet. Create your first role to start + managing permissions and access control.
{ key={column.key} className={cn( "text-xs align-middle whitespace-nowrap", - column.key === "role" ? "py-[6px]" : "py-1", + column.key === "role" ? "py-[6px]" : "py-1" )} style={{ height: `${rowHeight}px` }} > From ecf5a04dd40c4b189395b9f0aff707b2107344a3 Mon Sep 17 00:00:00 2001 From: naaa760 Date: Mon, 15 Sep 2025 08:43:40 +0530 Subject: [PATCH 12/18] authorization permissions table --- .../components/table/permissions-list.tsx | 71 ++++++++++++++----- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/apps/dashboard/app/(app)/authorization/permissions/components/table/permissions-list.tsx b/apps/dashboard/app/(app)/authorization/permissions/components/table/permissions-list.tsx index 29c47a5175..e51f0071aa 100644 --- a/apps/dashboard/app/(app)/authorization/permissions/components/table/permissions-list.tsx +++ b/apps/dashboard/app/(app)/authorization/permissions/components/table/permissions-list.tsx @@ -22,11 +22,22 @@ import { usePermissionsListQuery } from "./hooks/use-permissions-list-query"; import { getRowClassName } from "./utils/get-row-class"; export const PermissionsList = () => { - const { permissions, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = - usePermissionsListQuery(); - const [selectedPermission, setSelectedPermission] = useState(null); - const [selectedPermissions, setSelectedPermissions] = useState>(new Set()); - const [hoveredPermissionName, setHoveredPermissionName] = useState(null); + const { + permissions, + isLoading, + isLoadingMore, + loadMore, + totalCount, + hasMore, + } = usePermissionsListQuery(); + const [selectedPermission, setSelectedPermission] = + useState(null); + const [selectedPermissions, setSelectedPermissions] = useState>( + new Set() + ); + const [hoveredPermissionName, setHoveredPermissionName] = useState< + string | null + >(null); const toggleSelection = useCallback((permissionName: string) => { setSelectedPermissions((prevSelected) => { @@ -56,12 +67,14 @@ export const PermissionsList = () => { className={cn( "size-5 rounded flex items-center justify-center cursor-pointer border border-grayA-3 transition-all duration-100", "bg-grayA-3", - isSelected && "bg-grayA-5", + isSelected && "bg-grayA-5" )} onMouseEnter={() => setHoveredPermissionName(permission.name)} onMouseLeave={() => setHoveredPermissionName(null)} > - {!isSelected && !isHovered && } + {!isSelected && !isHovered && ( + + )} {(isSelected || isHovered) && ( { ), }, @@ -118,7 +133,9 @@ export const PermissionsList = () => { ), }, @@ -130,7 +147,9 @@ export const PermissionsList = () => { ), }, @@ -142,7 +161,9 @@ export const PermissionsList = () => { return ( ); }, @@ -156,7 +177,12 @@ export const PermissionsList = () => { }, }, ], - [selectedPermissions, toggleSelection, hoveredPermissionName, selectedPermission?.permissionId], + [ + selectedPermissions, + toggleSelection, + hoveredPermissionName, + selectedPermission?.permissionId, + ] ); return ( @@ -169,7 +195,9 @@ export const PermissionsList = () => { onRowClick={setSelectedPermission} selectedItem={selectedPermission} keyExtractor={(permission) => permission.permissionId} - rowClassName={(permission) => getRowClassName(permission, selectedPermission)} + rowClassName={(permission) => + getRowClassName(permission, selectedPermission) + } loadMoreFooterProps={{ hide: isLoading, buttonText: "Load more permissions", @@ -182,9 +210,12 @@ export const PermissionsList = () => { ), countInfoText: (
- Showing {permissions.length} + Showing{" "} + + {new Intl.NumberFormat().format(permissions.length)} + of - {totalCount} + {new Intl.NumberFormat().format(totalCount)} permissions
), @@ -195,8 +226,8 @@ export const PermissionsList = () => { No Permissions Found - There are no permissions configured yet. Create your first permission to start - managing permissions and access control. + There are no permissions configured yet. Create your first + permission to start managing permissions and access control.
{ key={column.key} className={cn( "text-xs align-middle whitespace-nowrap", - column.key === "permission" ? "py-[6px]" : "py-1", + column.key === "permission" ? "py-[6px]" : "py-1" )} style={{ height: `${rowHeight}px` }} > {column.key === "permission" && } {column.key === "slug" && } {column.key === "used_in_roles" && } - {column.key === "assigned_to_keys" && } + {column.key === "assigned_to_keys" && ( + + )} {column.key === "last_updated" && } {column.key === "action" && } From c8a35f0b84a38a3bb9a17a21070e20b73799cf3b Mon Sep 17 00:00:00 2001 From: naaa760 Date: Mon, 15 Sep 2025 08:47:36 +0530 Subject: [PATCH 13/18] This is the api-list-client.tsx file located in the APIs --- .../(app)/apis/_components/api-list-client.tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/apps/dashboard/app/(app)/apis/_components/api-list-client.tsx b/apps/dashboard/app/(app)/apis/_components/api-list-client.tsx index 2256810f9d..3f1c8028bc 100644 --- a/apps/dashboard/app/(app)/apis/_components/api-list-client.tsx +++ b/apps/dashboard/app/(app)/apis/_components/api-list-client.tsx @@ -30,7 +30,7 @@ export const ApiListClient = () => { { limit: DEFAULT_LIMIT }, { getNextPageParam: (lastPage) => lastPage.nextCursor, - }, + } ); const allApis = useMemo(() => { @@ -61,7 +61,11 @@ export const ApiListClient = () => { return (
- + {isLoading ? ( @@ -81,11 +85,17 @@ export const ApiListClient = () => {
- Showing {apiList.length} of {apisData?.pages[0]?.total || 0} APIs + Showing {new Intl.NumberFormat().format(apiList.length)} of{" "} + {new Intl.NumberFormat().format(apisData?.pages[0]?.total || 0)}{" "} + APIs
{!isSearching && hasNextPage && ( -
), - } + }, ); export const KeysList = ({ @@ -57,10 +54,9 @@ export const KeysList = ({ keyspaceId: string; apiId: string; }) => { - const { keys, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = - useKeysListQuery({ - keyAuthId: keyspaceId, - }); + const { keys, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = useKeysListQuery({ + keyAuthId: keyspaceId, + }); const [selectedKey, setSelectedKey] = useState(null); const [navigatingKeyId, setNavigatingKeyId] = useState(null); // Add state for selected keys @@ -103,17 +99,13 @@ export const KeysList = ({ className={cn( "size-5 rounded flex items-center justify-center cursor-pointer", identity ? "bg-successA-3" : "bg-grayA-3", - isSelected && "bg-brand-5" + isSelected && "bg-brand-5", )} onMouseEnter={() => setHoveredKeyId(key.id)} onMouseLeave={() => setHoveredKeyId(null)} > {isNavigating ? ( -
+
) : ( @@ -164,24 +156,17 @@ export const KeysList = ({ rel="noopener noreferrer" aria-disabled={isNavigating} > - - {identity} - + {identity} ) : ( - - {identity} - + {identity} )} } asChild > {React.cloneElement(iconContainer, { - className: cn( - iconContainer.props.className, - "cursor-pointer" - ), + className: cn(iconContainer.props.className, "cursor-pointer"), })} ) : ( @@ -221,11 +206,7 @@ export const KeysList = ({ header: "Value", width: "15%", render: (key) => ( - + ), }, { @@ -286,7 +267,7 @@ export const KeysList = ({ selectedKeys, toggleSelection, hoveredKeyId, - ] + ], ); const getSelectedKeysState = useCallback(() => { @@ -311,17 +292,15 @@ export const KeysList = ({ // Early exit if we already found a mix if (!allEnabled && !allDisabled) { - break; + return "mixed"; } } if (allEnabled) { return "all-enabled"; } - if (allDisabled) { - return "all-disabled"; - } - return "mixed"; + + return "all-disabled"; }, [selectedKeys, keys]); return ( @@ -351,9 +330,7 @@ export const KeysList = ({ countInfoText: (
Showing{" "} - - {formatNumberFull(keys.length)} - + {formatNumberFull(keys.length)} of {formatNumberFull(totalCount)} keys @@ -366,8 +343,8 @@ export const KeysList = ({ No API Keys Found - There are no API keys associated with this service yet. Create - your first API key to get started. + There are no API keys associated with this service yet. Create your first API key to + get started. @@ -407,17 +384,9 @@ export const KeysList = ({ {column.key === "last_used" && } {column.key === "status" && } {column.key === "action" && } - {![ - "select", - "key", - "value", - "usage", - "last_used", - "status", - "action", - ].includes(column.key) && ( -
- )} + {!["select", "key", "value", "usage", "last_used", "status", "action"].includes( + column.key, + ) &&
} )) } diff --git a/apps/dashboard/app/(app)/apis/_components/api-list-client.tsx b/apps/dashboard/app/(app)/apis/_components/api-list-client.tsx index 527283cbcc..111056236a 100644 --- a/apps/dashboard/app/(app)/apis/_components/api-list-client.tsx +++ b/apps/dashboard/app/(app)/apis/_components/api-list-client.tsx @@ -31,7 +31,7 @@ export const ApiListClient = () => { { limit: DEFAULT_LIMIT }, { getNextPageParam: (lastPage) => lastPage.nextCursor, - } + }, ); const allApis = useMemo(() => { @@ -62,11 +62,7 @@ export const ApiListClient = () => { return (
- + {isLoading ? ( @@ -91,11 +87,7 @@ export const ApiListClient = () => {
{!isSearching && hasNextPage && ( -
), - } + }, ); export const RootKeysList = () => { @@ -81,7 +76,7 @@ export const RootKeysList = () => { // Memoize the row className function const getRowClassNameMemoized = useCallback( (rootKey: RootKey) => getRowClassName(rootKey, selectedRootKey), - [selectedRootKey] + [selectedRootKey], ); // Memoize the loadMoreFooterProps to prevent unnecessary re-renders @@ -93,16 +88,14 @@ export const RootKeysList = () => { countInfoText: (
Showing{" "} - - {formatNumberFull(rootKeys.length)} - + {formatNumberFull(rootKeys.length)} of {formatNumberFull(totalCount)} root keys
), }), - [isLoading, hasMore, rootKeys.length, totalCount] + [isLoading, hasMore, rootKeys.length, totalCount], ); // Memoize the emptyState to prevent unnecessary re-renders @@ -113,8 +106,8 @@ export const RootKeysList = () => { No Root Keys Found - There are no root keys configured yet. Create your first root key to - start managing permissions and access control. + There are no root keys configured yet. Create your first root key to start managing + permissions and access control.
{
), - [] + [], ); // Memoize the config to prevent unnecessary re-renders @@ -143,7 +136,7 @@ export const RootKeysList = () => { rowBorders: true, containerPadding: "px-0", }), - [] + [], ); // Memoize the keyExtractor to prevent unnecessary re-renders @@ -163,7 +156,7 @@ export const RootKeysList = () => { key={column.key} className={cn( "text-xs align-middle whitespace-nowrap", - column.key === "root_key" ? "py-[6px]" : "py-1" + column.key === "root_key" ? "py-[6px]" : "py-1", )} style={{ height: `${rowHeight}px` }} > @@ -175,7 +168,7 @@ export const RootKeysList = () => { {column.key === "action" && } )), - [] + [], ); // Memoize the existingKey object to prevent unnecessary re-renders @@ -186,9 +179,7 @@ export const RootKeysList = () => { // Guard against undefined permissions and use type guard function const permissions = editingKey.permissions ?? []; - const validatedPermissions = permissions - .map((p) => p.name) - .filter(isUnkeyPermission); + const validatedPermissions = permissions.map((p) => p.name).filter(isUnkeyPermission); return { id: editingKey.id, @@ -211,7 +202,7 @@ export const RootKeysList = () => { className={cn( "size-5 rounded flex items-center justify-center cursor-pointer border border-grayA-3 transition-all duration-100", "bg-grayA-3", - isSelected && "bg-grayA-5" + isSelected && "bg-grayA-5", )} > @@ -225,9 +216,7 @@ export const RootKeysList = () => {
{rootKey.name ?? "Unnamed Root Key"} @@ -246,8 +235,8 @@ export const RootKeysList = () => { - This is the first part of the key to visually match it. We don't - store the full key for security reasons. + This is the first part of the key to visually match it. We don't store the full key + for security reasons.

} > @@ -278,9 +267,7 @@ export const RootKeysList = () => { return ( ); }, @@ -303,13 +290,11 @@ export const RootKeysList = () => { header: "", width: "auto", render: (rootKey) => { - return ( - - ); + return ; }, }, ], - [selectedRootKeyId, handleEditKey] + [selectedRootKeyId, handleEditKey], ); return ( diff --git a/apps/dashboard/components/virtual-table/components/loading-indicator.tsx b/apps/dashboard/components/virtual-table/components/loading-indicator.tsx index 28556331ac..c1ce4f202b 100644 --- a/apps/dashboard/components/virtual-table/components/loading-indicator.tsx +++ b/apps/dashboard/components/virtual-table/components/loading-indicator.tsx @@ -59,14 +59,12 @@ export const LoadMoreFooter = ({ onClick={handleOpen} className="bg-gray-1 dark:bg-black border border-gray-6 rounded-lg shadow-lg p-3 transition-all duration-200 hover:shadow-xl hover:scale-105 group" title={`${buttonText} • ${formatNumberFull( - totalVisible + totalVisible, )} of ${formatNumberFull(totalCount)} ${itemLabel}`} >
- - {countInfoText} - + {countInfoText}
@@ -119,9 +117,7 @@ export const LoadMoreFooter = ({ animation: "fadeInUp 0.3s ease-out 0.3s both", }} > - {countInfoText && ( -
{countInfoText}
- )} + {countInfoText &&
{countInfoText}
} {!countInfoText && (
Viewing From a01a4c223bca663db4e5a7f48afbd6e089a33d3f Mon Sep 17 00:00:00 2001 From: neha Date: Thu, 18 Sep 2025 07:50:40 +0530 Subject: [PATCH 16/18] fix: apply final formatting fixes to keys-list.tsx --- .../components/table/keys-list.tsx | 71 +++++++++++++------ 1 file changed, 50 insertions(+), 21 deletions(-) diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx index f1ee406fce..69e6853e9c 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx @@ -29,7 +29,7 @@ import { getRowClassName } from "./utils/get-row-class"; const KeysTableActionPopover = dynamic( () => import("./components/actions/keys-table-action.popover.constants").then( - (mod) => mod.KeysTableActions, + (mod) => mod.KeysTableActions ), { ssr: false, @@ -38,13 +38,16 @@ const KeysTableActionPopover = dynamic( type="button" className={cn( "group-data-[state=open]:bg-gray-6 group-hover:bg-gray-6 group size-5 p-0 rounded m-0 items-center flex justify-center", - "border border-gray-6 group-hover:border-gray-8 ring-2 ring-transparent focus-visible:ring-gray-7 focus-visible:border-gray-7", + "border border-gray-6 group-hover:border-gray-8 ring-2 ring-transparent focus-visible:ring-gray-7 focus-visible:border-gray-7" )} > - + ), - }, + } ); export const KeysList = ({ @@ -54,9 +57,10 @@ export const KeysList = ({ keyspaceId: string; apiId: string; }) => { - const { keys, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = useKeysListQuery({ - keyAuthId: keyspaceId, - }); + const { keys, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = + useKeysListQuery({ + keyAuthId: keyspaceId, + }); const [selectedKey, setSelectedKey] = useState(null); const [navigatingKeyId, setNavigatingKeyId] = useState(null); // Add state for selected keys @@ -99,13 +103,17 @@ export const KeysList = ({ className={cn( "size-5 rounded flex items-center justify-center cursor-pointer", identity ? "bg-successA-3" : "bg-grayA-3", - isSelected && "bg-brand-5", + isSelected && "bg-brand-5" )} onMouseEnter={() => setHoveredKeyId(key.id)} onMouseLeave={() => setHoveredKeyId(null)} > {isNavigating ? ( -
+
) : ( @@ -156,17 +164,24 @@ export const KeysList = ({ rel="noopener noreferrer" aria-disabled={isNavigating} > - {identity} + + {identity} + ) : ( - {identity} + + {identity} + )} } asChild > {React.cloneElement(iconContainer, { - className: cn(iconContainer.props.className, "cursor-pointer"), + className: cn( + iconContainer.props.className, + "cursor-pointer" + ), })} ) : ( @@ -206,7 +221,11 @@ export const KeysList = ({ header: "Value", width: "15%", render: (key) => ( - + ), }, { @@ -267,7 +286,7 @@ export const KeysList = ({ selectedKeys, toggleSelection, hoveredKeyId, - ], + ] ); const getSelectedKeysState = useCallback(() => { @@ -330,7 +349,9 @@ export const KeysList = ({ countInfoText: (
Showing{" "} - {formatNumberFull(keys.length)} + + {formatNumberFull(keys.length)} + of {formatNumberFull(totalCount)} keys @@ -343,8 +364,8 @@ export const KeysList = ({ No API Keys Found - There are no API keys associated with this service yet. Create your first API key to - get started. + There are no API keys associated with this service yet. Create + your first API key to get started. @@ -384,9 +405,17 @@ export const KeysList = ({ {column.key === "last_used" && } {column.key === "status" && } {column.key === "action" && } - {!["select", "key", "value", "usage", "last_used", "status", "action"].includes( - column.key, - ) &&
} + {![ + "select", + "key", + "value", + "usage", + "last_used", + "status", + "action", + ].includes(column.key) && ( +
+ )} )) } From b8ebdd820412ac9b2abc083e63d255148a8829cc Mon Sep 17 00:00:00 2001 From: neha Date: Thu, 18 Sep 2025 08:04:54 +0530 Subject: [PATCH 17/18] fix: address all CodeRabbit suggestions - Use memoized number formatters instead of creating new instances - Extract inline array to constant to avoid recreation - Fix type safety by replacing 'any' with proper type assertion - Apply code formatting fixes --- .../components/table/keys-list.tsx | 81 +++++++------------ apps/dashboard/lib/fmt.ts | 7 +- 2 files changed, 36 insertions(+), 52 deletions(-) diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx index 69e6853e9c..8833dfa8df 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx @@ -26,10 +26,20 @@ import { StatusDisplay } from "./components/status-cell"; import { useKeysListQuery } from "./hooks/use-keys-list-query"; import { getRowClassName } from "./utils/get-row-class"; +const SKELETON_COLUMN_KEYS = [ + "select", + "key", + "value", + "usage", + "last_used", + "status", + "action", +] as const; + const KeysTableActionPopover = dynamic( () => import("./components/actions/keys-table-action.popover.constants").then( - (mod) => mod.KeysTableActions + (mod) => mod.KeysTableActions, ), { ssr: false, @@ -38,16 +48,13 @@ const KeysTableActionPopover = dynamic( type="button" className={cn( "group-data-[state=open]:bg-gray-6 group-hover:bg-gray-6 group size-5 p-0 rounded m-0 items-center flex justify-center", - "border border-gray-6 group-hover:border-gray-8 ring-2 ring-transparent focus-visible:ring-gray-7 focus-visible:border-gray-7" + "border border-gray-6 group-hover:border-gray-8 ring-2 ring-transparent focus-visible:ring-gray-7 focus-visible:border-gray-7", )} > - + ), - } + }, ); export const KeysList = ({ @@ -57,10 +64,9 @@ export const KeysList = ({ keyspaceId: string; apiId: string; }) => { - const { keys, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = - useKeysListQuery({ - keyAuthId: keyspaceId, - }); + const { keys, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = useKeysListQuery({ + keyAuthId: keyspaceId, + }); const [selectedKey, setSelectedKey] = useState(null); const [navigatingKeyId, setNavigatingKeyId] = useState(null); // Add state for selected keys @@ -103,17 +109,13 @@ export const KeysList = ({ className={cn( "size-5 rounded flex items-center justify-center cursor-pointer", identity ? "bg-successA-3" : "bg-grayA-3", - isSelected && "bg-brand-5" + isSelected && "bg-brand-5", )} onMouseEnter={() => setHoveredKeyId(key.id)} onMouseLeave={() => setHoveredKeyId(null)} > {isNavigating ? ( -
+
) : ( @@ -164,24 +166,17 @@ export const KeysList = ({ rel="noopener noreferrer" aria-disabled={isNavigating} > - - {identity} - + {identity} ) : ( - - {identity} - + {identity} )} } asChild > {React.cloneElement(iconContainer, { - className: cn( - iconContainer.props.className, - "cursor-pointer" - ), + className: cn(iconContainer.props.className, "cursor-pointer"), })} ) : ( @@ -221,11 +216,7 @@ export const KeysList = ({ header: "Value", width: "15%", render: (key) => ( - + ), }, { @@ -286,7 +277,7 @@ export const KeysList = ({ selectedKeys, toggleSelection, hoveredKeyId, - ] + ], ); const getSelectedKeysState = useCallback(() => { @@ -349,9 +340,7 @@ export const KeysList = ({ countInfoText: (
Showing{" "} - - {formatNumberFull(keys.length)} - + {formatNumberFull(keys.length)} of {formatNumberFull(totalCount)} keys @@ -364,8 +353,8 @@ export const KeysList = ({ No API Keys Found - There are no API keys associated with this service yet. Create - your first API key to get started. + There are no API keys associated with this service yet. Create your first API key to + get started. @@ -405,17 +394,9 @@ export const KeysList = ({ {column.key === "last_used" && } {column.key === "status" && } {column.key === "action" && } - {![ - "select", - "key", - "value", - "usage", - "last_used", - "status", - "action", - ].includes(column.key) && ( -
- )} + {!SKELETON_COLUMN_KEYS.includes( + column.key as (typeof SKELETON_COLUMN_KEYS)[number], + ) &&
} )) } diff --git a/apps/dashboard/lib/fmt.ts b/apps/dashboard/lib/fmt.ts index edbbccdd8a..4dd53e4ac8 100644 --- a/apps/dashboard/lib/fmt.ts +++ b/apps/dashboard/lib/fmt.ts @@ -1,7 +1,10 @@ +const compactFormatter = new Intl.NumberFormat("en", { notation: "compact" }); +const fullFormatter = new Intl.NumberFormat("en-US"); + export function formatNumber(n: number): string { - return Intl.NumberFormat("en", { notation: "compact" }).format(n); + return compactFormatter.format(n); } export function formatNumberFull(n: number): string { - return Intl.NumberFormat("en-US").format(n); + return fullFormatter.format(n); } From e2d9de781f723bae03b26c6b634e31cba39da8a2 Mon Sep 17 00:00:00 2001 From: neha Date: Thu, 18 Sep 2025 08:05:18 +0530 Subject: [PATCH 18/18] fix: apply final formatting changes --- .../components/table/keys-list.tsx | 63 +++++++++++++------ 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx index 8833dfa8df..ac96d9ada6 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx @@ -39,7 +39,7 @@ const SKELETON_COLUMN_KEYS = [ const KeysTableActionPopover = dynamic( () => import("./components/actions/keys-table-action.popover.constants").then( - (mod) => mod.KeysTableActions, + (mod) => mod.KeysTableActions ), { ssr: false, @@ -48,13 +48,16 @@ const KeysTableActionPopover = dynamic( type="button" className={cn( "group-data-[state=open]:bg-gray-6 group-hover:bg-gray-6 group size-5 p-0 rounded m-0 items-center flex justify-center", - "border border-gray-6 group-hover:border-gray-8 ring-2 ring-transparent focus-visible:ring-gray-7 focus-visible:border-gray-7", + "border border-gray-6 group-hover:border-gray-8 ring-2 ring-transparent focus-visible:ring-gray-7 focus-visible:border-gray-7" )} > - + ), - }, + } ); export const KeysList = ({ @@ -64,9 +67,10 @@ export const KeysList = ({ keyspaceId: string; apiId: string; }) => { - const { keys, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = useKeysListQuery({ - keyAuthId: keyspaceId, - }); + const { keys, isLoading, isLoadingMore, loadMore, totalCount, hasMore } = + useKeysListQuery({ + keyAuthId: keyspaceId, + }); const [selectedKey, setSelectedKey] = useState(null); const [navigatingKeyId, setNavigatingKeyId] = useState(null); // Add state for selected keys @@ -109,13 +113,17 @@ export const KeysList = ({ className={cn( "size-5 rounded flex items-center justify-center cursor-pointer", identity ? "bg-successA-3" : "bg-grayA-3", - isSelected && "bg-brand-5", + isSelected && "bg-brand-5" )} onMouseEnter={() => setHoveredKeyId(key.id)} onMouseLeave={() => setHoveredKeyId(null)} > {isNavigating ? ( -
+
) : ( @@ -166,17 +174,24 @@ export const KeysList = ({ rel="noopener noreferrer" aria-disabled={isNavigating} > - {identity} + + {identity} + ) : ( - {identity} + + {identity} + )} } asChild > {React.cloneElement(iconContainer, { - className: cn(iconContainer.props.className, "cursor-pointer"), + className: cn( + iconContainer.props.className, + "cursor-pointer" + ), })} ) : ( @@ -216,7 +231,11 @@ export const KeysList = ({ header: "Value", width: "15%", render: (key) => ( - + ), }, { @@ -277,7 +296,7 @@ export const KeysList = ({ selectedKeys, toggleSelection, hoveredKeyId, - ], + ] ); const getSelectedKeysState = useCallback(() => { @@ -340,7 +359,9 @@ export const KeysList = ({ countInfoText: (