Skip to content

Commit

Permalink
[GEN-1767]: fix test-connection (#1821)
Browse files Browse the repository at this point in the history
  • Loading branch information
BenElferink authored Nov 21, 2024
1 parent 28c3eee commit 42ea556
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { GET_DESTINATION_TYPE_DETAILS } from '@/graphql';
import { Body, Container, SideMenuWrapper } from '../styled';
import { Divider, SectionTitle } from '@/reuseable-components';
import { ConnectionNotification } from './connection-notification';
import type { StepProps, DestinationInput, DestinationTypeItem, DestinationDetailsResponse, ConfiguredDestination } from '@/types';
import { useComputePlatform, useConnectDestinationForm, useConnectEnv, useDestinationFormData, useEditDestinationFormHandlers } from '@/hooks';
import { StepProps, DestinationInput, DestinationTypeItem, DestinationDetailsResponse, ConfiguredDestination } from '@/types';

const SIDE_MENU_DATA: StepProps[] = [
{
Expand All @@ -34,14 +34,24 @@ interface ConnectDestinationModalBodyProps {
export function ConnectDestinationModalBody({ destination, onSubmitRef, onFormValidChange }: ConnectDestinationModalBodyProps) {
const [destinationName, setDestinationName] = useState<string>('');
const [showConnectionError, setShowConnectionError] = useState(false);
const [isFormDirty, setIsFormDirty] = useState(false);

const { dynamicFields, exportedSignals, setDynamicFields, setExportedSignals } = useDestinationFormData();

const { connectEnv } = useConnectEnv();
const { refetch } = useComputePlatform();
const { buildFormDynamicFields } = useConnectDestinationForm();

const { handleDynamicFieldChange, handleSignalChange } = useEditDestinationFormHandlers(setExportedSignals, setDynamicFields);
const { handleDynamicFieldChange, handleSignalChange } = useEditDestinationFormHandlers(
(...params) => {
setIsFormDirty(true);
setExportedSignals(...params);
},
(...params) => {
setIsFormDirty(true);
setDynamicFields(...params);
},
);

const addConfiguredDestination = useAppStore(({ addConfiguredDestination }) => addConfiguredDestination);

Expand Down Expand Up @@ -96,6 +106,7 @@ export function ConnectDestinationModalBody({ destination, onSubmitRef, onFormVa
}, [destination]);

function onDynamicFieldChange(name: string, value: any) {
setIsFormDirty(true);
setShowConnectionError(false);
handleDynamicFieldChange(name, value);
}
Expand Down Expand Up @@ -161,26 +172,6 @@ export function ConnectDestinationModalBody({ destination, onSubmitRef, onFormVa
}
}

const actionButton = useMemo(() => {
if (!!destination?.testConnectionSupported) {
return (
<TestConnection
onError={() => {
setShowConnectionError(true);
onFormValidChange(false);
}}
destination={{
name: destinationName,
type: destination?.type || '',
exportedSignals,
fields: processFormFields(),
}}
/>
);
}
return null;
}, [destination, destinationName, exportedSignals, processFormFields, onFormValidChange]);

if (!destination) return null;

return (
Expand All @@ -190,7 +181,28 @@ export function ConnectDestinationModalBody({ destination, onSubmitRef, onFormVa
</SideMenuWrapper>

<Body>
<SectionTitle title='Create connection' description='Connect selected destination with Odigos.' actionButton={actionButton} />
<SectionTitle
title='Create connection'
description='Connect selected destination with Odigos.'
actionButton={
!!destination.testConnectionSupported ? (
<TestConnection
destination={{
name: destinationName,
type: destination.type || '',
exportedSignals,
fields: processFormFields(),
}}
isFormDirty={isFormDirty}
clearFormDirty={() => setIsFormDirty(false)}
onError={() => {
setShowConnectionError(true);
onFormValidChange(false);
}}
/>
) : undefined
}
/>
<ConnectionNotification showConnectionError={showConnectionError} destination={destination} />
<Divider margin='24px 0' />
<FormContainer
Expand Down
Original file line number Diff line number Diff line change
@@ -1,54 +1,54 @@
import React, { useEffect, useMemo } from 'react';
import Image from 'next/image';
import styled from 'styled-components';
import React, { useState } from 'react';
import { DestinationInput } from '@/types';
import { getStatusIcon } from '@/utils';
import { useTestConnection } from '@/hooks';
import type { DestinationInput } from '@/types';
import { Button, FadeLoader, Text } from '@/reuseable-components';

interface TestConnectionProps {
destination: DestinationInput | undefined;
onError?: () => void;
destination: DestinationInput;
isFormDirty: boolean;
clearFormDirty: () => void;
onError: () => void;
}

const ActionButton = styled(Button)<{ $isTestConnectionSuccess?: boolean }>`
const ActionButton = styled(Button)<{ $success?: boolean }>`
display: flex;
align-items: center;
gap: 8px;
background-color: ${({ $isTestConnectionSuccess }) => ($isTestConnectionSuccess ? 'rgba(129, 175, 101, 0.16)' : 'transparent')};
background-color: ${({ $success }) => ($success ? 'rgba(129, 175, 101, 0.16)' : 'transparent')};
`;

const ActionButtonText = styled(Text)<{ $isTestConnectionSuccess?: boolean }>`
const ActionButtonText = styled(Text)<{ $success?: boolean }>`
font-family: ${({ theme }) => theme.font_family.secondary};
font-weight: 500;
text-decoration: underline;
text-transform: uppercase;
font-size: 14px;
line-height: 157.143%;
color: ${({ theme, $isTestConnectionSuccess }) => ($isTestConnectionSuccess ? theme.text.success : theme.colors.white)};
color: ${({ theme, $success }) => ($success ? theme.text.success : theme.colors.white)};
`;

const TestConnection: React.FC<TestConnectionProps> = ({ destination, onError }) => {
const [isTestConnectionSuccess, setIsTestConnectionSuccess] = useState<boolean>(false);
const { testConnection, loading, error } = useTestConnection();
const TestConnection: React.FC<TestConnectionProps> = ({ destination, isFormDirty, clearFormDirty, onError }) => {
const { testConnection, loading, data } = useTestConnection();

const onButtonClick = async () => {
if (!destination) {
return;
}
const disabled = useMemo(() => !destination.fields.find((field) => !!field.value), [destination.fields]);
const success = useMemo(() => data?.testConnectionForDestination.succeeded || false, [data]);

const res = await testConnection(destination);
if (res) {
setIsTestConnectionSuccess(res.succeeded);
!res.succeeded && onError && onError();
useEffect(() => {
if (data) {
clearFormDirty();
if (!success) onError && onError();
}
};
}, [data, success]);

return (
<ActionButton variant={'secondary'} onClick={onButtonClick} $isTestConnectionSuccess={isTestConnectionSuccess}>
{isTestConnectionSuccess && <Image alt='checkmark' src='/icons/common/connection-succeeded.svg' width={16} height={16} />}
{loading && <FadeLoader />}
<ActionButton variant='secondary' disabled={disabled || !isFormDirty} onClick={() => testConnection(destination)} $success={success}>
{loading ? <FadeLoader /> : success ? <Image alt='checkmark' src={getStatusIcon('success')} width={16} height={16} /> : null}

<ActionButtonText size={14} $isTestConnectionSuccess={isTestConnectionSuccess}>
{loading ? 'Checking' : isTestConnectionSuccess ? 'Connection ok' : 'Test Connection'}
<ActionButtonText size={14} $success={success}>
{loading ? 'Checking' : success ? 'Connection OK' : 'Test Connection'}
</ActionButtonText>
</ActionButton>
);
Expand Down
41 changes: 14 additions & 27 deletions frontend/webapp/hooks/destinations/useTestConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,20 @@ interface TestConnectionResponse {
reason: string;
}

interface UseTestConnectionResult {
testConnection: (
destination: DestinationInput
) => Promise<TestConnectionResponse | undefined>;
loading: boolean;
error?: Error;
}

export const useTestConnection = (): UseTestConnectionResult => {
const [testConnectionMutation, { loading, error }] = useMutation<
{ testConnectionForDestination: TestConnectionResponse },
{ destination: DestinationInput }
>(TEST_CONNECTION_MUTATION);
export const useTestConnection = () => {
const [testConnectionMutation, { loading, error, data }] = useMutation<{ testConnectionForDestination: TestConnectionResponse }, { destination: DestinationInput }>(TEST_CONNECTION_MUTATION, {
onError: (error, clientOptions) => {
console.error('Error testing connection:', error);
},
onCompleted: (data, clientOptions) => {
console.log('Successfully tested connection:', data);
},
});

const testConnection = async (
destination: DestinationInput
): Promise<TestConnectionResponse | undefined> => {
try {
const { data } = await testConnectionMutation({
variables: { destination },
});
return data?.testConnectionForDestination;
} catch (err) {
console.error('Error testing connection:', err);
return undefined;
}
return {
testConnection: (destination: DestinationInput) => testConnectionMutation({ variables: { destination } }),
loading,
error,
data,
};

return { testConnection, loading, error };
};

0 comments on commit 42ea556

Please sign in to comment.