react-bootstrap#Tooltip TypeScript Examples
The following examples show how to use
react-bootstrap#Tooltip.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ScriptDialogueLine.tsx From apps with MIT License | 6 votes |
DialoguePopover = (props: { children: Renderable[]; tooltipComponent: Renderable[] }) => {
const { children, tooltipComponent } = props;
const maleToolTip = (props: any) => (
<Tooltip lang={Manager.lang()} {...props}>
{tooltipComponent}
</Tooltip>
);
return (
<OverlayTrigger placement="top" delay={{ show: 250, hide: 400 }} overlay={maleToolTip}>
<span style={{ textDecoration: "underline" }}>{mergeElements(children, "")}</span>
</OverlayTrigger>
);
}
Example #2
Source File: AgeDisplay.tsx From devex with GNU General Public License v3.0 | 6 votes |
AgeDisplay: React.FC<IProps> = ({ timestamp, className }) => {
const parsedTime: Dayjs = dayjs(timestamp / 1000);
return (
<OverlayTrigger
placement="top"
overlay={
<Tooltip id={"overlay-to"}>
{parsedTime.format("YYYY-DD-MM HH:mm")}
</Tooltip>
}
>
<div className={className}>
<span>{parsedTime.fromNow()}</span>
</div>
</OverlayTrigger>
);
}
Example #3
Source File: ServantBondGrowth.tsx From apps with MIT License | 6 votes |
function BondCell(props = { value: 0, span: 1, previous: NaN }) {
let diff = props.value - props.previous,
cell = <td colSpan={props.span}>{formatNumber(props.value)}</td>;
let diffText = diff > 0 ? `From previous level : ${formatNumber(diff)}` : "";
return diffText ? (
<OverlayTrigger
placement="bottom"
overlay={(p) => (
<Tooltip id={`tooltip_bond_${props.value}`} {...p}>
{diffText}
</Tooltip>
)}
>
{cell}
</OverlayTrigger>
) : (
cell
);
}
Example #4
Source File: TypeDisplay.tsx From devex with GNU General Public License v3.0 | 6 votes |
TypeDisplay: React.FC<IProps> = ({ fromAddr, toAddr, addr, type }) => {
const hexAddr = zilAddrToHexAddr(addr);
let type2: any;
let typeText: string;
// sender
if (hexAddr === fromAddr.toLowerCase()) {
type2 = <RightArrow width="20px" height="14px" fill="red" />;
}
// receiver
if (hexAddr === toAddr) {
if (type === "contract-call") {
type2 = <RightArrow width="20px" height="14px" fill="green" />;
} else {
type2 = <RightArrow width="20px" height="14px" fill="green" />;
}
}
if (fromAddr.toLowerCase() === toAddr.toLowerCase()) {
type2 = <BothArrow width="20px" height="14px" fill="gray" />;
typeText = "SELF";
} else {
typeText = fromAddr.toLowerCase() === hexAddr ? "OUT" : "IN";
}
return (
<OverlayTrigger
placement="top"
overlay={<Tooltip id={"overlay-to"}>{typeText}</Tooltip>}
>
<div>{type2}</div>
</OverlayTrigger>
);
}
Example #5
Source File: ViewBlockLink.tsx From devex with GNU General Public License v3.0 | 6 votes |
ViewBlockLink: React.FC<IProps> = ({ network, type, identifier }) => {
if (network !== 'https://api.zilliqa.com' && network !== 'https://dev-api.zilliqa.com')
return null
let viewBlockUrl = `https://viewblock.io/zilliqa/${type}/${identifier}`
if (network === 'https://dev-api.zilliqa.com')
viewBlockUrl += '?network=testnet'
return <a href={viewBlockUrl} className='vb-link-div'>
<OverlayTrigger placement='top'
overlay={<Tooltip id={'vb-tt'}>Open in ViewBlock</Tooltip>}>
<span className='p-1'>
<img
src={VBLogo}
alt=""
width="28"
height="28"
className="d-inline-block align-top"
/>
</span>
</OverlayTrigger>
</a>
}
Example #6
Source File: tooltip.tsx From advocacy-maps with MIT License | 6 votes |
QuestionTooltip = ({ text }: { text: string }) => {
return (
<OverlayTrigger
placement="auto"
overlay={
<Tooltip id="tooltip-text">
<p>{text}</p>
</Tooltip>
}
>
<span className="m-1">
<FontAwesomeIcon icon={faQuestionCircle} className="text-secondary" />
</span>
</OverlayTrigger>
)
}
Example #7
Source File: IconWithMessage.tsx From bada-frame with GNU General Public License v3.0 | 6 votes |
IconWithMessage = (props: IconWithMessageProps) => (
<OverlayTrigger
placement="bottom"
overlay={
<Tooltip id="on-hover-info" style={{ zIndex: 1002 }}>
{props.message}
</Tooltip>
}>
{props.children}
</OverlayTrigger>
)
Example #8
Source File: CodeBlock.tsx From bada-frame with GNU General Public License v3.0 | 5 votes |
CodeBlock = (props: Iprops) => {
const [copied, setCopied] = useState<boolean>(false);
const copyToClipboardHelper = (text: string) => () => {
navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 1000);
};
const RenderCopiedMessage = (props) => {
const { style, ...rest } = props;
return (
<Tooltip
{...rest}
style={{ ...style, zIndex: 2001 }}
id="button-tooltip">
copied
</Tooltip>
);
};
return (
<Wrapper>
<CodeWrapper>
{props.code ? (
<FreeFlowText style={{ wordBreak: props.wordBreak }}>
{props.code}
</FreeFlowText>
) : (
<EnteSpinner />
)}
</CodeWrapper>
{props.code && (
<OverlayTrigger
show={copied}
placement="bottom"
trigger={'click'}
overlay={RenderCopiedMessage}
delay={{ show: 200, hide: 800 }}>
<CopyButtonWrapper
onClick={copyToClipboardHelper(props.code)}
style={{
background: 'none',
...(copied ? { color: '#51cd7c' } : {}),
}}>
{copied ? <TickIcon /> : <CopyIcon />}
</CopyButtonWrapper>
</OverlayTrigger>
)}
</Wrapper>
);
}
Example #9
Source File: QuestEnemy.tsx From apps with MIT License | 5 votes |
QuestDropDescriptor = ({ region, drops }: { region: Region; drops: QuestEnemy.EnemyDrop[] }) => {
return (
<Alert variant="success">
<ul style={{ marginBottom: 0 }}>
{drops.map((drop) => {
const dummyGift = {
...drop,
id: 0,
priority: 0,
giftAdds: [],
};
let ciText = <></>;
if (drop.runs > 1) {
const c = quantile(0.975, drop.runs - 1);
const stdDevOverRuns = Math.sqrt(drop.dropVariance / drop.runs);
const lower = drop.dropExpected - c * stdDevOverRuns;
const upper = drop.dropExpected + c * stdDevOverRuns;
ciText = (
<>
<br />
95% CI: {numToPct(lower)} – {numToPct(upper)}
</>
);
}
const tooltip = (
<Tooltip id={`drop-detail-tooltip`} style={{ fontSize: "1em" }}>
{drop.dropCount.toLocaleString()} drops / {drop.runs.toLocaleString()} runs
{ciText}
</Tooltip>
);
return (
<li key={`${drop.type}-${drop.objectId}-${drop.num}`}>
<GiftDescriptor region={region} gift={dummyGift} />:{" "}
<span>{numToPct(drop.dropExpected)}</span>{" "}
<OverlayTrigger overlay={tooltip}>
<FontAwesomeIcon icon={faInfoCircle} />
</OverlayTrigger>
</li>
);
})}
</ul>
</Alert>
);
}
Example #10
Source File: SkillBreakdown.tsx From apps with MIT License | 5 votes |
render() {
const skill = this.props.skill;
const skillAdd =
this.props.skill.skillAdd.length > 0 ? (
<Tooltip id="skillAdd-tooltip" style={{ fontSize: "1em" }} lang={Manager.lang()}>
{getRubyText(this.props.region, skill.skillAdd[0].name, skill.skillAdd[0].ruby, true)}
</Tooltip>
) : null;
return (
<div>
<h3>
<SkillDescriptor region={this.props.region} skill={skill} iconHeight={33} />
{skillAdd !== null ? (
<>
{" "}
<OverlayTrigger overlay={skillAdd}>
<FontAwesomeIcon icon={faInfoCircle} style={{ fontSize: "0.75em" }} />
</OverlayTrigger>
</>
) : null}
</h3>
{this.props.rankUp !== undefined ? (
<Alert variant={"primary"}>Rank Up +{this.props.rankUp}</Alert>
) : null}
{skill.condQuestId && skill.condQuestPhase ? (
<Alert variant={"primary"}>
Available after{" "}
<QuestDescriptor
region={this.props.region}
questId={skill.condQuestId}
questPhase={
["91", "94"].includes(skill.condQuestId.toString().slice(0, 2))
? 1
: skill.condQuestPhase
}
/>
</Alert>
) : null}
<p className="newline">{skill.detail}</p>
{this.props.extraPassiveCond && skill.extraPassive.length > 0 ? (
<>
<ExtraPassiveCondition region={this.props.region} extraPassive={skill.extraPassive[0]} />
</>
) : null}
<EffectBreakdown
region={this.props.region}
cooldowns={this.props.cooldowns ? skill.coolDown : undefined}
funcs={skill.functions}
triggerSkillIdStack={[skill.id]}
levels={this.props.levels}
scripts={skill.script}
additionalSkillId={skill.script.additionalSkillId}
/>
</div>
);
}
Example #11
Source File: ToAddrDispSimplified.tsx From devex with GNU General Public License v3.0 | 5 votes |
ToAddrDispSimplified: any = ({ toAddr, fromAddr, txType, addr }: any) => {
const hexAddr = stripHexPrefix(zilAddrToHexAddr(addr));
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let type: any;
if (fromAddr.toLowerCase() === toAddr.toLowerCase()) {
type = <BothArrow width="20px" height="14px" fill="gray" />;
} else {
type =
fromAddr.toLowerCase() === hexAddr ? (
<RightArrow width="20px" height="14px" fill="red" />
) : (
<LeftArrow width="20px" height="14px" fill="green" />
);
}
let txTypeIcon: any = undefined;
if (txType === "contract-creation") {
txTypeIcon = (
<FontAwesomeIcon color="darkturquoise" icon={faFileContract} />
);
}
if (txType === "contract-call") {
txTypeIcon = <FontAwesomeIcon color="darkorange" icon={faFileContract} />;
}
return (
<OverlayTrigger
placement="top"
overlay={<Tooltip id={"overlay-to"}>{txType}</Tooltip>}
>
<div className="d-flex align-items-center">
{txTypeIcon ? <div className="mr-2">{txTypeIcon}</div> : null}
{txType === "contract-creation" ? (
<div>Contract</div>
) : toAddr.toLowerCase() !== hexAddr ? (
<QueryPreservingLink to={`/address/${hexAddrToZilAddr(toAddr)}`} className="ellipsis mono">
{hexAddrToZilAddr(toAddr)}
</QueryPreservingLink>
) : (
<span className="text-muted">{addr}</span>
)}
</div>
</OverlayTrigger>
);
}
Example #12
Source File: NetworkSwitcher.tsx From devex with GNU General Public License v3.0 | 5 votes |
NetworkSwitcher: React.FC = () => {
const history = useHistory()
const networkName = useNetworkName()
const networkUrl = useNetworkUrl()
const userPrefContext = useContext(UserPrefContext)
const { networkMap } = userPrefContext!
const [showDropdown, setShowDropdown] = useState(false)
const [currentNetwork, setCurrentNetwork] = useState(networkName)
useEffect(() => {
setCurrentNetwork(networkName)
}, [networkName])
const changeNetwork = useCallback((k: string) => {
history.push({
pathname: '/',
search: '?' + new URLSearchParams({ network: k }).toString()
})
}, [history])
return (
<Nav style={{ minWidth: '120px' }}>
<OverlayTrigger placement='left'
overlay={<Tooltip id={'network-tt'}> {networkUrl} </Tooltip>}>
<FontAwesomeIcon className='info-icon' icon={faInfoCircle} />
</OverlayTrigger>
<NavDropdown onToggle={(e: boolean) => { setShowDropdown(e) }}
show={showDropdown} title={currentNetwork} id="header-network-dropdown">
{networkMap.size === 0
? <div className='text-center'>
No networks
</div>
: Array.from(networkMap, ([k, v]) => (
<div key={k} className='node-div'>
<NavDropdown.Item className='node-item' onClick={() => {
if (currentNetwork !== v) {
changeNetwork(k)
}
}}>
{v}
</NavDropdown.Item>
</div>
))}
</NavDropdown>
</Nav>
)
}
Example #13
Source File: form-group.component.tsx From cwa-quick-test-frontend with Apache License 2.0 | 5 votes |
FormGroupInput = (props: any) => {
return (!props ? <></> :
<Form.Group as={Row} controlId={props.controlId} hidden={props.hidden} className='mb-1'>
<Form.Label className={`'input-label' ${props.lableAlign && 'align-self-'+props.lableAlign}`} column xs='5' sm='3'>{props.title + (props.required ? '*' : '')}</Form.Label>
<Col xs='7' sm='9' className='d-flex'>
<Row className='m-0 w-100'>
{props.infoText ? <Form.Label className='text-justify'>{props.infoText}</Form.Label> : <></>}
<InputGroup>
{!props.dropdown
? <></>
: <DropdownButton
as={InputGroup.Prepend}
variant="outline-secondary"
title={props.dropdownTitle}
id="input-group-dropdown-1"
>
{props.dropdown}
</DropdownButton>
}
<Form.Control
className={!props.prepend ? 'qt-input' : 'qt-input-prepend'}
value={props.value}
readOnly={props.readOnly}
disabled={props.disabled}
onClick={props.onClick}
onChange={props.onChange}
placeholder={props.placeholder ? props.placeholder : props.title}
type={props.type ? props.type : 'text'}
required={props.required}
maxLength={props.maxLength}
minLength={props.minLength}
min={props.min}
max={props.max}
pattern={props.pattern}
list={props.datalistId}
isInvalid={props.isInvalid}
/>
{
!(props.datalist && props.datalistId)
? <></>
: <datalist id={props.datalistId}>
{props.datalist}
</datalist>
}
{
!props.prepend
? <></>
: <OverlayTrigger
placement='top-end'
overlay={
<Tooltip id='prepend-tooltip'>
{props.tooltip}
</Tooltip>
}
><InputGroup.Text className='prepend px-3' >{props.prepend}</InputGroup.Text>
</OverlayTrigger>
}
<Form.Control.Feedback type="invalid">
{props.InvalidText}
</Form.Control.Feedback>
</InputGroup>
</Row>
</Col>
</Form.Group>
)
}
Example #14
Source File: copy-to-clipboard.tsx From remix-project with MIT License | 5 votes |
CopyToClipboard = (props: ICopyToClipboard) => { const { tip = 'Copy', icon = 'fa-copy', direction = 'right', getContent, children, ...otherProps } = props let { content } = props const [message, setMessage] = useState(tip) const copyData = () => { try { if (content === '') { setMessage('Cannot copy empty content!') return } if (typeof content !== 'string') { content = JSON.stringify(content, null, '\t') } copy(content) setMessage('Copied') } catch (e) { console.error(e) } } const handleClick = (e) => { if (content) { // module `copy` keeps last copied thing in the memory, so don't show tooltip if nothing is copied, because nothing was added to memory copyData() } else { content = getContent && getContent() copyData() } e.preventDefault() } const reset = () => { setTimeout(() => setMessage(tip), 500) } return ( // eslint-disable-next-line jsx-a11y/anchor-is-valid <a href='#' onClick={handleClick} onMouseLeave={reset}> <OverlayTrigger placement={direction} overlay={ <Tooltip id="overlay-tooltip"> { message } </Tooltip> }> { children || (<i className={`far ${icon} ml-1 p-2`} aria-hidden="true" {...otherProps} ></i>) } </OverlayTrigger> </a> ) }
Example #15
Source File: user-table.component.tsx From cwa-quick-test-frontend with Apache License 2.0 | 4 votes |
UserTable = (props: any) => {
// const context = React.useContext(AppContext);
const { t } = useTranslation();
const { keycloak } = useKeycloak();
const handleSuccess = () => {
setIsUserSuccessfullUpdated(true);
setIsUserCreationError(false);
setTimeout(setShowUserModal, 300, false);
setShowConfirm(false);
}
const [bUsers,
// refreshUsers,
createUser,
readUser,
updateUser,
deleteUser] = useGetUsers(handleSuccess, props.handleError);
const [users, setUsers] = React.useState<IDisplayUser[]>([]);
const [reload, setReload] = React.useState(true);
const [showUserModal, setShowUserModal] = React.useState(false);
const [isUserSuccessfullUpdated, setIsUserSuccessfullUpdated] = React.useState(false);
const [isUserCreationError, setIsUserCreationError] = React.useState(false);
const [editUser, setEditUser] = React.useState<IDisplayUser>(emptyUser);
const [ownUserId, setOwnUserId] = React.useState<string>('');
const [showConfirm, setShowConfirm] = React.useState(false);
const [confirmMessage, setConfirmMessage] = React.useState('');
const [confirmTitle, setConfirmTitle] = React.useState('');
const [confirmHandle, setConfirmHandle] = React.useState<() => void>();
// set user name from keycloak
React.useEffect(() => {
if (keycloak.idTokenParsed) {
setOwnUserId((keycloak.idTokenParsed as any).sub ?? '');
}
}, [keycloak])
React.useEffect(() => {
if (bUsers) {
setUsers(bUsers);
setEditUser({ ...emptyUser });
}
}, [bUsers]);
React.useEffect(() => {
if (props.userReload) {
users.forEach((user => updateDisplayUser(user, false)));
props.setUserReload(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.userReload]);
React.useEffect(() => {
if (props.groupNodes && users && users.length > 0 && reload) {
setReload(false);
users.forEach((user => updateDisplayUser(user, true)));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify(props.groupNodes), users, reload]);
const sortUsers = () => {
users.sort((a, b) => {
const nameA = a.username.toUpperCase(); // ignore upper and lowercase
const nameB = b.username.toUpperCase(); // ignore upper and lowercase
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
// names must be equal
return 0;
});
}
const addDisplayUser = (user: IDisplayUser) => {
setGroupPath(user);
user.displayRole = getDisplayRole(user);
users.push(user);
sortUsers();
setUsers(users);
}
const updateDisplayUser = (user: IDisplayUser, withApi: boolean, onSuccess?: () => void) => {
// set all groupPath for display
setGroupPath(user);
// set all rollDisplay async
if (withApi) {
readUser(user)
.then((response) => {
user.roleCounter = response.data.roleCounter;
user.roleLab = response.data.roleLab;
user.displayRole = getDisplayRole(user);
})
.finally(() => {
updateUsers(user);
if (onSuccess) {
onSuccess();
}
})
}
else {
updateUsers(user);
}
}
const updateUsers = (user: IDisplayUser | IUser) => {
const _users: IDisplayUser[] = [...users];
_users[_users.findIndex(_user => user.id === _user.id)] = { ...user };
setUsers(_users);
}
const removeUsers = (user: IDisplayUser | IUser) => {
users.splice(users.findIndex(_user => user.id === _user.id), 1);
setUsers(users);
}
const userUpdate = (user: IUser) => {
if (editUser && editUser.username) {
const fuser = users.find(u => u.username === user.username);
if (!user.password) {
user.password = undefined;
}
updateUser(user)
.then(() => {
if (
fuser
&& fuser.subGroup !== user.subGroup
&& keycloak.token
&& user.subGroup
) {
addUserToGroup(user.id, user.subGroup, keycloak.token)
.then(() => {
updateDisplayUser(user, true, handleSuccess);
})
.catch(e => {
props.handleError(e);
});
} else {
updateDisplayUser(user, true, handleSuccess);
}
})
} else {
const newUser: any = { ...user };
createUser(newUser)
.then((response) => {
const displayUser: IDisplayUser = { ...response.data };
addDisplayUser(displayUser);
handleSuccess();
})
.catch(e => {
if (e && e.message && (e.message as string).includes('409')) {
setIsUserCreationError(true);
}
else {
props.handleError(e);
}
})
}
}
const startEditUser = (user: IUser) => {
setEditUser({ ...user });
setShowUserModal(true);
}
const handleDeleteUser = (user: IDisplayUser) => {
setConfirmTitle(t('translation:delete-user-title', { userName: user.username }));
setConfirmMessage('');
setShowConfirm(true);
const handle = () => {
if (keycloak.token && user.username) {
deleteUser(user.id)
.then(() => {
removeUsers(user);
handleSuccess();
})
.catch(e => {
props.handleError(e);
})
}
};
// need to wrap a function again because react apply each function passed to hook
setConfirmHandle(() => handle);
}
const getDisplayRole = (user: IUser) => {
let roleString = '';
if (user.roleLab) {
roleString = t('translation:lab');
}
if (user.roleCounter) {
if (roleString) {
roleString += ', ';
}
roleString += t('translation:counter');
}
return roleString;
}
const setGroupPath = (user: IDisplayUser) => {
if (user.subGroup) {
const _groupName = getGroupPath(user.subGroup);
if (_groupName) {
user.displayGroup = _groupName;
}
else {
user.subGroup = '';
user.displayGroup = '';
}
}
else {
user.displayGroup = '';
}
}
const getGroupPath = (groupId: string | null): string => {
let groupName = ''
if (props.groupNodes && groupId) {
const fNode = (props.groupNodes as IGroupNode[]).find(gnode => gnode.group.id === groupId);
if (fNode) {
groupName = fNode.group.path;
}
}
return groupName;
}
return (<>
{
!(users && users.length > 0)
? <CwaSpinner background='#eeeeee' />
: <Collapse appear={true} in={true}>
<Container className='p-0 '>
<Table bordered hover responsive>
<thead>
<tr>
<th>{t('translation:user-name')}</th>
<th>{t('translation:first-name')}</th>
<th>{t('translation:name')}</th>
<th>{t('translation:group')}</th>
<th>{t('translation:permission')}</th>
<th></th>
</tr>
</thead>
<tbody>{
users.map((u, i) =>
<tr key={i}>
<td>{u.subGroup || (ownUserId && u.id === ownUserId)
? <></>
: <OverlayTrigger
placement='top-end'
overlay={
<Tooltip id='no-group-tooltip'>
{t('translation:no-group-tooltip')}
</Tooltip>
}
>
<span className='ff-fa px-1'> </span>
</OverlayTrigger>}
{u.username}</td>
<td>{u.firstName}</td>
<td>{u.lastName}</td>
<td>
{
u.displayGroup
? u.displayGroup
: u.subGroup
? <Spinner
animation="border"
className='d-flex mx-auto'
size="sm"
role="status"
aria-hidden="true"
variant='primary'
/>
: <></>
}
</td>
<td>{
u.displayRole !== undefined
? u.displayRole
: <Spinner
animation="border"
className='d-flex mx-auto'
size="sm"
role="status"
aria-hidden="true"
variant='primary'
/>
}
</td>
<td className='td-btn'>
<Row className='m-0 justify-content-around'>
<Button
className="btn-icon edit-icon"
onClick={() => startEditUser({ ...u })}
>
</Button>
<Button className="btn-icon delete-icon"
onClick={() => handleDeleteUser(u)}
disabled={!(ownUserId && u.id !== ownUserId)}
/>
</Row>
</td>
</tr>
)
}</tbody>
</Table>
<Button
className='btn-add'
size="sm"
variant="light"
onClick={() => { setEditUser({ ...emptyUser }); setShowUserModal(true) }}>
<img className='mr-2' src={imageAdd} alt="Hinzufügen" />
{t('translation:add-user')}
</Button>
</Container>
</Collapse>
}
<UserModal
show={showUserModal}
groups={props.groupNodes}
handleOk={userUpdate}
user={editUser}
onEnter={() => setIsUserSuccessfullUpdated(false)}
isSuccess={isUserSuccessfullUpdated}
isCreationError={isUserCreationError}
resetError={() => setIsUserCreationError(false)}
onCancel={() => setShowUserModal(false)}
onExit={
() => {
setEditUser({ ...emptyUser });
setIsUserSuccessfullUpdated(false);
setIsUserCreationError(false);
}
}
/>
<ConfirmModal
show={showConfirm}
title={confirmTitle}
message={confirmMessage}
onCancel={() => {
setConfirmHandle(undefined);
setShowConfirm(false);
}}
handleOk={() => {
if (confirmHandle) {
confirmHandle();
}
}}
/>
</>
)
}
Example #16
Source File: TxBlocksPage.tsx From devex with GNU General Public License v3.0 | 4 votes |
TxBlocksPage: React.FC = () => {
const networkContext = useContext(NetworkContext)
const { dataService } = networkContext!
const fetchIdRef = useRef(0)
const [isLoading, setIsLoading] = useState(false)
const [pageCount, setPageCount] = useState(0)
const [data, setData] = useState<TxBlockObj[] | null>(null)
const columns = useMemo(
() => [{
id: 'height-col',
Header: 'Height',
accessor: 'header.BlockNum',
Cell: ({ value }: { value: string }) => (
<QueryPreservingLink to={`/txbk/${value}`}>
{value}
</QueryPreservingLink>
)
},
{
id: 'mbs-count-col',
Header: 'MB Count',
accessor: 'body.MicroBlockInfos',
Cell: ({ value }: { value: string }) => (
<div className='text-center'>
{value.length > 0 ? value.length : '0'}
</div>
)
},
{
id: 'numTxns-col',
Header: 'Txns',
accessor: 'header.NumTxns',
Cell: ({ value }: { value: string }) => (
<div className='text-center'>
{value}
</div>
)
},
{
id: 'ds-leader-col',
Header: 'DS Leader',
accessor: 'header.MinerPubKey',
Cell: ({ value }: { value: string }) => (
<div className='mono'>
<QueryPreservingLink to={`/address/${pubKeyToZilAddr(value)}`}>
{pubKeyToZilAddr(value)}
</QueryPreservingLink>
</div>
)
},
{
id: 'bkhash-col',
Header: 'Block Hash',
accessor: 'body.BlockHash',
Cell: ({ value }: { value: string }) => (
<div style={{ textOverflow: 'ellipsis', overflow: 'hidden' }} className='mono'>{'0x' + value}</div>
)
}, {
id: 'total-txn-fees-col',
Header: 'Txn Fees',
accessor: 'header.TxnFees',
Cell: ({ value }: { value: string }) => (
<OverlayTrigger placement='right'
overlay={<Tooltip id={'total-txn-fees-tt'}> {qaToZil(value)} </Tooltip>}>
<div className='text-right'>{qaToZil(value, 5)}</div>
</OverlayTrigger>
)
},
{
id: 'rewards-col',
Header: 'Rewards',
accessor: 'header.Rewards',
Cell: ({ value }: { value: string }) => (
<OverlayTrigger placement='right'
overlay={<Tooltip id={'rewards-tt'}> {qaToZil(value)} </Tooltip>}>
<div className='text-right'>{qaToZil(value, 5)}</div>
</OverlayTrigger>
)
},
{
id: 'age-col',
Header: 'Age',
accessor: 'header.Timestamp',
Cell: ({ value }: { value: string }) => (
<div className='text-right'>{
timestampToTimeago(value)}
</div>
)
}], []
)
const fetchData = useCallback(({ pageIndex }) => {
if (!dataService) return
const fetchId = ++fetchIdRef.current
let receivedData: TxBlockObjListing
const getData = async () => {
try {
setIsLoading(true)
receivedData = await dataService.getTxBlocksListing(pageIndex + 1)
if (receivedData) {
setData(receivedData.data)
setPageCount(receivedData.maxPages)
}
} catch (e) {
console.log(e)
} finally {
setIsLoading(false)
}
}
if (fetchId === fetchIdRef.current)
getData()
}, [dataService])
return (
<>
{<div>
<h2>Transaction Blocks</h2>
<ViewAllTable
columns={columns}
data={data ? data : []}
isLoading={isLoading}
fetchData={fetchData}
pageCount={pageCount}
/>
</div>}
</>
)
}
Example #17
Source File: Collections.tsx From bada-frame with GNU General Public License v3.0 | 4 votes |
export default function Collections(props: CollectionProps) {
const { activeCollection, collections, setActiveCollection } = props;
const [selectedCollectionID, setSelectedCollectionID] =
useState<number>(null);
const collectionWrapperRef = useRef<HTMLDivElement>(null);
const collectionChipsRef = props.collections.reduce(
(refMap, collection) => {
refMap[collection.id] = React.createRef();
return refMap;
},
{}
);
const [collectionShareModalView, setCollectionShareModalView] =
useState(false);
const [scrollObj, setScrollObj] = useState<{
scrollLeft?: number;
scrollWidth?: number;
clientWidth?: number;
}>({});
const [collectionSortBy, setCollectionSortBy] =
useState<COLLECTION_SORT_BY>(COLLECTION_SORT_BY.LATEST_FILE);
const updateScrollObj = () => {
if (collectionWrapperRef.current) {
const { scrollLeft, scrollWidth, clientWidth } =
collectionWrapperRef.current;
setScrollObj({ scrollLeft, scrollWidth, clientWidth });
}
};
useEffect(() => {
updateScrollObj();
}, [collectionWrapperRef.current, props.isInSearchMode, collections]);
useEffect(() => {
if (!collectionWrapperRef?.current) {
return;
}
collectionWrapperRef.current.scrollLeft = 0;
}, [collections]);
useEffect(() => {
collectionChipsRef[activeCollection]?.current.scrollIntoView({
inline: 'center',
});
}, [activeCollection]);
const clickHandler = (collectionID?: number) => () => {
setSelectedCollectionID(collectionID);
setActiveCollection(collectionID ?? ALL_SECTION);
};
const user: User = getData(LS_KEYS.USER);
const collectionOptions = CollectionOptions({
syncWithRemote: props.syncWithRemote,
setCollectionNamerAttributes: props.setCollectionNamerAttributes,
collections: props.collections,
selectedCollectionID,
setDialogMessage: props.setDialogMessage,
startLoading: props.startLoading,
finishLoading: props.finishLoading,
showCollectionShareModal: setCollectionShareModalView.bind(null, true),
redirectToAll: setActiveCollection.bind(null, ALL_SECTION),
});
const scrollCollection = (direction: SCROLL_DIRECTION) => () => {
collectionWrapperRef.current.scrollBy(250 * direction, 0);
};
const renderTooltip = (collectionID: number) => {
const fileCount = props.collectionFilesCount?.get(collectionID) ?? 0;
return (
<Tooltip id="button-tooltip">
{fileCount} {fileCount > 1 ? 'items' : 'item'}
</Tooltip>
);
};
const SectionChip = SectionChipCreater({ activeCollection, clickHandler });
return (
<Hider hide={props.isInSearchMode}>
<CollectionShare
show={collectionShareModalView}
onHide={() => setCollectionShareModalView(false)}
collection={getSelectedCollection(
selectedCollectionID,
props.collections
)}
syncWithRemote={props.syncWithRemote}
/>
<CollectionBar>
<CollectionContainer>
{scrollObj.scrollLeft > 0 && (
<NavigationButton
scrollDirection={SCROLL_DIRECTION.LEFT}
onClick={scrollCollection(SCROLL_DIRECTION.LEFT)}
/>
)}
<Wrapper
ref={collectionWrapperRef}
onScroll={updateScrollObj}>
<SectionChip
section={ALL_SECTION}
label={constants.ALL}
/>
{sortCollections(
collections,
props.collectionAndTheirLatestFile,
collectionSortBy
).map((item) => (
<OverlayTrigger
key={item.id}
placement="top"
delay={{ show: 250, hide: 400 }}
overlay={renderTooltip(item.id)}>
<Chip
ref={collectionChipsRef[item.id]}
active={activeCollection === item.id}
onClick={clickHandler(item.id)}
archived={IsArchived(item)}>
{IsArchived(item) && (
<IconWithMessage
message={constants.ARCHIVED_ALBUM}>
<div
style={{
display: 'inline-block',
marginRight: '5px',
}}>
<Archive />
</div>
</IconWithMessage>
)}
{item.name}
{item.type !== CollectionType.favorites &&
item.owner.id === user?.id ? (
<OverlayTrigger
rootClose
trigger="click"
placement="bottom"
overlay={collectionOptions}>
<OptionIcon
onClick={() =>
setSelectedCollectionID(
item.id
)
}
/>
</OverlayTrigger>
) : (
<div
style={{
display: 'inline-block',
width: '24px',
}}
/>
)}
</Chip>
</OverlayTrigger>
))}
<SectionChip
section={ARCHIVE_SECTION}
label={constants.ARCHIVE}
/>
<SectionChip
section={TRASH_SECTION}
label={constants.TRASH}
/>
</Wrapper>
{scrollObj.scrollLeft <
scrollObj.scrollWidth - scrollObj.clientWidth && (
<NavigationButton
scrollDirection={SCROLL_DIRECTION.RIGHT}
onClick={scrollCollection(SCROLL_DIRECTION.RIGHT)}
/>
)}
</CollectionContainer>
<CollectionSort
setCollectionSortBy={setCollectionSortBy}
activeSortBy={collectionSortBy}
/>
</CollectionBar>
</Hider>
);
}
Example #18
Source File: compiler-container.tsx From remix-project with MIT License | 4 votes |
CompilerContainer = (props: CompilerContainerProps) => {
const { api, compileTabLogic, tooltip, modal, compiledFileName, updateCurrentVersion, configurationSettings, isHardhatProject, isTruffleProject, workspaceName } = props // eslint-disable-line
const [state, setState] = useState({
hideWarnings: false,
autoCompile: false,
configFilePath: "compiler_config.json",
useFileConfiguration: false,
matomoAutocompileOnce: true,
optimize: false,
compileTimeout: null,
timeout: 300,
allversions: [],
customVersions: [],
selectedVersion: null,
defaultVersion: 'soljson-v0.8.7+commit.e28d00a7.js', // this default version is defined: in makeMockCompiler (for browser test)
runs: '',
compiledFileName: '',
includeNightlies: false,
language: 'Solidity',
evmVersion: ''
})
const [showFilePathInput, setShowFilePathInput] = useState<boolean>(false)
const [toggleExpander, setToggleExpander] = useState<boolean>(false)
const [disableCompileButton, setDisableCompileButton] = useState<boolean>(false)
const compileIcon = useRef(null)
const promptMessageInput = useRef(null)
const configFilePathInput = useRef(null)
const [hhCompilation, sethhCompilation] = useState(false)
const [truffleCompilation, setTruffleCompilation] = useState(false)
const [compilerContainer, dispatch] = useReducer(compilerReducer, compilerInitialState)
useEffect(() => {
api.setAppParameter('configFilePath', "/compiler_config.json")
api.fileExists("/compiler_config.json").then((exists) => {
if (!exists) createNewConfigFile()
else {
// what to do? discuss
}
})
api.setAppParameter('configFilePath', "/compiler_config.json")
setShowFilePathInput(false)
}, [workspaceName])
useEffect(() => {
const listener = (event) => {
if (configFilePathInput.current !== event.target) {
setShowFilePathInput(false)
return;
}
};
document.addEventListener("mousedown", listener);
document.addEventListener("touchstart", listener);
return () => {
document.removeEventListener("mousedown", listener);
document.removeEventListener("touchstart", listener);
}
})
useEffect(() => {
fetchAllVersion((allversions, selectedVersion, isURL) => {
setState(prevState => {
return { ...prevState, allversions }
})
if (isURL) _updateVersionSelector(state.defaultVersion, selectedVersion)
else {
setState(prevState => {
return { ...prevState, selectedVersion }
})
updateCurrentVersion(selectedVersion)
_updateVersionSelector(selectedVersion)
}
})
const currentFileName = api.currentFile
currentFile(currentFileName)
listenToEvents(compileTabLogic, api)(dispatch)
}, [])
useEffect(() => {
(async () => {
if (compileTabLogic && compileTabLogic.compiler) {
const autocompile = await api.getAppParameter('autoCompile') as boolean || false
const hideWarnings = await api.getAppParameter('hideWarnings') as boolean || false
const includeNightlies = await api.getAppParameter('includeNightlies') as boolean || false
const useFileConfiguration = await api.getAppParameter('useFileConfiguration') as boolean || false
let configFilePath = await api.getAppParameter('configFilePath')
if (!configFilePath || configFilePath == '') configFilePath = "/compiler_config.json"
setState(prevState => {
const params = api.getCompilerParameters()
const optimize = params.optimize
const runs = params.runs as string
const evmVersion = compileTabLogic.evmVersions.includes(params.evmVersion) ? params.evmVersion : 'default'
const language = getValidLanguage(params.language)
return {
...prevState,
hideWarnings: hideWarnings,
autoCompile: autocompile,
includeNightlies: includeNightlies,
useFileConfiguration: useFileConfiguration,
configFilePath: configFilePath,
optimize: optimize,
runs: runs,
evmVersion: (evmVersion !== null) && (evmVersion !== 'null') && (evmVersion !== undefined) && (evmVersion !== 'undefined') ? evmVersion : 'default',
language: (language !== null) ? language : 'Solidity'
}
})
}
})()
}, [compileTabLogic])
useEffect(() => {
const isDisabled = !compiledFileName || (compiledFileName && !isSolFileSelected(compiledFileName))
setDisableCompileButton(isDisabled)
setState(prevState => {
return { ...prevState, compiledFileName }
})
}, [compiledFileName])
useEffect(() => {
if (compilerContainer.compiler.mode) {
switch (compilerContainer.compiler.mode) {
case 'startingCompilation':
startingCompilation()
break
case 'compilationDuration':
compilationDuration(compilerContainer.compiler.args[0])
break
case 'loadingCompiler':
loadingCompiler()
break
case 'compilerLoaded':
compilerLoaded()
break
case 'compilationFinished':
compilationFinished()
break
}
}
}, [compilerContainer.compiler.mode])
useEffect(() => {
if (compilerContainer.editor.mode) {
switch (compilerContainer.editor.mode) {
case 'sessionSwitched':
sessionSwitched()
resetEditorMode()(dispatch)
break
case 'contentChanged':
contentChanged()
resetEditorMode()(dispatch)
break
}
}
}, [compilerContainer.editor.mode])
useEffect(() => {
compileTabLogic.setUseFileConfiguration(state.useFileConfiguration)
if (state.useFileConfiguration) compileTabLogic.setConfigFilePath(state.configFilePath)
}, [state.useFileConfiguration])
useEffect(() => {
if (configurationSettings) {
setConfiguration(configurationSettings)
}
}, [configurationSettings])
const toggleConfigType = () => {
setState(prevState => {
api.setAppParameter('useFileConfiguration', !state.useFileConfiguration)
return { ...prevState, useFileConfiguration: !state.useFileConfiguration }
})
}
const openFile = async () => {
api.open(state.configFilePath)
}
const createNewConfigFile = async () => {
let filePath = configFilePathInput.current && configFilePathInput.current.value !== '' ? configFilePathInput.current.value : state.configFilePath
if (!filePath.endsWith('.json')) filePath = filePath + '.json'
await api.writeFile(filePath, configFileContent)
api.setAppParameter('configFilePath', filePath)
setState(prevState => {
return { ...prevState, configFilePath: filePath }
})
compileTabLogic.setConfigFilePath(filePath)
setShowFilePathInput(false)
}
const handleConfigPathChange = async () => {
if (configFilePathInput.current.value !== '') {
if (!configFilePathInput.current.value.endsWith('.json')) configFilePathInput.current.value += '.json'
if (await api.fileExists(configFilePathInput.current.value)) {
api.setAppParameter('configFilePath', configFilePathInput.current.value)
setState(prevState => {
return { ...prevState, configFilePath: configFilePathInput.current.value }
})
compileTabLogic.setConfigFilePath(configFilePathInput.current.value)
setShowFilePathInput(false)
} else {
modal(
'New configuration file', `The file "${configFilePathInput.current.value}" you entered does not exist. Do you want to create a new one?`,
'Create',
async () => await createNewConfigFile(),
'Cancel',
() => {
setShowFilePathInput(false)
}
)
}
}
}
const _retrieveVersion = (version?) => {
if (!version) version = state.selectedVersion
if (version === 'builtin') version = state.defaultVersion
return semver.coerce(version) ? semver.coerce(version).version : ''
}
// fetching both normal and wasm builds and creating a [version, baseUrl] map
const fetchAllVersion = async (callback) => {
let selectedVersion, allVersionsWasm, isURL
let allVersions = [{ path: 'builtin', longVersion: 'latest local version - ' + state.defaultVersion }]
// fetch normal builds
const binRes: any = await promisedMiniXhr(`${baseURLBin}/list.json`)
// fetch wasm builds
const wasmRes: any = await promisedMiniXhr(`${baseURLWasm}/list.json`)
if (binRes.event.type === 'error' && wasmRes.event.type === 'error') {
selectedVersion = 'builtin'
return callback(allVersions, selectedVersion)
}
try {
const versions = JSON.parse(binRes.json).builds.slice().reverse()
allVersions = [...allVersions, ...versions]
selectedVersion = state.defaultVersion
if (api.getCompilerParameters().version) selectedVersion = api.getCompilerParameters().version
// Check if version is a URL and corresponding filename starts with 'soljson'
if (selectedVersion.startsWith('https://')) {
const urlArr = selectedVersion.split('/')
if (urlArr[urlArr.length - 1].startsWith('soljson')) isURL = true
}
if (wasmRes.event.type !== 'error') {
allVersionsWasm = JSON.parse(wasmRes.json).builds.slice().reverse()
}
} catch (e) {
tooltip('Cannot load compiler version list. It might have been blocked by an advertisement blocker. Please try deactivating any of them from this page and reload. Error: ' + e)
}
// replace in allVersions those compiler builds which exist in allVersionsWasm with new once
if (allVersionsWasm && allVersions) {
allVersions.forEach((compiler, index) => {
const wasmIndex = allVersionsWasm.findIndex(wasmCompiler => { return wasmCompiler.longVersion === compiler.longVersion })
if (wasmIndex !== -1) {
allVersions[index] = allVersionsWasm[wasmIndex]
pathToURL[compiler.path] = baseURLWasm
} else {
pathToURL[compiler.path] = baseURLBin
}
})
}
callback(allVersions, selectedVersion, isURL)
}
/**
* Update the compilation button with the name of the current file
*/
const currentFile = (name = '') => {
if (name && name !== '') {
_setCompilerVersionFromPragma(name)
}
const compiledFileName = name.split('/').pop()
setState(prevState => {
return { ...prevState, compiledFileName }
})
}
// Load solc compiler version according to pragma in contract file
const _setCompilerVersionFromPragma = (filename: string) => {
if (!state.allversions) return
api.readFile(filename).then(data => {
if (!data) return
const pragmaArr = data.match(/(pragma solidity (.+?);)/g)
if (pragmaArr && pragmaArr.length === 1) {
const pragmaStr = pragmaArr[0].replace('pragma solidity', '').trim()
const pragma = pragmaStr.substring(0, pragmaStr.length - 1)
const releasedVersions = state.allversions.filter(obj => !obj.prerelease).map(obj => obj.version)
const allVersions = state.allversions.map(obj => _retrieveVersion(obj.version))
const currentCompilerName = _retrieveVersion(state.selectedVersion)
// contains only numbers part, for example '0.4.22'
const pureVersion = _retrieveVersion()
// is nightly build newer than the last release
const isNewestNightly = currentCompilerName.includes('nightly') && semver.gt(pureVersion, releasedVersions[0])
// checking if the selected version is in the pragma range
const isInRange = semver.satisfies(pureVersion, pragma)
// checking if the selected version is from official compilers list(excluding custom versions) and in range or greater
const isOfficial = allVersions.includes(currentCompilerName)
if (isOfficial && (!isInRange && !isNewestNightly)) {
const compilerToLoad = semver.maxSatisfying(releasedVersions, pragma)
const compilerPath = state.allversions.filter(obj => !obj.prerelease && obj.version === compilerToLoad)[0].path
if (state.selectedVersion !== compilerPath) {
setState((prevState) => {
return { ...prevState, selectedVersion: compilerPath }
})
_updateVersionSelector(compilerPath)
}
}
}
})
}
const isSolFileSelected = (currentFile = '') => {
if (!currentFile) currentFile = api.currentFile
if (!currentFile) return false
const extention = currentFile.substr(currentFile.length - 3, currentFile.length)
return extention.toLowerCase() === 'sol' || extention.toLowerCase() === 'yul'
}
const sessionSwitched = () => {
if (!compileIcon.current) return
scheduleCompilation()
}
const startingCompilation = () => {
if (!compileIcon.current) return
compileIcon.current.setAttribute('title', 'compiling...')
compileIcon.current.classList.remove('remixui_bouncingIcon')
compileIcon.current.classList.add('remixui_spinningIcon')
}
const compilationDuration = (speed: number) => {
if (speed > 1000) {
console.log(`Last compilation took ${speed}ms. We suggest to turn off autocompilation.`)
}
}
const contentChanged = () => {
if (!compileIcon.current) return
scheduleCompilation()
compileIcon.current.classList.add('remixui_bouncingIcon') // @TODO: compileView tab
}
const loadingCompiler = () => {
if (!compileIcon.current) return
compileIcon.current.setAttribute('title', 'compiler is loading, please wait a few moments.')
compileIcon.current.classList.add('remixui_spinningIcon')
_updateLanguageSelector()
setDisableCompileButton(true)
}
const compilerLoaded = () => {
if (!compileIcon.current) return
compileIcon.current.setAttribute('title', '')
compileIcon.current.classList.remove('remixui_spinningIcon')
if (state.autoCompile) compile()
const isDisabled = !compiledFileName || (compiledFileName && !isSolFileSelected(compiledFileName))
setDisableCompileButton(isDisabled)
}
const compilationFinished = () => {
if (!compileIcon.current) return
compileIcon.current.setAttribute('title', 'idle')
compileIcon.current.classList.remove('remixui_spinningIcon')
compileIcon.current.classList.remove('remixui_bouncingIcon')
if (!state.autoCompile || (state.autoCompile && state.matomoAutocompileOnce)) {
_paq.push(['trackEvent', 'compiler', 'compiled_with_version', _retrieveVersion()])
if (state.autoCompile && state.matomoAutocompileOnce) {
setState(prevState => {
return { ...prevState, matomoAutocompileOnce: false }
})
}
}
}
const scheduleCompilation = () => {
if (!state.autoCompile) return
if (state.compileTimeout) window.clearTimeout(state.compileTimeout)
const compileTimeout = window.setTimeout(() => {
state.autoCompile && compile()
}, state.timeout)
setState(prevState => {
return { ...prevState, compileTimeout }
})
}
const compile = () => {
const currentFile = api.currentFile
if (!isSolFileSelected()) return
_setCompilerVersionFromPragma(currentFile)
let externalCompType
if (hhCompilation) externalCompType = 'hardhat'
else if (truffleCompilation) externalCompType = 'truffle'
compileTabLogic.runCompiler(externalCompType)
}
const compileAndRun = () => {
const currentFile = api.currentFile
if (!isSolFileSelected()) return
_setCompilerVersionFromPragma(currentFile)
let externalCompType
if (hhCompilation) externalCompType = 'hardhat'
else if (truffleCompilation) externalCompType = 'truffle'
api.runScriptAfterCompilation(currentFile)
compileTabLogic.runCompiler(externalCompType)
}
const _updateVersionSelector = (version, customUrl = '') => {
// update selectedversion of previous one got filtered out
let selectedVersion = version
if (!selectedVersion || !_shouldBeAdded(selectedVersion)) {
selectedVersion = state.defaultVersion
setState(prevState => {
return { ...prevState, selectedVersion }
})
}
updateCurrentVersion(selectedVersion)
api.setCompilerParameters({ version: selectedVersion })
let url
if (customUrl !== '') {
selectedVersion = customUrl
setState(prevState => {
return { ...prevState, selectedVersion, customVersions: [...state.customVersions, selectedVersion] }
})
updateCurrentVersion(selectedVersion)
url = customUrl
api.setCompilerParameters({ version: selectedVersion })
} else {
if (checkSpecialChars(selectedVersion)) {
return console.log('loading ' + selectedVersion + ' not allowed, special chars not allowed.')
}
if (selectedVersion === 'builtin' || selectedVersion.indexOf('soljson') === 0) {
url = urlFromVersion(selectedVersion)
} else {
return console.log('loading ' + selectedVersion + ' not allowed, version should start with "soljson"')
}
}
// Workers cannot load js on "file:"-URLs and we get a
// "Uncaught RangeError: Maximum call stack size exceeded" error on Chromium,
// resort to non-worker version in that case.
if (selectedVersion === 'builtin') selectedVersion = state.defaultVersion
if (selectedVersion !== 'builtin' && canUseWorker(selectedVersion)) {
compileTabLogic.compiler.loadVersion(true, url)
} else {
compileTabLogic.compiler.loadVersion(false, url)
}
}
const _shouldBeAdded = (version) => {
return !version.includes('nightly') ||
(version.includes('nightly') && state.includeNightlies)
}
const promptCompiler = () => {
// custom url https://solidity-blog.s3.eu-central-1.amazonaws.com/data/08preview/soljson.js
modal('Add a custom compiler', promptMessage('URL'), 'OK', addCustomCompiler, 'Cancel', () => {})
}
const promptMessage = (message) => {
return (
<>
<span>{ message }</span>
<input type="text" data-id="modalDialogCustomPromptCompiler" className="form-control" ref={promptMessageInput} />
</>
)
}
const addCustomCompiler = () => {
const url = promptMessageInput.current.value
setState(prevState => {
return { ...prevState, selectedVersion: url }
})
_updateVersionSelector(state.defaultVersion, url)
}
const handleLoadVersion = (value) => {
setState(prevState => {
return { ...prevState, selectedVersion: value, matomoAutocompileOnce: true }
})
updateCurrentVersion(value)
_updateVersionSelector(value)
_updateLanguageSelector()
}
const _updateLanguageSelector = () => {
// This is the first version when Yul is available
if (!semver.valid(_retrieveVersion()) || semver.lt(_retrieveVersion(), 'v0.5.7+commit.6da8b019.js')) {
handleLanguageChange('Solidity')
compileTabLogic.setLanguage('Solidity')
}
}
const handleAutoCompile = (e) => {
const checked = e.target.checked
api.setAppParameter('autoCompile', checked)
checked && compile()
setState(prevState => {
return { ...prevState, autoCompile: checked, matomoAutocompileOnce: state.matomoAutocompileOnce || checked }
})
}
const handleOptimizeChange = (value) => {
const checked = !!value
api.setAppParameter('optimize', checked)
compileTabLogic.setOptimize(checked)
if (compileTabLogic.optimize) {
compileTabLogic.setRuns(parseInt(state.runs))
} else {
compileTabLogic.setRuns(200)
}
state.autoCompile && compile()
setState(prevState => {
return { ...prevState, optimize: checked }
})
}
const onChangeRuns = (value) => {
const runs = value
compileTabLogic.setRuns(parseInt(runs))
state.autoCompile && compile()
setState(prevState => {
return { ...prevState, runs }
})
}
const handleHideWarningsChange = (e) => {
const checked = e.target.checked
api.setAppParameter('hideWarnings', checked)
state.autoCompile && compile()
setState(prevState => {
return { ...prevState, hideWarnings: checked }
})
}
const handleNightliesChange = (e) => {
const checked = e.target.checked
if (!checked) handleLoadVersion(state.defaultVersion)
api.setAppParameter('includeNightlies', checked)
setState(prevState => {
return { ...prevState, includeNightlies: checked }
})
}
const handleLanguageChange = (value) => {
compileTabLogic.setLanguage(value)
state.autoCompile && compile()
setState(prevState => {
return { ...prevState, language: value }
})
}
const handleEvmVersionChange = (value) => {
if (!value) return
let v = value
if (v === 'default') {
v = null
}
compileTabLogic.setEvmVersion(v)
state.autoCompile && compile()
setState(prevState => {
return { ...prevState, evmVersion: value }
})
}
const updatehhCompilation = (event) => {
const checked = event.target.checked
if (checked) setTruffleCompilation(false) // wayaround to reset the variable
sethhCompilation(checked)
api.setAppParameter('hardhat-compilation', checked)
}
const updateTruffleCompilation = (event) => {
const checked = event.target.checked
if (checked) sethhCompilation(false) // wayaround to reset the variable
setTruffleCompilation(checked)
api.setAppParameter('truffle-compilation', checked)
}
/*
The following functions map with the above event handlers.
They are an external API for modifying the compiler configuration.
*/
const setConfiguration = (settings: ConfigurationSettings) => {
handleLoadVersion(`soljson-v${settings.version}.js`)
handleEvmVersionChange(settings.evmVersion)
handleLanguageChange(settings.language)
handleOptimizeChange(settings.optimize)
onChangeRuns(settings.runs)
}
const toggleConfigurations = () => {
setToggleExpander(!toggleExpander)
}
return (
<section>
<article>
<div className='pt-0 remixui_compilerSection'>
<div className="mb-1">
<label className="remixui_compilerLabel form-check-label" htmlFor="versionSelector">
Compiler
<button className="far fa-plus btn-light border-0 p-0 mx-2 btn-sm" onClick={promptCompiler} title="Add a custom compiler with URL"></button>
</label>
<select value={ state.selectedVersion || state.defaultVersion } onChange={(e) => handleLoadVersion(e.target.value) } className="custom-select" id="versionSelector" disabled={state.allversions.length <= 0}>
{ state.allversions.length <= 0 && <option disabled data-id={state.selectedVersion === state.defaultVersion ? 'selected' : ''}>{ state.defaultVersion }</option> }
{ state.allversions.length <= 0 && <option disabled data-id={state.selectedVersion === 'builtin' ? 'selected' : ''}>builtin</option> }
{ state.customVersions.map((url, i) => <option key={i} data-id={state.selectedVersion === url ? 'selected' : ''} value={url}>custom</option>)}
{ state.allversions.map((build, i) => {
return _shouldBeAdded(build.longVersion)
? <option key={i} value={build.path} data-id={state.selectedVersion === build.path ? 'selected' : ''}>{build.longVersion}</option>
: null
})
}
</select>
</div>
<div className="mb-2 flex-row-reverse remixui_nightlyBuilds custom-control custom-checkbox">
<input className="mr-2 custom-control-input" id="nightlies" type="checkbox" onChange={handleNightliesChange} checked={state.includeNightlies} />
<label htmlFor="nightlies" data-id="compilerNightliesBuild" className="form-check-label custom-control-label">Include nightly builds</label>
</div>
<div className="mt-2 remixui_compilerConfig custom-control custom-checkbox">
<input className="remixui_autocompile custom-control-input" type="checkbox" onChange={handleAutoCompile} data-id="compilerContainerAutoCompile" id="autoCompile" title="Auto compile" checked={state.autoCompile} />
<label className="form-check-label custom-control-label" htmlFor="autoCompile">Auto compile</label>
</div>
<div className="mt-1 mb-2 remixui_compilerConfig custom-control custom-checkbox">
<input className="remixui_autocompile custom-control-input" onChange={handleHideWarningsChange} id="hideWarningsBox" type="checkbox" title="Hide warnings" checked={state.hideWarnings} />
<label className="form-check-label custom-control-label" htmlFor="hideWarningsBox">Hide warnings</label>
</div>
{
isHardhatProject &&
<div className="mt-3 remixui_compilerConfig custom-control custom-checkbox">
<input className="remixui_autocompile custom-control-input" onChange={updatehhCompilation} id="enableHardhat" type="checkbox" title="Enable Hardhat Compilation" checked={hhCompilation} />
<label className="form-check-label custom-control-label" htmlFor="enableHardhat">Enable Hardhat Compilation</label>
<a className="mt-1 text-nowrap" href='https://remix-ide.readthedocs.io/en/latest/hardhat.html#enable-hardhat-compilation' target={'_blank'}>
<OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="overlay-tooltip-hardhat">
<span className="p-1 pr-3" style={{ backgroundColor: 'black', minWidth: '230px' }}>Learn how to use Hardhat Compilation</span>
</Tooltip>
}>
<i style={{ fontSize: 'medium' }} className={'ml-2 fal fa-info-circle'} aria-hidden="true"></i>
</OverlayTrigger>
</a>
</div>
}
{
isTruffleProject &&
<div className="mt-3 remixui_compilerConfig custom-control custom-checkbox">
<input className="remixui_autocompile custom-control-input" onChange={updateTruffleCompilation} id="enableTruffle" type="checkbox" title="Enable Truffle Compilation" checked={truffleCompilation} />
<label className="form-check-label custom-control-label" htmlFor="enableTruffle">Enable Truffle Compilation</label>
<a className="mt-1 text-nowrap" href='https://remix-ide.readthedocs.io/en/latest/truffle.html#enable-truffle-compilation' target={'_blank'}>
<OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="overlay-tooltip-truffle">
<span className="p-1 pr-3" style={{ backgroundColor: 'black', minWidth: '230px' }}>Learn how to use Truffle Compilation</span>
</Tooltip>
}>
<i style={{ fontSize: 'medium' }} className={'ml-2 fal fa-info-circle'} aria-hidden="true"></i>
</OverlayTrigger>
</a>
</div>
}
</div>
<div className="d-flex px-4 remixui_compilerConfigSection justify-content-between" onClick={toggleConfigurations}>
<div className="d-flex">
<label className="mt-1 remixui_compilerConfigSection">Advanced Configurations</label>
</div>
<div>
<span data-id='scConfigExpander' onClick={toggleConfigurations}>
<i className={!toggleExpander ? 'fas fa-angle-right' : 'fas fa-angle-down'} aria-hidden="true"></i>
</span>
</div>
</div>
<div className={`px-4 pb-4 border-bottom flex-column ${toggleExpander ? "d-flex" : "d-none"}`}>
<div className="d-flex pb-1 remixui_compilerConfig custom-control custom-radio">
<input className="custom-control-input" type="radio" name="configradio" value="manual" onChange={toggleConfigType} checked={!state.useFileConfiguration} id="scManualConfig" />
<label className="form-check-label custom-control-label" htmlFor="scManualConfig">Compiler configuration</label>
</div>
<div className={`flex-column 'd-flex'}`}>
<div className="mb-2 ml-4">
<label className="remixui_compilerLabel form-check-label" htmlFor="compilierLanguageSelector">Language</label>
<select onChange={(e) => handleLanguageChange(e.target.value)} disabled={state.useFileConfiguration} value={state.language} className="custom-select" id="compilierLanguageSelector" title="Available since v0.5.7">
<option data-id={state.language === 'Solidity' ? 'selected' : ''} value='Solidity'>Solidity</option>
<option data-id={state.language === 'Yul' ? 'selected' : ''} value='Yul'>Yul</option>
</select>
</div>
<div className="mb-2 ml-4">
<label className="remixui_compilerLabel form-check-label" htmlFor="evmVersionSelector">EVM Version</label>
<select value={state.evmVersion} onChange={(e) => handleEvmVersionChange(e.target.value)} disabled={state.useFileConfiguration} className="custom-select" id="evmVersionSelector">
{compileTabLogic.evmVersions.map((version, index) => (<option key={index} data-id={state.evmVersion === version ? 'selected' : ''} value={version}>{version}</option>))}
</select>
</div>
<div className="mt-1 mt-3 border-dark pb-3 ml-4 remixui_compilerConfig custom-control custom-checkbox">
<div className="justify-content-between align-items-center d-flex">
<input onChange={(e) => { handleOptimizeChange(e.target.checked) }} disabled={state.useFileConfiguration} className="custom-control-input" id="optimize" type="checkbox" checked={state.optimize} />
<label className="form-check-label custom-control-label" htmlFor="optimize">Enable optimization</label>
<input
min="1"
className="custom-select ml-2 remixui_runs"
id="runs"
placeholder="200"
value={state.runs}
type="number"
title="Estimated number of times each opcode of the deployed code will be executed across the life-time of the contract."
onChange={(e) => onChangeRuns(e.target.value)}
disabled={!state.optimize || state.useFileConfiguration}
/>
</div>
</div>
</div>
<div className="d-flex pb-1 remixui_compilerConfig custom-control custom-radio">
<input className="custom-control-input" type="radio" name="configradio" value="file" onChange={toggleConfigType} checked={state.useFileConfiguration} id="scFileConfig" />
<label className="form-check-label custom-control-label" htmlFor="scFileConfig">Use configuration file</label>
</div>
<div className={`pt-2 ml-4 ml-2 align-items-start justify-content-between d-flex`}>
{ (!showFilePathInput && state.useFileConfiguration) && <span
title="Click to open the config file."
onClick={openFile}
className="py-2 text-primary remixui_compilerConfigPath"
>{state.configFilePath}</span> }
{ (!showFilePathInput&& !state.useFileConfiguration) && <span className="py-2 text-secondary">{state.configFilePath}</span> }
<input
ref={configFilePathInput}
className={`py-0 my-0 form-control ${showFilePathInput ? "d-flex" : "d-none"}`}
placeholder={"Enter the new path"}
title="If the file you entered does not exist you will be able to create one in the next step."
disabled={!state.useFileConfiguration}
onKeyPress={event => {
if (event.key === 'Enter') {
handleConfigPathChange()
}
}}
/>
{ !showFilePathInput && <button disabled={!state.useFileConfiguration} className="btn-secondary" onClick={() => {setShowFilePathInput(true)}}>Change</button> }
</div>
</div>
<div className="px-4">
<button id="compileBtn" data-id="compilerContainerCompileBtn" className="btn btn-primary btn-block d-block w-100 text-break remixui_disabled mb-1 mt-3" onClick={compile} disabled={disableCompileButton}>
<OverlayTrigger overlay={
<Tooltip id="overlay-tooltip-compile">
<div className="text-left">
<div><b>Ctrl+S</b> for compiling</div>
</div>
</Tooltip>
}>
<span>
{ <i ref={compileIcon} className="fas fa-sync remixui_iconbtn" aria-hidden="true"></i> }
Compile { typeof state.compiledFileName === 'string' ? extractNameFromKey(state.compiledFileName) || '<no file selected>' : '<no file selected>' }
</span>
</OverlayTrigger>
</button>
<div className='d-flex align-items-center'>
<button id="compileAndRunBtn" data-id="compilerContainerCompileAndRunBtn" className="btn btn-secondary btn-block d-block w-100 text-break remixui_solidityCompileAndRunButton d-inline-block remixui_disabled mb-1 mt-3" onClick={compileAndRun} disabled={disableCompileButton}>
<OverlayTrigger overlay={
<Tooltip id="overlay-tooltip-compile-run">
<div className="text-left">
<div><b>Ctrl+Shift+S</b> for compiling and script execution</div>
</div>
</Tooltip>
}>
<span>
Compile and Run script
</span>
</OverlayTrigger>
</button>
<OverlayTrigger overlay={
<Tooltip id="overlay-tooltip-compile-run-doc">
<div className="text-left p-2">
<div>Choose the script to execute right after compilation by adding the `dev-run-script` natspec tag, as in:</div>
<pre>
<code>
/**<br />
* @title ContractName<br />
* @dev ContractDescription<br />
* @custom:dev-run-script file_path<br />
*/<br />
contract ContractName {'{}'}<br />
</code>
</pre>
Click to know more
</div>
</Tooltip>
}>
<a href="https://remix-ide.readthedocs.io/en/latest/running_js_scripts.html#compile-a-contract-and-run-a-script-on-the-fly" target="_blank" ><i className="pl-2 ml-2 mt-3 mb-1 fas fa-info text-dark"></i></a>
</OverlayTrigger>
<CopyToClipboard tip="Copy tag to use in contract NatSpec" getContent={() => '@custom:dev-run-script file_path'} direction='top'>
<button className="btn remixui_copyButton ml-2 mt-3 mb-1 text-dark">
<i className="remixui_copyIcon far fa-copy" aria-hidden="true"></i>
</button>
</CopyToClipboard>
</div>
</div>
</article>
</section>
)
}
Example #19
Source File: remix-ui-static-analyser.tsx From remix-project with MIT License | 4 votes |
RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
const [runner] = useState(new CodeAnalysis())
const preProcessModules = (arr: any) => {
return arr.map((Item, i) => {
const itemObj = new Item()
itemObj._index = i
itemObj.categoryDisplayName = itemObj.category.displayName
itemObj.categoryId = itemObj.category.id
return itemObj
})
}
const groupedModules = util.groupBy(
preProcessModules(runner.modules()),
'categoryId'
)
const getIndex = (modules, array) => {
Object.values(modules).map((value: {_index}) => {
if (Array.isArray(value)) {
value.forEach((x) => {
array.push(x._index.toString())
})
} else {
array.push(value._index.toString())
}
})
}
const groupedModuleIndex = (modules) => {
const indexOfCategory = []
if (!_.isEmpty(modules)) {
getIndex(modules, indexOfCategory)
}
return indexOfCategory
}
const [autoRun, setAutoRun] = useState(true)
const [slitherEnabled, setSlitherEnabled] = useState(false)
const [showSlither, setShowSlither] = useState(false)
let [showLibsWarning, setShowLibsWarning] = useState(false) // eslint-disable-line prefer-const
const [categoryIndex, setCategoryIndex] = useState(groupedModuleIndex(groupedModules))
const [warningState, setWarningState] = useState({})
const warningContainer = useRef(null)
const allWarnings = useRef({})
const [state, dispatch] = useReducer(analysisReducer, initialState)
useEffect(() => {
compilation(props.analysisModule, dispatch)
}, [props])
useEffect(() => {
setWarningState({})
const runAnalysis = async () => {
await run(state.data, state.source, state.file)
}
if (autoRun) {
if (state.data !== null) {
runAnalysis().catch(console.error);
}
} else {
props.event.trigger('staticAnaysisWarning', [])
}
return () => { }
}, [state])
useEffect(() => {
props.analysisModule.on('filePanel', 'setWorkspace', (currentWorkspace) => {
// Reset warning state
setWarningState([])
// Reset badge
props.event.trigger('staticAnaysisWarning', [])
// Reset state
dispatch({ type: '', payload: {} })
// Show 'Enable Slither Analysis' checkbox
if (currentWorkspace && currentWorkspace.isLocalhost === true) setShowSlither(true)
else {
setShowSlither(false)
setSlitherEnabled(false)
}
})
props.analysisModule.on('manager', 'pluginDeactivated', (plugin) => {
// Hide 'Enable Slither Analysis' checkbox
if (plugin.name === 'remixd') {
// Reset warning state
setWarningState([])
// Reset badge
props.event.trigger('staticAnaysisWarning', [])
// Reset state
dispatch({ type: '', payload: {} })
setShowSlither(false)
setSlitherEnabled(false)
}
})
return () => { }
}, [props])
const message = (name, warning, more, fileName, locationString) : string => {
return (`
<span className='d-flex flex-column'>
<span className='h6 font-weight-bold'>${name}</span>
${warning}
${more
? (<span><a href={more} target='_blank'>more</a></span>)
: (<span> </span>)
}
<span className="" title={Position in ${fileName}}>Pos: ${locationString}</span>
</span>`
)
}
const filterWarnings = () => {
let newWarningState = {}
let newWarningCount = 0
if (showLibsWarning) {
for (const category in allWarnings.current)
newWarningCount = newWarningCount + allWarnings.current[category].length
newWarningState = allWarnings.current
}
else {
for (const category in allWarnings.current) {
const warnings = allWarnings.current[category]
newWarningState[category] = []
for (const warning of warnings) {
if (!warning.options.isLibrary) {
newWarningCount++
newWarningState[category].push(warning)
}
}
}
}
props.event.trigger('staticAnaysisWarning', [newWarningCount])
setWarningState(newWarningState)
}
const showWarnings = (warningMessage, groupByKey) => {
const resultArray = []
warningMessage.map(x => {
resultArray.push(x)
})
function groupBy (objectArray, property) {
return objectArray.reduce((acc, obj) => {
const key = obj[property]
if (!acc[key]) {
acc[key] = []
}
// Add object to list for given key's value
acc[key].push(obj)
return acc
}, {})
}
const groupedCategory = groupBy(resultArray, groupByKey)
allWarnings.current = groupedCategory
filterWarnings()
}
const run = async (lastCompilationResult, lastCompilationSource, currentFile) => {
if (state.data !== null) {
if (lastCompilationResult && (categoryIndex.length > 0 || slitherEnabled)) {
const warningMessage = []
const warningErrors = []
// Remix Analysis
_paq.push(['trackEvent', 'solidityStaticAnalyzer', 'analyzeWithRemixAnalyzer'])
const results = runner.run(lastCompilationResult, categoryIndex)
for (const result of results) {
let moduleName
Object.keys(groupedModules).map(key => {
groupedModules[key].forEach(el => {
if (el.name === result.name) {
moduleName = groupedModules[key][0].categoryDisplayName
}
})
})
for (const item of result.report) {
let location: any = {}
let locationString = 'not available'
let column = 0
let row = 0
let fileName = currentFile
let isLibrary = false
if (item.location) {
const split = item.location.split(':')
const file = split[2]
location = {
start: parseInt(split[0]),
length: parseInt(split[1])
}
location = props.analysisModule._deps.offsetToLineColumnConverter.offsetToLineColumn(
location,
parseInt(file),
lastCompilationSource.sources,
lastCompilationResult.sources
)
row = location.start.line
column = location.start.column
locationString = row + 1 + ':' + column + ':'
fileName = Object.keys(lastCompilationResult.sources)[file]
}
if(fileName !== currentFile) {
const {file, provider} = await props.analysisModule.call('fileManager', 'getPathFromUrl', fileName)
if (file.startsWith('.deps') || (provider.type === 'localhost' && file.startsWith('localhost/node_modules'))) isLibrary = true
}
const msg = message(result.name, item.warning, item.more, fileName, locationString)
const options = {
type: 'warning',
useSpan: true,
errFile: fileName,
fileName,
isLibrary,
errLine: row,
errCol: column,
item: item,
name: result.name,
locationString,
more: item.more,
location: location
}
warningErrors.push(options)
warningMessage.push({ msg, options, hasWarning: true, warningModuleName: moduleName })
}
}
// Slither Analysis
if (slitherEnabled) {
try {
const compilerState = await props.analysisModule.call('solidity', 'getCompilerState')
const { currentVersion, optimize, evmVersion } = compilerState
await props.analysisModule.call('terminal', 'log', { type: 'info', value: '[Slither Analysis]: Running...' })
_paq.push(['trackEvent', 'solidityStaticAnalyzer', 'analyzeWithSlither'])
const result = await props.analysisModule.call('slither', 'analyse', state.file, { currentVersion, optimize, evmVersion })
if (result.status) {
props.analysisModule.call('terminal', 'log', { type: 'info', value: `[Slither Analysis]: Analysis Completed!! ${result.count} warnings found.` })
const report = result.data
for (const item of report) {
let location: any = {}
let locationString = 'not available'
let column = 0
let row = 0
let fileName = currentFile
let isLibrary = false
if (item.sourceMap && item.sourceMap.length) {
let path = item.sourceMap[0].source_mapping.filename_relative
let fileIndex = Object.keys(lastCompilationResult.sources).indexOf(path)
if (fileIndex === -1) {
path = await props.analysisModule.call('fileManager', 'getUrlFromPath', path)
fileIndex = Object.keys(lastCompilationResult.sources).indexOf(path.file)
}
if (fileIndex >= 0) {
location = {
start: item.sourceMap[0].source_mapping.start,
length: item.sourceMap[0].source_mapping.length
}
location = props.analysisModule._deps.offsetToLineColumnConverter.offsetToLineColumn(
location,
fileIndex,
lastCompilationSource.sources,
lastCompilationResult.sources
)
row = location.start.line
column = location.start.column
locationString = row + 1 + ':' + column + ':'
fileName = Object.keys(lastCompilationResult.sources)[fileIndex]
}
}
if(fileName !== currentFile) {
const {file, provider} = await props.analysisModule.call('fileManager', 'getPathFromUrl', fileName)
if (file.startsWith('.deps') || (provider.type === 'localhost' && file.startsWith('localhost/node_modules'))) isLibrary = true
}
const msg = message(item.title, item.description, item.more, fileName, locationString)
const options = {
type: 'warning',
useSpan: true,
errFile: fileName,
fileName,
isLibrary,
errLine: row,
errCol: column,
item: { warning: item.description },
name: item.title,
locationString,
more: item.more,
location: location
}
warningErrors.push(options)
warningMessage.push({ msg, options, hasWarning: true, warningModuleName: 'Slither Analysis' })
}
showWarnings(warningMessage, 'warningModuleName')
}
} catch(error) {
props.analysisModule.call('terminal', 'log', { type: 'error', value: '[Slither Analysis]: Error occured! See remixd console for details.' })
showWarnings(warningMessage, 'warningModuleName')
}
} else showWarnings(warningMessage, 'warningModuleName')
} else {
if (categoryIndex.length) {
warningContainer.current.innerText = 'No compiled AST available'
}
props.event.trigger('staticAnaysisWarning', [-1])
}
}
}
const handleCheckAllModules = (groupedModules) => {
const index = groupedModuleIndex(groupedModules)
if (index.every(el => categoryIndex.includes(el))) {
setCategoryIndex(
categoryIndex.filter((el) => {
return !index.includes(el)
})
)
} else {
setCategoryIndex(_.uniq([...categoryIndex, ...index]))
}
}
const handleCheckOrUncheckCategory = (category) => {
const index = groupedModuleIndex(category)
if (index.every(el => categoryIndex.includes(el))) {
setCategoryIndex(
categoryIndex.filter((el) => {
return !index.includes(el)
})
)
} else {
setCategoryIndex(_.uniq([...categoryIndex, ...index]))
}
}
const handleSlitherEnabled = () => {
if (slitherEnabled) {
setSlitherEnabled(false)
} else {
setSlitherEnabled(true)
}
}
const handleAutoRun = () => {
if (autoRun) {
setAutoRun(false)
} else {
setAutoRun(true)
}
}
const handleCheckSingle = (event, _index) => {
_index = _index.toString()
if (categoryIndex.includes(_index)) {
setCategoryIndex(categoryIndex.filter(val => val !== _index))
} else {
setCategoryIndex(_.uniq([...categoryIndex, _index]))
}
}
const handleShowLibsWarning = () => {
if (showLibsWarning) {
showLibsWarning = false
setShowLibsWarning(false)
} else {
showLibsWarning = true
setShowLibsWarning(true)
}
filterWarnings()
}
const categoryItem = (categoryId, item, i) => {
return (
<div className="form-check" key={i}>
<RemixUiCheckbox
categoryId={categoryId}
id={`staticanalysismodule_${categoryId}_${i}`}
inputType="checkbox"
name="checkSingleEntry"
itemName={item.name}
label={item.description}
onClick={event => handleCheckSingle(event, item._index)}
checked={categoryIndex.includes(item._index.toString())}
onChange={() => {}}
/>
</div>
)
}
const categorySection = (category, categoryId, i) => {
return (
<div className="" key={i}>
<div className="block">
<TreeView>
<TreeViewItem
label={
<label
htmlFor={`heading${categoryId}`}
style={{ cursor: 'pointer' }}
className="pl-3 card-header h6 d-flex justify-content-between font-weight-bold px-1 py-2 w-100"
data-bs-toggle="collapse"
data-bs-expanded="false"
data-bs-controls={`heading${categoryId}`}
data-bs-target={`#heading${categoryId}`}
>
{category[0].categoryDisplayName}
</label>
}
expand={false}
>
<div>
<RemixUiCheckbox onClick={() => handleCheckOrUncheckCategory(category)} id={categoryId} inputType="checkbox" label={`Select ${category[0].categoryDisplayName}`} name='checkCategoryEntry' checked={category.map(x => x._index.toString()).every(el => categoryIndex.includes(el))} onChange={() => {}}/>
</div>
<div className="w-100 d-block px-2 my-1 entries collapse multi-collapse" id={`heading${categoryId}`}>
{category.map((item, i) => {
return (
categoryItem(categoryId, item, i)
)
})}
</div>
</TreeViewItem>
</TreeView>
</div>
</div>
)
}
return (
<div className="analysis_3ECCBV px-3 pb-1">
<div className="my-2 d-flex flex-column align-items-left">
<div className="d-flex justify-content-between" id="staticanalysisButton">
<RemixUiCheckbox
id="checkAllEntries"
inputType="checkbox"
title="Select all Remix analysis modules"
checked={Object.values(groupedModules).map((value: any) => {
return (value.map(x => {
return x._index.toString()
}))
}).flat().every(el => categoryIndex.includes(el))}
label="Select all"
onClick={() => handleCheckAllModules(groupedModules)}
onChange={() => {}}
/>
<RemixUiCheckbox
id="autorunstaticanalysis"
inputType="checkbox"
title="Run static analysis after the compilation"
onClick={handleAutoRun}
checked={autoRun}
label="Autorun"
onChange={() => {}}
/>
<Button buttonText="Run" onClick={async () => await run(state.data, state.source, state.file)} disabled={(state.data === null || categoryIndex.length === 0) && !slitherEnabled }/>
</div>
{ showSlither &&
<div className="d-flex mt-2" id="enableSlitherAnalysis">
<RemixUiCheckbox
id="enableSlither"
inputType="checkbox"
onClick={handleSlitherEnabled}
checked={slitherEnabled}
label="Enable Slither Analysis"
onChange={() => {}}
/>
<a className="mt-1 text-nowrap" href='https://remix-ide.readthedocs.io/en/latest/slither.html#enable-slither-analysis' target={'_blank'}>
<OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="overlay-tooltip">
<span className="p-1 pr-3" style={{ backgroundColor: 'black', minWidth: '230px' }}>Learn how to use Slither Analysis</span>
</Tooltip>
}>
<i style={{ fontSize: 'medium' }} className={'fal fa-info-circle ml-3'} aria-hidden="true"></i>
</OverlayTrigger>
</a>
</div>
}
</div>
<div id="staticanalysismodules" className="list-group list-group-flush">
{Object.keys(groupedModules).map((categoryId, i) => {
const category = groupedModules[categoryId]
return (
categorySection(category, categoryId, i)
)
})
}
</div>
<div className="mt-2 p-2 d-flex border-top flex-column">
<span>Last results for:</span>
<span
className="text-break break-word word-break font-weight-bold"
id="staticAnalysisCurrentFile"
>
{state.file}
</span>
</div>
{Object.entries(warningState).length > 0 &&
<div id='staticanalysisresult' >
<RemixUiCheckbox
id="showLibWarnings"
name="showLibWarnings"
categoryId="showLibWarnings"
title="when checked, the results are also displayed for external contract libraries"
inputType="checkbox"
checked={showLibsWarning}
label="Show warnings for external libraries"
onClick={handleShowLibsWarning}
onChange={() => {}}
/>
<br/>
<div className="mb-4">
{
(Object.entries(warningState).map((element, index) => (
<div key={index}>
{element[1]['length'] > 0 ? <span className="text-dark h6">{element[0]}</span> : null}
{element[1]['map']((x, i) => ( // eslint-disable-line dot-notation
x.hasWarning ? ( // eslint-disable-next-line dot-notation
<div data-id={`staticAnalysisModule${x.warningModuleName}${i}`} id={`staticAnalysisModule${x.warningModuleName}${i}`} key={i}>
<ErrorRenderer name={`staticAnalysisModule${x.warningModuleName}${i}`} message={x.msg} opt={x.options} warningErrors={ x.warningErrors} editor={props.analysisModule}/>
</div>
) : null
))}
</div>
)))
}
</div>
</div>
}
</div>
)
}
Example #20
Source File: ContestList.tsx From cftracker with MIT License | 4 votes |
ContestList = (props: PropsType) => {
let short = props.category !== ContestCat.ALL;
let mxInd: number = 0;
for (let contest of props.contestlist) {
if (contest.mxInd > mxInd) {
mxInd = contest.mxInd;
}
}
interface indInt {
minIndex: number;
maxIndex: number;
}
let ind: indInt = {
minIndex: 1,
maxIndex: mxInd,
};
// console.log(ind.minIndex);
// console.log(ind.maxIndex);
const getStatus = (problem: Problem) => {
if (!props.submissions.get(problem.contestId)) return Verdict.UNSOLVED;
if (props.submissions.get(problem.contestId).has(Verdict.SOLVED)) {
if (
props.submissions
.get(problem.contestId)
.get(Verdict.SOLVED)
.has(problem.index)
)
return Verdict.SOLVED;
}
if (props.submissions.get(problem.contestId).has(Verdict.ATTEMPTED)) {
if (
props.submissions
.get(problem.contestId)
.get(Verdict.ATTEMPTED)
.has(problem.index)
)
return Verdict.ATTEMPTED;
}
};
const renderProblem = (problem: Problem, inside = 0) => {
let solved = false;
let attempted = false;
let v = getStatus(problem);
if (v === Verdict.SOLVED) solved = true;
if (v === Verdict.ATTEMPTED) attempted = true;
if (props.submissions.has(problem.contestId)) {
if (props.submissions.get(problem.contestId).has(Verdict.SOLVED)) {
if (
props.submissions
.get(problem.contestId)
.get(Verdict.SOLVED)
.has(problem.index)
)
solved = true;
}
if (props.submissions.get(problem.contestId).has(Verdict.ATTEMPTED)) {
if (
props.submissions
.get(problem.contestId)
.get(Verdict.ATTEMPTED)
.has(problem.index)
)
attempted = true;
}
}
let name = problem.name;
let id = problem.id;
let className =
(solved ? props.theme.bgSuccess : attempted ? props.theme.bgDanger : "") +
(inside ? " w-50 " : " w-100 ");
return (
<div
className={
className +
" p-2" +
(inside === 1
? " pe-0 border-end" +
(props.theme.themeType === ThemesType.DARK ? " border-dark" : "")
: "")
}
key={id}
>
{/* <OverlayTrigger
placement={"top"}
key={`p-${problem.id}`}
overlay={
<Tooltip id={`p-${problem.id}`}>
<div className="d-flex flex-column">
<div>{problem.name}</div>
<div>Rating:{problem.rating}</div>
<div>{problem.solvedCount}</div>
</div>
</Tooltip>
}
> */}
<a
className={
"text-decoration-none wrap font-bold d-inline-block text-truncate " +
(props.showColor
? props.theme.color(problem.rating)
: props.theme.text)
}
target="_blank"
rel="noreferrer"
tabIndex={0}
title={
problem.name +
",Rating:" +
(problem.rating > 0 ? problem.rating : "Not Rated")
}
data-bs-html="true"
data-bs-toggle="tooltip"
data-bs-placement="top"
href={getProblemUrl(problem.contestId, problem.index)}
>
{problem.index + ". "}
{name}
{props.showRating ? (
<span className="fs-6">
<br />({problem.rating ? problem.rating : "Not Rated"})
</span>
) : (
""
)}
</a>
{/* </OverlayTrigger> */}
</div>
);
};
const getInfo = (contest: Contest, index) => {
const EMPTY = "EMPTY " + props.theme.bg;
let contestId = contest.id;
let problems = contest.problemList[index];
if (problems === undefined || problems.length === 0) {
return (
<td key={contest.id + index} className={EMPTY + "w-problem "}></td>
);
}
if (problems.length === 1) {
let v = getStatus(problems[0]);
return (
<td
className={
"p-0 " +
"w-problem " +
(v === Verdict.SOLVED
? props.theme.bgSuccess
: v === Verdict.ATTEMPTED
? props.theme.bgDanger
: "")
}
key={contestId + index.charAt(0) + "1"}
>
{renderProblem(problems[0])}
</td>
);
}
if (problems.length <= 2) {
return (
<td className={"p-0 " + "w-problem "} key={contestId + index.charAt(0)}>
<div className="d-flex">
{problems.map((element, index) =>
renderProblem(element, problems.length === 0 ? 0 : index + 1)
)}
</div>
</td>
);
}
return (
<td className={"inside p-0 " + "w-problem "} key={contestId + index}>
More than 2
</td>
);
};
const contestCard = (contest: Contest, index: number) => {
let solved = false;
if (
props.submissions.has(contest.id) &&
props.submissions.get(contest.id).has(Verdict.SOLVED) &&
props.submissions.get(contest.id).get(Verdict.SOLVED).size ===
contest.count
)
solved = true;
return (
<tr key={contest.id}>
<td
scope="row"
className={
"w-sl p-2 first-column " + (solved ? props.theme.bgSuccess : " ")
}
>
<div className="d-inline-block">
{props.pageSelected * props.perPage + index + 1}
</div>
</td>
{/* {short ? (
""
) : (
<td
scope="row"
className={
"w-id p-2 second-column " + (solved ? props.theme.bgSuccess : " ")
}
title={
"Solve Count: " + contest.solveCount + " , Total:" + contest.count
}
>
<div className="d-inline-block">{contest.id}</div>
</td>
)} */}
<td
className={
"w-contest p-0 " +
(solved ? props.theme.bgSuccess : " ") +
(short ? " short" : " ")
}
>
<div className="d-inline-block w-100 name">
<OverlayTrigger
placement={"top"}
key={`contest-name-${contest.id.toString()}`}
overlay={
<Tooltip id={`contest-name-${contest.id.toString()}`}>
<p
className="text-center text-wrap pe-1"
// style={{ minWidth: "300px" }}
>
<div>{contest.name}</div>
<div>ID: {contest.id}</div>
</p>
</Tooltip>
}
>
<a
className={
"text-decoration-none wrap d-inline-block pt-2 pb-2 ps-2 pe-1 mw-100 " +
props.theme.text +
(short ? " text-truncate" : " ")
}
target="_blank"
rel="noreferrer"
//title={contest.name}
href={getContestUrl(contest.id)}
>
{short ? contest.short : contest.name}
</a>
</OverlayTrigger>
</div>
{props.showDate ? (
<div className="time ps-2">
{formateDate(contest.startTimeSeconds)}
</div>
) : (
""
)}
</td>
{[...Array(ind.maxIndex - ind.minIndex + 1)].map((x, i) => {
return getInfo(contest, charInc("A", i));
})}
</tr>
);
};
return (
<React.Fragment>
<table className={"table table-bordered m-0 " + props.theme.table}>
<thead className={props.theme.thead}>
<tr>
<th
scope="col"
className="w-sl first-column"
style={{ width: "20px" }}
>
#
</th>
<th
scope="col"
className={
"w-contest third-column" +
(props.category !== ContestCat.ALL ? " short" : "")
}
>
Contest
</th>
{[...Array(ind.maxIndex - ind.minIndex + 1)].map((x, i) => {
return (
<th
scope="col"
key={"problem-index-" + charInc("A", i)}
className={"w-problem"}
>
{charInc("A", i)}
</th>
);
})}
</tr>
</thead>
<tbody className={props.theme.bg}>
{props.contestlist.map((contest: Contest, index: number) => {
return contestCard(contest, index);
})}
</tbody>
</table>
</React.Fragment>
);
}
Example #21
Source File: TxnsPage.tsx From devex with GNU General Public License v3.0 | 4 votes |
TxnsPage: React.FC = () => {
const networkContext = useContext(NetworkContext)
const { dataService } = networkContext!
const fetchIdRef = useRef(0)
const [isLoading, setIsLoading] = useState(false)
const [pageCount, setPageCount] = useState(0)
const [data, setData] = useState<TransactionDetails[] | null>(null)
const [recentTxnHashes, setRecentTxnHashes] = useState<string[] | null>(null)
const columns = useMemo(
() => [{
id: 'from-col',
Header: 'From',
accessor: 'txn.senderAddress',
Cell: ({ value }: { value: string }) => (
<QueryPreservingLink to={`/address/${hexAddrToZilAddr(value)}`}>
{hexAddrToZilAddr(value)}
</QueryPreservingLink>)
}, {
id: 'to-col',
Header: 'To',
Cell: ({ row }: { row: Row<TransactionDetails> }) => {
return <ToAddrDisp txnDetails={row.original} />
}
}, {
id: 'hash-col',
Header: 'Hash',
accessor: 'hash',
Cell: ({ row }: { row: Row<TransactionDetails> }) => {
console.log(row)
return <QueryPreservingLink to={`/tx/0x${row.original.hash}`}>
<div className='text-right mono'>
{row.original.txn.txParams.receipt && !row.original.txn.txParams.receipt.success
&& <FontAwesomeIcon className='mr-1' icon={faExclamationCircle} color='red' />
}
{'0x' + row.original.hash}
</div>
</QueryPreservingLink>
}
}, {
id: 'amount-col',
Header: 'Amount',
accessor: 'txn.amount',
Cell: ({ value }: { value: string }) => (
<OverlayTrigger placement='right'
overlay={<Tooltip id={'amt-tt'}>{qaToZil(value)}</Tooltip>}>
<div className='text-right sm'>{qaToZil(value, 12)}</div>
</OverlayTrigger>
)
}, {
id: 'fee-col',
Header: 'Fee',
accessor: 'txn',
Cell: ({ value }: { value: Transaction }) => {
const fee = Number(value.txParams.gasPrice) * value.txParams.receipt!.cumulative_gas
return <OverlayTrigger placement='top'
overlay={<Tooltip id={'fee-tt'}>{qaToZil(fee)}</Tooltip>}>
<div className='text-center sm' >{qaToZil(fee, 4)}</div>
</OverlayTrigger>
}
}], []
)
const fetchData = useCallback(({ pageIndex }) => {
if (!dataService) return
const fetchId = ++fetchIdRef.current
let txnHashes: string[] | null
let txnList: TxList
let txnBodies: TransactionDetails[]
const getData = async () => {
try {
setIsLoading(true)
txnHashes = recentTxnHashes
if (!txnHashes) {
txnList = await dataService.getRecentTransactions()
if (!txnList) return
txnHashes = txnList.TxnHashes
setPageCount(Math.ceil(txnList.number / 10))
setRecentTxnHashes(txnHashes)
}
const slicedTxnHashes = txnHashes.slice(pageIndex * 10, pageIndex * 10 + 10)
if (slicedTxnHashes) {
txnBodies = await dataService.getTransactionsDetails(slicedTxnHashes)
if (txnBodies)
setData(txnBodies)
}
} catch (e) {
console.log(e)
} finally {
setIsLoading(false)
}
}
if (fetchId === fetchIdRef.current)
getData()
// Recent transaction hashes is not changed after the initial fetch, until the user refreshes/re-render the component
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dataService])
return (
<>
{<div>
<h2>Recent Transactions</h2>
<ViewAllTable
columns={columns}
data={data ? data : []}
isLoading={isLoading}
fetchData={fetchData}
pageCount={pageCount}
/>
</div>}
</>
)
}
Example #22
Source File: PostComment.tsx From 3Speak-app with GNU General Public License v3.0 | 4 votes |
/**
* @todo Implement displaying numbers of comments and comment value. Requires support on backend to count votes.
* @todo Implement interactibility.
* @todo Implement 3 dot action menu.
*/
export function PostComment(props: any) {
const [commentInfo, setCommentInfo] = useState({ description: '', creation: 0 })
const [replying, setReplying] = useState(false)
const [profilePicture, setProfilePicture] = useState('')
useEffect(() => {
const load = async () => {
let info
let profilePicture
if (props.commentInfo) {
info = props.commentInfo
} else {
info = await AccountService.permalinkToVideoInfo(props.reflink)
}
if (info) {
profilePicture = setProfilePicture(await AccountService.getProfilePictureURL(info.reflink))
setCommentInfo(info)
}
}
void load()
}, [])
const handleAction = async (eventKey) => {
const reflink = props.reflink
switch (eventKey) {
case 'block_post': {
await electronIpc.send('blocklist.add', reflink, {
reason: 'manual block',
})
break
}
case 'block_user': {
const ref = RefLink.parse(reflink) as any as any
await electronIpc.send('blocklist.add', `${ref.source.value}:${ref.root}`, {
reason: 'manual block',
})
break
}
case 'copy_reflink': {
clipboard.writeText(reflink, clipboard as any)
break
}
default: {
throw new Error(`Unrecognized action: ${eventKey}!`)
}
}
}
const postTimeDistance = useMemo(() => {
return millisecondsAsString((new Date() as any) - (new Date(commentInfo.creation) as any))
}, [commentInfo])
const postTime = useMemo(() => {
return DateAndTime.format(new Date(commentInfo.creation), 'YYYY/MM/DD HH:mm:ss')
}, [commentInfo])
return (
<div>
<div className="col">
<div className="thumbnail mr-2 float-left">
<img className="img-responsive user-photo" width="24" src={profilePicture} />
</div>
</div>
<div className="col" style={{ zIndex: 1000 }}>
<div className="mr-3 float-right">
<Dropdown onSelect={handleAction}>
<Dropdown.Toggle as={CustomToggle}></Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item style={{ color: 'red' }} eventKey="block_post">
Block post
</Dropdown.Item>
<Dropdown.Item style={{ color: 'red' }} eventKey="block_user">
Block user
</Dropdown.Item>
<Dropdown.Item eventKey="copy_reflink">Copy to clipboard permlink</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</div>
</div>
<div className="col-12">
<div className="panel ml-2 panel-default">
<div className="panel-heading ml-4">
<strong>
<a href={`#/user?=${props.reflink}`}>{RefLink.parse(props.reflink).root}</a>{' '}
</strong>
•{' '}
<span className="text-muted">
<OverlayTrigger overlay={<Tooltip id="post-time">{postTime}</Tooltip>}>
<div>{postTimeDistance}</div>
</OverlayTrigger>
</span>
</div>
<div className="panel-body mt-1">
<ReactMarkdown
escapeHtml={false}
source={DOMPurify.sanitize(commentInfo.description)}
></ReactMarkdown>
</div>
<div className="panel-footer ml-0 ml-md-4">
<hr />
<ul className="list-inline list-inline-separate">
<li className="list-inline-item">
<VoteWidget reflink={props.reflink} />
</li>
<li
className="list-inline-item"
style={{ cursor: 'pointer' }}
onClick={() => {
setReplying(!replying)
}}
>
{replying ? 'Cancel' : 'Reply'}
</li>
</ul>
</div>
</div>
</div>
{replying ? (
<div className="box mb-3 clearfix">
<CommentForm parent_reflink={props.reflink} onCommentPost={props.onCommentPost} />
</div>
) : null}
</div>
)
}
Example #23
Source File: ImportExport.tsx From devex with GNU General Public License v3.0 | 4 votes |
ImportExport: React.FC<IProps> = ({ type, map, setMapCb, toJson, fromJson }) => {
const onDrop = useCallback((acceptedFiles: Blob[]) => {
acceptedFiles.forEach((file: Blob) => {
const reader = new FileReader()
reader.onload = () => {
const parsedFile = JSON.parse(reader.result as string)
setMapCb(fromJson ? fromJson(parsedFile) : parsedFile)
}
reader.readAsText(file)
})
}, [setMapCb, fromJson])
const { getRootProps, getInputProps } = useDropzone({ noDrag: true, onDrop })
return (
<>
<div className='import-export'>
<span className='mr-1' {...getRootProps()}>
<input {...getInputProps()} />
<OverlayTrigger placement='top'
overlay={<Tooltip id={'import-tt'}>{type === 'labels' ? 'Import Labels' : 'Import Networks'}</Tooltip>}>
<Button>
<FontAwesomeIcon
icon={faDownload}
size='sm' />
</Button>
</OverlayTrigger>
</span>
<span className='ml-2'>
<OverlayTrigger placement='top'
overlay={<Tooltip id={'export-tt'}>{type === 'labels' ? 'Export Labels' : 'Export Networks'}</Tooltip>}>
<Button
onClick={() => {
exportToJson(type, toJson, map)
}}>
<FontAwesomeIcon
icon={faUpload}
size='sm' />
</Button>
</OverlayTrigger>
</span>
</div>
</>
)
}
Example #24
Source File: Footer.tsx From devex with GNU General Public License v3.0 | 4 votes |
Footer: React.FC = () => {
const themeContext = useContext(ThemeContext)
const { theme, toggle } = themeContext!
return <div className='custom-footer'>
<Container>
<Row className='justify-content-between'>
<Col sm md lg={2}>
<Row>
<span className='social-header'>Social</span>
</Row>
<Row>
<a target='_blank' rel='noopener noreferrer' href='https://www.twitter.com/zilliqa'>
<FontAwesomeIcon size='lg' icon={faTwitter} cursor='pointer' />
</a>
<a target='_blank' rel='noopener noreferrer' href='https://www.facebook.com/zilliqa/'>
<FontAwesomeIcon size='lg' icon={faFacebookF} cursor='pointer' />
</a>
<a target='_blank' rel='noopener noreferrer' href='https://www.reddit.com/r/zilliqa'>
<FontAwesomeIcon size='lg' icon={faRedditAlien} cursor='pointer' />
</a>
</Row>
<Row>
<a target='_blank' rel='noopener noreferrer' href='https://blog.zilliqa.com'>
<FontAwesomeIcon size='lg' icon={faMediumM} cursor='pointer' />
</a>
<a target='_blank' rel='noopener noreferrer' href='https://www.youtube.com/channel/UCvinnFbf0u71cajoxKcfZIQ'>
<FontAwesomeIcon size='lg' icon={faYoutube} cursor='pointer' />
</a>
<a target='_blank' rel='noopener noreferrer' href='https://t.me/zilliqachat'>
<FontAwesomeIcon size='lg' icon={faTelegramPlane} cursor='pointer' />
</a>
</Row>
</Col>
<Col>
<span className='related-links-header'>Related Links</span>
<div>
<a target='_blank' rel='noopener noreferrer' href='https://github.com/Zilliqa/dev-explorer'>Project Repo</a>
</div>
<div>
<a target='_blank' rel='noopener noreferrer' href='https://ide.zilliqa.com/#/'>Neo Savant IDE</a>
</div>
<div>
<a target='_blank' rel='noopener noreferrer' href='https://github.com/Zilliqa/Zilliqa-JavaScript-Library'>Javascript SDK</a>
</div>
<div>
<a target='_blank' rel='noopener noreferrer' href='https://viewblock.io/zilliqa'>ViewBlock</a>
</div>
</Col>
<Col className='align-self-center'>
<Row className='justify-content-end'>
Powered by <a href='http://www.zilliqa.com'>
<span><u>Zilliqa</u></span></a>
</Row>
<Row className='justify-content-end'>
<span><small>© 2020 Zilliqa</small></span>
</Row>
<Row className='justify-content-end pt-1'>
<OverlayTrigger placement='top'
overlay={<Tooltip id={'theme-tt'}>Toggle Light/Dark</Tooltip>}>
<Switch
className='theme-switch'
loadingIcon={null}
onChange={() => {
toggle()
}}
disabled={false}
defaultChecked={theme === 'light'}
checkedChildren={
<div className='theme-icon-div'>
<FontAwesomeIcon className='theme-icon' icon={faMoon} size='xs' color='white' />
</div>}
unCheckedChildren={
<div className='theme-icon-div'>
<FontAwesomeIcon className='theme-icon' icon={faSun} size='xs' color='white' />
</div>}
/>
</OverlayTrigger>
</Row>
</Col>
</Row>
</Container>
</div >
}
Example #25
Source File: ValTxnList.tsx From devex with GNU General Public License v3.0 | 4 votes |
ValTxnList: React.FC = () => {
const networkContext = useContext(NetworkContext)
const { dataService, networkUrl } = networkContext!
useEffect(() => { setData(null) }, [networkUrl])
const [data, setData] = useState<TransactionDetails[] | null>(null)
const columns = useMemo(
() => [{
id: 'from-col',
Header: 'From',
accessor: 'txn.senderAddress',
Cell: ({ value }: { value: string }) => (
<QueryPreservingLink to={`/address/${hexAddrToZilAddr(value)}`}>
{hexAddrToZilAddr(value)}
</QueryPreservingLink>)
}, {
id: 'to-col',
Header: 'To',
Cell: ({ row }: { row: Row<TransactionDetails> }) => {
return <ToAddrDisp txnDetails={row.original} />
}
}, {
id: 'hash-col',
Header: 'Hash',
accessor: 'hash',
Cell: ({ row }: { row: Row<TransactionDetails> }) => {
return <QueryPreservingLink to={`/tx/0x${row.original.hash}`}>
<div className='text-right mono'>
{row.original.txn.txParams.receipt && !row.original.txn.txParams.receipt.success
&& <FontAwesomeIcon className='mr-1' icon={faExclamationCircle} color='red' />
}
{'0x' + row.original.hash}
</div>
</QueryPreservingLink>
}
}, {
id: 'amount-col',
Header: 'Amount',
accessor: 'txn.amount',
Cell: ({ value }: { value: string }) => (
<OverlayTrigger placement='right'
overlay={<Tooltip id={'amt-tt'}>{qaToZil(value)}</Tooltip>}>
<div className='text-right sm'>{qaToZil(value, 13)}</div>
</OverlayTrigger>
)
}, {
id: 'fee-col',
Header: 'Fee',
accessor: 'txn',
Cell: ({ value }: { value: Transaction }) => {
const fee = Number(value.txParams.gasPrice) * value.txParams.receipt!.cumulative_gas
return <OverlayTrigger placement='top'
overlay={<Tooltip id={'fee-tt'}>{qaToZil(fee)}</Tooltip>}>
<div className='text-center sm'>{qaToZil(fee, 4)}</div>
</OverlayTrigger>
}
}], []
)
// Fetch Data
useEffect(() => {
let isCancelled = false
if (!dataService) return
let receivedData: TransactionDetails[]
const getData = async () => {
try {
receivedData = await dataService.getLatest5ValidatedTransactions()
if (!isCancelled && receivedData)
setData(receivedData)
} catch (e) {
if (!isCancelled)
console.log(e)
}
}
getData()
const getDataTimer = setInterval(async () => {
await getData()
}, refreshRate)
return () => {
isCancelled = true
clearInterval(getDataTimer)
}
}, [networkUrl, dataService])
return <>
<Card className='valtxlist-card'>
<Card.Header>
<div className='valtxlist-card-header'>
<span>Transactions</span>
<QueryPreservingLink to={'/tx'}>View Recent Transactions</QueryPreservingLink>
</div>
</Card.Header>
<Card.Body>
{data
? <DisplayTable columns={columns} data={data} />
: <Spinner animation="border" role="status" />
}
</Card.Body>
</Card>
</>
}
Example #26
Source File: TxBlockList.tsx From devex with GNU General Public License v3.0 | 4 votes |
TxBlockList: React.FC = () => {
const networkContext = useContext(NetworkContext)
const { dataService, networkUrl } = networkContext!
useEffect(() => { setData(null) }, [networkUrl]) // Unset data on url change
const [data, setData] = useState<TxBlockObj[] | null>(null)
const columns = useMemo(
() => [{
id: 'txheight-col',
Header: 'Height',
accessor: 'header.BlockNum',
Cell: ({ value }: { value: string }) => (
<QueryPreservingLink to={`/txbk/${value}`}>
{value}
</QueryPreservingLink>
)
},
{
id: 'numTxns-col',
Header: 'Txns',
accessor: 'header.NumTxns',
Cell: ({ value }: { value: string }) => (
<div className='text-center'>{value}</div>
),
},
{
id: 'total-txn-fees-col',
Header: 'Txn Fees',
accessor: 'header.TxnFees',
Cell: ({ value }: { value: string }) => (
<div className='text-right'>
<OverlayTrigger placement='top'
overlay={<Tooltip id={'amt-tt'}> {qaToZil(value)} </Tooltip>}>
<span>{qaToZil(value, 5)}</span>
</OverlayTrigger>
</div>)
},
{
id: 'rewards-col',
Header: 'Rewards',
accessor: 'header.Rewards',
Cell: ({ value }: { value: string }) => (
<div className='text-right'>
<OverlayTrigger placement='top'
overlay={<Tooltip id={'amt-tt'}> {qaToZil(value)} </Tooltip>}>
<span>{qaToZil(value, 5)}</span>
</OverlayTrigger>
</div>)
},
{
id: 'ds-block-col',
Header: 'DS Block',
accessor: 'header.DSBlockNum',
Cell: ({ value }: { value: string }) => (
<QueryPreservingLink to={`/dsbk/${value}`}>
<div className='text-center'>{value}</div>
</QueryPreservingLink>
)
},
{
id: 'age-col',
Header: 'Age',
accessor: 'header.Timestamp',
Cell: ({ value }: { value: string }) => (
<div className='text-right'>{
timestampToTimeago(value)}
</div>
),
}], []
)
// Fetch Data
useEffect(() => {
let isCancelled = false
if (!dataService) return
let receivedData: TxBlockObj[]
const getData = async () => {
try {
receivedData = await dataService.getLatest5TxBlocks()
if (!isCancelled && receivedData)
setData(receivedData)
} catch (e) {
if (!isCancelled)
console.log(e)
}
}
getData()
const getDataTimer = setInterval(async () => {
await getData()
}, refreshRate)
return () => {
isCancelled = true
clearInterval(getDataTimer)
}
}, [dataService])
return <>
<Card className='txblock-card'>
<Card.Header>
<div className='dsblock-card-header'>
<span>Transaction Blocks</span>
<QueryPreservingLink to={'/txbk'}>View All</QueryPreservingLink>
</div>
</Card.Header>
<Card.Body>
{data
? <DisplayTable columns={columns} data={data} />
: <Spinner animation="border" role="status" />
}
</Card.Body>
</Card>
</>
}
Example #27
Source File: BCInfo.tsx From devex with GNU General Public License v3.0 | 4 votes |
BCInfo: React.FC = () => {
const networkContext = useContext(NetworkContext)
const { dataService, networkUrl } = networkContext!
const [data, setData] = useState<BlockchainInfo | null>(null)
const [state, setState] = useState<BCInfoState>(defaultBCInfoState)
useEffect(() => { setData(null); setState(defaultBCInfoState) }, [networkUrl]) // Unset data on url change
useEffect(() => {
if (!data) return
setState((prevState: BCInfoState) => {
const newState: BCInfoState = { ...prevState }
if (!prevState.startTxBlock)
newState.startTxBlock = parseInt(data.NumTxBlocks, 10) - 1
if (!prevState.maxTPS || prevState.maxTPS <= data.TransactionRate) {
newState.maxTPS = data.TransactionRate
newState.maxTPSTxBlockNum = parseInt(data.NumTxBlocks, 10) - 1
}
if (!prevState.maxTxnCount || prevState.maxTxnCount <= parseInt(data.NumTxnsTxEpoch, 10)) {
newState.maxTxnCount = parseInt(data.NumTxnsTxEpoch, 10)
newState.maxTxnCountTxBlockNum = parseInt(data.NumTxBlocks, 10) - 1
}
return newState
})
}, [data])
// Fetch data
useEffect(() => {
let isCancelled = false
if (!dataService) return
let receivedData: BlockchainInfo
const getData = async () => {
try {
receivedData = await dataService.getBlockchainInfo()
if (!isCancelled && receivedData)
setData(receivedData)
} catch (e) {
if (!isCancelled)
console.log(e)
}
}
getData()
const getDataTimer = setInterval(async () => {
await getData()
}, refreshRate)
return () => {
isCancelled = true
clearInterval(getDataTimer)
}
}, [dataService])
return <>
<Card className='bcstats-card'>
<Card.Body>
{data
? <Container>
<Row className='mb-3'>
<Col>
<span className='subtext'>Current Tx Epoch:</span>
<br />
<span>{parseInt(data.NumTxBlocks).toLocaleString('en')}</span>
</Col>
<Col>
<span className='subtext'>Number of Transactions:</span>
<br />
<span>{parseInt(data.NumTransactions).toLocaleString('en')}</span>
</Col>
<Col>
<span className='subtext'>Peers:</span>
<br />
<span>{data.NumPeers.toLocaleString('en')}</span>
</Col>
<Col>
<span className='subtext'>Sharding Structure:</span>
<br />
<span>[{data.ShardingStructure && data.ShardingStructure.NumPeers
? data.ShardingStructure.NumPeers.toString()
: "no shards"}]</span>
</Col>
</Row>
<Row className='mb-3'>
<Col>
<span className='subtext'>Current DS Epoch:</span>
<br />
<span>{parseInt(data.CurrentDSEpoch).toLocaleString('en')}</span>
</Col>
<Col>
<span className='subtext'>DS Block Rate:</span>
<br />
<span>{data.DSBlockRate.toFixed(5)}</span>
</Col>
<Col>
<span className='subtext'>Tx Block Rate:</span>
<br />
<span>{data.TxBlockRate.toFixed(5)}</span>
</Col>
<Col>
<span className='subtext'>TPS:</span>
<br />
<span>{data.TransactionRate.toFixed(5)}</span>
</Col>
</Row>
<Row>
<Col>
<span className='subtext'>Number of Txns in DS Epoch:</span>
<br />
<span>{parseInt(data.NumTxnsDSEpoch).toLocaleString('en')}</span>
</Col>
<Col>
<span className='subtext'>Number of Txns in Txn Epoch:</span>
<br />
<span>{parseInt(data.NumTxnsTxEpoch).toLocaleString('en')}</span>
</Col>
<Col>
<OverlayTrigger placement='left'
overlay={<Tooltip id={'tt'}>This statistic is accurate from TxBlock {state.startTxBlock}. Requires user to stay on the Home Page</Tooltip>}>
<FontAwesomeIcon className='info-icon' icon={faInfoCircle} />
</OverlayTrigger>
{' '}
<span className='subtext'>Recent Max Observed TPS:</span>
<br />
<span>{state.maxTPS && state.maxTPS.toFixed(5)}</span>
<span>
{' '}
<small className='text-nowrap subtext'>
(on TxBlock <QueryPreservingLink to={`/txbk/${state.maxTPSTxBlockNum}`}>{state.maxTPSTxBlockNum}</QueryPreservingLink>)
</small>
</span>
</Col>
<Col>
<OverlayTrigger placement='left'
overlay={<Tooltip id={'tt'}>This statistic is accurate from TxBlock {state.startTxBlock}. Requires user to stay on the Home Page</Tooltip>}>
<FontAwesomeIcon className='info-icon' icon={faInfoCircle} />
</OverlayTrigger>
{' '}
<span className='subtext'>Recent Max Observed Txn Count:</span>
<br />
<span>{state.maxTxnCount}
{' '}
<small className='text-nowrap subtext'>
(on TxBlock <QueryPreservingLink to={`/txbk/${state.maxTxnCountTxBlockNum}`}>{state.maxTxnCountTxBlockNum}</QueryPreservingLink>)
</small>
</span>
</Col>
</Row>
</Container>
: <Spinner animation="border" role="status" />
}
</Card.Body>
</Card>
</>
}
Example #28
Source File: TxBlockDetailsPage.tsx From devex with GNU General Public License v3.0 | 4 votes |
TxBlockDetailsPage: React.FC = () => {
const { blockNum } = useParams()
const networkContext = useContext(NetworkContext)
const { dataService, isIsolatedServer } = networkContext!
const [error, setError] = useState<string | null>(null)
const [isLoading, setIsLoading] = useState(false)
const [isLoadingTrans, setIsLoadingTrans] = useState(false)
const [txBlockObj, setTxBlockObj] = useState<TxBlockObj | null>(null)
const [txBlockTxns, setTxBlockTxns] = useState<string[] | null>(null)
const [latestTxBlockNum, setLatestTxBlockNum] = useState<number | null>(null)
const [transactionData, setTransactionData] = useState<TransactionDetails[] | null>(null)
// Fetch data
useEffect(() => {
setIsLoading(true)
if (!dataService || isIsolatedServer === null) return
let latestTxBlockNum: number
let txBlockObj: TxBlockObj
let txBlockTxns: string[]
const getData = async () => {
try {
if (isNaN(blockNum))
throw new Error('Not a valid block number')
if (isIsolatedServer) {
txBlockTxns = await dataService.getISTransactionsForTxBlock(parseInt(blockNum))
latestTxBlockNum = await dataService.getISBlockNum()
} else {
txBlockObj = await dataService.getTxBlockObj(parseInt(blockNum))
latestTxBlockNum = await dataService.getNumTxBlocks()
try {
txBlockTxns = await dataService.getTransactionsForTxBlock(parseInt(blockNum))
} catch (e) { console.log(e) }
}
if (txBlockObj)
setTxBlockObj(txBlockObj)
if (txBlockTxns)
setTxBlockTxns(txBlockTxns)
if (latestTxBlockNum)
setLatestTxBlockNum(latestTxBlockNum)
} catch (e) {
console.log(e)
setError(e)
} finally {
setIsLoading(false)
}
}
getData()
return () => {
setTxBlockObj(null)
setTxBlockTxns(null)
setLatestTxBlockNum(null)
setError(null)
}
}, [blockNum, dataService, isIsolatedServer])
const columns = useMemo(
() => [{
id: 'from-col',
Header: 'From',
accessor: 'txn.senderAddress',
Cell: ({ value }: { value: string }) => (
<QueryPreservingLink to={`/address/${hexAddrToZilAddr(value)}`}>
{hexAddrToZilAddr(value)}
</QueryPreservingLink>
)
}, {
id: 'to-col',
Header: 'To',
Cell: ({ row }: { row: Row<TransactionDetails> }) => {
return <ToAddrDisp txnDetails={row.original} />
}
}, {
id: 'hash-col',
Header: 'Hash',
Cell: ({ row }: { row: Row<TransactionDetails> }) => {
console.log(row)
return <QueryPreservingLink to={`/tx/0x${row.original.hash}`}>
<div className='text-right mono'>
{row.original.txn.txParams.receipt && !row.original.txn.txParams.receipt.success
&& <FontAwesomeIcon className='mr-1' icon={faExclamationCircle} color='red' />
}
{'0x' + row.original.hash}
</div>
</QueryPreservingLink>
}
}, {
id: 'amount-col',
Header: 'Amount',
accessor: 'txn.amount',
Cell: ({ value }: { value: string }) => (
<OverlayTrigger placement='right'
overlay={<Tooltip id={'amt-tt'}>{qaToZil(value)}</Tooltip>}>
<div className='text-right'>{qaToZil(value, 10)}</div>
</OverlayTrigger>
)
}, {
id: 'fee-col',
Header: 'Fee',
accessor: 'txn',
Cell: ({ value }: { value: Transaction }) => {
const fee = Number(value.txParams.gasPrice) * value.txParams.receipt!.cumulative_gas
return <OverlayTrigger placement='top'
overlay={<Tooltip id={'fee-tt'}>{qaToZil(fee)}</Tooltip>}>
<div className='text-center'>{qaToZil(fee, 4)}</div>
</OverlayTrigger>
}
}], []
)
const fetchData = useCallback(({ pageIndex }) => {
if (!txBlockTxns || !dataService) return
let receivedData: TransactionDetails[]
const getData = async () => {
try {
setIsLoadingTrans(true)
receivedData = await dataService.getTransactionsDetails(txBlockTxns.slice(pageIndex * 10, pageIndex * 10 + 10))
if (receivedData)
setTransactionData(receivedData)
} catch (e) {
console.log(e)
} finally {
setIsLoadingTrans(false)
}
}
getData()
}, [dataService, txBlockTxns])
return <>
{isLoading ? <div className='center-spinner'><Spinner animation="border" /></div> : null}
{error
? <NotFoundPage />
: <>
{latestTxBlockNum &&
<div className={isIsolatedServer ? 'txblock-header mb-3' : 'txblock-header'}>
<h3 className='mb-1'>
<span className='mr-1'>
<FontAwesomeIcon className='fa-icon' icon={faCubes} />
</span>
<span className='ml-2'>
Tx Block
</span>
{' '}
<span className='subtext'>#{blockNum}</span>
<LabelStar type='Tx Block' />
</h3>
<span>
<QueryPreservingLink
className={
isIsolatedServer
? parseInt(blockNum, 10) === 1 ? 'disabled mr-3' : 'mr-3'
: parseInt(blockNum, 10) === 0 ? 'disabled mr-3' : 'mr-3'}
to={`/txbk/${parseInt(blockNum, 10) - 1}`}>
<FontAwesomeIcon size='2x' className='fa-icon' icon={faCaretSquareLeft} />
</QueryPreservingLink>
<QueryPreservingLink
className={
isIsolatedServer
? parseInt(blockNum, 10) === latestTxBlockNum ? 'disabled' : ''
: parseInt(blockNum, 10) === latestTxBlockNum - 1 ? 'disabled' : ''}
to={`/txbk/${parseInt(blockNum, 10) + 1}`}>
<FontAwesomeIcon size='2x' className='fa-icon' icon={faCaretSquareRight} />
</QueryPreservingLink>
</span>
</div>
}
{txBlockObj && (
<>
<div className='subtext'>
<HashDisp hash={'0x' + txBlockObj.body.BlockHash} />
</div>
<Card className='txblock-details-card'>
<Card.Body>
<Container>
<BRow>
<BCol>
<div className='txblock-detail'>
<span>Date:</span>
<span>
{timestampToDisplay(txBlockObj.header.Timestamp)}
{' '}
({timestampToTimeago(txBlockObj.header.Timestamp)})
</span>
</div>
</BCol>
<BCol>
<div className='txblock-detail'>
<span>Transactions:</span>
<span>{txBlockObj.header.NumTxns}</span>
</div>
</BCol>
</BRow>
<BRow>
<BCol>
<div className='txblock-detail'>
<span>Gas Limit:</span>
<span>{txBlockObj.header.GasLimit}</span>
</div>
</BCol>
<BCol>
<div className='txblock-detail'>
<span>Gas Used:</span>
<span>{txBlockObj.header.GasUsed}</span>
</div>
</BCol>
</BRow>
<BRow>
<BCol>
<div className='txblock-detail'>
<span>Txn Fees:</span>
<span>{qaToZil(txBlockObj.header.TxnFees)}</span>
</div>
</BCol>
<BCol>
<div className='txblock-detail'>
<span>Rewards Fees:</span>
<span>{qaToZil(txBlockObj.header.Rewards)}</span>
</div>
</BCol>
</BRow>
<BRow>
<BCol>
<div className='txblock-detail'>
<span>DS Block:</span>
<span><QueryPreservingLink to={`/dsbk/${txBlockObj.header.DSBlockNum}`}>{txBlockObj.header.DSBlockNum}</QueryPreservingLink></span>
</div>
</BCol>
<BCol>
<div className='txblock-detail'>
<span>DS Leader:</span>
<span><QueryPreservingLink to={`/address/${pubKeyToZilAddr(txBlockObj.header.MinerPubKey)}`}>{pubKeyToZilAddr(txBlockObj.header.MinerPubKey)}</QueryPreservingLink></span>
</div>
</BCol>
</BRow>
</Container>
</Card.Body>
</Card>
{txBlockObj.body.MicroBlockInfos.length > 0 && (
<Card className='txblock-details-card mono'>
<Card.Body>
<Container>
<span>Micro Blocks</span>
{txBlockObj.body.MicroBlockInfos
.map((x) => (
<div key={x.MicroBlockHash}>[{x.MicroBlockShardId}] {x.MicroBlockHash}</div>
))}
</Container>
</Card.Body>
</Card>
)}
</>
)}
{txBlockTxns && txBlockTxns.length > 0 && (
<>
<h4>Transactions</h4>
<ViewAllTable
isLoading={isLoadingTrans}
fetchData={fetchData}
pageCount={Math.ceil(txBlockTxns.length / 10)}
columns={columns}
data={transactionData ? transactionData : []} />
</>
)}
</>
}
</>
}
Example #29
Source File: TransactionsCard.tsx From devex with GNU General Public License v3.0 | 4 votes |
TransactionsCard: React.FC<IProps> = ({
transactions: txs,
addr,
fungibleToken,
}) => {
const transactions: any[] = txs.flatMap(
(tx: { receipt: { transitions: [] } }) => {
if (fungibleToken && tx.receipt.transitions.length) {
console.log(tx.receipt.transitions);
const tokenTx: any | undefined = tx.receipt.transitions.find(
(transition: { msg: { _tag: string } }) =>
transition.msg._tag === "TransferSuccessCallBack"
);
if (tokenTx !== undefined) {
const toAddr = tokenTx.msg.params.find(
(p: any) => p.vname === "recipient"
);
const fromAddr = tokenTx.msg.params.find(
(p: any) => p.vname === "sender"
);
const amount = tokenTx.msg.params.find(
(p: any) => p.vname === "amount"
);
return [
{ ...tx },
{
...tx,
ID: "token-transfer",
toAddr: toAddr.value,
fromAddr: fromAddr.value,
amount: amount.value,
type: "token-transfer",
fungibleToken,
},
];
}
}
return {
...tx,
};
}
);
const columns = useMemo(
() => [
{
id: "alert-col",
Header: "",
Cell: ({ row }: { row: any }) => {
return (
<div className="d-flex align-items-center justify-content-start">
{row.original.receipt && !row.original.receipt.success && (
<FontAwesomeIcon icon={faExclamationCircle} color="red" />
)}
<AgeDisplay className="ml-2" timestamp={row.original.timestamp} />
</div>
);
},
},
{
id: "hash-col",
Header: "Hash",
accessor: "hash",
Cell: ({ row }: { row: any }) => {
return row.original.ID !== "token-transfer" ? (
<QueryPreservingLink
to={`/tx/0x${row.original.ID}`}
className="d-flex"
>
<div className="text-right mono ellipsis">
{"0x" + row.original.ID}
</div>
</QueryPreservingLink>
) : (
`${fungibleToken.name.value} Transfer`
);
},
},
{
id: "from-col",
Header: "From",
accessor: "fromAddr",
Cell: ({ value }: { value: string }) => {
const ziladdr = hexAddrToZilAddr(value);
return (
<>
{addr === ziladdr ? (
<span className="text-muted">{addr}</span>
) : (
<QueryPreservingLink to={`/address/${ziladdr}`}>
{ziladdr}
</QueryPreservingLink>
)}
</>
);
},
},
{
id: "type-col",
Header: "",
Cell: ({ row }: { row: any }) => {
console.log(row.original);
return (
<>
<TypeDisplay
fromAddr={row.original.fromAddr}
toAddr={row.original.toAddr}
addr={addr}
type={row.original.type}
/>
</>
);
},
},
{
id: "to-col",
Header: "To",
Cell: ({ row }: { row: any }) => {
return (
<ToAddrDispSimplified
fromAddr={row.original.fromAddr}
toAddr={row.original.toAddr}
txType={row.original.type}
addr={addr}
/>
);
},
},
{
id: "amount-col",
Header: "Amount",
Cell: ({ row }: any) => {
const value = row.original.amount;
let formattedValue: string =
numbro(qaToZilSimplified(value)).format({
thousandSeparated: true,
mantissa: 3,
}) + " ZIL";
if (row.original.ID === "token-transfer") {
formattedValue =
value / Math.pow(10, parseInt(fungibleToken.decimals.value)) +
` ${fungibleToken.symbol.value}`;
}
return (
<OverlayTrigger
placement="top"
overlay={
<Tooltip id={"amt-tt"}>
{numbro(value).format({ thousandSeparated: true })}
</Tooltip>
}
>
<div className="text-right sm">{formattedValue}</div>
</OverlayTrigger>
);
},
},
{
id: "fee-col",
Header: "Fee",
Cell: ({ row }: any) => {
const fee =
parseFloat(row.original.receipt.cumulative_gas) *
row.original.gasPrice;
return (
<OverlayTrigger
placement="top"
overlay={<Tooltip id={"fee-tt"}>{fee} Qa</Tooltip>}
>
<div className="text-center sm">{qaToZil(fee, 4)}</div>
</OverlayTrigger>
);
},
},
],
[addr]
);
return (
<div>
<DisplayTable columns={columns} data={transactions} />
</div>
);
}