Skip to content

Commit

Permalink
fix: pr comments
Browse files Browse the repository at this point in the history
  • Loading branch information
scopsy committed Dec 18, 2024
1 parent 8fece59 commit 1d0a181
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 86 deletions.
20 changes: 20 additions & 0 deletions apps/dashboard/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import { FeatureFlagsProvider } from './context/feature-flags-provider';
import { ConfigureStep } from '@/components/workflow-editor/steps/configure-step';
import { ConfigureStepTemplate } from '@/components/workflow-editor/steps/configure-step-template';
import { RedirectToLegacyStudioAuth } from './pages/redirect-to-legacy-studio-auth';
import { CreateIntegrationSidebar } from './pages/integrations/components/create-integration-sidebar';
import { UpdateIntegrationSidebar } from './pages/integrations/components/update-integration-sidebar';

initializeSentry();
overrideZodErrorMap();
Expand Down Expand Up @@ -140,6 +142,24 @@ const router = createBrowserRouter([
},
],
},
{
path: ROUTES.INTEGRATIONS,
element: <IntegrationsListPage />,
children: [
{
path: ROUTES.INTEGRATIONS_CONNECT,
element: <CreateIntegrationSidebar isOpened onClose={() => history.back()} />,
},
{
path: ROUTES.INTEGRATIONS_CONNECT_PROVIDER,
element: <CreateIntegrationSidebar isOpened onClose={() => history.back()} />,
},
{
path: ROUTES.INTEGRATIONS_UPDATE,
element: <UpdateIntegrationSidebar isOpened onClose={() => history.back()} />,
},
],
},
{
path: ROUTES.INTEGRATIONS,
element: <IntegrationsListPage />,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useNavigate, useParams } from 'react-router-dom';
import { ChannelTypeEnum, providers as novuProviders } from '@novu/shared';
import { useCreateIntegration } from '@/hooks/use-create-integration';
import { useIntegrationList } from './hooks/use-integration-list';
Expand All @@ -12,6 +13,7 @@ import { SelectPrimaryIntegrationModal } from './modals/select-primary-integrati
import { IntegrationFormData } from '../types';
import { useIntegrationPrimaryModal } from './hooks/use-integration-primary-modal';
import { useFetchIntegrations } from '@/hooks/use-fetch-integrations';
import { buildRoute, ROUTES } from '../../../utils/routes';

