From 8bd4fca4874102e009452a005f299e3388b34a04 Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Sun, 8 Dec 2024 12:18:02 +0200 Subject: [PATCH 01/10] fix: refactor --- .../src/components/primitives/card.tsx | 6 +- .../src/components/primitives/container.tsx | 5 + .../primitives/help-tooltip-indicator.tsx | 24 +++ .../components/settings/setting-section.tsx | 23 +++ .../src/components/shared/external-link.tsx | 11 +- apps/dashboard/src/pages/api-keys.tsx | 184 ++++++++++++------ 6 files changed, 184 insertions(+), 69 deletions(-) create mode 100644 apps/dashboard/src/components/primitives/container.tsx create mode 100644 apps/dashboard/src/components/primitives/help-tooltip-indicator.tsx create mode 100644 apps/dashboard/src/components/settings/setting-section.tsx 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/settings/setting-section.tsx b/apps/dashboard/src/components/settings/setting-section.tsx new file mode 100644 index 00000000000..c4fa87bed21 --- /dev/null +++ b/apps/dashboard/src/components/settings/setting-section.tsx @@ -0,0 +1,23 @@ +import { ReactNode } from 'react'; +import { Card, CardContent, CardHeader } from '@/components/primitives/card'; + +interface SettingSectionProps { + title: string; + description?: string; + children: ReactNode; +} + +export function SettingSection({ title, description, children }: SettingSectionProps) { + return ( + + + {title} + {description &&

{description}

} +
+ + +
{children}
+
+
+ ); +} diff --git a/apps/dashboard/src/components/shared/external-link.tsx b/apps/dashboard/src/components/shared/external-link.tsx index 798b8d6e01d..44081b36ea4 100644 --- a/apps/dashboard/src/components/shared/external-link.tsx +++ b/apps/dashboard/src/components/shared/external-link.tsx @@ -1,21 +1,24 @@ -import { RiExternalLinkLine } from 'react-icons/ri'; +import { RiBookMarkedLine, RiBookmarkLine, RiExternalLinkLine } from 'react-icons/ri'; import { cn } from '@/utils/ui'; interface ExternalLinkProps extends React.AnchorHTMLAttributes { children: React.ReactNode; iconClassName?: string; + variant?: 'default' | 'documentation'; } -export function ExternalLink({ children, className, iconClassName, ...props }: ExternalLinkProps) { +export function ExternalLink({ children, className, variant = 'default', iconClassName, ...props }: ExternalLinkProps) { return ( + {variant === 'documentation' && ); } diff --git a/apps/dashboard/src/pages/api-keys.tsx b/apps/dashboard/src/pages/api-keys.tsx index 4c4d4f1453e..0d9cff934de 100644 --- a/apps/dashboard/src/pages/api-keys.tsx +++ b/apps/dashboard/src/pages/api-keys.tsx @@ -1,8 +1,8 @@ -import { useState } from 'react'; +import { useState, ReactNode } 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,63 @@ 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'; + +interface SettingFieldProps { + label: string; + tooltip?: string; + children: ReactNode; +} + +function SettingField({ label, tooltip, children }: SettingFieldProps) { + return ( +
+ +
{children}
+
+ ); +} + +interface SettingSecretFieldProps extends Omit { + value: string; + onCopy: (value: string) => void; +} + +function SettingSecretField({ label, tooltip, value, onCopy }: SettingSecretFieldProps) { + const [showSecret, setShowSecret] = useState(false); + + const toggleSecretVisibility = () => { + setShowSecret(!showSecret); + }; + + const maskSecret = (secret: string) => { + return `${'•'.repeat(28)} ${secret.slice(-4)}`; + }; + + return ( + +
+ + + + + + +
+
+ ); +} interface ApiKeysFormData { apiKey: string; @@ -21,7 +78,6 @@ interface ApiKeysFormData { export function ApiKeysPage() { const apiKeysQuery = useFetchApiKeys(); const { currentEnvironment } = useEnvironment(); - const [showApiKey, setShowApiKey] = useState(false); const apiKeys = apiKeysQuery.data?.data; const form = useForm({ @@ -36,79 +92,79 @@ 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

+

Copy and 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. +

+
+ + +
+ {}} + alignTop + /> +
+
+
+
+
-
+ ); From 984f8415bbc9366ab192270530efa9470a35cf7c Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Sun, 8 Dec 2024 12:22:20 +0200 Subject: [PATCH 02/10] fix: styling --- apps/dashboard/src/pages/api-keys.tsx | 116 ++++++++++++-------------- 1 file changed, 55 insertions(+), 61 deletions(-) diff --git a/apps/dashboard/src/pages/api-keys.tsx b/apps/dashboard/src/pages/api-keys.tsx index 0d9cff934de..bae1710cf95 100644 --- a/apps/dashboard/src/pages/api-keys.tsx +++ b/apps/dashboard/src/pages/api-keys.tsx @@ -13,61 +13,7 @@ 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'; - -interface SettingFieldProps { - label: string; - tooltip?: string; - children: ReactNode; -} - -function SettingField({ label, tooltip, children }: SettingFieldProps) { - return ( -
- -
{children}
-
- ); -} - -interface SettingSecretFieldProps extends Omit { - value: string; - onCopy: (value: string) => void; -} - -function SettingSecretField({ label, tooltip, value, onCopy }: SettingSecretFieldProps) { - const [showSecret, setShowSecret] = useState(false); - - const toggleSecretVisibility = () => { - setShowSecret(!showSecret); - }; - - const maskSecret = (secret: string) => { - return `${'•'.repeat(28)} ${secret.slice(-4)}`; - }; - - return ( - -
- - - - - - -
-
- ); -} +import { API_HOSTNAME } from '../config'; interface ApiKeysFormData { apiKey: string; @@ -119,8 +65,8 @@ export function ApiKeysPage() {
- - + +
@@ -128,7 +74,6 @@ export function ApiKeysPage() {
@@ -151,12 +96,11 @@ export function ApiKeysPage() {
- {}} - alignTop + secret />
@@ -169,3 +113,53 @@ export function ApiKeysPage() { ); } + +interface SettingFieldProps { + label: string; + tooltip?: string; + children?: ReactNode; + value?: string; + secret?: boolean; +} + +function SettingField({ label, tooltip, children, value, secret = false }: SettingFieldProps) { + const [showSecret, setShowSecret] = useState(false); + + const toggleSecretVisibility = () => { + setShowSecret(!showSecret); + }; + + const maskSecret = (secret: string) => { + return `${'•'.repeat(28)} ${secret.slice(-4)}`; + }; + + return ( +
+ +
+ {secret && value ? ( +
+ + + + + + +
+ ) : ( + children + )} +
+
+ ); +} From 84b4d5bd6ba21a2ef344db6dd428b60e6f6410b3 Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Sun, 8 Dec 2024 12:31:07 +0200 Subject: [PATCH 03/10] fix: reuse --- apps/dashboard/src/pages/api-keys.tsx | 81 ++++++++++++++++----------- 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/apps/dashboard/src/pages/api-keys.tsx b/apps/dashboard/src/pages/api-keys.tsx index bae1710cf95..e5f7965296f 100644 --- a/apps/dashboard/src/pages/api-keys.tsx +++ b/apps/dashboard/src/pages/api-keys.tsx @@ -14,6 +14,7 @@ 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; @@ -25,6 +26,7 @@ export function ApiKeysPage() { const apiKeysQuery = useFetchApiKeys(); const { currentEnvironment } = useEnvironment(); const apiKeys = apiKeysQuery.data?.data; + const isLoading = apiKeysQuery.isLoading; const form = useForm({ values: { @@ -62,26 +64,18 @@ export function ApiKeysPage() {
- -
- - - - -
-
+ -
- - - - -
-
+ value={form.getValues('identifier')} + isLoading={isLoading} + />
@@ -101,6 +95,7 @@ export function ApiKeysPage() { tooltip="Use this key to authenticate your API requests. Keep it secure and never share it publicly." value={form.getValues('apiKey')} secret + isLoading={isLoading} />
@@ -117,12 +112,20 @@ export function ApiKeysPage() { interface SettingFieldProps { label: string; tooltip?: string; - children?: ReactNode; value?: string; secret?: boolean; + isLoading?: boolean; + readOnly?: boolean; } -function SettingField({ label, tooltip, children, value, secret = false }: SettingFieldProps) { +function SettingField({ + label, + tooltip, + value, + secret = false, + isLoading = false, + readOnly = true, +}: SettingFieldProps) { const [showSecret, setShowSecret] = useState(false); const toggleSecretVisibility = () => { @@ -139,25 +142,35 @@ function SettingField({ label, tooltip, children, value, secret = false }: Setti {label} {tooltip && } -
- {secret && value ? ( -
+
+ {isLoading ? ( + <> + + {secret && } + + ) : ( + <> - - + + - -
- ) : ( - children + {secret && ( + + )} + )}
From bc7dd4adc2ca5c4f151dac0edd23e997fa595084 Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Sun, 8 Dec 2024 12:35:04 +0200 Subject: [PATCH 04/10] fix: wudth --- .../src/components/header-navigation/header-navigation.tsx | 5 ++++- apps/dashboard/src/pages/api-keys.tsx | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) 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/pages/api-keys.tsx b/apps/dashboard/src/pages/api-keys.tsx index e5f7965296f..7bb9d740a9e 100644 --- a/apps/dashboard/src/pages/api-keys.tsx +++ b/apps/dashboard/src/pages/api-keys.tsx @@ -46,7 +46,7 @@ export function ApiKeysPage() { API Keys}>
-
+

Environment Keys

@@ -57,7 +57,7 @@ export function ApiKeysPage() {
-
+
Application From 1ff70169a774731d5f8aa9c1a9ebbbd2f61a4523 Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Sun, 8 Dec 2024 12:44:50 +0200 Subject: [PATCH 05/10] fix: pr review --- .../components/settings/setting-section.tsx | 23 -------- .../src/components/shared/external-link.tsx | 6 +-- apps/dashboard/src/pages/api-keys.tsx | 53 +++++++++++-------- 3 files changed, 35 insertions(+), 47 deletions(-) delete mode 100644 apps/dashboard/src/components/settings/setting-section.tsx diff --git a/apps/dashboard/src/components/settings/setting-section.tsx b/apps/dashboard/src/components/settings/setting-section.tsx deleted file mode 100644 index c4fa87bed21..00000000000 --- a/apps/dashboard/src/components/settings/setting-section.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { ReactNode } from 'react'; -import { Card, CardContent, CardHeader } from '@/components/primitives/card'; - -interface SettingSectionProps { - title: string; - description?: string; - children: ReactNode; -} - -export function SettingSection({ title, description, children }: SettingSectionProps) { - return ( - - - {title} - {description &&

{description}

} -
- - -
{children}
-
-
- ); -} diff --git a/apps/dashboard/src/components/shared/external-link.tsx b/apps/dashboard/src/components/shared/external-link.tsx index 44081b36ea4..ade6bb1ecd4 100644 --- a/apps/dashboard/src/components/shared/external-link.tsx +++ b/apps/dashboard/src/components/shared/external-link.tsx @@ -1,10 +1,10 @@ -import { RiBookMarkedLine, RiBookmarkLine, RiExternalLinkLine } from 'react-icons/ri'; +import { RiBookMarkedLine, RiExternalLinkLine, RiQuestionLine } from 'react-icons/ri'; import { cn } from '@/utils/ui'; interface ExternalLinkProps extends React.AnchorHTMLAttributes { children: React.ReactNode; iconClassName?: string; - variant?: 'default' | 'documentation'; + variant?: 'default' | 'documentation' | 'tip'; } export function ExternalLink({ children, className, variant = 'default', iconClassName, ...props }: ExternalLinkProps) { @@ -17,7 +17,7 @@ export function ExternalLink({ children, className, variant = 'default', iconCla > {variant === 'documentation' &&
- - - Secret Keys -

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

-
- - -
- -
-
-
+
+ + + Secret Keys +

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

+
+ + +
+ +
+
+
+ + Learn more about APIs in Novu + +
From d94d7852ffa3964148185ec6c5260c8c4810e43d Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Sun, 8 Dec 2024 12:45:13 +0200 Subject: [PATCH 06/10] fix: --- apps/dashboard/src/pages/api-keys.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/dashboard/src/pages/api-keys.tsx b/apps/dashboard/src/pages/api-keys.tsx index 13d8729d15f..4ad6b0062a0 100644 --- a/apps/dashboard/src/pages/api-keys.tsx +++ b/apps/dashboard/src/pages/api-keys.tsx @@ -1,5 +1,5 @@ -import { useState, ReactNode } from 'react'; -import { RiKey2Line, RiEyeLine, RiEyeOffLine, RiQuestionLine } from 'react-icons/ri'; +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, CardHeader } from '@/components/primitives/card'; @@ -15,7 +15,6 @@ 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'; -import { HelpCircle } from 'lucide-react'; interface ApiKeysFormData { apiKey: string; From 385908765e1d73c3baa95131fb6210f0908f1d59 Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Sun, 8 Dec 2024 12:48:59 +0200 Subject: [PATCH 07/10] fix: link --- apps/dashboard/src/pages/api-keys.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/dashboard/src/pages/api-keys.tsx b/apps/dashboard/src/pages/api-keys.tsx index 4ad6b0062a0..9821dfa1441 100644 --- a/apps/dashboard/src/pages/api-keys.tsx +++ b/apps/dashboard/src/pages/api-keys.tsx @@ -104,10 +104,10 @@ export function ApiKeysPage() { - Learn more about APIs in Novu + Learn more about our APIs
From 0acb8707a36a6b6e6e6f4cd2ff056aac1794ee42 Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Sun, 8 Dec 2024 12:50:32 +0200 Subject: [PATCH 08/10] fix: add telemtry --- .../src/components/shared/external-link.tsx | 22 ++++++++++++++++++- apps/dashboard/src/utils/telemetry.ts | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/dashboard/src/components/shared/external-link.tsx b/apps/dashboard/src/components/shared/external-link.tsx index ade6bb1ecd4..483c083a4af 100644 --- a/apps/dashboard/src/components/shared/external-link.tsx +++ b/apps/dashboard/src/components/shared/external-link.tsx @@ -1,5 +1,7 @@ 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; @@ -7,12 +9,30 @@ interface ExternalLinkProps extends React.AnchorHTMLAttributes { + telemetry(TelemetryEvent.EXTERNAL_LINK_CLICKED, { + href, + variant, + }); + }; + return ( {variant === 'documentation' &&