Minor: improve the entity export modal feedback message (#18526)

(cherry picked from commit 305f02c62a86a380f65e6ada7e9e2f1d22052aca)
This commit is contained in:
Sachin Chaurasiya 2024-11-06 21:05:07 +05:30
parent 1995b17a8d
commit 7d3a1b0a9e
4 changed files with 34 additions and 26 deletions

View File

@ -12,12 +12,13 @@
*/ */
import { Form, Input, Modal } from 'antd'; import { Form, Input, Modal } from 'antd';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import classNames from 'classnames';
import { isString } from 'lodash'; import { isString } from 'lodash';
import React, { ReactNode, useEffect, useMemo, useRef, useState } from 'react'; import React, { ReactNode, useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { getCurrentISODate } from '../../../utils/date-time/DateTimeUtils'; import { getCurrentISODate } from '../../../utils/date-time/DateTimeUtils';
import { showErrorToast } from '../../../utils/ToastUtils'; import { showErrorToast } from '../../../utils/ToastUtils';
import Banner, { BannerProps } from '../../common/Banner/Banner'; import Banner from '../../common/Banner/Banner';
import { import {
CSVExportJob, CSVExportJob,
CSVExportWebsocketResponse, CSVExportWebsocketResponse,
@ -149,16 +150,6 @@ export const EntityExportModalProvider = ({
[] []
); );
const bannerConfig = useMemo(() => {
const isCompleted = csvExportJob?.status === 'COMPLETED';
return {
type: isCompleted ? 'success' : 'error',
message: isCompleted ? csvExportJob?.message : csvExportJob?.error,
hasJobId: !!csvExportJob?.jobId,
};
}, [csvExportJob]);
return ( return (
<EntityExportModalContext.Provider value={providerValue}> <EntityExportModalContext.Provider value={providerValue}>
<> <>
@ -169,13 +160,13 @@ export const EntityExportModalProvider = ({
open open
cancelText={t('label.cancel')} cancelText={t('label.cancel')}
closable={false} closable={false}
confirmLoading={downloading}
data-testid="export-entity-modal" data-testid="export-entity-modal"
maskClosable={false} maskClosable={false}
okButtonProps={{ okButtonProps={{
form: 'export-form', form: 'export-form',
htmlType: 'submit', htmlType: 'submit',
id: 'submit-button', id: 'submit-button',
disabled: downloading,
}} }}
okText={t('label.export')} okText={t('label.export')}
title={exportData.title ?? t('label.export')} title={exportData.title ?? t('label.export')}
@ -186,6 +177,7 @@ export const EntityExportModalProvider = ({
layout="vertical" layout="vertical"
onFinish={handleExport}> onFinish={handleExport}>
<Form.Item <Form.Item
className={classNames({ 'mb-0': !csvExportJob?.jobId })}
label={`${t('label.entity-name', { label={`${t('label.entity-name', {
entity: t('label.file'), entity: t('label.file'),
})}:`} })}:`}
@ -194,11 +186,12 @@ export const EntityExportModalProvider = ({
</Form.Item> </Form.Item>
</Form> </Form>
{bannerConfig.hasJobId && bannerConfig.message && ( {csvExportJob?.jobId && (
<Banner <Banner
className="border-radius" className="border-radius"
message={bannerConfig.message} isLoading={downloading}
type={bannerConfig.type as BannerProps['type']} message={csvExportJob.error ?? csvExportJob.message ?? ''}
type={csvExportJob.error ? 'error' : 'success'}
/> />
)} )}
</Modal> </Modal>

View File

@ -18,17 +18,14 @@ import {
} from './EntityExportModalProvider.component'; } from './EntityExportModalProvider.component';
import { ExportData } from './EntityExportModalProvider.interface'; import { ExportData } from './EntityExportModalProvider.interface';
const dummyTeamsCSV = `name*,displayName,description,teamType*,parents*,Owner,isJoinable,defaultRoles,policies const mockExportJob = {
access table only,access table only,,Group,Organization,,true,Only table, jobId: '123456',
Engineering,,,BusinessUnit,Organization,,true,, message: 'Export initiated successfyully',
Finance,,,BusinessUnit,Organization,,true,, };
Legal,,,BusinessUnit,Organization,,true,,
Applications,,,Group,Engineering,,true,,
`;
const mockShowModal: ExportData = { const mockShowModal: ExportData = {
name: 'test', name: 'test',
onExport: jest.fn().mockImplementation(() => Promise.resolve(dummyTeamsCSV)), onExport: jest.fn().mockImplementation(() => Promise.resolve(mockExportJob)),
}; };
const ConsumerComponent = () => { const ConsumerComponent = () => {
@ -140,6 +137,7 @@ describe('EntityExportModalProvider component', () => {
}); });
expect(mockShowModal.onExport).toHaveBeenCalledWith(mockShowModal.name); expect(mockShowModal.onExport).toHaveBeenCalledWith(mockShowModal.name);
expect(screen.queryByTestId('export-entity-modal')).not.toBeInTheDocument();
expect(await screen.findByText(mockExportJob.message)).toBeInTheDocument();
}); });
}); });

View File

@ -1,6 +1,8 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import './banner.less'; import './banner.less';
import { LoadingOutlined } from '@ant-design/icons';
import { Spin } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { ReactComponent as ErrorIcon } from '../../../assets/svg/banner/ic-banner-error.svg'; import { ReactComponent as ErrorIcon } from '../../../assets/svg/banner/ic-banner-error.svg';
import { ReactComponent as SuccessIcon } from '../../../assets/svg/banner/ic-banner-success.svg'; import { ReactComponent as SuccessIcon } from '../../../assets/svg/banner/ic-banner-success.svg';
@ -8,12 +10,23 @@ import { ReactComponent as SuccessIcon } from '../../../assets/svg/banner/ic-ban
export interface BannerProps extends React.HTMLAttributes<HTMLDivElement> { export interface BannerProps extends React.HTMLAttributes<HTMLDivElement> {
type: 'success' | 'error'; type: 'success' | 'error';
message: string; message: string;
isLoading?: boolean;
} }
const Banner: FC<BannerProps> = ({ type, message, className }) => { const Banner: FC<BannerProps> = ({ type, message, className, isLoading }) => {
const icon = type === 'success' ? <SuccessIcon /> : <ErrorIcon />;
return ( return (
<div className={classNames('message-banner-wrapper', type, className)}> <div className={classNames('message-banner-wrapper', type, className)}>
{type === 'success' ? <SuccessIcon /> : <ErrorIcon />} {isLoading ? (
<Spin
className={`loading-spinner-${type}`}
indicator={<LoadingOutlined spin />}
size="small"
/>
) : (
icon
)}
<span className="message-banner-text">{message}</span> <span className="message-banner-text">{message}</span>
</div> </div>
); );

View File

@ -20,4 +20,8 @@
background-color: @error-bg-color; background-color: @error-bg-color;
color: @error-color; color: @error-color;
} }
.loading-spinner-success {
color: @success-color;
}
} }