diff --git a/apps/api/src/app/template/template.controller.ts b/apps/api/src/app/template/template.controller.ts index d3c74d1e6..0add2b252 100644 --- a/apps/api/src/app/template/template.controller.ts +++ b/apps/api/src/app/template/template.controller.ts @@ -15,6 +15,7 @@ import { CreateTemplate, DeleteTemplate, UpdateTemplate, + SyncCustomization, GetTemplateDetails, GetUploadsCommand, CreateTemplateCommand, @@ -47,17 +48,18 @@ import { UpdateCustomizationRequestDto } from './dtos/update-customization-reque @UseGuards(JwtAuthGuard) export class TemplateController { constructor( - private getTemplateColumns: GetTemplateColumns, private getUploads: GetUploads, private getValidations: GetValidations, private downloadSample: DownloadSample, private getCustomization: GetCustomization, private updateValidations: UpdateValidations, - private updateCustomization: UpdateCustomization, + private syncCustomization: SyncCustomization, private createTemplateUsecase: CreateTemplate, private updateTemplateUsecase: UpdateTemplate, private deleteTemplateUsecase: DeleteTemplate, + private getTemplateColumns: GetTemplateColumns, private getTemplateDetails: GetTemplateDetails, + private updateCustomization: UpdateCustomization, private updateTemplateColumns: UpdateTemplateColumns ) {} @@ -205,6 +207,7 @@ export class TemplateController { ); } + // Customization @Get(':templateId/customizations') @ApiOperation({ summary: 'Get template customizations', @@ -230,6 +233,20 @@ export class TemplateController { return this.updateCustomization.execute(templateId, UpdateCustomizationCommand.create(body)); } + @Put(':templateId/customizations/sync') + @ApiOperation({ + summary: 'Sync template customizations', + }) + @ApiOkResponse({ + type: CustomizationResponseDto, + }) + async syncCustomizationRoute( + @Param('templateId', ValidateMongoId) templateId: string + ): Promise { + return this.syncCustomization.execute(templateId); + } + + // Validations @Get(':templateId/validations') @ApiOperation({ summary: 'Get template validations', diff --git a/apps/api/src/app/template/usecases/index.ts b/apps/api/src/app/template/usecases/index.ts index 403b9fa07..922550243 100644 --- a/apps/api/src/app/template/usecases/index.ts +++ b/apps/api/src/app/template/usecases/index.ts @@ -4,13 +4,14 @@ import { CreateTemplate } from './create-template/create-template.usecase'; import { UpdateTemplate } from './update-template/update-template.usecase'; import { DeleteTemplate } from './delete-template/delete-template.usecase'; import { DownloadSample } from './download-sample/download-sample.usecase'; -import { GetTemplateDetails } from './get-template-details/get-template-details.usecase'; -import { UpdateTemplateColumns } from './update-template-columns/update-template-columns.usecase'; -import { UpdateCustomization } from './update-customization/update-customization.usecase'; +import { GetValidations } from './get-validations/get-validations.usecase'; import { GetCustomization } from './get-customization/get-customization.usecase'; +import { SyncCustomization } from './sync-customization/sync-customization.usecase'; import { UpdateValidations } from './update-validations/update-validations.usecase'; -import { GetValidations } from './get-validations/get-validations.usecase'; +import { GetTemplateDetails } from './get-template-details/get-template-details.usecase'; +import { UpdateCustomization } from './update-customization/update-customization.usecase'; import { SaveSampleFile } from '@shared/usecases/save-sample-file/save-sample-file.usecase'; +import { UpdateTemplateColumns } from './update-template-columns/update-template-columns.usecase'; import { GetUploadsCommand } from './get-uploads/get-uploads.command'; import { CreateTemplateCommand } from './create-template/create-template.command'; @@ -24,6 +25,7 @@ export const USE_CASES = [ DeleteTemplate, GetTemplateDetails, GetUploads, + SyncCustomization, GetTemplateColumns, UpdateTemplateColumns, UpdateCustomization, @@ -39,6 +41,7 @@ export { CreateTemplate, UpdateTemplate, DeleteTemplate, + SyncCustomization, GetTemplateDetails, GetUploads, GetTemplateColumns, diff --git a/apps/api/src/app/template/usecases/sync-customization/sync-customization.usecase.ts b/apps/api/src/app/template/usecases/sync-customization/sync-customization.usecase.ts new file mode 100644 index 000000000..c1e0c3253 --- /dev/null +++ b/apps/api/src/app/template/usecases/sync-customization/sync-customization.usecase.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@nestjs/common'; + +import { CONSTANTS } from '@shared/constants'; +import { createRecordFormat, updateCombinedFormat } from '@impler/shared'; +import { CustomizationRepository } from '@impler/dal'; + +@Injectable() +export class SyncCustomization { + constructor(private customizationRepository: CustomizationRepository) {} + + async execute(_templateId: string) { + const customization = await this.customizationRepository.findOne({ + _templateId, + }); + customization.isChunkFormatUpdated = false; + customization.isRecordFormatUpdated = false; + customization.isCombinedFormatUpdated = false; + + customization.recordFormat = createRecordFormat(customization.recordVariables); + customization.combinedFormat = updateCombinedFormat(CONSTANTS.COMBINED_FORMAT, customization.recordVariables); + + await this.customizationRepository.update({ _templateId }, customization); + + return customization; + } +} diff --git a/apps/api/src/app/template/usecases/update-customization/update-customization.usecase.ts b/apps/api/src/app/template/usecases/update-customization/update-customization.usecase.ts index 3a9056e56..1dfec752d 100644 --- a/apps/api/src/app/template/usecases/update-customization/update-customization.usecase.ts +++ b/apps/api/src/app/template/usecases/update-customization/update-customization.usecase.ts @@ -1,5 +1,5 @@ import { CustomizationRepository } from '@impler/dal'; -import { createVariable, getRecordFormat } from '@impler/shared'; +import { getRecordFormat } from '@impler/shared'; import { HttpException, Injectable } from '@nestjs/common'; import { UpdateCustomizationCommand } from './update-customization.command'; @@ -25,7 +25,7 @@ export class UpdateCustomization { throw new DocumentNotFoundException('Customization', _templateId); } - this.customizationRepository.findOneAndUpdate( + return this.customizationRepository.findOneAndUpdate( { _templateId, }, @@ -36,11 +36,5 @@ export class UpdateCustomization { isChunkFormatUpdated: data.chunkFormat !== customization.chunkFormat, } ); - - return { - ...customization, - recordVariables: customization.recordVariables?.map((variable) => createVariable(variable)), - chunkVariables: customization.chunkVariables?.map((variable) => createVariable(variable)), - }; } } diff --git a/apps/api/src/app/template/usecases/update-template-columns/update-template-columns.usecase.ts b/apps/api/src/app/template/usecases/update-template-columns/update-template-columns.usecase.ts index 2a11c28f2..539ddee86 100644 --- a/apps/api/src/app/template/usecases/update-template-columns/update-template-columns.usecase.ts +++ b/apps/api/src/app/template/usecases/update-template-columns/update-template-columns.usecase.ts @@ -43,12 +43,12 @@ export class UpdateTemplateColumns { customizationUpdate.recordVariables = this.listRecordVariables(data); if (!customization.isRecordFormatUpdated) { - customizationUpdate.recordFormat = createRecordFormat(customization.recordVariables); + customizationUpdate.recordFormat = createRecordFormat(customizationUpdate.recordVariables); } if (!customization.isCombinedFormatUpdated) { customizationUpdate.combinedFormat = updateCombinedFormat( CONSTANTS.COMBINED_FORMAT, - customization.recordVariables + customizationUpdate.recordVariables ); } diff --git a/apps/web/assets/icons/Warning.icon.tsx b/apps/web/assets/icons/Warning.icon.tsx new file mode 100644 index 000000000..f1a9c0b7e --- /dev/null +++ b/apps/web/assets/icons/Warning.icon.tsx @@ -0,0 +1,17 @@ +import { IconType } from '@types'; +import { IconSizes } from 'config'; + +export const WarningIcon = ({ size = 'sm', color }: IconType) => { + return ( + + + + ); +}; diff --git a/apps/web/components/imports/editor/Editor.tsx b/apps/web/components/imports/editor/Editor.tsx index 785740294..7e7a931bb 100644 --- a/apps/web/components/imports/editor/Editor.tsx +++ b/apps/web/components/imports/editor/Editor.tsx @@ -1,15 +1,17 @@ import { Controller } from 'react-hook-form'; -import { Group, Title, Text, useMantineColorScheme, Flex, Alert, Code, Stack } from '@mantine/core'; +import { Group, Title, Text, useMantineColorScheme, Flex, Code, Stack } from '@mantine/core'; import { colors } from '@config'; import { Button } from '@ui/button'; import { Editor } from '@ui/editor/Editor'; import { useEditor } from '@hooks/useEditor'; +import { Alert } from '@ui/Alert'; import { VarLabel } from './VarLabel'; import { VarItemWrapper } from './VarItemWrapper'; -import { PossibleJSONErrors } from '@components/common/PossibleJsonErrors'; +import { WarningIcon } from '@assets/icons/Warning.icon'; import { InformationIcon } from '@assets/icons/Information.icon'; +import { PossibleJSONErrors } from '@components/common/PossibleJsonErrors'; interface OutputEditorProps { templateId: string; @@ -17,7 +19,9 @@ interface OutputEditorProps { export function OutputEditor({ templateId }: OutputEditorProps) { const { colorScheme } = useMantineColorScheme(); - const { customization, control, errors, onSaveClick } = useEditor({ templateId }); + const { customization, control, errors, onSaveClick, syncCustomization, isSyncCustomizationLoading } = useEditor({ + templateId, + }); return ( @@ -33,9 +37,19 @@ export function OutputEditor({ templateId }: OutputEditorProps) { - } p="xs"> + } p="xs"> {`%%`} will be used to loop over data items. + {customization?.isCombinedFormatUpdated && ( + }> + + Format is updated manually. The update in schema will not reflact automatically in output. + + + + )}
( ({ + alignItems: 'center', +}); + +export default createStyles((): Record => { + return { + wrapper: getWrapperStyles(), + }; +}); diff --git a/apps/web/design-system/Alert/Alert.tsx b/apps/web/design-system/Alert/Alert.tsx new file mode 100644 index 000000000..5ebea6767 --- /dev/null +++ b/apps/web/design-system/Alert/Alert.tsx @@ -0,0 +1,11 @@ +import { Alert as MantineAlert, AlertProps as MantineAlertProps } from '@mantine/core'; + +import useStyles from './Alert.styles'; + +type AlertProps = MantineAlertProps; + +export function Alert(props: AlertProps) { + const { classes } = useStyles(); + + return ; +} diff --git a/apps/web/design-system/Alert/index.ts b/apps/web/design-system/Alert/index.ts new file mode 100644 index 000000000..79e3b155f --- /dev/null +++ b/apps/web/design-system/Alert/index.ts @@ -0,0 +1 @@ +export * from './Alert'; diff --git a/apps/web/hooks/useEditor.tsx b/apps/web/hooks/useEditor.tsx index fd23fb393..5d6c7a73e 100644 --- a/apps/web/hooks/useEditor.tsx +++ b/apps/web/hooks/useEditor.tsx @@ -21,6 +21,7 @@ export function useEditor({ templateId }: UseEditorProps) { reset, control, setError, + setValue, handleSubmit, formState: { errors }, } = useForm(); @@ -63,6 +64,21 @@ export function useEditor({ templateId }: UseEditorProps) { }, } ); + const { mutate: syncCustomization, isLoading: isSyncCustomizationLoading } = useMutation< + ICustomization, + IErrorObject, + void, + string[] + >( + [API_KEYS.TEMPLATE_CUSTOMIZATION_UPDATE, templateId], + () => commonApi(API_KEYS.TEMPLATE_CUSTOMIZATION_SYNC as any, { parameters: [templateId] }), + { + onSuccess(data) { + queryClient.setQueryData([API_KEYS.TEMPLATE_CUSTOMIZATION_GET, templateId], data); + setValue('combinedFormat', data.combinedFormat); + }, + } + ); const validateFormat = (data: string): boolean => { try { @@ -100,8 +116,10 @@ export function useEditor({ templateId }: UseEditorProps) { onSaveClick, handleSubmit, customization, + syncCustomization, updateCustomization, isCustomizationLoading, + isSyncCustomizationLoading, isUpdateCustomizationLoading, }; } diff --git a/apps/web/libs/api.ts b/apps/web/libs/api.ts index d0495e199..95289f9c9 100644 --- a/apps/web/libs/api.ts +++ b/apps/web/libs/api.ts @@ -80,6 +80,10 @@ const routes: Record = { url: (templateId) => `/v1/template/${templateId}/customizations`, method: 'PUT', }, + [API_KEYS.TEMPLATE_CUSTOMIZATION_SYNC]: { + url: (templateId) => `/v1/template/${templateId}/customizations/sync`, + method: 'PUT', + }, [API_KEYS.COLUMN_CREATE]: { url: (templateId) => `/v1/column/${templateId}`, method: 'POST', diff --git a/apps/web/libs/notify.ts b/apps/web/libs/notify.ts index 8b8145a0b..7d0fc3079 100644 --- a/apps/web/libs/notify.ts +++ b/apps/web/libs/notify.ts @@ -7,12 +7,12 @@ const Messages: Record = { message: 'Import details has been updated', }, [NOTIFICATION_KEYS.IMPORT_CREATED]: { - title: 'Import record created', - message: 'Import record has been created successfully', + title: 'Import created', + message: 'Import has been created successfully', }, [NOTIFICATION_KEYS.IMPORT_DELETED]: { - title: 'Import record deleted', - message: 'Import record has been deleted successfully', + title: 'Import deleted', + message: 'Import has been deleted successfully', }, [NOTIFICATION_KEYS.DESTINATION_UPDATED]: { title: 'Destination details updated',