From cee5ac384400130e8451e44dfcfd60fc770c6810 Mon Sep 17 00:00:00 2001 From: Sokratis Vidros Date: Tue, 24 Dec 2024 15:33:28 +0200 Subject: [PATCH] fix(dashboard): Crate with fixes (#7367) --- .../src/components/create-workflow-button.tsx | 14 +- .../edit-bridge-url-button.tsx | 2 +- .../src/components/primitives/button.tsx | 8 +- .../src/components/shared/external-link.tsx | 12 +- .../side-navigation/free-trial-card.tsx | 2 +- .../dashboard/src/components/user-profile.tsx | 19 ++- .../src/components/workflow-list-empty.tsx | 8 +- apps/dashboard/src/context/clerk-provider.tsx | 63 ++++---- apps/dashboard/src/pages/api-keys.tsx | 147 +++++++++--------- apps/dashboard/src/pages/workflows.tsx | 3 +- 10 files changed, 140 insertions(+), 138 deletions(-) diff --git a/apps/dashboard/src/components/create-workflow-button.tsx b/apps/dashboard/src/components/create-workflow-button.tsx index 1adebbae0d4..d999cb1f37d 100644 --- a/apps/dashboard/src/components/create-workflow-button.tsx +++ b/apps/dashboard/src/components/create-workflow-button.tsx @@ -2,8 +2,9 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { ComponentProps, useState } from 'react'; import { useForm } from 'react-hook-form'; -import { RiExternalLinkLine } from 'react-icons/ri'; -import { Link, useNavigate } from 'react-router-dom'; +import { RiArrowRightSLine } from 'react-icons/ri'; +import { ExternalLink } from '@/components/shared/external-link'; +import { useNavigate } from 'react-router-dom'; import { z } from 'zod'; import { type CreateWorkflowDto, WorkflowCreationSourceEnum, slugify } from '@novu/shared'; import { createWorkflow } from '@/api/workflows'; @@ -73,13 +74,7 @@ export const CreateWorkflowButton = (props: CreateWorkflowButtonProps) => {
Define the steps to notify subscribers using channels like in-app, email, and more.{' '} - - Learn more - + Learn more
@@ -195,6 +190,7 @@ export const CreateWorkflowButton = (props: CreateWorkflowButtonProps) => { diff --git a/apps/dashboard/src/components/header-navigation/edit-bridge-url-button.tsx b/apps/dashboard/src/components/header-navigation/edit-bridge-url-button.tsx index 6d120015218..85183462719 100644 --- a/apps/dashboard/src/components/header-navigation/edit-bridge-url-button.tsx +++ b/apps/dashboard/src/components/header-navigation/edit-bridge-url-button.tsx @@ -63,7 +63,7 @@ export const EditBridgeUrlButton = () => { className={cn( 'relative size-1.5 animate-[pulse-shadow_1s_ease-in-out_infinite] rounded-full', status === ConnectionStatus.DISCONNECTED || status === ConnectionStatus.LOADING - ? 'bg-destructive [--pulse-color:var(--destructive)]' + ? 'bg-destructive' : 'bg-success [--pulse-color:var(--success)]' )} /> diff --git a/apps/dashboard/src/components/primitives/button.tsx b/apps/dashboard/src/components/primitives/button.tsx index 617b4758723..993a4322530 100644 --- a/apps/dashboard/src/components/primitives/button.tsx +++ b/apps/dashboard/src/components/primitives/button.tsx @@ -5,7 +5,7 @@ import { cn } from '@/utils/ui'; import { RiLoader4Line } from 'react-icons/ri'; export const buttonVariants = cva( - `relative isolate inline-flex items-center justify-center whitespace-nowrap rounded-lg gap-1 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50`, + `relative isolate inline-flex items-center justify-center whitespace-nowrap rounded-lg gap-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50`, { variants: { variant: { @@ -26,10 +26,10 @@ export const buttonVariants = cva( }, size: { default: 'h-9 p-2.5', - xs: 'h-6 px-1.5 rounded-md text-xs', - sm: 'h-8 px-1.5 rounded-md text-xs', + xs: 'h-6 px-2 rounded-md', + sm: 'h-8 px-2 rounded-md', lg: 'h-10 rounded-md px-8', - 'input-right': 'rounded-none border-b-0 h-full text-xs border-r-0 border-t-0 px-2 py-0', + 'input-right': 'rounded-none border-b-0 h-full border-r-0 border-t-0 px-2 py-0', icon: 'size-8', }, }, diff --git a/apps/dashboard/src/components/shared/external-link.tsx b/apps/dashboard/src/components/shared/external-link.tsx index 483c083a4af..bf1cba85309 100644 --- a/apps/dashboard/src/components/shared/external-link.tsx +++ b/apps/dashboard/src/components/shared/external-link.tsx @@ -1,4 +1,4 @@ -import { RiBookMarkedLine, RiExternalLinkLine, RiQuestionLine } from 'react-icons/ri'; +import { RiBookMarkedLine, RiArrowRightUpLine, RiQuestionLine } from 'react-icons/ri'; import { cn } from '@/utils/ui'; import { useTelemetry } from '@/hooks/use-telemetry'; import { TelemetryEvent } from '@/utils/telemetry'; @@ -26,19 +26,21 @@ export function ExternalLink({ }); }; + const finalIconClassName = cn('inline size-3 mb-1', iconClassName); + return ( - {variant === 'documentation' && ); } diff --git a/apps/dashboard/src/components/side-navigation/free-trial-card.tsx b/apps/dashboard/src/components/side-navigation/free-trial-card.tsx index a490217f878..e60c997b204 100644 --- a/apps/dashboard/src/components/side-navigation/free-trial-card.tsx +++ b/apps/dashboard/src/components/side-navigation/free-trial-card.tsx @@ -53,7 +53,7 @@ const CardContent = ({ - Experience Novu without any limits for free for the next {pluralizedDays}. + Enjoy unlimited access to Novu for free for the next {pluralizedDays}.
diff --git a/apps/dashboard/src/components/user-profile.tsx b/apps/dashboard/src/components/user-profile.tsx index a7dd7b3f99b..f1702bd1430 100644 --- a/apps/dashboard/src/components/user-profile.tsx +++ b/apps/dashboard/src/components/user-profile.tsx @@ -1,9 +1,10 @@ -import { UserButton } from '@clerk/clerk-react'; +import { UserButton, useOrganization } from '@clerk/clerk-react'; import { useNewDashboardOptIn } from '@/hooks/use-new-dashboard-opt-in'; import { RiSignpostFill } from 'react-icons/ri'; import { ROUTES } from '../utils/routes'; export function UserProfile() { + const { organization } = useOrganization(); const { optOut } = useNewDashboardOptIn(); return ( @@ -16,13 +17,15 @@ export function UserProfile() { }, }} > - - } - onClick={optOut} - /> - + {organization && organization.createdAt < new Date('2024-12-24') && ( + + } + onClick={optOut} + /> + + )} ); } diff --git a/apps/dashboard/src/components/workflow-list-empty.tsx b/apps/dashboard/src/components/workflow-list-empty.tsx index df277a9ca32..ff7bf93913d 100644 --- a/apps/dashboard/src/components/workflow-list-empty.tsx +++ b/apps/dashboard/src/components/workflow-list-empty.tsx @@ -50,12 +50,10 @@ const WorkflowListEmptyDev = () => (
- - Create your first workflow to orchestrate notifications - + Create your first workflow to send notifications

- Workflows in Novu handle event-driven notifications across multiple channels in a single, version-controlled - flow, with the ability to manage preference for each subscriber. + Workflows handle notifications across multiple channels in a single, version-controlled flow, with the ability + to manage preference for each subscriber.

diff --git a/apps/dashboard/src/context/clerk-provider.tsx b/apps/dashboard/src/context/clerk-provider.tsx index 259aa679531..064ea1f48f1 100644 --- a/apps/dashboard/src/context/clerk-provider.tsx +++ b/apps/dashboard/src/context/clerk-provider.tsx @@ -6,31 +6,6 @@ import { PropsWithChildren } from 'react'; import { useNavigate } from 'react-router-dom'; import { ROUTES } from '../utils/routes'; -const CLERK_LOCALIZATION = { - userProfile: { - navbar: { - title: 'Settings', - description: '', - account: 'User profile', - security: 'Access security', - }, - }, - organizationProfile: { - membersPage: { - requestsTab: { autoSuggestions: { headerTitle: '' } }, - invitationsTab: { autoInvitations: { headerTitle: '' } }, - }, - }, - userButton: { - action__signOut: 'Log out', - action__signOutAll: 'Log out from all accounts', - action__manageAccount: 'Settings', - }, - formFieldLabel__organizationSlug: 'URL friendly identifier', -}; - -const ALLOWED_REDIRECT_ORIGINS = ['http://localhost:*', window.location.origin]; - type ClerkProviderProps = PropsWithChildren; export const ClerkProvider = (props: ClerkProviderProps) => { const navigate = useNavigate(); @@ -61,6 +36,16 @@ export const ClerkProvider = (props: ClerkProviderProps) => { }, }, }, + organizationList: { + elements: { + cardBox: { + borderRadius: '0', + }, + card: { + borderRadius: '0', + }, + }, + }, elements: { formButtonPrimary: cn(buttonVariants({ variant: 'primary' })), }, @@ -68,8 +53,32 @@ export const ClerkProvider = (props: ClerkProviderProps) => { fontSize: '14px !important', }, }} - localization={CLERK_LOCALIZATION} - allowedRedirectOrigins={ALLOWED_REDIRECT_ORIGINS} + localization={{ + userProfile: { + navbar: { + title: 'Settings', + description: '', + account: 'User profile', + security: 'Access security', + }, + }, + organizationProfile: { + membersPage: { + requestsTab: { autoSuggestions: { headerTitle: '' } }, + invitationsTab: { autoInvitations: { headerTitle: '' } }, + }, + }, + userButton: { + action__signOut: 'Log out', + action__signOutAll: 'Log out from all accounts', + action__manageAccount: 'Settings', + }, + formFieldLabel__organizationSlug: 'URL friendly identifier', + unstable__errors: { + form_identifier_exists: 'Already taken, please choose another', + }, + }} + allowedRedirectOrigins={['http://localhost:*', window.location.origin]} > {children} diff --git a/apps/dashboard/src/pages/api-keys.tsx b/apps/dashboard/src/pages/api-keys.tsx index 033d68ee3a4..e1058b7402a 100644 --- a/apps/dashboard/src/pages/api-keys.tsx +++ b/apps/dashboard/src/pages/api-keys.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { RiKey2Line, RiEyeLine, RiEyeOffLine } from 'react-icons/ri'; +import { 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'; @@ -40,94 +40,85 @@ export function ApiKeysPage() { return null; } + const region = window.location.hostname.includes('eu') ? 'EU' : 'US'; + return ( <> API 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 + + + + + {''} +

+ {'Use the public application identifier in Novu . '} + + Learn more +

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

+ {'Use the secret key to authenticate your SDK requests. Keep it secure and never share it publicly. '} + + Learn more + +

+
+ + +
+ +
+
+
+ + + API URLs +

+ {`URLs for Novu Cloud in the ${region} region. `} + + Learn more + +

+
+ +
+ +
+
+
+ ); } -interface SettingFieldProps { - label: string; - tooltip?: string; - value?: string; - secret?: boolean; - isLoading?: boolean; - readOnly?: boolean; -} - function SettingField({ label, tooltip, @@ -173,6 +164,8 @@ function SettingField({