Skip to content

Commit

Permalink
feat(CE): Enable and Disable sync via UI
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] authored Sep 6, 2024
1 parent 3fba113 commit 3c44a0e
Show file tree
Hide file tree
Showing 18 changed files with 678 additions and 320 deletions.
24 changes: 23 additions & 1 deletion ui/src/chakra.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
import { extendTheme } from '@chakra-ui/react';

import { defaultExtension } from './chakra-core.config';
import { switchAnatomy } from '@chakra-ui/anatomy';
import { createMultiStyleConfigHelpers } from '@chakra-ui/react';

const mwTheme = extendTheme(defaultExtension);
const { definePartsStyle, defineMultiStyleConfig } = createMultiStyleConfigHelpers(
switchAnatomy.keys,
);

const baseStyle = definePartsStyle({
thumb: {
bg: 'gray.100',
borderRadius: '3px',
},
track: {
bg: 'gray.500',
borderRadius: '5px',
_checked: {
bg: 'brand.400',
},
},
});

export const switchTheme = defineMultiStyleConfig({ baseStyle });

const mwTheme = extendTheme(defaultExtension, { components: { Switch: switchTheme } });

export default mwTheme;
36 changes: 19 additions & 17 deletions ui/src/components/Alerts/Alerts.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import { AlertData } from '../commonTypes';
import { Alert, AlertIcon, AlertDescription } from '@chakra-ui/react';
import { Alert, AlertIcon, AlertTitle, Box, AlertDescription } from '@chakra-ui/react';

export const alertMessage: AlertData = {
status: undefined,
description: [''],
type AlertBoxProps = {
title: string;
description: string;
status: AlertData['status'];
};

function AlertPopUp({ status, description }: AlertData) {
return (
<>
{description.map((desc, index) => (
<Alert status={status} marginBottom={5} width='fit' rounded='md' key={index}>
<AlertIcon />
<AlertDescription>{desc}</AlertDescription>
</Alert>
))}
</>
);
}
const AlertBox = ({ title, description, status }: AlertBoxProps) => (
<Alert status={status} borderRadius='8px' paddingX='16px' paddingY='12px'>
<AlertIcon />
<Box>
<AlertTitle fontSize='14px' fontWeight='semibold' letterSpacing='-0.14px'>
{title}
</AlertTitle>
<AlertDescription color='black.200' fontSize='12px' fontWeight={400} letterSpacing='-0.14px'>
{description}
</AlertDescription>
</Box>
</Alert>
);

export default AlertPopUp;
export default AlertBox;
37 changes: 37 additions & 0 deletions ui/src/components/BaseButton/BaseButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Button } from '@chakra-ui/react';

type BaseButtonProps = {
variant: string;
onClick: () => void;
text: string;
color: string;
leftIcon?: React.ReactElement;
isDisabled?: boolean;
isLoading?: boolean;
};

const BaseButton = ({
variant,
onClick,
text,
color,
leftIcon,
isDisabled = false,
isLoading = false,
}: BaseButtonProps) => (
<Button
variant={variant}
borderRadius='6px'
minWidth={0}
width='auto'
onClick={onClick}
color={color}
leftIcon={leftIcon}
isDisabled={isDisabled}
isLoading={isLoading}
>
{text}
</Button>
);

export default BaseButton;
1 change: 1 addition & 0 deletions ui/src/components/BaseButton/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './BaseButton';
20 changes: 20 additions & 0 deletions ui/src/components/TabsWrapper/TabsWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Tabs, TabIndicator } from '@chakra-ui/react';

const TabsWrapper = ({ children }: { children: JSX.Element }) => (
<Tabs
size='md'
variant='indicator'
background='gray.300'
padding={1}
borderRadius='8px'
borderStyle='solid'
borderWidth='1px'
borderColor='gray.400'
width='fit-content'
>
{children}
<TabIndicator />
</Tabs>
);

