From 973d1832bdb8256928d5b38cdd1e98627d36362e Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Fri, 22 Mar 2024 20:45:05 +0200 Subject: [PATCH] fix: import accounts issue --- .../server/src/api/controllers/Accounts.ts | 2 +- packages/server/src/interfaces/Model.ts | 3 ++ .../server/src/models/Account.Settings.ts | 8 +++-- .../src/services/Import/ImportFileUpload.ts | 28 ++++++++++++--- .../server/src/services/Import/interfaces.ts | 10 ++++-- .../webapp/src/components/Hint/FieldHint.tsx | 17 +++++++-- .../webapp/src/components/Layout/Box/Box.tsx | 3 +- .../Import/ImportFileMapping.module.scss | 7 +++- .../containers/Import/ImportFileMapping.tsx | 36 +++++++++++-------- .../Import/ImportFileMappingForm.tsx | 25 +++++++------ .../containers/Import/ImportFilePreview.tsx | 6 ++++ .../Import/ImportFilePreviewBoot.tsx | 13 +++++-- .../containers/Import/ImportFileProvider.tsx | 11 ++++-- packages/webapp/src/routes/dashboard.tsx | 4 +-- 14 files changed, 125 insertions(+), 48 deletions(-) diff --git a/packages/server/src/api/controllers/Accounts.ts b/packages/server/src/api/controllers/Accounts.ts index 297201ae7..0930a9014 100644 --- a/packages/server/src/api/controllers/Accounts.ts +++ b/packages/server/src/api/controllers/Accounts.ts @@ -349,7 +349,7 @@ export default class AccountsController extends BaseController { // Filter query. const filter = { sortOrder: 'desc', - columnSortBy: 'created_at', + columnSortBy: 'createdAt', inactiveMode: false, structure: IAccountsStructureType.Tree, ...this.matchedQueryData(req), diff --git a/packages/server/src/interfaces/Model.ts b/packages/server/src/interfaces/Model.ts index 385bce172..96ba461c0 100644 --- a/packages/server/src/interfaces/Model.ts +++ b/packages/server/src/interfaces/Model.ts @@ -1,3 +1,4 @@ + export interface IModel { name: string; tableName: string; @@ -35,6 +36,8 @@ export interface IModelMetaFieldCommon { fieldType: IModelColumnType; customQuery?: Function; required?: boolean; + importHint?: string; + order?: number; } export interface IModelMetaFieldNumber { diff --git a/packages/server/src/models/Account.Settings.ts b/packages/server/src/models/Account.Settings.ts index ec67885c4..c52f3c022 100644 --- a/packages/server/src/models/Account.Settings.ts +++ b/packages/server/src/models/Account.Settings.ts @@ -15,6 +15,7 @@ export default { unique: true, required: true, importable: true, + order: 1, }, description: { name: 'account.field.description', @@ -37,6 +38,7 @@ export default { importable: true, minLength: 3, maxLength: 6, + importHint: 'Unique number to identify the account.', }, rootType: { name: 'account.field.root_type', @@ -73,6 +75,7 @@ export default { })), required: true, importable: true, + order: 2, }, active: { name: 'account.field.active', @@ -81,11 +84,11 @@ export default { filterable: false, importable: true, }, - openingBalance: { + balance: { name: 'account.field.balance', column: 'amount', fieldType: 'number', - importable: true, + importable: false, }, currencyCode: { name: 'account.field.currency', @@ -99,6 +102,7 @@ export default { column: 'parent_account_id', fieldType: 'relation', to: { model: 'Account', to: 'id' }, + importable: false, }, createdAt: { name: 'account.field.created_at', diff --git a/packages/server/src/services/Import/ImportFileUpload.ts b/packages/server/src/services/Import/ImportFileUpload.ts index 19135d94a..fc4a805eb 100644 --- a/packages/server/src/services/Import/ImportFileUpload.ts +++ b/packages/server/src/services/Import/ImportFileUpload.ts @@ -61,20 +61,38 @@ export class ImportFileUploadService { resource: _resourceName, columns: coumnsStringified, }); - const resourceColumns = this.resourceService.getResourceImportableFields( + const resourceColumnsMap = this.resourceService.getResourceImportableFields( tenantId, _resourceName ); - const resourceColumnsTransformeed = Object.entries(resourceColumns).map( - ([key, { name }]: [string, IModelMetaField]) => ({ key, name }) - ); + const resourceColumns = this.getResourceColumns(resourceColumnsMap); + return { import: { importId: importFile.importId, resource: importFile.resource, }, sheetColumns, - resourceColumns: resourceColumnsTransformeed, + resourceColumns, }; } + + getResourceColumns(resourceColumns: { [key: string]: IModelMetaField }) { + return Object.entries(resourceColumns) + .map( + ([key, { name, importHint, required, order }]: [ + string, + IModelMetaField + ]) => ({ + key, + name, + required, + hint: importHint, + order, + }) + ) + .sort((a, b) => + a.order && b.order ? a.order - b.order : a.order ? -1 : b.order ? 1 : 0 + ); + } } diff --git a/packages/server/src/services/Import/interfaces.ts b/packages/server/src/services/Import/interfaces.ts index 3eca339f7..ab6bf5c38 100644 --- a/packages/server/src/services/Import/interfaces.ts +++ b/packages/server/src/services/Import/interfaces.ts @@ -25,7 +25,12 @@ export interface ImportFileUploadPOJO { resource: string; }; sheetColumns: string[]; - resourceColumns: { key: string; name: string }[]; + resourceColumns: { + key: string; + name: string; + required?: boolean; + hint?: string; + }[]; } export interface ImportFileMapPOJO { @@ -45,7 +50,6 @@ export interface ImportFilePreviewPOJO { unmappedColumnsCount: number; } - export interface ImportOperSuccess { data: unknown; index: number; @@ -54,4 +58,4 @@ export interface ImportOperSuccess { export interface ImportOperError { error: ImportInsertError; index: number; -} \ No newline at end of file +} diff --git a/packages/webapp/src/components/Hint/FieldHint.tsx b/packages/webapp/src/components/Hint/FieldHint.tsx index eee87299f..796600a85 100644 --- a/packages/webapp/src/components/Hint/FieldHint.tsx +++ b/packages/webapp/src/components/Hint/FieldHint.tsx @@ -1,14 +1,27 @@ // @ts-nocheck import React from 'react'; -import { Tooltip } from '@blueprintjs/core'; +import { Position, Tooltip } from '@blueprintjs/core'; import { Icon } from '../Icon'; import '@/style/components/Hint.scss'; +import { Tooltip2Props } from '@blueprintjs/popover2'; + +interface HintProps { + content: string; + position?: Position; + iconSize?: number; + tooltipProps?: Partial; +} /** * Field hint. */ -export function FieldHint({ content, position, iconSize = 12, tooltipProps }) { +export function FieldHint({ + content, + position, + iconSize = 12, + tooltipProps, +}: HintProps) { return ( diff --git a/packages/webapp/src/components/Layout/Box/Box.tsx b/packages/webapp/src/components/Layout/Box/Box.tsx index fdc7fd949..15acc305b 100644 --- a/packages/webapp/src/components/Layout/Box/Box.tsx +++ b/packages/webapp/src/components/Layout/Box/Box.tsx @@ -1,6 +1,7 @@ import React from 'react'; +import { HTMLDivProps, Props } from '@blueprintjs/core'; -export interface BoxProps { +export interface BoxProps extends Props, HTMLDivProps { className?: string; } diff --git a/packages/webapp/src/containers/Import/ImportFileMapping.module.scss b/packages/webapp/src/containers/Import/ImportFileMapping.module.scss index 873dcf043..4885aeb34 100644 --- a/packages/webapp/src/containers/Import/ImportFileMapping.module.scss +++ b/packages/webapp/src/containers/Import/ImportFileMapping.module.scss @@ -23,9 +23,14 @@ } tr td{ - :global(.bp4-popover-target .bp4-button){ + :global(.bp4-popover-target .bp4-button), + :global(.bp4-popover-wrapper){ max-width: 250px; } } } +} + +.requiredSign{ + color: rgb(250, 82, 82); } \ No newline at end of file diff --git a/packages/webapp/src/containers/Import/ImportFileMapping.tsx b/packages/webapp/src/containers/Import/ImportFileMapping.tsx index b0ccb24ca..b5b387b28 100644 --- a/packages/webapp/src/containers/Import/ImportFileMapping.tsx +++ b/packages/webapp/src/containers/Import/ImportFileMapping.tsx @@ -1,10 +1,10 @@ import { useMemo } from 'react'; import clsx from 'classnames'; -import { Button, Intent } from '@blueprintjs/core'; +import { Button, Intent, Position } from '@blueprintjs/core'; import { useFormikContext } from 'formik'; -import { FSelect, Group } from '@/components'; +import { FSelect, Group, Hint } from '@/components'; import { ImportFileMappingForm } from './ImportFileMappingForm'; -import { useImportFileContext } from './ImportFileProvider'; +import { EntityColumn, useImportFileContext } from './ImportFileProvider'; import { CLASSES } from '@/constants'; import { ImportFileContainer } from './ImportFileContainer'; import styles from './ImportFileMapping.module.scss'; @@ -44,21 +44,29 @@ function ImportFileMappingFields() { () => sheetColumns.map((column) => ({ value: column, text: column })), [sheetColumns], ); - - const columns = entityColumns.map((column, index) => ( + const columnMapper = (column: EntityColumn, index: number) => ( - {column.name} + + {column.name}{' '} + {column.required && *} + - + + + {column.hint && ( + + )} + - )); + ); + const columns = entityColumns.map(columnMapper); return <>{columns}; } diff --git a/packages/webapp/src/containers/Import/ImportFileMappingForm.tsx b/packages/webapp/src/containers/Import/ImportFileMappingForm.tsx index ebe8e2f16..a518fe3ea 100644 --- a/packages/webapp/src/containers/Import/ImportFileMappingForm.tsx +++ b/packages/webapp/src/containers/Import/ImportFileMappingForm.tsx @@ -4,7 +4,7 @@ import { useImportFileMapping } from '@/hooks/query/import'; import { Form, Formik, FormikHelpers } from 'formik'; import { useImportFileContext } from './ImportFileProvider'; import { useMemo } from 'react'; -import { isEmpty } from 'lodash'; +import { isEmpty, lowerCase } from 'lodash'; import { AppToaster } from '@/components'; interface ImportFileMappingFormProps { @@ -34,21 +34,18 @@ export function ImportFileMappingForm({ setStep(2); }) .catch(({ response: { data } }) => { - if (data.errors.find(e => e.type === "DUPLICATED_FROM_MAP_ATTR")) { + if (data.errors.find((e) => e.type === 'DUPLICATED_FROM_MAP_ATTR')) { AppToaster.show({ message: 'Selected the same sheet columns to multiple fields.', - intent: Intent.DANGER - }) + intent: Intent.DANGER, + }); } setSubmitting(false); }); }; return ( - +
{children}
); @@ -62,14 +59,20 @@ const transformValueToReq = (value: ImportFileMappingFormValues) => { }; const useImportFileMappingInitialValues = () => { - const { entityColumns } = useImportFileContext(); + const { entityColumns, sheetColumns } = useImportFileContext(); return useMemo( () => entityColumns.reduce((acc, { key, name }) => { - acc[key] = ''; + const _name = lowerCase(name); + const _matched = sheetColumns.find( + (column) => lowerCase(column) === _name, + ); + // Match the default column name the same field name + // if matched one of sheet columns has the same field name. + acc[key] = _matched ? _matched : ''; return acc; }, {}), - [entityColumns], + [entityColumns, sheetColumns], ); }; diff --git a/packages/webapp/src/containers/Import/ImportFilePreview.tsx b/packages/webapp/src/containers/Import/ImportFilePreview.tsx index 326d72f73..552c75713 100644 --- a/packages/webapp/src/containers/Import/ImportFilePreview.tsx +++ b/packages/webapp/src/containers/Import/ImportFilePreview.tsx @@ -83,6 +83,9 @@ function ImportFilePreviewImported() { function ImportFilePreviewSkipped() { const { importPreview } = useImportFilePreviewBootContext(); + // Can't continue if there's no skipped items. + if (importPreview.skippedCount <= 0) return null; + return (
- {isImportPreviewLoading ? 'loading' : <>{children}} + {isImportPreviewLoading ? ( + + + + ) : ( + <>{children} + )} ); }; diff --git a/packages/webapp/src/containers/Import/ImportFileProvider.tsx b/packages/webapp/src/containers/Import/ImportFileProvider.tsx index a28ef5ac1..387c21f8c 100644 --- a/packages/webapp/src/containers/Import/ImportFileProvider.tsx +++ b/packages/webapp/src/containers/Import/ImportFileProvider.tsx @@ -7,9 +7,14 @@ import React, { useState, } from 'react'; -type EntityColumn = { key: string; name: string }; -type SheetColumn = string; -type SheetMap = { from: string; to: string }; +export type EntityColumn = { + key: string; + name: string; + required?: boolean; + hint?: string; +}; +export type SheetColumn = string; +export type SheetMap = { from: string; to: string }; interface ImportFileContextValue { sheetColumns: SheetColumn[]; diff --git a/packages/webapp/src/routes/dashboard.tsx b/packages/webapp/src/routes/dashboard.tsx index d2d69e450..415ce009d 100644 --- a/packages/webapp/src/routes/dashboard.tsx +++ b/packages/webapp/src/routes/dashboard.tsx @@ -13,8 +13,8 @@ export const getDashboardRoutes = () => [ { path: '/accounts/import', component: lazy(() => import('@/containers/Import/ImportPage')), - breadcrumb: 'Import Accounts', - pageTitle: 'Import Accounts', + breadcrumb: 'Accounts Import', + pageTitle: 'Accounts Import', }, { path: `/accounts`,