Skip to content

Commit

Permalink
feat: Added edge case to handle empty columns while importing (#242)
Browse files Browse the repository at this point in the history
  • Loading branch information
chavda-bhavik authored May 16, 2023
2 parents a8c6b51 + 5ec957c commit e8a95be
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 34 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
import { Injectable } from '@nestjs/common';
import { TemplateRepository } from '@impler/dal';
import { TemplateResponseDto } from 'app/template/dtos/template-response.dto';
import { TemplateRepository, CommonRepository } from '@impler/dal';
import { WidgetTemplateResponseDto } from 'app/template/dtos/widget-templates-response.dto';

@Injectable()
export class GetTemplates {
constructor(private templateRepository: TemplateRepository) {}
constructor(private templateRepository: TemplateRepository, private commonRepository: CommonRepository) {}

async execute(_projectId: string): Promise<TemplateResponseDto[]> {
const templates = await this.templateRepository.find({ _projectId });
async execute(_projectId: string): Promise<WidgetTemplateResponseDto[]> {
const templates = await this.templateRepository.aggregate([
{
$match: {
_projectId: this.commonRepository.generateMongoId(_projectId),
},
},
{ $addFields: { templateId: { $toString: '$_id' } } },
{
$lookup: {
from: 'columns',
localField: 'templateId',
foreignField: '_templateId',
as: 'columns',
pipeline: [
{
$project: {
_id: 1,
},
},
],
},
},
]);

return templates.map((template) => ({
_projectId: template._projectId,
Expand All @@ -20,6 +42,7 @@ export class GetTemplates {
totalInvalidRecords: template.totalInvalidRecords,
totalRecords: template.totalRecords,
authHeaderName: template.authHeaderName,
totalColumns: template.columns?.length,
}));
}
}
81 changes: 81 additions & 0 deletions apps/api/src/app/template/dtos/widget-templates-response.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsDefined, IsNumber, IsOptional, IsString } from 'class-validator';

export class WidgetTemplateResponseDto {
@ApiPropertyOptional({
description: 'Id of the template',
})
@IsString()
@IsDefined()
_id?: string;

@ApiProperty({
description: 'Name of the template',
})
@IsString()
@IsDefined()
name: string;

@ApiProperty({
description: 'Callback URL of the template, gets called when sending data to the application',
})
@IsString()
@IsOptional()
callbackUrl: string;

@ApiProperty({
description: 'Name of the header that gets sent to the application',
})
@IsString()
@IsOptional()
authHeaderName: string;

@ApiProperty({
description: 'Size of data in rows that gets sent to the application',
})
@IsNumber()
@IsDefined()
chunkSize: number;

@ApiProperty({
description: 'URL to download samle csv file',
})
@IsString()
@IsDefined()
sampleFileUrl: string;

@ApiProperty({
description: 'Id of project related to the template',
})
@IsString()
@IsDefined()
_projectId: string;

@ApiProperty({
description: 'Total columns available',
})
@IsNumber()
@IsDefined()
totalColumns: number;

@ApiProperty({
description: 'Total number of imports',
})
@IsNumber()
@IsDefined()
totalUploads: number;

@ApiProperty({
description: 'Total number of imported records',
})
@IsNumber()
@IsDefined()
totalRecords: number;

@ApiProperty({
description: 'Total number of invalid records',
})
@IsNumber()
@IsDefined()
totalInvalidRecords: number;
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class MakeUploadEntry {
async execute({ file, templateId, extra, authHeaderValue }: MakeUploadEntryCommand) {
const fileService: FileService = getFileService(file.mimetype);
const fileInformation = await fileService.getFileInformation(file, { headers: true });
const uploadId = this.commonRepository.generateMongoId();
const uploadId = this.commonRepository.generateMongoId().toString();
const fileEntity = await this.makeFileEntry(uploadId, file);
const allDataFile = await this.addAllDataEntry(uploadId, fileInformation.data);

Expand Down
2 changes: 1 addition & 1 deletion apps/widget/src/config/texts.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const TEXTS = {
NOTIFICATIONS: {
INCOMPLETE_TEMPLATE: {
title: 'Oops!',
message: 'It looks like selected Template is Incomplete, Please select another one!',
message: 'This import is empty! Please try again with a different import.',
},
TEMPLATE_NOT_FOUND: {
title: 'Oops!',
Expand Down
56 changes: 31 additions & 25 deletions apps/widget/src/hooks/Phase1/usePhase1.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useImplerState } from '@store/impler.context';
import { useMutation, useQuery } from '@tanstack/react-query';
Expand Down Expand Up @@ -36,6 +36,7 @@ export function usePhase1({ goNext }: IUsePhase1Props) {
onError(error: IErrorObject) {
notifier.showError({ message: error.message, title: error.error });
},
refetchOnWindowFocus: true,
});
const { isLoading: isUploadLoading, mutate: submitUpload } = useMutation<IUpload, IErrorObject, IUploadValues>(
['upload'],
Expand Down Expand Up @@ -68,10 +69,28 @@ export function usePhase1({ goNext }: IUsePhase1Props) {
register,
trigger,
getValues,
setValue,
handleSubmit,
formState: { errors },
} = useForm<IFormvalues>();

useEffect(() => {
if (templateId) setValue('templateId', templateId);
}, []);

const findTemplate = (): ITemplate | undefined => {
let foundTemplate: ITemplate | undefined;
const selectedTemplateValue = getValues('templateId');
if (selectedTemplateValue && dataTemplates) {
foundTemplate = dataTemplates.find((templateItem) => templateItem._id === selectedTemplateValue);
}
if (!foundTemplate) notifier.showError('TEMPLATE_NOT_FOUND');
else if (foundTemplate.totalColumns === variables.baseIndex) notifier.showError('INCOMPLETE_TEMPLATE');
else return foundTemplate;

return undefined;
};

const onDownload = async () => {
setIsDownloadInProgress(true);
const isTemplateValid = await trigger('templateId');
Expand All @@ -81,37 +100,24 @@ export function usePhase1({ goNext }: IUsePhase1Props) {
return;
}

let foundTemplate: ITemplate | undefined;
const selectedTemplateValue = getValues('templateId');
if (selectedTemplateValue && dataTemplates) {
foundTemplate = dataTemplates.find((templateItem) => templateItem._id === selectedTemplateValue);
}

const foundTemplate = findTemplate();
if (foundTemplate && foundTemplate.sampleFileUrl) {
getSignedUrl([foundTemplate.sampleFileUrl, foundTemplate.name + ' (sample).csv']);
} else if (foundTemplate && !foundTemplate.sampleFileUrl) notifier.showError('INCOMPLETE_TEMPLATE');
else notifier.showError('TEMPLATE_NOT_FOUND');
}
setIsDownloadInProgress(false);
};

const onSubmit = (submitData: IFormvalues) => {
if ((templateId || submitData.templateId) && dataTemplates) {
const foundTemplate = dataTemplates.find(
(templateItem) => templateItem._id === templateId || templateItem._id === submitData.templateId
);
if (foundTemplate) {
submitData.templateId = foundTemplate._id;
logAmplitudeEvent('UPLOAD', { fileSize: submitData.file.size, fileType: submitData.file.type });
submitUpload({
...submitData,
authHeaderValue,
extra,
});

return;
}
const foundTemplate = findTemplate();
if (foundTemplate) {
submitData.templateId = foundTemplate._id;
logAmplitudeEvent('UPLOAD', { fileSize: submitData.file.size, fileType: submitData.file.type });
submitUpload({
...submitData,
authHeaderValue,
extra,
});
}
notifier.showError('TEMPLATE_NOT_FOUND');
};

return {
Expand Down
4 changes: 2 additions & 2 deletions libs/dal/src/repositories/common/common.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class CommonRepository {
return Types.ObjectId.isValid(id);
}

generateMongoId(): string {
return new Types.ObjectId().toString();
generateMongoId(inputId?: string): Types.ObjectId {
return new Types.ObjectId(inputId);
}
}
1 change: 1 addition & 0 deletions libs/shared/src/entities/Template/Template.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface ITemplate {
chunkSize: number;
sampleFileUrl?: string;
_projectId: string;
totalColumns: number;
totalUploads: number;
totalRecords: number;
totalInvalidRecords: number;
Expand Down

0 comments on commit e8a95be

Please sign in to comment.