mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2026-01-06 12:36:56 +00:00
MINOR: move the export png logic to utils to work independently (#20601)
* move the export png logic to utils to work independently * added support for manage button in dataInsightHeader * fix unit test issue * added common class for the export selector * optimize the code and remove unwanted thing
This commit is contained in:
parent
5ca4db0849
commit
286ccfeba2
@ -92,7 +92,7 @@ const DailyActiveUsersChart: FC<Props> = ({ chartFilter, selectedDays }) => {
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="data-insight-card"
|
||||
className="data-insight-card data-insight-card-chart"
|
||||
data-testid="entity-active-user-card"
|
||||
id={DataInsightChartType.DailyActiveUsers}
|
||||
loading={isLoading}
|
||||
|
||||
@ -478,7 +478,10 @@ export const DataInsightChartCard = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="data-insight-card" data-testid={`${type}-graph`} id={type}>
|
||||
<Card
|
||||
className="data-insight-card data-insight-card-chart"
|
||||
data-testid={`${type}-graph`}
|
||||
id={type}>
|
||||
<Row gutter={DI_STRUCTURE.rowContainerGutter}>
|
||||
<Col span={DI_STRUCTURE.leftContainerSpan}>
|
||||
<PageHeader
|
||||
|
||||
@ -227,7 +227,7 @@ const KPIChart: FC<Props> = ({
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="data-insight-card"
|
||||
className="data-insight-card data-insight-card-chart"
|
||||
data-testid="kpi-card"
|
||||
id="kpi-charts"
|
||||
loading={isLoading || isKpiLoading}
|
||||
|
||||
@ -121,7 +121,7 @@ const PageViewsByEntitiesChart: FC<Props> = ({ chartFilter, selectedDays }) => {
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="data-insight-card"
|
||||
className="data-insight-card data-insight-card-chart"
|
||||
data-testid="entity-page-views-card"
|
||||
id={DataInsightChartType.PageViewsByEntities}
|
||||
loading={isLoading}>
|
||||
|
||||
@ -27,7 +27,6 @@ import { useLocation } from 'react-router-dom';
|
||||
import { ExportTypes } from '../../../constants/Export.constants';
|
||||
import { getCurrentISODate } from '../../../utils/date-time/DateTimeUtils';
|
||||
import { isBulkEditRoute } from '../../../utils/EntityBulkEdit/EntityBulkEditUtils';
|
||||
import { handleExportFile } from '../../../utils/EntityUtils';
|
||||
import exportUtilClassBase from '../../../utils/ExportUtilClassBase';
|
||||
import { showErrorToast } from '../../../utils/ToastUtils';
|
||||
import Banner from '../../common/Banner/Banner';
|
||||
@ -123,7 +122,10 @@ export const EntityExportModalProvider = ({
|
||||
setDownloading(true);
|
||||
|
||||
if (exportType !== ExportTypes.CSV) {
|
||||
await handleExportFile(exportType, exportData);
|
||||
await exportUtilClassBase.exportMethodBasedOnType({
|
||||
exportType,
|
||||
exportData,
|
||||
});
|
||||
|
||||
handleCancel();
|
||||
setDownloading(false);
|
||||
|
||||
@ -156,7 +156,7 @@ const TotalDataAssetsWidget = ({
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="total-data-insight-card"
|
||||
className="total-data-insight-card data-insight-card-chart"
|
||||
data-testid="total-assets-widget"
|
||||
id={SystemChartType.TotalDataAssets}
|
||||
loading={isLoading}>
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
import { Col, Row, Typography } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { noop } from 'lodash';
|
||||
import React from 'react';
|
||||
import { MangeButtonItemLabelProps } from './ManageButtonItemLabel.interface';
|
||||
|
||||
@ -34,7 +35,7 @@ export const ManageButtonItemLabel = ({
|
||||
'opacity-50': disabled,
|
||||
})}
|
||||
data-testid={id}
|
||||
onClick={onClick}>
|
||||
onClick={disabled ? noop : onClick}>
|
||||
<Col className="self-center" data-testid={`${id}-icon`} span={3}>
|
||||
<Icon width="18px" />
|
||||
</Col>
|
||||
|
||||
@ -10,6 +10,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ItemType } from 'antd/lib/menu/hooks/useItems';
|
||||
|
||||
import { ReactComponent as AppAnalyticsIcon } from '../../assets/svg/app-analytics.svg';
|
||||
import { ReactComponent as DataAssetsIcon } from '../../assets/svg/data-asset.svg';
|
||||
import { ReactComponent as KPIIcon } from '../../assets/svg/kpi.svg';
|
||||
@ -81,6 +83,10 @@ class DataInsightClassBase {
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
public getManageExtraOptions(): ItemType[] {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
const dataInsightClassBase = new DataInsightClassBase();
|
||||
|
||||
@ -11,21 +11,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Button, Col, Row, Space, Typography } from 'antd';
|
||||
import { isEmpty } from 'lodash';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useHistory, useParams } from 'react-router-dom';
|
||||
import DatePickerMenu from '../../../components/common/DatePickerMenu/DatePickerMenu.component';
|
||||
import ManageButton from '../../../components/common/EntityPageInfos/ManageButton/ManageButton';
|
||||
import DataInsightSummary from '../../../components/DataInsight/DataInsightSummary';
|
||||
import KPIChart from '../../../components/DataInsight/KPIChart';
|
||||
import SearchDropdown from '../../../components/SearchDropdown/SearchDropdown';
|
||||
import { ROUTES } from '../../../constants/constants';
|
||||
import { usePermissionProvider } from '../../../context/PermissionProvider/PermissionProvider';
|
||||
import { ResourceEntity } from '../../../context/PermissionProvider/PermissionProvider.interface';
|
||||
import { EntityType } from '../../../enums/entity.enum';
|
||||
import { Operation } from '../../../generated/entity/policies/policy';
|
||||
import { DataInsightTabs } from '../../../interface/data-insight.interface';
|
||||
import { getOptionalDataInsightTabFlag } from '../../../utils/DataInsightUtils';
|
||||
import { formatDate } from '../../../utils/date-time/DateTimeUtils';
|
||||
import { checkPermission } from '../../../utils/PermissionsUtils';
|
||||
import dataInsightClassBase from '../DataInsightClassBase';
|
||||
import { useDataInsightProvider } from '../DataInsightProvider';
|
||||
import { DataInsightHeaderProps } from './DataInsightHeader.interface';
|
||||
|
||||
@ -56,6 +60,11 @@ const DataInsightHeader = ({ onScrollToChart }: DataInsightHeaderProps) => {
|
||||
[permissions]
|
||||
);
|
||||
|
||||
const extraDropdownContent = useMemo(
|
||||
() => dataInsightClassBase.getManageExtraOptions(),
|
||||
[]
|
||||
);
|
||||
|
||||
const handleAddKPI = () => {
|
||||
history.push(ROUTES.ADD_KPI);
|
||||
};
|
||||
@ -73,16 +82,26 @@ const DataInsightHeader = ({ onScrollToChart }: DataInsightHeaderProps) => {
|
||||
</Typography.Text>
|
||||
</div>
|
||||
|
||||
{createKPIPermission && (
|
||||
<Button
|
||||
data-testid="add-kpi-btn"
|
||||
type="primary"
|
||||
onClick={handleAddKPI}>
|
||||
{t('label.add-entity', {
|
||||
entity: t('label.kpi-uppercase'),
|
||||
})}
|
||||
</Button>
|
||||
)}
|
||||
<div className="d-flex gap-2">
|
||||
{createKPIPermission && (
|
||||
<Button
|
||||
data-testid="add-kpi-btn"
|
||||
type="primary"
|
||||
onClick={handleAddKPI}>
|
||||
{t('label.add-entity', {
|
||||
entity: t('label.kpi-uppercase'),
|
||||
})}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{!isEmpty(extraDropdownContent) ? (
|
||||
<ManageButton
|
||||
entityName={EntityType.KPI}
|
||||
entityType={EntityType.KPI}
|
||||
extraDropdownContent={extraDropdownContent}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
|
||||
@ -73,6 +73,15 @@ jest.mock('../../../constants/constants', () => ({
|
||||
ROUTES: {},
|
||||
}));
|
||||
|
||||
jest.mock(
|
||||
'../../../components/common/EntityPageInfos/ManageButton/ManageButton',
|
||||
() => jest.fn(() => <div>ManageButton</div>)
|
||||
);
|
||||
|
||||
jest.mock('../DataInsightClassBase', () => ({
|
||||
getManageExtraOptions: jest.fn().mockReturnValue([]),
|
||||
}));
|
||||
|
||||
const mockProps = {
|
||||
onScrollToChart: jest.fn(),
|
||||
};
|
||||
|
||||
@ -69,6 +69,17 @@ jest.mock('./ServiceUtils', () => ({
|
||||
getServiceRouteFromServiceType: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('./ToastUtils', () => ({
|
||||
showErrorToast: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('./ExportUtilClassBase', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
exportMethodBasedOnType: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('EntityUtils unit tests', () => {
|
||||
describe('highlightEntityNameAndDescription method', () => {
|
||||
it('highlightEntityNameAndDescription method should return the entity with highlighted name and description', () => {
|
||||
|
||||
@ -12,8 +12,6 @@
|
||||
*/
|
||||
|
||||
import { Popover, Space, Typography } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import { toPng } from 'html-to-image';
|
||||
import i18next, { t } from 'i18next';
|
||||
import {
|
||||
isEmpty,
|
||||
@ -35,7 +33,6 @@ import { DataAssetsWithoutServiceField } from '../components/DataAssets/DataAsse
|
||||
import { DataAssetSummaryPanelProps } from '../components/DataAssetSummaryPanel/DataAssetSummaryPanel.interface';
|
||||
import { TableProfilerTab } from '../components/Database/Profiler/ProfilerDashboard/profilerDashboard.interface';
|
||||
import { QueryVoteType } from '../components/Database/TableQueries/TableQueries.interface';
|
||||
import { ExportData } from '../components/Entity/EntityExportModalProvider/EntityExportModalProvider.interface';
|
||||
import {
|
||||
EntityServiceUnion,
|
||||
EntityWithServices,
|
||||
@ -52,7 +49,6 @@ import {
|
||||
PLACEHOLDER_ROUTE_FQN,
|
||||
ROUTES,
|
||||
} from '../constants/constants';
|
||||
import { ExportTypes } from '../constants/Export.constants';
|
||||
import {
|
||||
GlobalSettingOptions,
|
||||
GlobalSettingsMenuCategory,
|
||||
@ -119,9 +115,7 @@ import {
|
||||
import { getDataInsightPathWithFqn } from './DataInsightUtils';
|
||||
import EntityLink from './EntityLink';
|
||||
import { BasicEntityOverviewInfo } from './EntityUtils.interface';
|
||||
import exportUtilClassBase from './ExportUtilClassBase';
|
||||
import Fqn from './Fqn';
|
||||
import i18n from './i18next/LocalUtil';
|
||||
import {
|
||||
getApplicationDetailsPath,
|
||||
getBotsPagePath,
|
||||
@ -154,7 +148,6 @@ import {
|
||||
getUsagePercentile,
|
||||
} from './TableUtils';
|
||||
import { getTableTags } from './TagsUtils';
|
||||
import { showErrorToast } from './ToastUtils';
|
||||
|
||||
export enum DRAWER_NAVIGATION_OPTIONS {
|
||||
explore = 'Explore',
|
||||
@ -2548,65 +2541,3 @@ export const updateNodeType = (
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
export const handleExportFile = async (
|
||||
exportType: ExportTypes,
|
||||
exportData: ExportData
|
||||
) => {
|
||||
const { name: fileName, documentSelector = '', viewport } = exportData;
|
||||
try {
|
||||
const exportElement = document.querySelector(documentSelector);
|
||||
|
||||
if (!exportElement) {
|
||||
throw new Error(
|
||||
i18n.t('message.error-generating-export-type', {
|
||||
exportType,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Minimum width and height for the image
|
||||
const minWidth = 1000;
|
||||
const minHeight = 800;
|
||||
const padding = 20;
|
||||
|
||||
const imageWidth = Math.max(minWidth, exportElement.scrollWidth);
|
||||
const imageHeight = Math.max(minHeight, exportElement.scrollHeight);
|
||||
|
||||
await toPng(exportElement as HTMLElement, {
|
||||
backgroundColor: '#ffffff',
|
||||
width: imageWidth + padding * 2,
|
||||
height: imageHeight + padding * 2,
|
||||
style: {
|
||||
width: imageWidth.toString(),
|
||||
height: imageHeight.toString(),
|
||||
margin: `${padding}px`,
|
||||
minWidth: `${minWidth}px`,
|
||||
minHeight: `${minHeight}px`,
|
||||
...(!isUndefined(viewport)
|
||||
? {
|
||||
transform: `translate(${viewport.x}px, ${viewport.y}px) scale(${viewport.zoom})`,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
})
|
||||
.then((base64Image: string) => {
|
||||
exportUtilClassBase.exportMethodBasedOnType({
|
||||
exportType,
|
||||
base64Image,
|
||||
fileName,
|
||||
exportData,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
throw error;
|
||||
});
|
||||
} catch (error) {
|
||||
showErrorToast(
|
||||
error as AxiosError,
|
||||
i18n.t('message.error-generating-export-type', {
|
||||
exportType,
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2025 Collate.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { toPng } from 'html-to-image';
|
||||
import { ExportData } from '../../components/Entity/EntityExportModalProvider/EntityExportModalProvider.interface';
|
||||
import { ExportTypes } from '../../constants/Export.constants';
|
||||
import { showErrorToast } from '../ToastUtils';
|
||||
import {
|
||||
downloadImageFromBase64,
|
||||
exportPNGImageFromElement,
|
||||
} from './ExportUtils';
|
||||
|
||||
jest.mock('html-to-image', () => ({
|
||||
toPng: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../ToastUtils', () => ({
|
||||
showErrorToast: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('ExportUtils', () => {
|
||||
describe('downloadImageFromBase64', () => {
|
||||
let mockCreateElement: jest.SpyInstance;
|
||||
let mockSetAttribute: jest.Mock;
|
||||
let mockClick: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
mockSetAttribute = jest.fn();
|
||||
mockClick = jest.fn();
|
||||
mockCreateElement = jest
|
||||
.spyOn(document, 'createElement')
|
||||
.mockReturnValue({
|
||||
setAttribute: mockSetAttribute,
|
||||
click: mockClick,
|
||||
} as unknown as HTMLAnchorElement);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockCreateElement.mockRestore();
|
||||
});
|
||||
|
||||
it('should create and trigger download with correct attributes', () => {
|
||||
const dataUrl = 'data:image/png;base64,test';
|
||||
const fileName = 'test-image';
|
||||
const exportType = ExportTypes.PNG;
|
||||
|
||||
downloadImageFromBase64(dataUrl, fileName, exportType);
|
||||
|
||||
expect(mockCreateElement).toHaveBeenCalledWith('a');
|
||||
expect(mockSetAttribute).toHaveBeenCalledWith(
|
||||
'download',
|
||||
'test-image.png'
|
||||
);
|
||||
expect(mockSetAttribute).toHaveBeenCalledWith('href', dataUrl);
|
||||
expect(mockClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('exportPNGImageFromElement', () => {
|
||||
const mockExportData: ExportData = {
|
||||
name: 'test-export',
|
||||
documentSelector: '#test-element',
|
||||
exportTypes: [ExportTypes.PNG],
|
||||
onExport: jest.fn(),
|
||||
};
|
||||
|
||||
const mockElement = {
|
||||
scrollWidth: 1200,
|
||||
scrollHeight: 900,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
// Mock document.querySelector
|
||||
document.querySelector = jest.fn().mockReturnValue(mockElement);
|
||||
|
||||
// Mock toPng
|
||||
(toPng as jest.Mock).mockResolvedValue('data:image/png;base64,test');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should successfully export PNG image when element exists', async () => {
|
||||
await exportPNGImageFromElement(mockExportData);
|
||||
|
||||
expect(document.querySelector).toHaveBeenCalledWith('#test-element');
|
||||
expect(toPng).toHaveBeenCalledWith(
|
||||
mockElement,
|
||||
expect.objectContaining({
|
||||
backgroundColor: '#ffffff',
|
||||
width: 1240, // 1200 + (20 * 2) padding
|
||||
height: 940, // 900 + (20 * 2) padding
|
||||
style: expect.objectContaining({
|
||||
width: '1200',
|
||||
height: '900',
|
||||
margin: '20px',
|
||||
minWidth: '1000px',
|
||||
minHeight: '800px',
|
||||
}),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw error when element is not found', async () => {
|
||||
document.querySelector = jest.fn().mockReturnValue(null);
|
||||
|
||||
await expect(exportPNGImageFromElement(mockExportData)).rejects.toThrow(
|
||||
'message.error-generating-export-type'
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle viewport transformation when provided', async () => {
|
||||
const exportDataWithViewport = {
|
||||
...mockExportData,
|
||||
viewport: {
|
||||
x: 100,
|
||||
y: 200,
|
||||
zoom: 1.5,
|
||||
},
|
||||
};
|
||||
|
||||
await exportPNGImageFromElement(exportDataWithViewport);
|
||||
|
||||
expect(toPng).toHaveBeenCalledWith(
|
||||
mockElement,
|
||||
expect.objectContaining({
|
||||
style: expect.objectContaining({
|
||||
transform: 'translate(100px, 200px) scale(1.5)',
|
||||
}),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle toPng error', async () => {
|
||||
const error = new Error('PNG generation failed');
|
||||
(toPng as jest.Mock).mockRejectedValue(error);
|
||||
|
||||
await exportPNGImageFromElement(mockExportData);
|
||||
|
||||
expect(showErrorToast).toHaveBeenCalledWith(
|
||||
error,
|
||||
'message.error-generating-export-type'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -10,8 +10,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { lowerCase } from 'lodash';
|
||||
import { AxiosError } from 'axios';
|
||||
import { toPng } from 'html-to-image';
|
||||
import { isUndefined, lowerCase } from 'lodash';
|
||||
import { ExportData } from '../../components/Entity/EntityExportModalProvider/EntityExportModalProvider.interface';
|
||||
import { ExportTypes } from '../../constants/Export.constants';
|
||||
import i18n from '../i18next/LocalUtil';
|
||||
import { showErrorToast } from '../ToastUtils';
|
||||
|
||||
export const downloadImageFromBase64 = (
|
||||
dataUrl: string,
|
||||
@ -23,3 +28,54 @@ export const downloadImageFromBase64 = (
|
||||
a.setAttribute('href', dataUrl);
|
||||
a.click();
|
||||
};
|
||||
|
||||
export const exportPNGImageFromElement = async (exportData: ExportData) => {
|
||||
const { name, documentSelector = '', viewport } = exportData;
|
||||
|
||||
const exportElement = document.querySelector(documentSelector);
|
||||
|
||||
if (!exportElement) {
|
||||
throw new Error(
|
||||
i18n.t('message.error-generating-export-type', {
|
||||
exportType: ExportTypes.PNG,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Minimum width and height for the image
|
||||
const minWidth = 1000;
|
||||
const minHeight = 800;
|
||||
const padding = 20;
|
||||
|
||||
const imageWidth = Math.max(minWidth, exportElement.scrollWidth);
|
||||
const imageHeight = Math.max(minHeight, exportElement.scrollHeight);
|
||||
|
||||
await toPng(exportElement as HTMLElement, {
|
||||
backgroundColor: '#ffffff',
|
||||
width: imageWidth + padding * 2,
|
||||
height: imageHeight + padding * 2,
|
||||
style: {
|
||||
width: imageWidth.toString(),
|
||||
height: imageHeight.toString(),
|
||||
margin: `${padding}px`,
|
||||
minWidth: `${minWidth}px`,
|
||||
minHeight: `${minHeight}px`,
|
||||
...(!isUndefined(viewport)
|
||||
? {
|
||||
transform: `translate(${viewport.x}px, ${viewport.y}px) scale(${viewport.zoom})`,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
})
|
||||
.then((base64Image: string) => {
|
||||
downloadImageFromBase64(base64Image, name, ExportTypes.PNG);
|
||||
})
|
||||
.catch((error) => {
|
||||
showErrorToast(
|
||||
error as AxiosError,
|
||||
i18n.t('message.error-generating-export-type', {
|
||||
exportType: ExportTypes.PNG,
|
||||
})
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
import { ExportData } from '../components/Entity/EntityExportModalProvider/EntityExportModalProvider.interface';
|
||||
import { ExportTypes } from '../constants/Export.constants';
|
||||
import { downloadImageFromBase64 } from './Export/ExportUtils';
|
||||
import { exportPNGImageFromElement } from './Export/ExportUtils';
|
||||
|
||||
class ExportUtilClassBase {
|
||||
public getExportTypeOptions(): {
|
||||
@ -28,13 +28,11 @@ class ExportUtilClassBase {
|
||||
|
||||
public exportMethodBasedOnType(data: {
|
||||
exportType: ExportTypes;
|
||||
base64Image: string;
|
||||
fileName: string;
|
||||
exportData?: ExportData;
|
||||
exportData: ExportData;
|
||||
}) {
|
||||
const { exportType, base64Image, fileName } = data;
|
||||
const { exportType, exportData } = data;
|
||||
if (exportType === ExportTypes.PNG) {
|
||||
return downloadImageFromBase64(base64Image, fileName, exportType);
|
||||
return exportPNGImageFromElement(exportData);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user