export type CreateIntegrationSidebarProps = {
isOpened: boolean;
Expand All @@ -20,17 +22,31 @@ export type CreateIntegrationSidebarProps = {
};

export function CreateIntegrationSidebar({ isOpened, onClose }: CreateIntegrationSidebarProps) {
const navigate = useNavigate();
const { providerId } = useParams();

const providers = novuProviders;
const { mutateAsync: createIntegration, isPending } = useCreateIntegration();
const { mutateAsync: setPrimaryIntegration, isPending: isSettingPrimary } = useSetPrimaryIntegration();
const { integrations } = useFetchIntegrations();

const handleIntegrationSelect = (integrationId: string) => {
navigate(buildRoute(ROUTES.INTEGRATIONS_CONNECT_PROVIDER, { providerId: integrationId }), { replace: true });
};

const handleBack = () => {
navigate(ROUTES.INTEGRATIONS_CONNECT, { replace: true });
};

const { selectedIntegration, step, searchQuery, onIntegrationSelect, onBack } = useSidebarNavigationManager({
isOpened,
initialProviderId: providerId,
onIntegrationSelect: handleIntegrationSelect,
onBack: handleBack,
});

const { integrationsByChannel } = useIntegrationList(providers, searchQuery);
const provider = providers?.find((p) => p.id === selectedIntegration);
const provider = providers?.find((p) => p.id === (selectedIntegration || providerId));
const {
isPrimaryModalOpen,
setIsPrimaryModalOpen,
Expand Down Expand Up @@ -69,11 +85,16 @@ export function CreateIntegrationSidebar({ isOpened, onClose }: CreateIntegratio
}
}

const handleClose = () => {
onClose();
navigate('/integrations');
};

return (
<>
<IntegrationSheet
isOpened={isOpened}
onClose={onClose}
onClose={handleClose}
provider={provider}
mode="create"
step={step}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,52 @@ import { IntegrationStep } from '../../types';

type UseSidebarNavigationManagerProps = {
isOpened: boolean;
initialProviderId?: string;
onIntegrationSelect?: (integrationId: string) => void;
onBack?: () => void;
};

export function useSidebarNavigationManager({ isOpened }: UseSidebarNavigationManagerProps) {
export function useSidebarNavigationManager({
isOpened,
initialProviderId,
onIntegrationSelect: externalOnIntegrationSelect,
onBack: externalOnBack,
}: UseSidebarNavigationManagerProps) {
const [selectedIntegration, setSelectedIntegration] = useState<string>();
const [step, setStep] = useState<IntegrationStep>('select');
const [searchQuery, setSearchQuery] = useState('');

useEffect(() => {
if (isOpened) {
setSelectedIntegration(undefined);
setStep('select');
if (initialProviderId) {
setSelectedIntegration(initialProviderId);
setStep('configure');
} else {
setSelectedIntegration(undefined);
setStep('select');
}
setSearchQuery('');
}
}, [isOpened]);
}, [isOpened, initialProviderId]);

const onIntegrationSelect = (integrationId: string) => {
const handleIntegrationSelect = (integrationId: string) => {
setSelectedIntegration(integrationId);
setStep('configure');
externalOnIntegrationSelect?.(integrationId);
};

const onBack = () => {
const handleBack = () => {
setStep('select');
setSelectedIntegration(undefined);
externalOnBack?.();
};

return {
selectedIntegration,
step,
searchQuery,
setSearchQuery,
onIntegrationSelect,
onBack,
onIntegrationSelect: handleIntegrationSelect,
onBack: handleBack,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,13 @@ import { Badge } from '@/components/primitives/badge';
import { Button } from '@/components/primitives/button';
import { RiCheckboxCircleFill, RiGitBranchFill, RiSettings4Line, RiStarSmileLine } from 'react-icons/ri';
import { TableIntegration } from '../types';
import {
ChannelTypeEnum,
EmailProviderIdEnum,
SmsProviderIdEnum,
type IEnvironment,
type IIntegration,
type IProviderConfig,
} from '@novu/shared';
import { ChannelTypeEnum, type IEnvironment, type IIntegration, type IProviderConfig } from '@novu/shared';
import { useNavigate } from 'react-router-dom';
import { ROUTES } from '@/utils/routes';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/primitives/tooltip';
import { ProviderIcon } from './provider-icon';
import { cn } from '../../../utils/ui';
import { isDemoIntegration } from './utils/helpers';

type IntegrationCardProps = {
integration: IIntegration;
Expand Down Expand Up @@ -117,7 +111,3 @@ export function IntegrationCard({ integration, provider, environment, onRowClick
</div>
);
}

function isDemoIntegration(providerId: string) {
return providerId === EmailProviderIdEnum.Novu || providerId === SmsProviderIdEnum.Novu;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useForm } from 'react-hook-form';
import { useForm, useWatch } from 'react-hook-form';
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/primitives/accordion';
import { Form } from '@/components/primitives/form/form';
import { Label } from '@/components/primitives/label';
Expand All @@ -11,9 +11,9 @@ import { SegmentedControl, SegmentedControlList } from '../../../components/prim
import { SegmentedControlTrigger } from '../../../components/primitives/segmented-control';
import { useEnvironment, useFetchEnvironments } from '@/context/environment/hooks';
import { useAuth } from '@/context/auth/hooks';
import { isDemoIntegration } from './integration-card';
import { GeneralSettings } from './integration-general-settings';
import { CredentialsSection } from './integration-credentials';
import { isDemoIntegration } from './utils/helpers';

type IntegrationFormData = {
name: string;
Expand Down Expand Up @@ -78,11 +78,12 @@ export function IntegrationConfiguration({
handleSubmit,
control,
formState: { errors },
watch,
getValues,
setValue,
} = form;

const name = watch('name');
const name = useWatch({ control, name: 'name' });
const environmentId = useWatch({ control, name: 'environmentId' });

useEffect(() => {
if (mode === 'create') {
Expand All @@ -100,7 +101,7 @@ export function IntegrationConfiguration({
Environment
</Label>
<SegmentedControl
value={watch('environmentId')}
value={environmentId}
onValueChange={(value) => setValue('environmentId', value)}
className="w-full max-w-[260px]"
>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/components/primitives/alert-dialog';
import { ConfirmationModal } from '@/components/confirmation-modal';

export type DeleteIntegrationModalProps = {
isOpen: boolean;
Expand All @@ -17,27 +8,23 @@ export type DeleteIntegrationModalProps = {
};

export function DeleteIntegrationModal({ isOpen, onOpenChange, onConfirm, isPrimary }: DeleteIntegrationModalProps) {
const description = isPrimary ? (
<>
<p>Are you sure you want to delete this primary integration?</p>
<p>This will disable the channel until you set up a new integration.</p>
</>
) : (
<p>Are you sure you want to delete this integration?</p>
);

return (
<AlertDialog open={isOpen} onOpenChange={onOpenChange}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete {isPrimary ? 'Primary ' : ''}Integration</AlertDialogTitle>
<AlertDialogDescription className="space-y-2">
{isPrimary ? (
<>
<p>Are you sure you want to delete this primary integration?</p>
<p>This will disable the channel until you set up a new integration.</p>
</>
) : (
<p>Are you sure you want to delete this integration?</p>
)}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction onClick={onConfirm}>Delete Integration</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<ConfirmationModal
open={isOpen}
onOpenChange={onOpenChange}
onConfirm={onConfirm}
title={`Delete ${isPrimary ? 'Primary ' : ''}Integration`}
description={description}
confirmButtonText="Delete Integration"
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ import { IntegrationFormData } from '../types';
import { useDeleteIntegration } from '../../../hooks/use-delete-integration';
import { handleIntegrationError } from './utils/handle-integration-error';
import { useIntegrationPrimaryModal } from './hooks/use-integration-primary-modal';
import { useNavigate, useParams } from 'react-router-dom';

type UpdateIntegrationSidebarProps = {
isOpened: boolean;
integrationId?: string;
onClose: () => void;
};

export function UpdateIntegrationSidebar({ isOpened, integrationId, onClose }: UpdateIntegrationSidebarProps) {
export function UpdateIntegrationSidebar({ isOpened, onClose }: UpdateIntegrationSidebarProps) {
const navigate = useNavigate();
const { integrationId } = useParams();
const { integrations } = useFetchIntegrations();
const integration = integrations?.find((i) => i._id === integrationId);
const provider = novuProviders?.find((p) => p.id === integration?.providerId);
Expand Down Expand Up @@ -92,11 +94,16 @@ export function UpdateIntegrationSidebar({ isOpened, integrationId, onClose }: U
}
};

const handleClose = () => {
onClose();
navigate('/integrations');
};

if (!integration || !provider) return null;

return (
<>
<IntegrationSheet isOpened={isOpened} onClose={onClose} provider={provider} mode="update">
<IntegrationSheet isOpened={isOpened} onClose={handleClose} provider={provider} mode="update">
<div className="scrollbar-custom flex-1 overflow-y-auto">
<IntegrationConfiguration
isChannelSupportPrimary={isChannelSupportPrimary}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { EmailProviderIdEnum, SmsProviderIdEnum } from '@novu/shared';

export function isDemoIntegration(providerId: string) {
return providerId === EmailProviderIdEnum.Novu || providerId === SmsProviderIdEnum.Novu;
}
38 changes: 14 additions & 24 deletions apps/dashboard/src/pages/integrations/integrations-list-page.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
import { ChannelTypeEnum } from '@novu/shared';
import { useCallback, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useCallback } from 'react';
import { Outlet, useNavigate } from 'react-router-dom';

import { IntegrationsList } from './components/integrations-list';
import { ITableIntegration } from './types';
import { TableIntegration } from './types';
import { DashboardLayout } from '../../components/dashboard-layout';
import { UpdateIntegrationSidebar } from './components/update-integration-sidebar';
import { CreateIntegrationSidebar } from './components/create-integration-sidebar';
import { Badge } from '../../components/primitives/badge';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/primitives/tabs';
import { Button } from '@/components/primitives/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/primitives/tooltip';
import { ROUTES } from '@/utils/routes';

export function IntegrationsListPage() {
const [searchParams] = useSearchParams();
const [selectedIntegrationId, setSelectedIntegrationId] = useState<string>();
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const navigate = useNavigate();

const onRowClickCallback = useCallback((item: { original: ITableIntegration }) => {
setSelectedIntegrationId(item.original.integrationId);
}, []);
const onRowClickCallback = useCallback(
(item: TableIntegration) => {
navigate(`/integrations/${item.integrationId}/update`);
},
[navigate]
);

const onAddIntegrationClickCallback = useCallback(() => {
setIsCreateModalOpen(true);
}, []);
navigate(ROUTES.INTEGRATIONS_CONNECT);
}, [navigate]);

return (
<DashboardLayout
Expand Down Expand Up @@ -69,16 +68,7 @@ export function IntegrationsListPage() {
<div className="text-muted-foreground flex h-64 items-center justify-center">Coming soon</div>
</TabsContent>
</Tabs>
<UpdateIntegrationSidebar
isOpened={!!selectedIntegrationId}
integrationId={selectedIntegrationId}
onClose={() => setSelectedIntegrationId(undefined)}
/>
<CreateIntegrationSidebar
isOpened={isCreateModalOpen}
onClose={() => setIsCreateModalOpen(false)}
scrollToChannel={searchParams.get('scrollTo') as ChannelTypeEnum}
/>
<Outlet />
</DashboardLayout>
);
}
Loading

0 comments on commit 1d0a181

Please sign in to comment.