export default TabsWrapper;
1 change: 1 addition & 0 deletions ui/src/components/TabsWrapper/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './TabsWrapper';
97 changes: 97 additions & 0 deletions ui/src/hooks/syncs/useEditSync.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useQueryClient } from '@tanstack/react-query';
import { editSync } from '@/services/syncs';
import { CreateSyncPayload, CreateSyncResponse } from '@/views/Activate/Syncs/types';
import { CustomToastStatus } from '@/components/Toast/index';
import useCustomToast from '@/hooks/useCustomToast';
import titleCase from '@/utils/TitleCase';
import { SYNCS_LIST_QUERY_KEY } from '@/views/Activate/Syncs/constants';
import { FinalizeSyncFormFields, FieldMap as FieldMapType } from '@/views/Activate/Syncs/types';

const useEditSync = (
configuration: FieldMapType[] | null,
setIsEditLoading: (isLoading: boolean) => void,
syncData?: CreateSyncResponse['attributes'],
destinationId?: string,
modelId?: string,
sourceId?: string,
) => {
const navigate = useNavigate();
const queryClient = useQueryClient();
const showToast = useCustomToast();
const [selectedSyncMode, setSelectedSyncMode] = useState('');
const [cursorField, setCursorField] = useState('');

const handleSubmit = async (data: FinalizeSyncFormFields, syncId: string) => {
setIsEditLoading(true);
try {
if (destinationId && modelId && sourceId && configuration) {
const payload: CreateSyncPayload = {
sync: {
configuration,
destination_id: destinationId,
model_id: modelId,
schedule_type: data.schedule_type,
source_id: sourceId,
stream_name: syncData?.stream_name as string,
sync_interval: data.sync_interval,
sync_interval_unit: data.sync_interval_unit,
sync_mode: selectedSyncMode,
cursor_field: cursorField,
cron_expression: data?.cron_expression,
},
};

const editSyncResponse = await editSync(payload, syncId);
if (editSyncResponse?.data?.attributes) {
showToast({
title: 'Sync updated successfully',
status: CustomToastStatus.Success,
duration: 3000,
isClosable: true,
position: 'bottom-right',
});

queryClient.removeQueries({
queryKey: SYNCS_LIST_QUERY_KEY,
});

navigate('/activate/syncs');
return;
} else {
editSyncResponse.errors?.forEach((error) => {
showToast({
duration: 5000,
isClosable: true,
position: 'bottom-right',
colorScheme: 'red',
status: CustomToastStatus.Warning,
title: titleCase(error.detail),
});
});
}
}
} catch {
showToast({
status: CustomToastStatus.Error,
title: 'Error!!',
description: 'Something went wrong while editing the sync',
position: 'bottom-right',
isClosable: true,
});
} finally {
setIsEditLoading(false);
}
};

return {
handleSubmit,
selectedSyncMode,
setSelectedSyncMode,
cursorField,
setCursorField,
};
};

export default useEditSync;
14 changes: 14 additions & 0 deletions ui/src/hooks/syncs/useGetSyncById.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useQuery } from '@tanstack/react-query';
import { getSyncById } from '@/services/syncs';

const useGetSyncById = (syncId: string, activeWorkspaceId: number) => {
return useQuery({
queryKey: ['sync', syncId, activeWorkspaceId],
queryFn: () => getSyncById(syncId),
refetchOnMount: true,
refetchOnWindowFocus: false,
enabled: !!syncId && activeWorkspaceId > 0,
});
};

export default useGetSyncById;
55 changes: 55 additions & 0 deletions ui/src/hooks/syncs/useManualSync.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { useState } from 'react';
import { triggerManualSync, cancelManualSyncSchedule } from '@/services/syncs';
import { TriggerManualSyncPayload, CreateSyncResponse } from '@/views/Activate/Syncs/types';
import { APIRequestMethod } from '@/services/common';
import useApiMutation from '../useAPIMutation';

type TriggerSyncVariables = {
payload: TriggerManualSyncPayload;
method: APIRequestMethod;
};

