Skip to content

Commit

Permalink
feat prefilled dropdowns (#359)
Browse files Browse the repository at this point in the history
  • Loading branch information
chavda-bhavik committed Sep 6, 2023
2 parents 73ff970 + b49402b commit 1fc5158
Show file tree
Hide file tree
Showing 21 changed files with 133 additions and 75 deletions.
20 changes: 4 additions & 16 deletions apps/api/src/app/mapping/usecases/do-mapping/do-mapping.usecase.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,15 @@
import { Injectable } from '@nestjs/common';
import { Defaults, UploadStatusEnum } from '@impler/shared';
import { ColumnEntity, ColumnRepository, MappingEntity, MappingRepository, UploadRepository } from '@impler/dal';
import { ColumnEntity, MappingEntity, MappingRepository, UploadRepository } from '@impler/dal';
import { DoMappingCommand } from './do-mapping.command';

@Injectable()
export class DoMapping {
constructor(
private columnRepository: ColumnRepository,
private mappingRepository: MappingRepository,
private uploadRepository: UploadRepository
) {}
constructor(private mappingRepository: MappingRepository, private uploadRepository: UploadRepository) {}

async execute(command: DoMappingCommand) {
const columns = await this.columnRepository.find(
{
_templateId: command._templateId,
},
'key alternateKeys sequence',
{
sort: 'sequence',
}
);
const mapping = this.buildMapping(columns, command.headings, command._uploadId);
const uploadInfo = await this.uploadRepository.findById(command._uploadId, 'customSchema');
const mapping = this.buildMapping(JSON.parse(uploadInfo.customSchema), command.headings, command._uploadId);
const createdHeadings = await this.mappingRepository.createMany(mapping);
await this.uploadRepository.update({ _id: command._uploadId }, { status: UploadStatusEnum.MAPPING });

Expand Down
16 changes: 2 additions & 14 deletions apps/api/src/app/review/usecases/do-review/do-review.usecase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,9 @@ import addKeywords from 'ajv-keywords';
import { Injectable, BadRequestException } from '@nestjs/common';
import Ajv, { AnySchemaObject, ErrorObject, ValidateFunction } from 'ajv';

import {
ColumnRepository,
UploadRepository,
MappingRepository,
ColumnEntity,
ValidatorRepository,
FileRepository,
} from '@impler/dal';
import { StorageService } from '@impler/shared/dist/services/storage';
import { ColumnTypesEnum, FileMimeTypesEnum, UploadStatusEnum } from '@impler/shared';
import { UploadRepository, MappingRepository, ColumnEntity, ValidatorRepository, FileRepository } from '@impler/dal';

import { APIMessages } from '@shared/constants';
import { FileNameService } from '@shared/services';
Expand Down Expand Up @@ -82,7 +75,6 @@ export class DoReview {
constructor(
private uploadRepository: UploadRepository,
private storageService: StorageService,
private columnRepository: ColumnRepository,
private mappingRepository: MappingRepository,
private validatorRepository: ValidatorRepository,
private fileNameService: FileNameService,
Expand All @@ -96,11 +88,7 @@ export class DoReview {
throw new BadRequestException(APIMessages.UPLOAD_NOT_FOUND);
}
const mappings = await this.mappingRepository.getMappingWithColumnInfo(_uploadId);
const columns = await this.columnRepository.find(
{ _templateId: uploadInfo._templateId },
'isRequired isUnique selectValues type regex'
);
const schema = this.buildAJVSchema(columns, mappings);
const schema = this.buildAJVSchema(JSON.parse(uploadInfo.customSchema), mappings);
const validator = ajv.compile(schema);

const uploadedFileInfo = await this.fileRepository.findById(uploadInfo._uploadedFileId);
Expand Down
8 changes: 8 additions & 0 deletions apps/api/src/app/shared/helpers/common.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ export function validateNotFound(data: any, entityName: 'upload'): boolean {
}
}

export function mergeObjects(obj1: any, obj2: any, keysToMerge: string[]) {
for (const key of keysToMerge) {
if (obj2.hasOwnProperty(key)) {
obj1[key] = obj2[key];
}
}
}

export function paginateRecords(data: any[], page: number, limit: number): PaginationResult {
if (!page || Number(page) < Defaults.ONE) page = Defaults.ONE;
else page = Number(page);
Expand Down
8 changes: 8 additions & 0 deletions apps/api/src/app/upload/dtos/upload-request.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ export class UploadRequestDto {
@IsString()
authHeaderValue: string;

@ApiProperty({
description: 'Custom schema if provided by user',
required: false,
})
@IsOptional()
@IsJSON()
schema: string;

@ApiProperty({
description: 'Payload to send during webhook call',
required: false,
Expand Down
1 change: 1 addition & 0 deletions apps/api/src/app/upload/upload.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export class UploadController {
templateId,
extra: body.extra,
authHeaderValue: body.authHeaderValue,
schema: body.schema,
})
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,19 @@
import { IsDefined, IsString, IsOptional, IsJSON, IsArray, IsNumber } from 'class-validator';
import { BaseCommand } from '@shared/commands/base.command';

export class AddUploadEntryCommand extends BaseCommand {
@IsDefined()
@IsString()
export class AddUploadEntryCommand {
_templateId: string;

@IsOptional()
@IsString()
_allDataFileId?: string;

@IsDefined()
@IsString()
_uploadedFileId: string;

@IsDefined()
@IsString()
uploadId: string;

@IsOptional()
@IsJSON()
extra?: string;

@IsOptional()
@IsString()
authHeaderValue?: string;

@IsOptional()
@IsArray()
headings?: string[];

@IsOptional()
@IsNumber()
totalRecords?: number;

schema?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export class MakeUploadEntryCommand extends BaseCommand {
@IsJSON()
extra?: string;

@IsOptional()
@IsString()
schema?: string;

@IsOptional()
@IsString()
authHeaderValue?: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { Injectable } from '@nestjs/common';
import { FileMimeTypesEnum, UploadStatusEnum, Defaults } from '@impler/shared';
import { CommonRepository, FileEntity, FileRepository, TemplateRepository, UploadRepository } from '@impler/dal';
import { FileMimeTypesEnum, UploadStatusEnum, Defaults, ISchemaItem } from '@impler/shared';
import {
ColumnEntity,
ColumnRepository,
CommonRepository,
FileEntity,
FileRepository,
TemplateRepository,
UploadRepository,
} from '@impler/dal';

import { mergeObjects } from '@shared/helpers/common.helper';
import { AddUploadEntryCommand } from './add-upload-entry.command';
import { MakeUploadEntryCommand } from './make-upload-entry.command';
import { StorageService } from '@impler/shared/dist/services/storage';
Expand All @@ -15,10 +24,11 @@ export class MakeUploadEntry {
private fileRepository: FileRepository,
private storageService: StorageService,
private fileNameService: FileNameService,
private columnRepository: ColumnRepository,
private templateRepository: TemplateRepository
) {}

async execute({ file, templateId, extra, authHeaderValue }: MakeUploadEntryCommand) {
async execute({ file, templateId, extra, authHeaderValue, schema }: MakeUploadEntryCommand) {
const fileOriginalName = file.originalname;
let csvFile: string | Express.Multer.File = file;
if (file.mimetype === FileMimeTypesEnum.EXCEL || file.mimetype === FileMimeTypesEnum.EXCELX) {
Expand All @@ -30,6 +40,41 @@ export class MakeUploadEntry {
throw new Error('Invalid file type');
}

const columns = await this.columnRepository.find(
{
_templateId: templateId,
},
'key isRequired isUnique selectValues type regex sequence',
{
sort: 'sequence',
}
);
let parsedSchema: ISchemaItem[], combinedSchema: string;
try {
parsedSchema = JSON.parse(schema);
} catch (error) {}
if (Array.isArray(parsedSchema) && parsedSchema.length > 0) {
const formattedColumns: Record<string, ColumnEntity> = columns.reduce((acc, column) => {
acc[column.key] = { ...column };

return acc;
}, {});
parsedSchema.forEach((schemaItem) => {
if (formattedColumns.hasOwnProperty(schemaItem.key)) {
mergeObjects(formattedColumns[schemaItem.key], schemaItem, [
'isRequired',
'isUnique',
'selectValues',
'type',
'regex',
]);
}
});
combinedSchema = JSON.stringify(Object.values(formattedColumns));
} else {
combinedSchema = JSON.stringify(columns);
}

const fileService = new CSVFileService2();
const fileHeadings = await fileService.getFileHeaders(csvFile);
const uploadId = this.commonRepository.generateMongoId().toString();
Expand All @@ -44,16 +89,15 @@ export class MakeUploadEntry {
}
);

return this.addUploadEntry(
AddUploadEntryCommand.create({
_templateId: templateId,
_uploadedFileId: fileEntity._id,
uploadId,
extra,
authHeaderValue,
headings: fileHeadings,
})
);
return this.addUploadEntry({
_templateId: templateId,
_uploadedFileId: fileEntity._id,
uploadId,
extra,
authHeaderValue,
schema: combinedSchema,
headings: fileHeadings,
});
}

private async makeFileEntry(
Expand Down Expand Up @@ -86,6 +130,7 @@ export class MakeUploadEntry {
extra,
authHeaderValue,
headings,
schema,
totalRecords,
}: AddUploadEntryCommand) {
return this.uploadRepository.create({
Expand All @@ -94,6 +139,7 @@ export class MakeUploadEntry {
_templateId,
_allDataFileId,
extra: extra,
customSchema: schema,
headings: Array.isArray(headings) ? headings : [],
status: UploadStatusEnum.UPLOADED,
authHeaderValue: authHeaderValue,
Expand Down
1 change: 1 addition & 0 deletions apps/widget/src/components/Common/Container/Container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ export function Container({ children }: PropsWithChildren<{}>) {
>
<NotificationsProvider>
<Provider
schema={secondaryPayload?.schema}
title={secondaryPayload?.title}
// api
api={api}
Expand Down
18 changes: 15 additions & 3 deletions apps/widget/src/components/Common/Provider/Provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface IProviderProps {
// app-context
title?: string;
primaryColor: string;
schema?: string;
data?: Record<string, string | number>[];
// api-context
api: ApiService;
Expand All @@ -20,8 +21,19 @@ interface IProviderProps {
}

export function Provider(props: PropsWithChildren<IProviderProps>) {
const { api, data, title, projectId, templateId, accessToken, extra, authHeaderValue, children, primaryColor } =
props;
const {
api,
data,
title,
projectId,
templateId,
accessToken,
extra,
authHeaderValue,
children,
primaryColor,
schema,
} = props;

return (
<ImplerContextProvider
Expand All @@ -32,7 +44,7 @@ export function Provider(props: PropsWithChildren<IProviderProps>) {
authHeaderValue={authHeaderValue}
>
<APIContextProvider api={api}>
<AppContextProvider title={title} primaryColor={primaryColor} data={data}>
<AppContextProvider title={title} primaryColor={primaryColor} data={data} schema={schema}>
{children}
</AppContextProvider>
</APIContextProvider>
Expand Down
2 changes: 0 additions & 2 deletions apps/widget/src/design-system/Table/Table.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ export const getHeadingStyles = (theme: MantineTheme): React.CSSProperties => ({

export const getInvalidColumnStyles = (theme: MantineTheme): React.CSSProperties => ({
backgroundColor: colors.lightDanger,
display: 'flex',
gap: 2,
justifyContent: 'space-between',
});

Expand Down
3 changes: 2 additions & 1 deletion apps/widget/src/hooks/Phase1/usePhase1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface IUsePhase1Props {

export function usePhase1({ goNext }: IUsePhase1Props) {
const { api } = useAPIState();
const { setUploadInfo, setTemplateInfo, data } = useAppState();
const { setUploadInfo, setTemplateInfo, schema, data } = useAppState();
const [templates, setTemplates] = useState<IOption[]>([]);
const [isDownloadInProgress, setIsDownloadInProgress] = useState<boolean>(false);
const { projectId, templateId, authHeaderValue, extra } = useImplerState();
Expand Down Expand Up @@ -150,6 +150,7 @@ export function usePhase1({ goNext }: IUsePhase1Props) {
...submitData,
authHeaderValue,
extra,
schema,
});
}
};
Expand Down
4 changes: 2 additions & 2 deletions apps/widget/src/store/app.context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface AppContextProviderProps

const AppContext = createContext<IAppStore | null>(null);

const AppContextProvider = ({ children, primaryColor, title, data }: AppContextProviderProps) => {
const AppContextProvider = ({ children, primaryColor, title, data, schema }: AppContextProviderProps) => {
const [templateInfo, setTemplateInfo] = useState<ITemplate>({} as ITemplate);
const [uploadInfo, setUploadInfo] = useState<IUpload>({} as IUpload);

Expand All @@ -18,7 +18,7 @@ const AppContextProvider = ({ children, primaryColor, title, data }: AppContextP

return (
<AppContext.Provider
value={{ title, templateInfo, setTemplateInfo, uploadInfo, setUploadInfo, reset, primaryColor, data }}
value={{ title, templateInfo, setTemplateInfo, uploadInfo, setUploadInfo, reset, primaryColor, data, schema }}
>
{children}
</AppContext.Provider>
Expand Down
1 change: 1 addition & 0 deletions apps/widget/src/types/component.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ export interface IFormvalues {
export interface IUploadValues extends IFormvalues {
authHeaderValue?: string;
extra?: string;
schema?: string;
}
1 change: 1 addition & 0 deletions apps/widget/src/types/store.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface IAppStore {
uploadInfo: IUpload;
reset: () => void;
primaryColor: string;
schema?: string;
setTemplateInfo: (templateInfo: ITemplate) => void;
setUploadInfo: (uploadInfo: IUpload) => void;
}
2 changes: 2 additions & 0 deletions libs/dal/src/repositories/upload/upload.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@ export class UploadEntity {
extra: string;

processInvalidRecords: boolean;

customSchema: string;
}
1 change: 1 addition & 0 deletions libs/dal/src/repositories/upload/upload.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const uploadSchema = new Schema(
authHeaderValue: String,
status: String,
extra: String,
customSchema: String,
processInvalidRecords: {
type: Boolean,
default: false,
Expand Down
Loading

0 comments on commit 1fc5158

Please sign in to comment.