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
Expand Up @@ -2,9 +2,8 @@

import { ConfirmPopover } from "@/components/confirmation-popover";
import { Dialog, DialogContent } from "@/components/ui/dialog";
import { toast } from "@/components/ui/toaster";
import { ArrowRight, Check, CircleInfo, Key2, Plus } from "@unkey/icons";
import { Button, Code, CopyButton, InfoTooltip, VisibleButton } from "@unkey/ui";
import { Button, Code, CopyButton, InfoTooltip, VisibleButton, toast } from "@unkey/ui";
import { useRouter } from "next/navigation";
import { useEffect, useRef, useState } from "react";
import { UNNAMED_KEY } from "../create-key.constants";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use client";
import { toast } from "@/components/ui/toaster";
import { Code } from "@unkey/icons";
import { Button, FormTextarea } from "@unkey/ui";
import { Button, FormTextarea, toast } from "@unkey/ui";
import { useFormContext, useWatch } from "react-hook-form";
import type { MetadataFormValues } from "../create-key.schema";
import { ProtectionSwitch } from "./protection-switch";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const SecretKey = ({
className,
)}
>
<div className="flex items-center justify-between w-full gap-3">
<div className="flex items-center justify-between w-full gap-3 pointer-events-auto">
<div className="flex-shrink-0">
<CircleLock size="sm-regular" className="text-gray-12" />
</div>
Expand All @@ -39,7 +39,7 @@ export const SecretKey = ({
{displayValue}
</p>
</div>
<div className="flex items-center justify-between gap-2 flex-shrink-0">
<div className="flex items-center justify-between gap-2 flex-shrink-0 pointer-events-auto">
<VisibleButton
isVisible={isVisible}
setIsVisible={(visible) => setIsVisible(visible)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { toast } from "@/components/ui/toaster";
import { trpc } from "@/lib/trpc/client";
import { toast } from "@unkey/ui";

export const useCreateIdentity = (
onSuccess?: (data: { identityId: string; externalId: string }) => void,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { toast } from "@/components/ui/toaster";
import { trpc } from "@/lib/trpc/client";
import { toast } from "@unkey/ui";

export const useCreateKey = (
onSuccess: (data: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { toast } from "@/components/ui/toaster";
import { trpc } from "@/lib/trpc/client";
import { toast } from "@unkey/ui";
import { useMemo } from "react";

const MAX_IDENTITY_FETCH_LIMIT = 10;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import {
NavigableDialogHeader,
NavigableDialogNav,
NavigableDialogRoot,
toast,
} from "@unkey/ui";
import { type FC, useEffect, useState } from "react";
import { FormProvider } from "react-hook-form";
import { toast } from "sonner";
import { KeyCreatedSuccessDialog } from "./components/key-created-success-dialog";
import { SectionLabel } from "./components/section-label";
import { type DialogSectionName, SECTIONS } from "./create-key.constants";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { toast } from "@/components/ui/toaster";
import { trpc } from "@/lib/trpc/client";
import { LLMSearch } from "@unkey/ui";
import { transformStructuredOutputToFilters } from "@unkey/ui";
import { LLMSearch, toast, transformStructuredOutputToFilters } from "@unkey/ui";
import { useFilters } from "../../../../hooks/use-filters";

export const LogsSearch = ({ apiId }: { apiId: string }) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { formatNumber } from "@/lib/fmt";
import { cn } from "@/lib/utils";
import { Clone } from "@unkey/icons";
import { Button, Card, CardContent } from "@unkey/ui";
import { toast } from "sonner";
import { Card, CardContent, CopyButton } from "@unkey/ui";
import { formatOutcomeName, getOutcomeColor } from "../../../../../utils";

export const OutcomeDistributionSection = ({
Expand All @@ -16,20 +14,10 @@ export const OutcomeDistributionSection = ({
return null;
}

const handleClick = () => {
const formattedContent = outcomeEntries
const getTextToCopy = () => {
return outcomeEntries
.map(([outcome, count]) => `${formatOutcomeName(outcome)}: ${count}`)
.join("\n");

navigator.clipboard
.writeText(formattedContent)
.then(() => {
toast.success("Outcomes copied to clipboard");
})
.catch((error) => {
console.error("Failed to copy to clipboard:", error);
toast.error("Failed to copy to clipboard");
});
};

return (
Expand Down Expand Up @@ -59,15 +47,14 @@ export const OutcomeDistributionSection = ({
</div>
))}
</div>
<Button
<CopyButton
value={getTextToCopy()}
shape="square"
onClick={handleClick}
variant="outline"
className="absolute bottom-2 right-3 opacity-0 group-hover:opacity-100 transition-opacity rounded-sm"
variant="primary"
size="2xlg"
className="absolute bottom-1 right-1 opacity-0 group-hover:opacity-100 transition-opacity rounded-md p-4"
aria-label="Copy content"
>
<Clone />
</Button>
/>
</CardContent>
</Card>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use client";
import { toast } from "@/components/ui/toaster";
import { Clone } from "@unkey/icons";
import { Button, Card, CardContent } from "@unkey/ui";
import { Card, CardContent, CopyButton } from "@unkey/ui";
import React from "react";

export const LogSection = ({
details,
Expand All @@ -10,16 +9,79 @@ export const LogSection = ({
details: Record<string, React.ReactNode> | string;
title: string;
}) => {
const handleClick = () => {
navigator.clipboard
.writeText(JSON.stringify(details))
.then(() => {
toast.success(`${title} copied to clipboard`);
})
.catch((error) => {
console.error("Failed to copy to clipboard:", error);
toast.error("Failed to copy to clipboard");
});
// 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);
}

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 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("");
}
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 (
Expand All @@ -45,15 +107,15 @@ export const LogSection = ({
})
: details}
</pre>
<Button

<CopyButton
value={getTextToCopy()}
shape="square"
onClick={handleClick}
variant="outline"
className="absolute bottom-2 right-3 opacity-0 group-hover:opacity-100 transition-opacity rounded-sm"
variant="primary"
size="2xlg"
className="absolute bottom-1 right-1 opacity-0 group-hover:opacity-100 transition-opacity rounded-md p-4"
aria-label="Copy content"
>
<Clone />
</Button>
/>
</CardContent>
</Card>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { toast } from "@/components/ui/toaster";
import { Clone } from "@unkey/icons";
import { Button, Card, CardContent } from "@unkey/ui";
import { Card, CardContent, CopyButton } from "@unkey/ui";

type Role = {
name: string;
Expand All @@ -12,19 +10,6 @@ type RolesSectionProps = {
};

export const RolesSection: React.FC<RolesSectionProps> = ({ roles }) => {
const handleCopy = (role: Role) => {
const content = `${role.name}${role.description ? `\n${role.description}` : ""}`;
navigator.clipboard
.writeText(content)
.then(() => {
toast.success(`Role ${role.name} copied to clipboard`);
})
.catch((error) => {
console.error("Failed to copy to clipboard:", error);
toast.error("Failed to copy to clipboard");
});
};

if (!roles || roles.length === 0) {
return (
<div className="flex flex-col gap-1 mt-[16px]">
Expand Down Expand Up @@ -58,15 +43,14 @@ export const RolesSection: React.FC<RolesSectionProps> = ({ roles }) => {
) : (
<div className="text-accent-9 mt-2 text-xs italic">No description</div>
)}
<Button
<CopyButton
value={`${role.name}${role.description ? `\n${role.description}` : ""}`}
shape="square"
onClick={() => handleCopy(role)}
variant="outline"
className="absolute bottom-2 right-3 opacity-0 group-hover:opacity-100 transition-opacity rounded-sm"
toastMessage={`${role.name}${role.description ? `\n${role.description}` : ""}`}
variant="primary"
className="absolute bottom-1 right-1 opacity-0 group-hover:opacity-100 transition-opacity rounded-md p-4"
aria-label={`Copy ${role.name}`}
>
<Clone />
</Button>
/>
</CardContent>
</Card>
))}
Expand All @@ -85,40 +69,6 @@ type PermissionsSectionProps = {
};

export const PermissionsSection = ({ permissions }: PermissionsSectionProps) => {
const handleCopy = (permission: Permission) => {
const content = `${permission.name}${
permission.description ? `\n${permission.description}` : ""
}`;
navigator.clipboard
.writeText(content)
.then(() => {
toast.success(`Permission ${permission.name} copied to clipboard`);
})
.catch((error) => {
console.error("Failed to copy to clipboard:", error);
toast.error("Failed to copy to clipboard");
});
};

const handleCopyAll = () => {
const content = permissions
.map(
(permission) =>
`${permission.name}${permission.description ? `\n${permission.description}` : ""}`,
)
.join("\n\n");

navigator.clipboard
.writeText(content)
.then(() => {
toast.success("All permissions copied to clipboard");
})
.catch((error) => {
console.error("Failed to copy to clipboard:", error);
toast.error("Failed to copy to clipboard");
});
};

if (!permissions || permissions.length === 0) {
return (
<div className="flex flex-col gap-1 mt-[16px]">
Expand All @@ -141,15 +91,18 @@ export const PermissionsSection = ({ permissions }: PermissionsSectionProps) =>
Permissions ({permissions.length})
</span>
{permissions.length > 1 && (
<Button
<CopyButton
value={permissions
.map(
(permission) =>
`${permission.name}${permission.description ? `\n${permission.description}` : ""}`,
)
.join("\n\n")}
shape="square"
onClick={handleCopyAll}
variant="outline"
variant="primary"
className="h-6 w-6 rounded-sm"
aria-label="Copy all permissions"
>
<Clone />
</Button>
/>
)}
</div>
<div className="space-y-2">
Expand All @@ -167,15 +120,13 @@ export const PermissionsSection = ({ permissions }: PermissionsSectionProps) =>
) : (
<div className="text-accent-9 mt-2 text-xs italic">No description</div>
)}
<Button
<CopyButton
value={`${permission.name}${permission.description ? `\n${permission.description}` : ""}`}
shape="square"
onClick={() => handleCopy(permission)}
variant="outline"
className="absolute bottom-3 right-3 opacity-0 group-hover:opacity-100 transition-opacity rounded-sm"
variant="primary"
className="absolute bottom-1 right-1 opacity-0 group-hover:opacity-100 transition-opacity rounded-md p-4"
aria-label={`Copy ${permission.name}`}
>
<Clone />
</Button>
/>
</CardContent>
</Card>
))}
Expand Down
Loading
Loading