Commit 6d17681f authored by Max Alekseenko's avatar Max Alekseenko

rework solidity report component

parent 0052c025
import { Box, Text, chakra, Icon } from '@chakra-ui/react';
import { Box, Text, chakra, Icon, Popover, PopoverTrigger, PopoverContent, PopoverBody, useDisclosure } from '@chakra-ui/react';
import React from 'react';
// This icon doesn't work properly when it is in the sprite
......@@ -18,6 +18,8 @@ interface Props {
}
const SolidityscanReport = ({ className, hash }: Props) => {
const { isOpen, onToggle, onClose } = useDisclosure();
const { data, isPlaceholderData, isError } = useApiQuery('contract_solidityscan_report', {
pathParams: { hash },
queryOptions: {
......@@ -37,18 +39,23 @@ const SolidityscanReport = ({ className, hash }: Props) => {
const vulnerabilitiesCount = vulnerabilitiesCounts.reduce((acc, val) => acc + val, 0);
return (
<SolidityscanReportButton
className={ className }
score={ score }
isLoading={ isPlaceholderData }
popoverContent={ (
<>
<Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy>
<PopoverTrigger>
<SolidityscanReportButton
className={ className }
score={ score }
isLoading={ isPlaceholderData }
onClick={ onToggle }
/>
</PopoverTrigger>
<PopoverContent w={{ base: '100vw', lg: '328px' }}>
<PopoverBody px="26px" py="20px" fontSize="sm">
<Box mb={ 5 } lineHeight="25px">
Contract analyzed for 140+ vulnerability patterns by
<Icon as={ solidityScanIcon } mr={ 1 } ml="6px" w="23px" h="20px" display="inline-block" verticalAlign="middle"/>
<Text fontWeight={ 600 } display="inline-block">SolidityScan</Text>
</Box>
<SolidityscanReportScore score={ score }/>
<SolidityscanReportScore score={ score } mb={ 5 }/>
{ vulnerabilities && vulnerabilitiesCount > 0 && (
<Box mb={ 5 }>
<Text py="7px" variant="secondary" fontSize="xs" fontWeight={ 500 }>Vulnerabilities distribution</Text>
......@@ -56,9 +63,9 @@ const SolidityscanReport = ({ className, hash }: Props) => {
</Box>
) }
<LinkExternal href={ data?.scan_report.scanner_reference_url }>View full report</LinkExternal>
</>
) }
/>
</PopoverBody>
</PopoverContent>
</Popover>
);
};
......
import { Box, Text, Link } from '@chakra-ui/react';
import { Box, Text, Link, Popover, PopoverTrigger, PopoverBody, PopoverContent, useDisclosure } from '@chakra-ui/react';
import React from 'react';
import type { MarketplaceAppSecurityReport } from 'types/client/marketplace';
......@@ -22,10 +22,12 @@ type Props = {
}
const AppSecurityReport = ({ id, securityReport, height, showContractList, isLoading, onlyIcon, source }: Props) => {
const { isOpen, onToggle, onClose } = useDisclosure();
const handleButtonClick = React.useCallback(() => {
mixpanel.logEvent(mixpanel.EventTypes.PAGE_WIDGET, { Type: 'Security score', Info: id, Source: source });
}, [ id, source ]);
onToggle();
}, [ id, source, onToggle ]);
const handleLinkClick = React.useCallback(() => {
mixpanel.logEvent(mixpanel.EventTypes.PAGE_WIDGET, { Type: 'Analyzed contracts', Info: id, Source: 'Security score popup' });
......@@ -44,19 +46,23 @@ const AppSecurityReport = ({ id, securityReport, height, showContractList, isLoa
} = securityReport?.overallInfo || {};
return (
<SolidityscanReportButton
isLoading={ isLoading }
height={ height }
score={ securityScore }
onlyIcon={ onlyIcon }
onClick={ handleButtonClick }
popoverContent={ (
<>
<Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy>
<PopoverTrigger>
<SolidityscanReportButton
score={ securityScore }
isLoading={ isLoading }
onClick={ handleButtonClick }
height={ height }
onlyIcon={ onlyIcon }
/>
</PopoverTrigger>
<PopoverContent w={{ base: '100vw', lg: '328px' }}>
<PopoverBody px="26px" py="20px" fontSize="sm">
<Box mb={ 5 }>
{ solidityScanContractsNumber } smart contract{ solidityScanContractsNumber === 1 ? ' was' : 's were' } evaluated to determine
this protocol{ apos }s overall security score on the { config.chain.name } network.
</Box>
<SolidityscanReportScore score={ securityScore }/>
<SolidityscanReportScore score={ securityScore } mb={ 5 }/>
{ issueSeverityDistribution && totalIssues > 0 && (
<Box mb={ 5 }>
<Text py="7px" variant="secondary" fontSize="xs" fontWeight={ 500 }>Threat score & vulnerabilities</Text>
......@@ -67,9 +73,9 @@ const AppSecurityReport = ({ id, securityReport, height, showContractList, isLoa
Analyzed contracts
<IconSvg name="arrows/north-east" boxSize={ 5 } color="gray.400"/>
</Link>
</>
) }
/>
</PopoverBody>
</PopoverContent>
</Popover>
);
};
......
import { Box, Text } from '@chakra-ui/react';
import { Box, Text, Popover, PopoverTrigger, PopoverBody, PopoverContent, useDisclosure } from '@chakra-ui/react';
import React from 'react';
import type { SolidityscanReport } from 'types/api/contract';
......@@ -15,9 +15,12 @@ type Props = {
}
const ContractSecurityReport = ({ securityReport }: Props) => {
const { isOpen, onToggle, onClose } = useDisclosure();
const handleClick = React.useCallback(() => {
mixpanel.logEvent(mixpanel.EventTypes.PAGE_WIDGET, { Type: 'Security score', Source: 'Analyzed contracts popup' });
}, [ ]);
onToggle();
}, [ onToggle ]);
if (!securityReport) {
return null;
......@@ -32,15 +35,19 @@ const ContractSecurityReport = ({ securityReport }: Props) => {
const totalIssues = Object.values(issueSeverityDistribution as Record<string, number>).reduce((acc, val) => acc + val, 0);
return (
<SolidityscanReportButton
score={ parseFloat(securityScore) }
onClick={ handleClick }
popoverContent={ (
<>
<Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy>
<PopoverTrigger>
<SolidityscanReportButton
score={ parseFloat(securityScore) }
onClick={ handleClick }
/>
</PopoverTrigger>
<PopoverContent w={{ base: '100vw', lg: '328px' }}>
<PopoverBody px="26px" py="20px" fontSize="sm">
<Box mb={ 5 }>
The security score was derived from evaluating the smart contracts of a protocol on the { config.chain.name } network.
</Box>
<SolidityscanReportScore score={ parseFloat(securityScore) }/>
<SolidityscanReportScore score={ parseFloat(securityScore) } mb={ 5 }/>
{ issueSeverityDistribution && totalIssues > 0 && (
<Box mb={ 5 }>
<Text py="7px" variant="secondary" fontSize="xs" fontWeight={ 500 }>Threat score & vulnerabilities</Text>
......@@ -48,9 +55,9 @@ const ContractSecurityReport = ({ securityReport }: Props) => {
</Box>
) }
<LinkExternal href={ url }>View full report</LinkExternal>
</>
) }
/>
</PopoverBody>
</PopoverContent>
</Popover>
);
};
......
import {
Button,
chakra,
Popover,
PopoverTrigger,
PopoverBody,
PopoverContent,
useDisclosure,
Skeleton,
} from '@chakra-ui/react';
import { Button, Skeleton } from '@chakra-ui/react';
import React from 'react';
import IconSvg from 'ui/shared/IconSvg';
......@@ -17,51 +8,39 @@ import useScoreLevelAndColor from './useScoreLevelAndColor';
interface Props {
className?: string;
score: number;
popoverContent?: React.ReactNode;
isLoading?: boolean;
height?: string;
onlyIcon?: boolean;
onClick?: () => void;
}
const SolidityscanReportButton = ({ className, score, popoverContent, isLoading, height = '32px', onlyIcon, onClick }: Props) => {
const { isOpen, onToggle, onClose } = useDisclosure();
const SolidityscanReportButton = (
{ className, score, isLoading, height = '32px', onlyIcon, onClick }: Props,
ref: React.ForwardedRef<HTMLButtonElement>,
) => {
const { scoreColor } = useScoreLevelAndColor(score);
const handleClick = React.useCallback(() => {
onClick?.();
onToggle();
}, [ onClick, onToggle ]);
return (
<Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy>
<PopoverTrigger>
<Skeleton isLoaded={ !isLoading } borderRadius="base">
<Button
className={ className }
color={ scoreColor }
size="sm"
variant="outline"
colorScheme="gray"
onClick={ handleClick }
aria-label="SolidityScan score"
fontWeight={ 500 }
px="6px"
h={ height }
flexShrink={ 0 }
>
<IconSvg name={ score < 80 ? 'score/score-not-ok' : 'score/score-ok' } boxSize={ 5 } mr={ onlyIcon ? 0 : 1 }/>
{ onlyIcon ? null : score }
</Button>
</Skeleton>
</PopoverTrigger>
<PopoverContent w={{ base: '100vw', lg: '328px' }}>
<PopoverBody px="26px" py="20px" fontSize="sm">
{ popoverContent }
</PopoverBody>
</PopoverContent>
</Popover>
<Skeleton isLoaded={ !isLoading } borderRadius="base">
<Button
ref={ ref }
className={ className }
color={ scoreColor }
size="sm"
variant="outline"
colorScheme="gray"
onClick={ onClick }
aria-label="SolidityScan score"
fontWeight={ 500 }
px="6px"
h={ height }
flexShrink={ 0 }
>
<IconSvg name={ score < 80 ? 'score/score-not-ok' : 'score/score-ok' } boxSize={ 5 } mr={ onlyIcon ? 0 : 1 }/>
{ onlyIcon ? null : score }
</Button>
</Skeleton>
);
};
export default chakra(SolidityscanReportButton);
export default React.forwardRef(SolidityscanReportButton);
......@@ -6,10 +6,11 @@ import IconSvg from 'ui/shared/IconSvg';
import useScoreLevelAndColor from './useScoreLevelAndColor';
interface Props {
className?: string;
score: number;
}
const SolidityscanReportScore = ({ score }: Props) => {
const SolidityscanReportScore = ({ className, score }: Props) => {
const { scoreLevel, scoreColor } = useScoreLevelAndColor(score);
const chartGrayColor = useColorModeValue('gray.100', 'gray.700');
......@@ -17,7 +18,7 @@ const SolidityscanReportScore = ({ score }: Props) => {
const popoverBgColor = useColorModeValue('white', 'gray.900');
return (
<Flex alignItems="center" mb={ 5 }>
<Flex className={ className } alignItems="center">
<Box
w={ 12 }
h={ 12 }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment