diff --git a/apps/dashboard/src/components/header-navigation/header-navigation.tsx b/apps/dashboard/src/components/header-navigation/header-navigation.tsx index 19c2e376e0e..263026c64bc 100644 --- a/apps/dashboard/src/components/header-navigation/header-navigation.tsx +++ b/apps/dashboard/src/components/header-navigation/header-navigation.tsx @@ -13,7 +13,10 @@ export const HeaderNavigation = (props: HeaderNavigationProps) => { const { startItems, hideBridgeUrl = false, className, ...rest } = props; return (
{startItems} diff --git a/apps/dashboard/src/components/primitives/card.tsx b/apps/dashboard/src/components/primitives/card.tsx index bd9cfec1d6c..4a00b9acc61 100644 --- a/apps/dashboard/src/components/primitives/card.tsx +++ b/apps/dashboard/src/components/primitives/card.tsx @@ -9,7 +9,11 @@ Card.displayName = 'Card'; const CardHeader = React.forwardRef>( ({ className, ...props }, ref) => ( -
+
) ); CardHeader.displayName = 'CardHeader'; diff --git a/apps/dashboard/src/components/primitives/container.tsx b/apps/dashboard/src/components/primitives/container.tsx new file mode 100644 index 00000000000..517da98c7b5 --- /dev/null +++ b/apps/dashboard/src/components/primitives/container.tsx @@ -0,0 +1,5 @@ +import { cn } from '../../utils/ui'; + +export const Container = ({ children, className }: { children: React.ReactNode; className?: string }) => { + return
{children}
; +}; diff --git a/apps/dashboard/src/components/primitives/help-tooltip-indicator.tsx b/apps/dashboard/src/components/primitives/help-tooltip-indicator.tsx new file mode 100644 index 00000000000..b712a1de004 --- /dev/null +++ b/apps/dashboard/src/components/primitives/help-tooltip-indicator.tsx @@ -0,0 +1,24 @@ +import { RiInformation2Line } from 'react-icons/ri'; +import { Tooltip, TooltipContent, TooltipTrigger } from './tooltip'; +import { cn } from '../../utils/ui'; + +interface HelpTooltipIndicatorProps { + text: string; + className?: string; + size?: '4' | '5'; +} + +export function HelpTooltipIndicator({ text, className, size = '5' }: HelpTooltipIndicatorProps) { + return ( + + + + + + + +

{text}

+
+
+ ); +} diff --git a/apps/dashboard/src/components/shared/external-link.tsx b/apps/dashboard/src/components/shared/external-link.tsx index 798b8d6e01d..483c083a4af 100644 --- a/apps/dashboard/src/components/shared/external-link.tsx +++ b/apps/dashboard/src/components/shared/external-link.tsx @@ -1,21 +1,44 @@ -import { RiExternalLinkLine } from 'react-icons/ri'; +import { RiBookMarkedLine, RiExternalLinkLine, RiQuestionLine } from 'react-icons/ri'; import { cn } from '@/utils/ui'; +import { useTelemetry } from '@/hooks/use-telemetry'; +import { TelemetryEvent } from '@/utils/telemetry'; interface ExternalLinkProps extends React.AnchorHTMLAttributes { children: React.ReactNode; iconClassName?: string; + variant?: 'default' | 'documentation' | 'tip'; } -export function ExternalLink({ children, className, iconClassName, ...props }: ExternalLinkProps) { +export function ExternalLink({ + children, + className, + variant = 'default', + iconClassName, + href, + ...props +}: ExternalLinkProps) { + const telemetry = useTelemetry(); + + const handleClick = () => { + telemetry(TelemetryEvent.EXTERNAL_LINK_CLICKED, { + href, + variant, + }); + }; + return ( + {variant === 'documentation' && ); } diff --git a/apps/dashboard/src/components/side-navigation/side-navigation.tsx b/apps/dashboard/src/components/side-navigation/side-navigation.tsx index 2795bc5800f..cdafcf23875 100644 --- a/apps/dashboard/src/components/side-navigation/side-navigation.tsx +++ b/apps/dashboard/src/components/side-navigation/side-navigation.tsx @@ -70,7 +70,7 @@ export const SideNavigation = () => { Integration Store - + API Keys diff --git a/apps/dashboard/src/pages/api-keys.tsx b/apps/dashboard/src/pages/api-keys.tsx index 4c4d4f1453e..033d68ee3a4 100644 --- a/apps/dashboard/src/pages/api-keys.tsx +++ b/apps/dashboard/src/pages/api-keys.tsx @@ -2,7 +2,7 @@ import { useState } from 'react'; import { RiKey2Line, RiEyeLine, RiEyeOffLine } from 'react-icons/ri'; import { useEnvironment } from '@/context/environment/hooks'; import { CopyButton } from '@/components/primitives/copy-button'; -import { Card, CardContent } from '@/components/primitives/card'; +import { Card, CardContent, CardHeader } from '@/components/primitives/card'; import { Button } from '@/components/primitives/button'; import { Input, InputField } from '@/components/primitives/input'; import { Form } from '@/components/primitives/form/form'; @@ -11,6 +11,10 @@ import { DashboardLayout } from '../components/dashboard-layout'; import { PageMeta } from '@/components/page-meta'; import { useFetchApiKeys } from '../hooks/use-fetch-api-keys'; import { ExternalLink } from '@/components/shared/external-link'; +import { Container } from '../components/primitives/container'; +import { HelpTooltipIndicator } from '../components/primitives/help-tooltip-indicator'; +import { API_HOSTNAME } from '../config'; +import { Skeleton } from '@/components/primitives/skeleton'; interface ApiKeysFormData { apiKey: string; @@ -21,8 +25,8 @@ interface ApiKeysFormData { export function ApiKeysPage() { const apiKeysQuery = useFetchApiKeys(); const { currentEnvironment } = useEnvironment(); - const [showApiKey, setShowApiKey] = useState(false); const apiKeys = apiKeysQuery.data?.data; + const isLoading = apiKeysQuery.isLoading; const form = useForm({ values: { @@ -36,80 +40,149 @@ export function ApiKeysPage() { return null; } - const toggleApiKeyVisibility = () => { - setShowApiKey(!showApiKey); - }; - - const maskApiKey = (key: string) => { - return `${'•'.repeat(28)} ${key.slice(-4)}`; - }; - return ( <> API Keys}> -
-
-
- - -
-
- -
- - - - - - -
-

- Use this key to authenticate your API requests. Keep it secure and never share it publicly. -

-
- -
- -
- - - - -
-

- The public application identifier used for the Inbox component -

-
-
-
-
-
-
+ +
+
- -

Environment Keys

-

Copy and manage your public and private keys

+ +

Environment Keys

+

Manage your public and private keys

- + Read about our SDKs
+
+
+ + Application + + +
+ + + +
+
+
+ +
+ + + Secret Keys +

+ Use this key to authenticate your API requests. Keep it secure and never share it publicly. +

+
+ + +
+ +
+
+
+ + Learn more about our APIs + +
+
+
-
+ ); } + +interface SettingFieldProps { + label: string; + tooltip?: string; + value?: string; + secret?: boolean; + isLoading?: boolean; + readOnly?: boolean; +} + +function SettingField({ + label, + tooltip, + value, + secret = false, + isLoading = false, + readOnly = true, +}: SettingFieldProps) { + const [showSecret, setShowSecret] = useState(false); + + const toggleSecretVisibility = () => { + setShowSecret(!showSecret); + }; + + const maskSecret = (secret: string) => { + return `${'•'.repeat(28)} ${secret.slice(-4)}`; + }; + + return ( +
+ +
+ {isLoading ? ( + <> + + {secret && } + + ) : ( + <> + + + + + + {secret && ( + + )} + + )} +
+
+ ); +} diff --git a/apps/dashboard/src/utils/telemetry.ts b/apps/dashboard/src/utils/telemetry.ts index 2e7642e8618..0212716ce5d 100644 --- a/apps/dashboard/src/utils/telemetry.ts +++ b/apps/dashboard/src/utils/telemetry.ts @@ -22,4 +22,5 @@ export enum TelemetryEvent { INBOX_EMBED_SUCCESS_PAGE_VIEWED = 'Inbox embed success page viewed - [Onboarding]', WORKFLOW_PREFERENCES_OVERRIDE_USED = 'Workflow preferences override used', EXPORT_TO_CODE_BANNER_REACTION = 'Export to Code banner reaction - [Promotional]', + EXTERNAL_LINK_CLICKED = 'External link clicked', }