const useManualSync = (syncId: string) => {
const [showCancelSync, setShowCancelSync] = useState(false);

const { isSubmitting, triggerMutation: triggerSync } = useApiMutation<
CreateSyncResponse,
TriggerSyncVariables
>({
mutationFn: ({ payload, method }: TriggerSyncVariables) => triggerManualSync(payload, method),
successMessage: 'Sync started successfully!',
errorMessage: 'Failed to start sync',
onSuccessCallback: () => {
setShowCancelSync(true); // Update the state to show the cancel option
},
});

const { triggerMutation: cancelSync } = useApiMutation<CreateSyncResponse, string>({
mutationFn: (id) => cancelManualSyncSchedule(id),
successMessage: 'Sync run cancelled successfully!',
errorMessage: 'Failed to cancel sync run',
onSuccessCallback: () => {
setShowCancelSync(false); // Update the state to hide the cancel option
},
});

const runSyncNow = async (method: APIRequestMethod) => {
if (syncId) {
const payload: TriggerManualSyncPayload = {
schedule_sync: {
sync_id: parseInt(syncId, 10),
},
};

if (method === 'post') {
await triggerSync({ payload, method });
} else {
await cancelSync(syncId);
}
}
};

return { isSubmitting, runSyncNow, showCancelSync, setShowCancelSync };
};

export default useManualSync;
2 changes: 2 additions & 0 deletions ui/src/services/common.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export * from '@/services/axios';

export type APIRequestMethod = 'get' | 'post' | 'put' | 'delete';

type LinksType = {
first: string;
last: string;
Expand Down
37 changes: 32 additions & 5 deletions ui/src/services/syncs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ import {
CreateSyncPayload,
CreateSyncResponse,
DiscoverResponse,
ErrorResponse,
SyncRecordResponse,
SyncsConfigurationForTemplateMapping,
SyncRunsResponse,
TriggerManualSyncPayload,
ChangeSyncStatusPayload,
} from '@/views/Activate/Syncs/types';
import { multiwovenFetch, ApiResponse } from './common';
import { multiwovenFetch, ApiResponse, APIRequestMethod } from './common';

export const getCatalog = (
connectorId: string,
refresh: boolean = false,
): Promise<DiscoverResponse> =>
multiwovenFetch<null, DiscoverResponse>({
): Promise<ApiResponse<DiscoverResponse>> =>
multiwovenFetch<null, ApiResponse<DiscoverResponse>>({
method: 'get',
url: `/connectors/${connectorId}/discover?refresh=${refresh}`,
});
Expand All @@ -25,7 +26,7 @@ export const createSync = (payload: CreateSyncPayload): Promise<ApiResponse<Crea
data: payload,
});

export const fetchSyncs = (): Promise<ApiResponse<CreateSyncResponse[] | ErrorResponse>> =>
export const fetchSyncs = (): Promise<ApiResponse<CreateSyncResponse[]>> =>
multiwovenFetch<null, ApiResponse<CreateSyncResponse[]>>({
method: 'get',
url: `/syncs`,
Expand Down Expand Up @@ -90,3 +91,29 @@ export const getSyncsConfiguration = (): Promise<SyncsConfigurationForTemplateMa
method: 'get',
url: `/syncs/configurations`,
});

export const triggerManualSync = (
payload: TriggerManualSyncPayload,
method: APIRequestMethod,
): Promise<ApiResponse<CreateSyncResponse>> =>
multiwovenFetch<TriggerManualSyncPayload, ApiResponse<CreateSyncResponse>>({
method,
url: '/schedule_syncs',
data: payload,
});

export const cancelManualSyncSchedule = (id: string): Promise<ApiResponse<CreateSyncResponse>> =>
multiwovenFetch<null, ApiResponse<CreateSyncResponse>>({
method: 'delete',
url: `/schedule_syncs/${id}`,
});

export const changeSyncStatus = (
id: string,
payload: ChangeSyncStatusPayload,
): Promise<ApiResponse<CreateSyncResponse>> =>
multiwovenFetch<ChangeSyncStatusPayload, ApiResponse<CreateSyncResponse>>({
method: 'patch',
url: `/syncs/${id}/enable`,
data: payload,
});
Loading

0 comments on commit 3c44a0e

Please sign in to comment.