diff --git a/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/log-header.tsx b/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/log-header.tsx index 89b345c247..9e0c7616a6 100644 --- a/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/log-header.tsx +++ b/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/log-header.tsx @@ -11,7 +11,7 @@ export const LogHeader = ({ log: KeysOverviewLog; }) => { return ( -
+
{log.key_details?.enabled ? "Active" : "Disabled"} -

- {log.key_details?.name || log.key_id}{" "} +

+ {log.key_details?.name || log.key_id}

- +
+ +
); }; diff --git a/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/log-outcome-distribution-section.tsx b/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/log-outcome-distribution-section.tsx index a6598c5d20..7d29a09ca1 100644 --- a/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/log-outcome-distribution-section.tsx +++ b/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/log-outcome-distribution-section.tsx @@ -1,6 +1,6 @@ import { formatNumber } from "@/lib/fmt"; import { cn } from "@/lib/utils"; -import { Card, CardContent, CopyButton } from "@unkey/ui"; +import { CopyButton } from "@unkey/ui"; import { formatOutcomeName, getOutcomeColor } from "../../../../../utils"; export const OutcomeDistributionSection = ({ @@ -21,25 +21,23 @@ export const OutcomeDistributionSection = ({ }; return ( -
-
- +
+
+
Outcomes ({outcomeEntries.length}) - -
- - +
+
{outcomeEntries.map(([outcome, count]) => ( -
-
+
+
- {formatOutcomeName(outcome)}: + {formatOutcomeName(outcome)}:
{formatNumber(count)} @@ -47,16 +45,15 @@ export const OutcomeDistributionSection = ({
))}
- - - +
+ +
); }; diff --git a/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/log-section.tsx b/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/log-section.tsx index 034ea29893..82ef110347 100644 --- a/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/log-section.tsx +++ b/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/log-section.tsx @@ -1,6 +1,4 @@ -"use client"; -import { Card, CardContent, CopyButton } from "@unkey/ui"; -import React from "react"; +import { CopyButton } from "@unkey/ui"; export const LogSection = ({ details, @@ -9,115 +7,51 @@ export const LogSection = ({ details: Record | string; title: string; }) => { - // Helper function to get the text to copy const getTextToCopy = () => { - let textToCopy: string; - if (typeof details === "string") { - textToCopy = details; - } else { - // Extract text content from React components - textToCopy = Object.entries(details) - .map(([key, value]) => { - if (value === null || value === undefined) { - return key; - } - // If it's a React element, try to extract text content - if (typeof value === "object" && value !== null && "props" in value) { - return `${key}: ${extractTextFromReactElement(value)}`; - } - return `${key}: ${value}`; - }) - .join("\n"); - } - return textToCopy; - }; - - // Helper function to extract text from React elements - // This is used to extract text from React elements like TimestampInfo and Link components - const extractTextFromReactElement = (element: React.ReactNode): string => { - if (typeof element === "string" || typeof element === "number") { - return String(element); + return details; } - if (element === null || element === undefined) { - return ""; - } - - // Handle React elements - if (React.isValidElement(element)) { - const reactElement = element as React.ReactElement<{ - value?: string | Date | number; - children?: React.ReactNode; - href?: string; - title?: string; - }>; - - // For TimestampInfo and similar components, check for a 'value' prop first - if (reactElement.props.value) { - // If value is a date/timestamp, format it appropriately - if (reactElement.props.value instanceof Date) { - return reactElement.props.value.toISOString(); + return Object.entries(details) + .map(([key, value]) => { + if (value === null || value === undefined) { + return key; } - return String(reactElement.props.value); - } - - // Then check for children - if (reactElement.props.children) { - if (typeof reactElement.props.children === "string") { - return reactElement.props.children; - } - if (Array.isArray(reactElement.props.children)) { - return reactElement.props.children - .map((child: React.ReactNode) => extractTextFromReactElement(child)) - .join(""); + if (typeof value === "object" && value !== null && "props" in value) { + return `${key}: ${value}`; } - return extractTextFromReactElement(reactElement.props.children); - } - - // For Link components, check for href or title - if (reactElement.props.href || reactElement.props.title) { - return reactElement.props.title || reactElement.props.href || ""; - } - } - - return String(element); + return `${key}: ${value}`; + }) + .join("\n"); }; return ( -
-
- {title} -
- - -
+    
+
+
{title}
+
+
             {typeof details === "object"
-              ? Object.entries(details).map((detail) => {
-                  const [key, value] = detail;
-                  return (
-                    
- - {key} - {value ? ":" : ""} - - {value} -
- ); - }) + ? Object.entries(details).map(([key, value]) => ( +
+ + {key} + {value ? ":" : ""} + + {value} +
+ )) : details}
- - - - +
+ +
); }; diff --git a/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/roles-permissions.tsx b/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/roles-permissions.tsx index 4aa6f78362..429feadd3c 100644 --- a/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/roles-permissions.tsx +++ b/apps/dashboard/app/(app)/[workspaceSlug]/apis/[apiId]/_overview/components/table/components/log-details/components/roles-permissions.tsx @@ -1,4 +1,4 @@ -import { Card, CardContent, CopyButton } from "@unkey/ui"; +import { CopyButton } from "@unkey/ui"; type Role = { name: string; @@ -12,48 +12,45 @@ type RolesSectionProps = { export const RolesSection: React.FC = ({ roles }) => { if (!roles || roles.length === 0) { return ( -
-
- Roles +
+
+
Roles
+
+ No roles assigned +
- - - No roles assigned - -
); } return ( -
- Roles ({roles.length}) -
- {roles.map((role) => ( - - -
- {role.name} -
+
+
+
+ Roles ({roles.length}) +
+
+ {roles.map((role) => ( +
+
{role.name}
{role.description ? ( -
{role.description}
+
{role.description}
) : ( -
No description
+
No description
)} - - - ))} +
+ ))} +
); @@ -71,65 +68,65 @@ type PermissionsSectionProps = { export const PermissionsSection = ({ permissions }: PermissionsSectionProps) => { if (!permissions || permissions.length === 0) { return ( -
-
- Permissions +
+
+
+ Permissions +
+
+ No permissions assigned +
- - - No permissions assigned - -
); } return ( -
-
- - Permissions ({permissions.length}) - - {permissions.length > 1 && ( - - `${permission.name}${permission.description ? `\n${permission.description}` : ""}`, - ) - .join("\n\n")} - shape="square" - variant="primary" - className="h-6 w-6 rounded-sm" - aria-label="Copy all permissions" - /> - )} -
-
- {permissions.map((permission) => ( - - -
- {permission.name} -
+
+
+
+ Permissions ({permissions.length}) + {permissions.length > 1 && ( + + `${permission.name}${ + permission.description ? `\n${permission.description}` : "" + }`, + ) + .join("\n\n")} + shape="square" + variant="outline" + className="h-6 w-6 rounded-sm bg-gray-2 hover:bg-gray-2" + aria-label="Copy all permissions" + /> + )} +
+
+ {permissions.map((permission) => ( +
+
{permission.name}
{permission.description ? ( -
{permission.description}
+
{permission.description}
) : ( -
No description
+
No description
)} - - - ))} +
+ ))} +
); diff --git a/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/components/log-footer.tsx b/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/components/log-footer.tsx index 8057c86a23..259f6a7da8 100644 --- a/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/components/log-footer.tsx +++ b/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/components/log-footer.tsx @@ -13,6 +13,7 @@ type Props = { export const LogFooter = ({ log }: Props) => { return ( { {`${user.username}`}
) : log.actor.type === "key" ? ( -
+
{log.actor.id}
) : ( -
+
{log.actor.id}
diff --git a/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/components/log-header.tsx b/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/components/log-header.tsx index ecc0c3eb19..544669f3fe 100644 --- a/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/components/log-header.tsx +++ b/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/components/log-header.tsx @@ -14,18 +14,16 @@ export const LogHeader = ({ onClose, log }: Props) => { const styles = AUDIT_STATUS_STYLES[eventType]; return ( -
+
- + {log.auditLog.event}
-
-
- -
+
+
); diff --git a/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/components/log-section.tsx b/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/components/log-section.tsx index ff56a874cb..eada6cdfe9 100644 --- a/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/components/log-section.tsx +++ b/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/components/log-section.tsx @@ -1,4 +1,4 @@ -import { Card, CardContent, CopyButton } from "@unkey/ui"; +import { CopyButton } from "@unkey/ui"; export const LogSection = ({ details, @@ -7,50 +7,47 @@ export const LogSection = ({ details: string | string[]; title: string; }) => { + const getFormattedContent = () => { + if (Array.isArray(details)) { + return details + .map((header) => { + const [key, ...valueParts] = header.split(":"); + const value = valueParts.join(":").trim(); + return `${key}: ${value}`; + }) + .join("\n"); + } + return details; + }; + return ( -
-
- {title} -
- - -
+    
+
+
{title}
+
+
             {Array.isArray(details)
               ? details.map((header) => {
                   const [key, ...valueParts] = header.split(":");
                   const value = valueParts.join(":").trim();
                   return (
-                    
- {key}: - {value} +
+ {key}: + {value}
); }) : details}
- - - +
+ +
); }; - -const getFormattedContent = (details: string | string[]) => { - if (Array.isArray(details)) { - return details - .map((header) => { - const [key, ...valueParts] = header.split(":"); - const value = valueParts.join(":").trim(); - return `${key}: ${value}`; - }) - .join("\n"); - } - return details; -}; diff --git a/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/index.tsx b/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/index.tsx index 43bb852f01..19261fa928 100644 --- a/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/index.tsx +++ b/apps/dashboard/app/(app)/[workspaceSlug]/audit/components/table/log-details/index.tsx @@ -35,7 +35,7 @@ export const AuditLogDetails = ({ distanceToTop, selectedLog, setSelectedLog }: return ( diff --git a/apps/dashboard/components/logs/details/log-details/components/log-header.tsx b/apps/dashboard/components/logs/details/log-details/components/log-header.tsx index 8aa4785804..6645b9ce0e 100644 --- a/apps/dashboard/components/logs/details/log-details/components/log-header.tsx +++ b/apps/dashboard/components/logs/details/log-details/components/log-header.tsx @@ -10,30 +10,30 @@ type Props = { export const LogHeader = ({ onClose, log }: Props) => { return ( -
-
+
+
{log.method} -

{log.path}

+

{log.path}

+ + = 200 && log.response_status < 300, + "bg-warning-3 text-warning-11 hover:bg-warning-4": + log.response_status >= 400 && log.response_status < 500, + "bg-error-3 text-error-11 hover:bg-error-4": log.response_status >= 500, + })} + > + {log.response_status} +
- = 200 && log.response_status < 300, - "bg-warning-3 text-warning-11 hover:bg-warning-4": - log.response_status >= 400 && log.response_status < 500, - "bg-error-3 text-error-11 hover:bg-error-4": log.response_status >= 500, - })} - > - {log.response_status} - - |
diff --git a/apps/dashboard/components/logs/details/log-details/components/log-meta.tsx b/apps/dashboard/components/logs/details/log-details/components/log-meta.tsx index 3361a1e0a3..a0811af463 100644 --- a/apps/dashboard/components/logs/details/log-details/components/log-meta.tsx +++ b/apps/dashboard/components/logs/details/log-details/components/log-meta.tsx @@ -1,22 +1,23 @@ -import { Card, CardContent, CopyButton } from "@unkey/ui"; +import { CopyButton } from "@unkey/ui"; -export const LogMetaSection = ({ content }: { content: string }) => { +export const LogMetaSection = ({ content }: { content: React.ReactNode }) => { return ( -
-
Meta
- - -
{content ?? ""} 
- -
-
+
+
+
Meta
+
+
+            {content}
+          
+
+ +
); }; diff --git a/apps/dashboard/components/logs/details/log-details/components/log-section.tsx b/apps/dashboard/components/logs/details/log-details/components/log-section.tsx index 71a89eb7a8..c2be0a50c7 100644 --- a/apps/dashboard/components/logs/details/log-details/components/log-section.tsx +++ b/apps/dashboard/components/logs/details/log-details/components/log-section.tsx @@ -1,48 +1,47 @@ -import { Card, CardContent, CopyButton } from "@unkey/ui"; +import { CopyButton } from "@unkey/ui"; + +type LogSectionDetails = string | string[] | React.ReactNode; export const LogSection = ({ details, title, }: { - details: string | string[]; + details: LogSectionDetails; title: string; }) => { return ( -
-
- {title} -
- - -
+    
+
+
{title}
+
+
             {Array.isArray(details)
               ? details.map((header) => {
                   const [key, ...valueParts] = header.split(":");
                   const value = valueParts.join(":").trim();
                   return (
-                    
- {key}: - {value} +
+ {key}: + {value}
); }) : details}
- - - +
+ +
); }; -const getFormattedContent = (details: string | string[]) => { +const getFormattedContent = (details: LogSectionDetails): string => { if (Array.isArray(details)) { return details .map((header) => { @@ -52,5 +51,10 @@ const getFormattedContent = (details: string | string[]) => { }) .join("\n"); } - return details; + + if (typeof details === "string") { + return details; + } + + return ""; }; diff --git a/apps/dashboard/components/logs/details/log-details/index.tsx b/apps/dashboard/components/logs/details/log-details/index.tsx index 269ba67107..2397077464 100644 --- a/apps/dashboard/components/logs/details/log-details/index.tsx +++ b/apps/dashboard/components/logs/details/log-details/index.tsx @@ -46,9 +46,11 @@ const createLogSections = (log: Log | RatelimitLog) => [ { title: "Request Body", content: - JSON.stringify(safeParseJson(log.request_body), null, 2) === "null" - ? EMPTY_TEXT - : JSON.stringify(safeParseJson(log.request_body), null, 2), + JSON.stringify(safeParseJson(log.request_body), null, 2) === "null" ? ( + {EMPTY_TEXT} + ) : ( + JSON.stringify(safeParseJson(log.request_body), null, 2) + ), }, { title: "Response Header", @@ -57,9 +59,11 @@ const createLogSections = (log: Log | RatelimitLog) => [ { title: "Response Body", content: - JSON.stringify(safeParseJson(log.response_body), null, 2) === "null" - ? EMPTY_TEXT - : JSON.stringify(safeParseJson(log.response_body), null, 2), + JSON.stringify(safeParseJson(log.response_body), null, 2) === "null" ? ( + {EMPTY_TEXT} + ) : ( + JSON.stringify(safeParseJson(log.response_body), null, 2) + ), }, ]; @@ -70,17 +74,21 @@ const createMetaContent = (log: SupportedLogTypes) => { const parsedMeta = JSON.parse((log.key_details as { meta: string })?.meta); return JSON.stringify(parsedMeta, null, 2); } catch { - return EMPTY_TEXT; + return {EMPTY_TEXT}; } } // Standard log meta handling if ("request_body" in log || "response_body" in log) { const meta = extractResponseField(log as Log | RatelimitLog, "meta"); - return JSON.stringify(meta, null, 2) === "null" ? EMPTY_TEXT : JSON.stringify(meta, null, 2); + return JSON.stringify(meta, null, 2) === "null" ? ( + {EMPTY_TEXT} + ) : ( + JSON.stringify(meta, null, 2) + ); } - return EMPTY_TEXT; + return {EMPTY_TEXT}; }; // Type guards @@ -146,7 +154,7 @@ export const LogDetails = ({ isOpen ? "translate-x-0 opacity-100" : "translate-x-full opacity-0", ) : ""; - const staticClasses = animated ? "" : "absolute right-0 overflow-y-auto p-4"; + const staticClasses = animated ? "" : "absolute right-0 overflow-y-auto"; return ( - {children || (isStandardLog(log) ? : null)} + {children || + (isStandardLog(log) ? ( +
+ {" "} +
+ ) : null)} ); };