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 select header #823

Merged
merged 14 commits into from
Oct 4, 2024
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
15 changes: 6 additions & 9 deletions apps/api/src/app/mapping/mapping.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ import {
DoMapping,
GetMappings,
FinalizeUpload,
ReanameFileHeadings,
DoMappingCommand,
UpdateMappings,
ValidateMapping,
ReanameFileHeadings,
} from './usecases';

@Controller('/mapping')
Expand Down Expand Up @@ -56,13 +55,11 @@ export class MappingController {
]);

if (uploadInformation.status === UploadStatusEnum.UPLOADED) {
await this.doMapping.execute(
DoMappingCommand.create({
headings: uploadInformation.headings,
_templateId: uploadInformation._templateId,
_uploadId: uploadId,
})
);
await this.doMapping.execute({
headings: uploadInformation.headings,
_templateId: uploadInformation._templateId,
_uploadId: uploadId,
});
}

return this.getMappings.execute(uploadId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
import { IsArray, IsDefined, IsMongoId } from 'class-validator';
import { BaseCommand } from '@shared/commands/base.command';

export class DoMappingCommand extends BaseCommand {
@IsDefined()
@IsMongoId()
export class DoMappingCommand {
_uploadId: string;

@IsDefined()
@IsMongoId()
_templateId: string;

@IsDefined()
@IsArray()
headings: string[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface IBatchItem {
interface IRunData {
extra: any;
uploadId: string;
headerRow: number;
headings: string[];
csvFileStream: any;
dataStream: Writable;
Expand Down Expand Up @@ -392,6 +393,7 @@ export class BaseReview {
headings,
dateFormats,
dataStream,
headerRow,
uniqueCombinations,
numberColumnHeadings,
validationErrorMessages,
Expand All @@ -408,7 +410,7 @@ export class BaseReview {
totalRecords++;
const record = results.data;

if (totalRecords >= 1) {
if (totalRecords > headerRow) {
const recordObj: {
checkRecord: Record<string, unknown>;
passRecord: Record<string, unknown>;
Expand Down Expand Up @@ -574,8 +576,9 @@ export class BaseReview {
validator,
uploadId,
extra,
csvFileStream,
headerRow,
dateFormats,
csvFileStream,
uniqueCombinations,
numberColumnHeadings,
validationErrorMessages,
Expand All @@ -598,7 +601,7 @@ export class BaseReview {
checkRecord: Record<string, unknown>;
passRecord: Record<string, unknown>;
} = this.formatRecord({ headings, multiSelectColumnHeadings, record, numberColumnHeadings });
if (recordsCount >= 1) {
if (recordsCount > headerRow) {
const validationResultItem = this.validateRecord({
index: recordsCount,
checkRecord: recordObj.checkRecord,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ export class DoReview extends BaseReview {
numberColumnHeadings,
multiSelectColumnHeadings,
validationErrorMessages,
headerRow: uploadInfo.headerRow,
});

await this.processBatches({
Expand Down Expand Up @@ -185,6 +186,7 @@ export class DoReview extends BaseReview {
numberColumnHeadings,
validationErrorMessages,
multiSelectColumnHeadings,
headerRow: uploadInfo.headerRow,
});
response.invalidRecords = invalidRecords;
response.totalRecords = totalRecords;
Expand Down
18 changes: 18 additions & 0 deletions apps/api/src/app/upload/dtos/set-header.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsArray, IsNumber, IsOptional } from 'class-validator';

export class SetHeaderDto {
@ApiProperty({
description: 'Index of the header row',
})
@IsOptional()
@IsNumber()
index?: number;

@ApiProperty({
description: 'Headings of the header row',
type: [String],
})
@IsArray()
headings: string[];
}
29 changes: 28 additions & 1 deletion apps/api/src/app/upload/upload.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Get,
Param,
Post,
Put,
Query,
Res,
UploadedFile,
Expand All @@ -21,15 +22,18 @@ import { ApiTags, ApiSecurity, ApiConsumes, ApiOperation, ApiParam, ApiQuery, Ap

import { GetUpload, GetAsset } from './usecases';
import { JwtAuthGuard } from '@shared/framework/auth.gaurd';
import { getAssetMimeType, validateNotFound } from '@shared/helpers/common.helper';
import { validateUploadStatus } from '@shared/helpers/upload.helpers';
import { PaginationResponseDto } from '@shared/dtos/pagination-response.dto';
import { ValidateMongoId } from '@shared/validations/valid-mongo-id.validation';
import { ValidateTemplate } from '@shared/validations/valid-template.validation';
import { ValidImportFile } from '@shared/validations/valid-import-file.validation';
import { getAssetMimeType, validateNotFound } from '@shared/helpers/common.helper';

import { SetHeaderDto } from './dtos/set-header.dto';
import { UploadRequestDto } from './dtos/upload-request.dto';
import {
SetHeaderRow,
GetPreviewRows,
TerminateUpload,
MakeUploadEntry,
GetUploadColumns,
Expand All @@ -46,6 +50,8 @@ export class UploadController {
constructor(
private getAsset: GetAsset,
private getUpload: GetUpload,
private setHeaderRow: SetHeaderRow,
private getPreviewRows: GetPreviewRows,
private terminateUpload: TerminateUpload,
private makeUploadEntry: MakeUploadEntry,
private getUploadColumns: GetUploadColumns,
Expand Down Expand Up @@ -151,6 +157,27 @@ export class UploadController {
content.pipe(res);
}

@Get(':uploadId/preview')
@ApiOperation({
summary: 'Get rows of the uploaded file',
})
async getPreviewRowsRoute(@Param('uploadId') uploadId: string) {
const uploadData = await this.getUploadProcessInfo.execute(uploadId);

// throw error if upload information not found
validateNotFound(uploadData, 'upload');

return this.getPreviewRows.execute((uploadData._uploadedFileId as unknown as FileEntity).path);
}

@Put(':uploadId/header')
@ApiOperation({
summary: 'Set header row of the uploaded file',
})
async setHeaderRowRoute(@Param('uploadId') uploadId: string, @Body() body: SetHeaderDto) {
await this.setHeaderRow.execute(uploadId, body);
}

@Get(':uploadId/rows/valid')
@ApiOperation({
summary: 'Get valid rows of the uploaded file',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as Papa from 'papaparse';
import { Injectable } from '@nestjs/common';
import { StorageService } from '@impler/services';

@Injectable()
export class GetPreviewRows {
constructor(private storageServie: StorageService) {}

async execute(_uploadedFilePath: string) {
const csvFileStream = await this.storageServie.getFileStream(_uploadedFilePath);

return new Promise((resolve, reject) => {
Papa.parse(csvFileStream, {
dynamicTyping: false,
skipEmptyLines: true,
preview: 15,
complete({ data }) {
resolve(data);
},
error(error) {
reject(error);
},
});
});
}
}
6 changes: 6 additions & 0 deletions apps/api/src/app/upload/usecases/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { GetAsset } from './get-asset/get-asset.usecase';
import { GetUploadColumns } from './get-columns/get-columns.usecase';
import { SetHeaderRow } from './set-header-row/set-header-row.usecase';
import { GetUpload } from '@shared/usecases/get-upload/get-upload.usecase';
import { GetPreviewRows } from './get-preview-rows/get-preview-rows.usecase';
import { TerminateUpload } from './terminate-upload/terminate-upload.usecase';
import { MakeUploadEntry } from './make-upload-entry/make-upload-entry.usecase';
import { PaginateFileContent } from './paginate-file-content/paginate-file-content.usecase';
import { GetOriginalFileContent } from './get-original-file-content/get-original-file-content.usecase';
import { GetUploadProcessInformation } from './get-upload-process-info/get-upload-process-info.usecase';

export const USE_CASES = [
GetPreviewRows,
GetAsset,
GetUpload,
SetHeaderRow,
TerminateUpload,
MakeUploadEntry,
GetUploadColumns,
Expand All @@ -20,8 +24,10 @@ export const USE_CASES = [
];

export {
GetPreviewRows,
GetAsset,
GetUpload,
SetHeaderRow,
MakeUploadEntry,
TerminateUpload,
GetUploadColumns,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Injectable } from '@nestjs/common';
import { UploadRepository } from '@impler/dal';
import { ISetHeaderData } from '@impler/shared';

@Injectable()
export class SetHeaderRow {
constructor(private uploadRepository: UploadRepository) {}

async execute(_uploadId: string, data: ISetHeaderData) {
return this.uploadRepository.update(
{ _id: _uploadId },
{
$set: {
headings: data.headings,
headerRow: typeof data.index !== 'undefined' ? data.index : -1,
},
}
);
}
}
4 changes: 2 additions & 2 deletions apps/widget/src/components/Common/Container/Container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,9 @@ export function Container({ children }: PropsWithChildren<{}>) {
styles: {
root: {
borderRadius: 'var(--border-radius)',
backgroundColor: `var(--secondary-background)`,
backgroundColor: `var(--stepper-background)`,
'&:hover': {
backgroundColor: `var(--secondary-background-hover)`,
backgroundColor: `var(--secondary-background)`,
},
},
},
Expand Down
15 changes: 15 additions & 0 deletions apps/widget/src/components/Common/Footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,21 @@ export function Footer({
{texts['PHASE0-1'].GENERATE_TEMPLATE}
</Button>
),
[PhasesEnum.SELECT_HEADER]: (
<>
<Button
loading={secondaryButtonLoading}
disabled={secondaryButtonDisabled}
onClick={onPrevClick}
variant="outline"
>
{texts.SELECT_HEADER.FILE_DONT_HAVE_HEADERS}
</Button>
<Button loading={primaryButtonLoading} disabled={primaryButtonDisabled} onClick={onNextClick}>
{texts.SELECT_HEADER.CONFIRM_AND_CONTINUE}
</Button>
</>
),
[PhasesEnum.MAPPING]: (
<>
<Button
Expand Down
3 changes: 3 additions & 0 deletions apps/widget/src/components/Common/Heading/Heading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export function Heading({ active, title, mode, hasImageUpload, texts, onClose }:
{
label: texts.STEPPER_TITLES.UPLOAD_FILE,
},
{
label: texts.STEPPER_TITLES.SELECT_HEADER,
},
{
label: texts.STEPPER_TITLES.MAP_COLUMNS,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
border-color: var(--border-color) !important;
}
.handsontable th {
background-color: var(--secondary-background) !important;
background-color: var(--stepper-background) !important;
border-color: var(--border-color) !important;
}
.htCore thead tr th {
Expand Down
3 changes: 3 additions & 0 deletions apps/widget/src/components/Common/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ interface TableProps {
width?: string | number;
selectEnabled?: boolean;
afterRender?: () => void;
beforePaste?: () => void;
columnDefs: HotItemSchema[];
data?: Record<string, any>[];
columnDescriptions?: string[];
Expand All @@ -181,6 +182,7 @@ export const Table = forwardRef<HotTableClass, TableProps>(
headings,
columnDefs,
data,
beforePaste,
columnDescriptions,
allChecked,
onRowCheck,
Expand Down Expand Up @@ -278,6 +280,7 @@ export const Table = forwardRef<HotTableClass, TableProps>(
columns={columnDefs}
colHeaders={headings}
rowHeaders={rowHeaders}
beforePaste={beforePaste}
afterRender={afterRender}
minSpareRows={minSpareRows}
fixedColumnsLeft={frozenColumns}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import { colors, variables } from '@config';
import { logAmplitudeEvent } from '@amplitude';
import { FileDropzone } from '@ui/FileDropzone';
import { Footer } from 'components/Common/Footer';
import { usePhase01 } from '@hooks/Phase0-1/usePhase01';
import { useImageUpload } from '@hooks/ImageUpload/useImageUpload';
import { ImageWithIndicator } from '@ui/ImageWithIndicator';

interface Phase01Props {
interface ImageUploadProps {
goToUpload: () => void;
texts: typeof WIDGET_TEXTS;
}

export function Phase01({ goToUpload, texts }: Phase01Props) {
export function ImageUpload({ goToUpload, texts }: ImageUploadProps) {
const [showAlert, setShowAlert] = useLocalStorage<boolean>({
key: variables.SHOW_IMAGE_ALERT_STORAGE_KEY,
defaultValue: true,
Expand All @@ -33,7 +33,7 @@ export function Phase01({ goToUpload, texts }: Phase01Props) {
onRemoveImage,
isDownloadInProgress,
onGenerateTemplateClick,
} = usePhase01({ goToUpload });
} = useImageUpload({ goToUpload });
const wrapperRef = useRef<HTMLDivElement>() as React.MutableRefObject<HTMLDivElement>;
const [containerHeight, setContainerHeight] = useState<number>(200);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ImageUpload';
Loading
Loading