Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat prefilled dropdowns #359

Merged
merged 3 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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