Skip to content

Commit

Permalink
Merge pull request #20 from protofire/export-csv-verified-contracts
Browse files Browse the repository at this point in the history
Export csv verified contracts
  • Loading branch information
DenSmolonski authored Sep 11, 2024
2 parents 9b46e2f + 57b5a11 commit 331519e
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 21 deletions.
3 changes: 3 additions & 0 deletions lib/api/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,9 @@ export const RESOURCES = {
csv_export_logs: {
path: '/api/v1/logs-csv',
},
csv_export_contracts: {
path: '/api/v1/smart-contracts-csv',
},
graphql: {
path: '/api/v1/graphql',
},
Expand Down
4 changes: 4 additions & 0 deletions types/client/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@ export type CsvExportParams = {
type: 'logs';
filterType?: 'topic';
filterValue?: string;
} | {
type: 'contracts';
filterType?: string;
filterValue?: string;
}
4 changes: 2 additions & 2 deletions ui/address/AddressCsvExportLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/LinkInternal';

interface Props {
address: string;
address?: string;
params: CsvExportParams;
className?: string;
isLoading?: boolean;
Expand Down Expand Up @@ -44,7 +44,7 @@ const AddressCsvExportLink = ({ className, address, params, isLoading }: Props)
display="inline-flex"
alignItems="center"
whiteSpace="nowrap"
href={ route({ pathname: '/csv-export', query: { ...params, address } }) }
href={ route({ pathname: '/csv-export', query: { ...params, ...(address ? { address } : {}) } }) }
flexShrink={ 0 }
>
<IconSvg name="files/csv" boxSize={{ base: '30px', lg: 6 }}/>
Expand Down
4 changes: 2 additions & 2 deletions ui/csvExport/CsvExportForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import CsvExportFormField from './CsvExportFormField';
import CsvExportFormReCaptcha from './CsvExportFormReCaptcha';

interface Props {
hash: string;
hash?: string;
resource: ResourceName;
filterType?: CsvExportParams['filterType'] | null;
filterValue?: CsvExportParams['filterValue'] | null;
Expand Down Expand Up @@ -58,7 +58,7 @@ const CsvExportForm = ({ hash, resource, filterType, filterValue, fileNameTempla
const blob = await response.blob();
downloadBlob(
blob,
`${ fileNameTemplate }_${ hash }_${ data.from }_${ data.to }
`${ fileNameTemplate }${ hash ? `_${ hash }` : '' }_${ data.from }_${ data.to }
${ filterType && filterValue ? '_with_filter_type_' + filterType + '_value_' + filterValue : '' }.csv`,
);

Expand Down
64 changes: 48 additions & 16 deletions ui/pages/CsvExport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,15 @@ const EXPORT_TYPES: Record<CsvExportParams['type'], ExportTypeEntity> = {
fileNameTemplate: 'logs',
filterType: 'topic',
},
contracts: {
text: 'Contracts',
resource: 'csv_export_contracts',
fileNameTemplate: 'contracts',
},
};

const isCorrectExportType = (type: string): type is CsvExportParams['type'] => Object.keys(EXPORT_TYPES).includes(type);
const isCorrectExportType = (type: string): type is CsvExportParams['type'] =>
Object.keys(EXPORT_TYPES).includes(type);

const CsvExport = () => {
const router = useRouter();
Expand All @@ -64,7 +70,9 @@ const CsvExport = () => {

const addressHash = router.query.address?.toString() || '';
const exportTypeParam = router.query.type?.toString() || '';
const exportType = isCorrectExportType(exportTypeParam) ? EXPORT_TYPES[exportTypeParam] : null;
const exportType = isCorrectExportType(exportTypeParam) ?
EXPORT_TYPES[exportTypeParam] :
null;
const filterTypeFromQuery = router.query.filterType?.toString() || null;
const filterValueFromQuery = router.query.filterValue?.toString();

Expand All @@ -76,7 +84,8 @@ const CsvExport = () => {
});

const backLink = React.useMemo(() => {
const hasGoBackLink = appProps.referrer && appProps.referrer.includes('/address');
const hasGoBackLink =
appProps.referrer && appProps.referrer.includes('/address');

if (!hasGoBackLink) {
return;
Expand All @@ -88,30 +97,34 @@ const CsvExport = () => {
};
}, [ appProps.referrer ]);

throwOnAbsentParamError(addressHash);
throwOnAbsentParamError(exportType);
exportTypeParam !== 'contracts' && throwOnAbsentParamError(addressHash);

if (!exportType) {
return null;
}

const filterType = filterTypeFromQuery === exportType.filterType ? filterTypeFromQuery : null;
const filterType =
filterTypeFromQuery === exportType.filterType ? filterTypeFromQuery : null;
const filterValue = (() => {
if (!filterType || !filterValueFromQuery) {
return null;
}

if (exportType.filterValues && !exportType.filterValues?.includes(filterValueFromQuery)) {
if (
exportType.filterValues &&
!exportType.filterValues?.includes(filterValueFromQuery)
) {
return null;
}

return filterValueFromQuery;
})();

const content = (() => {
throwOnResourceLoadError(addressQuery);
exportTypeParam !== 'contracts' && throwOnResourceLoadError(addressQuery);

if (addressQuery.isPending) {
if (exportTypeParam !== 'contracts' && addressQuery.isPending) {
return <ContentLoader/>;
}

Expand All @@ -126,24 +139,43 @@ const CsvExport = () => {
);
})();

return (
<>
<PageTitle
title="Export data to CSV file"
backLink={ backLink }
/>
const header = (() => {
if (exportTypeParam === 'contracts') {
return (
<Flex mb={ 10 } whiteSpace="pre-wrap" flexWrap="wrap">
<span>Export { exportType.text } to CSV file.</span>
</Flex>
);
}

return (
<Flex mb={ 10 } whiteSpace="pre-wrap" flexWrap="wrap">
<span>Export { exportType.text } for address </span>
<AddressEntity
address={{ hash: addressHash, is_contract: true, implementation_name: null }}
address={{
hash: addressHash,
is_contract: true,
implementation_name: null,
}}
truncation={ isMobile ? 'constant' : 'dynamic' }
noCopy
/>
<span>{ nbsp }</span>
{ filterType && filterValue && <span>with applied filter by { filterType } ({ filterValue }) </span> }
{ filterType && filterValue && (
<span>
with applied filter by { filterType } ({ filterValue }){ ' ' }
</span>
) }
<span>to CSV file. </span>
<span>Exports are limited to the last 10K { exportType.text }.</span>
</Flex>
);
})();

return (
<>
<PageTitle title="Export data to CSV file" backLink={ backLink }/>
{ header }
{ content }
</>
);
Expand Down
18 changes: 17 additions & 1 deletion ui/pages/VerifiedContracts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { apos } from 'lib/html-entities';
import getQueryParamString from 'lib/router/getQueryParamString';
import { VERIFIED_CONTRACT_INFO } from 'stubs/contract';
import { generateListStub } from 'stubs/utils';
import AddressCsvExportLink from 'ui/address/AddressCsvExportLink';
import ActionBar from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
import FilterInput from 'ui/shared/filters/FilterInput';
Expand Down Expand Up @@ -92,6 +93,10 @@ const VerifiedContracts = () => {
/>
);

const showCSVDownload = React.useMemo(() => {
return localStorage.getItem('showCSVdownload') === 'true';
}, []);

const sortButton = (
<Sort
options={ SORT_OPTIONS }
Expand All @@ -100,6 +105,14 @@ const VerifiedContracts = () => {
/>
);

const csvExportLink = (
<AddressCsvExportLink
params={{ type: 'contracts' }}
className=""
isLoading={ isPlaceholderData }
/>
);

const actionBar = (
<>
<HStack spacing={ 3 } mb={ 6 } display={{ base: 'flex', lg: 'none' }}>
Expand All @@ -113,7 +126,10 @@ const VerifiedContracts = () => {
{ typeFilter }
{ filterInput }
</HStack>
<Pagination ml="auto" { ...pagination }/>
<HStack spacing={ 3 } display={{ base: 'none', lg: 'flex' }}>
{ showCSVDownload && csvExportLink }
<Pagination ml="auto" { ...pagination }/>
</HStack>
</ActionBar>
) }
</>
Expand Down

0 comments on commit 331519e

Please sign in to comment.